update Intel copyright years to 2014
[dpdk.git] / examples / vmdq_dcb / main.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  * 
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  * 
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  * 
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stdint.h>
35 #include <sys/queue.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <assert.h>
40 #include <errno.h>
41 #include <signal.h>
42 #include <stdarg.h>
43 #include <inttypes.h>
44 #include <getopt.h>
45
46 #include <rte_common.h>
47 #include <rte_log.h>
48 #include <rte_memory.h>
49 #include <rte_memcpy.h>
50 #include <rte_memzone.h>
51 #include <rte_tailq.h>
52 #include <rte_eal.h>
53 #include <rte_per_lcore.h>
54 #include <rte_launch.h>
55 #include <rte_atomic.h>
56 #include <rte_cycles.h>
57 #include <rte_prefetch.h>
58 #include <rte_lcore.h>
59 #include <rte_per_lcore.h>
60 #include <rte_branch_prediction.h>
61 #include <rte_interrupts.h>
62 #include <rte_pci.h>
63 #include <rte_random.h>
64 #include <rte_debug.h>
65 #include <rte_ether.h>
66 #include <rte_ethdev.h>
67 #include <rte_ring.h>
68 #include <rte_log.h>
69 #include <rte_mempool.h>
70 #include <rte_mbuf.h>
71 #include <rte_memcpy.h>
72
73 #include "main.h"
74
75 /* basic constants used in application */
76 #define NUM_QUEUES 128
77
78 #define NUM_MBUFS 64*1024
79 #define MBUF_CACHE_SIZE 64
80 #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
81
82 #define INVALID_PORT_ID 0xFF
83
84 /* mask of enabled ports */
85 static uint32_t enabled_port_mask = 0;
86
87 /* number of pools (if user does not specify any, 16 by default */
88 static enum rte_eth_nb_pools num_pools = ETH_16_POOLS;
89
90 /*
91  * RX and TX Prefetch, Host, and Write-back threshold values should be
92  * carefully set for optimal performance. Consult the network
93  * controller's datasheet and supporting DPDK documentation for guidance
94  * on how these parameters should be set.
95  */
96 /* Default configuration for rx and tx thresholds etc. */
97 static const struct rte_eth_rxconf rx_conf_default = {
98         .rx_thresh = {
99                 .pthresh = 8,
100                 .hthresh = 8,
101                 .wthresh = 4,
102         },
103 };
104
105 /*
106  * These default values are optimized for use with the Intel(R) 82599 10 GbE
107  * Controller and the DPDK ixgbe PMD. Consider using other values for other
108  * network controllers and/or network drivers.
109  */
110 static const struct rte_eth_txconf tx_conf_default = {
111         .tx_thresh = {
112                 .pthresh = 36,
113                 .hthresh = 0,
114                 .wthresh = 0,
115         },
116         .tx_free_thresh = 0, /* Use PMD default values */
117         .tx_rs_thresh = 0, /* Use PMD default values */
118 };
119
120 /* empty vmdq+dcb configuration structure. Filled in programatically */
121 static const struct rte_eth_conf vmdq_dcb_conf_default = {
122         .rxmode = {
123                 .mq_mode        = ETH_MQ_RX_VMDQ_DCB,
124                 .split_hdr_size = 0,
125                 .header_split   = 0, /**< Header Split disabled */
126                 .hw_ip_checksum = 0, /**< IP checksum offload disabled */
127                 .hw_vlan_filter = 0, /**< VLAN filtering disabled */
128                 .jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
129         },
130         .txmode = {
131                 .mq_mode = ETH_MQ_TX_NONE,
132         },
133         .rx_adv_conf = {
134                 /*
135                  * should be overridden separately in code with
136                  * appropriate values
137                  */
138                 .vmdq_dcb_conf = {
139                         .nb_queue_pools = ETH_16_POOLS,
140                         .enable_default_pool = 0,
141                         .default_pool = 0,
142                         .nb_pool_maps = 0,
143                         .pool_map = {{0, 0},},
144                         .dcb_queue = {0},
145                 },
146         },
147 };
148
149 static uint8_t ports[RTE_MAX_ETHPORTS];
150 static unsigned num_ports = 0;
151
152 /* array used for printing out statistics */
153 volatile unsigned long rxPackets[ NUM_QUEUES ] = {0};
154
155 const uint16_t vlan_tags[] = {
156         0,  1,  2,  3,  4,  5,  6,  7,
157         8,  9, 10, 11,  12, 13, 14, 15,
158         16, 17, 18, 19, 20, 21, 22, 23,
159         24, 25, 26, 27, 28, 29, 30, 31
160 };
161
162 /* Builds up the correct configuration for vmdq+dcb based on the vlan tags array
163  * given above, and the number of traffic classes available for use. */
164 static inline int
165 get_eth_conf(struct rte_eth_conf *eth_conf, enum rte_eth_nb_pools num_pools)
166 {
167         struct rte_eth_vmdq_dcb_conf conf;
168         unsigned i;
169
170         if (num_pools != ETH_16_POOLS && num_pools != ETH_32_POOLS ) return -1;
171
172         conf.nb_queue_pools = num_pools;
173         conf.enable_default_pool = 0;
174         conf.default_pool = 0; /* set explicit value, even if not used */
175         conf.nb_pool_maps = sizeof( vlan_tags )/sizeof( vlan_tags[ 0 ]);
176         for (i = 0; i < conf.nb_pool_maps; i++){
177                 conf.pool_map[i].vlan_id = vlan_tags[ i ];
178                 conf.pool_map[i].pools = 1 << (i % num_pools);
179         }
180         for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++){
181                 conf.dcb_queue[i] = (uint8_t)(i % (NUM_QUEUES/num_pools));
182         }
183         (void)(rte_memcpy(eth_conf, &vmdq_dcb_conf_default, sizeof(*eth_conf)));
184         (void)(rte_memcpy(&eth_conf->rx_adv_conf.vmdq_dcb_conf, &conf,
185                    sizeof(eth_conf->rx_adv_conf.vmdq_dcb_conf)));
186         return 0;
187 }
188
189 /*
190  * Initialises a given port using global settings and with the rx buffers
191  * coming from the mbuf_pool passed as parameter
192  */
193 static inline int
194 port_init(uint8_t port, struct rte_mempool *mbuf_pool)
195 {
196         struct rte_eth_conf port_conf;
197         const uint16_t rxRings = ETH_VMDQ_DCB_NUM_QUEUES,
198                 txRings = (uint16_t)rte_lcore_count();
199         const uint16_t rxRingSize = 128, txRingSize = 512;
200         int retval;
201         uint16_t q;
202
203         retval = get_eth_conf(&port_conf, num_pools);
204         if (retval < 0)
205                 return retval;
206
207         if (port >= rte_eth_dev_count()) return -1;
208
209         retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
210         if (retval != 0)
211                 return retval;
212
213         for (q = 0; q < rxRings; q ++) {
214                 retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
215                                                 rte_eth_dev_socket_id(port), &rx_conf_default,
216                                                 mbuf_pool);
217                 if (retval < 0)
218                         return retval;
219         }
220
221         for (q = 0; q < txRings; q ++) {
222                 retval = rte_eth_tx_queue_setup(port, q, txRingSize,
223                                                 rte_eth_dev_socket_id(port), &tx_conf_default);
224                 if (retval < 0)
225                         return retval;
226         }
227
228         retval  = rte_eth_dev_start(port);
229         if (retval < 0)
230                 return retval;
231
232         struct ether_addr addr;
233         rte_eth_macaddr_get(port, &addr);
234         printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
235                         " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
236                         (unsigned)port,
237                         addr.addr_bytes[0], addr.addr_bytes[1], addr.addr_bytes[2],
238                         addr.addr_bytes[3], addr.addr_bytes[4], addr.addr_bytes[5]);
239
240         return 0;
241 }
242
243 /* Check num_pools parameter and set it if OK*/
244 static int
245 vmdq_parse_num_pools(const char *q_arg)
246 {
247         char *end = NULL;
248         int n;
249
250         /* parse number string */
251         n = strtol(q_arg, &end, 10);
252         if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
253                 return -1;
254         if (n != 16 && n != 32)
255                 return -1;
256         if (n == 16)
257                 num_pools = ETH_16_POOLS;
258         else
259                 num_pools = ETH_32_POOLS;
260
261         return 0;
262 }
263
264 static int
265 parse_portmask(const char *portmask)
266 {
267         char *end = NULL;
268         unsigned long pm;
269
270         /* parse hexadecimal string */
271         pm = strtoul(portmask, &end, 16);
272         if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
273                 return -1;
274
275         if (pm == 0)
276                 return -1;
277
278         return pm;
279 }
280
281 /* Display usage */
282 static void
283 vmdq_usage(const char *prgname)
284 {
285         printf("%s [EAL options] -- -p PORTMASK]\n"
286                "  --nb-pools NP: number of pools (16 default, 32)\n",
287                prgname);
288 }
289
290 /*  Parse the argument (num_pools) given in the command line of the application */
291 static int
292 vmdq_parse_args(int argc, char **argv)
293 {
294         int opt;
295         int option_index;
296         unsigned i;
297         const char *prgname = argv[0];
298         static struct option long_option[] = {
299                 {"nb-pools", required_argument, NULL, 0},
300                 {NULL, 0, 0, 0}
301         };
302
303         /* Parse command line */
304         while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) {
305                 switch (opt) {
306                 /* portmask */
307                 case 'p':
308                         enabled_port_mask = parse_portmask(optarg);
309                         if (enabled_port_mask == 0) {
310                                 printf("invalid portmask\n");
311                                 vmdq_usage(prgname);
312                                 return -1;
313                         }
314                         break;
315                 case 0:
316                         if (vmdq_parse_num_pools(optarg) == -1){
317                                 printf("invalid number of pools\n");
318                                 vmdq_usage(prgname);
319                                 return -1;
320                         }
321                         break;
322                 default:
323                         vmdq_usage(prgname);
324                         return -1;
325                 }
326         }
327
328         for(i = 0; i < RTE_MAX_ETHPORTS; i++)
329         {
330                 if (enabled_port_mask & (1 << i))
331                         ports[num_ports++] = (uint8_t)i;
332         }
333
334         if (num_ports < 2 || num_ports % 2) {
335                 printf("Current enabled port number is %u,"
336                         "but it should be even and at least 2\n",num_ports);
337                 return -1;
338         }
339
340         return 0;
341 }
342
343
344 #ifndef RTE_EXEC_ENV_BAREMETAL
345 /* When we receive a HUP signal, print out our stats */
346 static void
347 sighup_handler(int signum)
348 {
349         unsigned q;
350         for (q = 0; q < NUM_QUEUES; q ++) {
351                 if (q % (NUM_QUEUES/num_pools) == 0)
352                         printf("\nPool %u: ", q/(NUM_QUEUES/num_pools));
353                 printf("%lu ", rxPackets[ q ]);
354         }
355         printf("\nFinished handling signal %d\n", signum);
356 }
357 #endif
358
359 /*
360  * Main thread that does the work, reading from INPUT_PORT
361  * and writing to OUTPUT_PORT
362  */
363 static  __attribute__((noreturn)) int
364 lcore_main(void *arg)
365 {
366         const uintptr_t core_num = (uintptr_t)arg;
367         const unsigned num_cores = rte_lcore_count();
368         uint16_t startQueue = (uint16_t)(core_num * (NUM_QUEUES/num_cores));
369         uint16_t endQueue = (uint16_t)(startQueue + (NUM_QUEUES/num_cores));
370         uint16_t q, i, p;
371         
372         printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num,
373                rte_lcore_id(), startQueue, endQueue - 1);
374
375         for (;;) {
376                 struct rte_mbuf *buf[32];
377                 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
378                 for (p = 0; p < num_ports; p++) {
379                         const uint8_t src = ports[p];
380                         const uint8_t dst = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
381
382                         if ((src == INVALID_PORT_ID) || (dst == INVALID_PORT_ID))
383                                 continue;
384
385                         for (q = startQueue; q < endQueue; q++) {
386                                 const uint16_t rxCount = rte_eth_rx_burst(src,
387                                         q, buf, buf_size);
388                                 if (rxCount == 0)
389                                         continue;
390                                 rxPackets[q] += rxCount;
391
392                                 const uint16_t txCount = rte_eth_tx_burst(dst,
393                                         (uint16_t)core_num, buf, rxCount);
394                                 if (txCount != rxCount) {
395                                         for (i = txCount; i < rxCount; i++)
396                                                 rte_pktmbuf_free(buf[i]);
397                                 }
398                         }
399                 }
400         }
401 }
402
403 /* 
404  * Update the global var NUM_PORTS and array PORTS according to system ports number
405  * and return valid ports number
406  */
407 static unsigned check_ports_num(unsigned nb_ports)
408 {
409         unsigned valid_num_ports = num_ports;
410         unsigned portid;
411  
412         if (num_ports > nb_ports) {
413                 printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
414                         num_ports, nb_ports);
415                 num_ports = nb_ports;
416         }
417  
418         for (portid = 0; portid < num_ports; portid ++) {
419                 if (ports[portid] >= nb_ports) {
420                         printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
421                                 ports[portid], (nb_ports - 1));
422                         ports[portid] = INVALID_PORT_ID;
423                         valid_num_ports --;
424                 }
425         }
426         return valid_num_ports;
427 }
428
429
430 /* Main function, does initialisation and calls the per-lcore functions */
431 int
432 MAIN(int argc, char *argv[])
433 {
434         unsigned cores;
435         struct rte_mempool *mbuf_pool;
436         unsigned lcore_id;
437         uintptr_t i;
438         int ret;
439         unsigned nb_ports, valid_num_ports;
440         uint8_t portid;
441
442 #ifndef RTE_EXEC_ENV_BAREMETAL
443         signal(SIGHUP, sighup_handler);
444 #endif
445
446         /* init EAL */
447         ret = rte_eal_init(argc, argv);
448         if (ret < 0)
449                 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
450         argc -= ret;
451         argv += ret;
452
453         /* parse app arguments */
454         ret = vmdq_parse_args(argc, argv);
455         if (ret < 0)
456                 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
457
458         if (rte_ixgbe_pmd_init() != 0 ||
459                         rte_eal_pci_probe() != 0)
460                 rte_exit(EXIT_FAILURE, "Error with NIC driver initialization\n");
461         
462         cores = rte_lcore_count();
463         if ((cores & (cores - 1)) != 0 || cores > 128) {
464                 rte_exit(EXIT_FAILURE,"This program can only run on an even"
465                                 "number of cores(1-128)\n\n");
466         }
467         
468         nb_ports = rte_eth_dev_count();
469         if (nb_ports > RTE_MAX_ETHPORTS)
470                 nb_ports = RTE_MAX_ETHPORTS;
471
472         /* 
473          * Update the global var NUM_PORTS and global array PORTS 
474          * and get value of var VALID_NUM_PORTS according to system ports number 
475          */
476         valid_num_ports = check_ports_num(nb_ports);
477  
478         if (valid_num_ports < 2 || valid_num_ports % 2) {
479                 printf("Current valid ports number is %u\n", valid_num_ports);
480                 rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
481         }
482
483         mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
484                                        MBUF_SIZE, MBUF_CACHE_SIZE,
485                                        sizeof(struct rte_pktmbuf_pool_private),
486                                        rte_pktmbuf_pool_init, NULL,
487                                        rte_pktmbuf_init, NULL,
488                                        rte_socket_id(), 0);
489         if (mbuf_pool == NULL)
490                 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
491
492         /* initialize all ports */
493         for (portid = 0; portid < nb_ports; portid++) {
494                 /* skip ports that are not enabled */
495                 if ((enabled_port_mask & (1 << portid)) == 0) {
496                         printf("\nSkipping disabled port %d\n", portid);
497                         continue;
498                 }
499                 if (port_init(portid, mbuf_pool) != 0) 
500                         rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
501         }
502
503         /* call lcore_main() on every slave lcore */
504         i = 0;
505         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
506                 rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id);
507         }
508         /* call on master too */
509         (void) lcore_main((void*)i);
510
511         return 0;
512 }