examples: use factorized default Rx/Tx configuration
[dpdk.git] / examples / vmdq / 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 #define MAX_QUEUES 128
76 /*
77  * For 10 GbE, 128 queues require roughly
78  * 128*512 (RX/TX_queue_nb * RX/TX_ring_descriptors_nb) per port.
79  */
80 #define NUM_MBUFS_PER_PORT (128*512)
81 #define MBUF_CACHE_SIZE 64
82 #define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
83
84 #define MAX_PKT_BURST 32
85
86 /*
87  * Configurable number of RX/TX ring descriptors
88  */
89 #define RTE_TEST_RX_DESC_DEFAULT 128
90 #define RTE_TEST_TX_DESC_DEFAULT 512
91
92 #define INVALID_PORT_ID 0xFF
93
94 /* mask of enabled ports */
95 static uint32_t enabled_port_mask = 0;
96
97 /* number of pools (if user does not specify any, 8 by default */
98 static uint32_t num_queues = 8;
99 static uint32_t num_pools = 8;
100
101 /* empty vmdq configuration structure. Filled in programatically */
102 static const struct rte_eth_conf vmdq_conf_default = {
103         .rxmode = {
104                 .mq_mode        = ETH_MQ_RX_VMDQ_ONLY,
105                 .split_hdr_size = 0,
106                 .header_split   = 0, /**< Header Split disabled */
107                 .hw_ip_checksum = 0, /**< IP checksum offload disabled */
108                 .hw_vlan_filter = 0, /**< VLAN filtering disabled */
109                 .jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
110         },
111
112         .txmode = {
113                 .mq_mode = ETH_MQ_TX_NONE,
114         },
115         .rx_adv_conf = {
116                 /*
117                  * should be overridden separately in code with
118                  * appropriate values
119                  */
120                 .vmdq_rx_conf = {
121                         .nb_queue_pools = ETH_8_POOLS,
122                         .enable_default_pool = 0,
123                         .default_pool = 0,
124                         .nb_pool_maps = 0,
125                         .pool_map = {{0, 0},},
126                 },
127         },
128 };
129
130 static unsigned lcore_ids[RTE_MAX_LCORE];
131 static uint8_t ports[RTE_MAX_ETHPORTS];
132 static unsigned num_ports = 0; /**< The number of ports specified in command line */
133
134 /* array used for printing out statistics */
135 volatile unsigned long rxPackets[ MAX_QUEUES ] = {0};
136
137 const uint16_t vlan_tags[] = {
138         0,  1,  2,  3,  4,  5,  6,  7,
139         8,  9, 10, 11,  12, 13, 14, 15,
140         16, 17, 18, 19, 20, 21, 22, 23,
141         24, 25, 26, 27, 28, 29, 30, 31,
142         32, 33, 34, 35, 36, 37, 38, 39,
143         40, 41, 42, 43, 44, 45, 46, 47,
144         48, 49, 50, 51, 52, 53, 54, 55,
145         56, 57, 58, 59, 60, 61, 62, 63,
146 };
147
148 /* ethernet addresses of ports */
149 static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS];
150
151 #define MAX_QUEUE_NUM_10G 128
152 #define MAX_QUEUE_NUM_1G 8
153 #define MAX_POOL_MAP_NUM_10G 64
154 #define MAX_POOL_MAP_NUM_1G 32
155 #define MAX_POOL_NUM_10G 64
156 #define MAX_POOL_NUM_1G 8
157 /* Builds up the correct configuration for vmdq based on the vlan tags array
158  * given above, and determine the queue number and pool map number according to valid pool number */
159 static inline int
160 get_eth_conf(struct rte_eth_conf *eth_conf, uint32_t num_pools)
161 {
162         struct rte_eth_vmdq_rx_conf conf;
163         unsigned i;
164
165         conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
166         conf.enable_default_pool = 0;
167         conf.default_pool = 0; /* set explicit value, even if not used */
168         switch (num_pools) {
169         /* For 10G NIC like 82599, 128 is valid for queue number */
170         case MAX_POOL_NUM_10G:
171                 num_queues = MAX_QUEUE_NUM_10G;
172                 conf.nb_pool_maps = MAX_POOL_MAP_NUM_10G;
173                 break;
174         /* For 1G NIC like i350, 82580 and 82576, 8 is valid for queue number */
175         case MAX_POOL_NUM_1G:
176                 num_queues = MAX_QUEUE_NUM_1G;
177                 conf.nb_pool_maps = MAX_POOL_MAP_NUM_1G;
178                 break;
179         default:
180                 return -1;
181         }
182
183         for (i = 0; i < conf.nb_pool_maps; i++){
184                 conf.pool_map[i].vlan_id = vlan_tags[ i ];
185                 conf.pool_map[i].pools = (1UL << (i % num_pools));
186         }
187
188         (void)(rte_memcpy(eth_conf, &vmdq_conf_default, sizeof(*eth_conf)));
189         (void)(rte_memcpy(&eth_conf->rx_adv_conf.vmdq_rx_conf, &conf,
190                    sizeof(eth_conf->rx_adv_conf.vmdq_rx_conf)));
191         return 0;
192 }
193
194 /*
195  * Validate the pool number accrording to the max pool number gotten form dev_info
196  * If the pool number is invalid, give the error message and return -1
197  */
198 static inline int
199 validate_num_pools(uint32_t max_nb_pools)
200 {
201         if (num_pools > max_nb_pools) {
202                 printf("invalid number of pools\n");
203                 return -1;
204         }
205
206         switch (max_nb_pools) {
207         /* For 10G NIC like 82599, 64 is valid for pool number */
208         case MAX_POOL_NUM_10G:
209                 if (num_pools != MAX_POOL_NUM_10G) {
210                         printf("invalid number of pools\n");
211                         return -1;
212                 }
213                 break;
214         /* For 1G NIC like i350, 82580 and 82576, 8 is valid for pool number */
215         case MAX_POOL_NUM_1G:
216                 if (num_pools != MAX_POOL_NUM_1G) {
217                         printf("invalid number of pools\n");
218                         return -1;
219                 }
220                 break;
221         default:
222                 return -1;
223         }
224
225         return 0;
226 }
227
228 /*
229  * Initialises a given port using global settings and with the rx buffers
230  * coming from the mbuf_pool passed as parameter
231  */
232 static inline int
233 port_init(uint8_t port, struct rte_mempool *mbuf_pool)
234 {
235         struct rte_eth_dev_info dev_info;
236         struct rte_eth_rxconf *rxconf;
237         struct rte_eth_conf port_conf;
238         uint16_t rxRings, txRings = (uint16_t)rte_lcore_count();
239         const uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT, txRingSize = RTE_TEST_TX_DESC_DEFAULT;
240         int retval;
241         uint16_t q;
242         uint32_t max_nb_pools;
243
244         /* The max pool number from dev_info will be used to validate the pool number specified in cmd line */
245         rte_eth_dev_info_get (port, &dev_info);
246         max_nb_pools = (uint32_t)dev_info.max_vmdq_pools;
247         retval = validate_num_pools(max_nb_pools);
248         if (retval < 0)
249                 return retval;
250
251         retval = get_eth_conf(&port_conf, num_pools);
252         if (retval < 0)
253                 return retval;
254
255         if (port >= rte_eth_dev_count()) return -1;
256
257         rxRings = (uint16_t)num_queues,
258         retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
259         if (retval != 0)
260                 return retval;
261
262         rte_eth_dev_info_get(port, &dev_info);
263         rxconf = &dev_info.default_rxconf;
264         rxconf->rx_drop_en = 1;
265         for (q = 0; q < rxRings; q ++) {
266                 retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
267                                         rte_eth_dev_socket_id(port),
268                                         rxconf,
269                                         mbuf_pool);
270                 if (retval < 0)
271                         return retval;
272         }
273
274         for (q = 0; q < txRings; q ++) {
275                 retval = rte_eth_tx_queue_setup(port, q, txRingSize,
276                                         rte_eth_dev_socket_id(port),
277                                         NULL);
278                 if (retval < 0)
279                         return retval;
280         }
281
282         retval  = rte_eth_dev_start(port);
283         if (retval < 0)
284                 return retval;
285
286         rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]);
287         printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
288                         " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
289                         (unsigned)port,
290                         vmdq_ports_eth_addr[port].addr_bytes[0],
291                         vmdq_ports_eth_addr[port].addr_bytes[1],
292                         vmdq_ports_eth_addr[port].addr_bytes[2],
293                         vmdq_ports_eth_addr[port].addr_bytes[3],
294                         vmdq_ports_eth_addr[port].addr_bytes[4],
295                         vmdq_ports_eth_addr[port].addr_bytes[5]);
296
297         return 0;
298 }
299
300 /* Check num_pools parameter and set it if OK*/
301 static int
302 vmdq_parse_num_pools(const char *q_arg)
303 {
304         char *end = NULL;
305         int n;
306
307         /* parse number string */
308         n = strtol(q_arg, &end, 10);
309         if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
310                 return -1;
311
312         num_pools = n;
313
314         return 0;
315 }
316
317
318 static int
319 parse_portmask(const char *portmask)
320 {
321         char *end = NULL;
322         unsigned long pm;
323
324         /* parse hexadecimal string */
325         pm = strtoul(portmask, &end, 16);
326         if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
327                 return -1;
328
329         if (pm == 0)
330                 return -1;
331
332         return pm;
333 }
334
335 /* Display usage */
336 static void
337 vmdq_usage(const char *prgname)
338 {
339         printf("%s [EAL options] -- -p PORTMASK]\n"
340         "  --nb-pools NP: number of pools\n",
341                prgname);
342 }
343
344 /*  Parse the argument (num_pools) given in the command line of the application */
345 static int
346 vmdq_parse_args(int argc, char **argv)
347 {
348         int opt;
349         int option_index;
350         unsigned i;
351         const char *prgname = argv[0];
352         static struct option long_option[] = {
353                 {"nb-pools", required_argument, NULL, 0},
354                 {NULL, 0, 0, 0}
355         };
356
357         /* Parse command line */
358         while ((opt = getopt_long(argc, argv, "p:",long_option,&option_index)) != EOF) {
359                 switch (opt) {
360                 /* portmask */
361                 case 'p':
362                         enabled_port_mask = parse_portmask(optarg);
363                         if (enabled_port_mask == 0) {
364                                 printf("invalid portmask\n");
365                                 vmdq_usage(prgname);
366                                 return -1;
367                         }
368                         break;
369                 case 0:
370                         if (vmdq_parse_num_pools(optarg) == -1){
371                                 printf("invalid number of pools\n");
372                                 vmdq_usage(prgname);
373                                 return -1;
374                         }
375                         break;
376
377                 default:
378                         vmdq_usage(prgname);
379                         return -1;
380                 }
381         }
382
383         for(i = 0; i < RTE_MAX_ETHPORTS; i++) {
384                 if (enabled_port_mask & (1 << i))
385                         ports[num_ports++] = (uint8_t)i;
386         }
387
388         if (num_ports < 2 || num_ports % 2) {
389                 printf("Current enabled port number is %u,"
390                         "but it should be even and at least 2\n",num_ports);
391                 return -1;
392         }
393
394         return 0;
395 }
396
397 static void
398 update_mac_address(struct rte_mbuf *m, unsigned dst_port)
399 {
400         struct ether_hdr *eth;
401         void *tmp;
402
403         eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
404
405         /* 02:00:00:00:00:xx */
406         tmp = &eth->d_addr.addr_bytes[0];
407         *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
408
409         /* src addr */
410         ether_addr_copy(&vmdq_ports_eth_addr[dst_port], &eth->s_addr);
411 }
412
413 #ifndef RTE_EXEC_ENV_BAREMETAL
414 /* When we receive a HUP signal, print out our stats */
415 static void
416 sighup_handler(int signum)
417 {
418         unsigned q;
419         for (q = 0; q < num_queues; q ++) {
420                 if (q % (num_queues/num_pools) == 0)
421                         printf("\nPool %u: ", q/(num_queues/num_pools));
422                 printf("%lu ", rxPackets[ q ]);
423         }
424         printf("\nFinished handling signal %d\n", signum);
425 }
426 #endif
427
428 /*
429  * Main thread that does the work, reading from INPUT_PORT
430  * and writing to OUTPUT_PORT
431  */
432 static int
433 lcore_main(__attribute__((__unused__)) void* dummy)
434 {
435         const uint16_t lcore_id = (uint16_t)rte_lcore_id();
436         const uint16_t num_cores = (uint16_t)rte_lcore_count();
437         uint16_t core_id = 0;
438         uint16_t startQueue, endQueue;
439         uint16_t q, i, p;
440         const uint16_t remainder = (uint16_t)(num_queues % num_cores);
441
442         for (i = 0; i < num_cores; i ++)
443                 if (lcore_ids[i] == lcore_id) {
444                         core_id = i;
445                         break;
446                 }
447
448         if (remainder != 0) {
449                 if (core_id < remainder) {
450                         startQueue = (uint16_t)(core_id * (num_queues/num_cores + 1));
451                         endQueue = (uint16_t)(startQueue + (num_queues/num_cores) + 1);
452                 } else {
453                         startQueue = (uint16_t)(core_id * (num_queues/num_cores) + remainder);
454                         endQueue = (uint16_t)(startQueue + (num_queues/num_cores));
455                 }
456         } else {
457                 startQueue = (uint16_t)(core_id * (num_queues/num_cores));
458                 endQueue = (uint16_t)(startQueue + (num_queues/num_cores));
459         }
460
461         printf("core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_id,
462                 (unsigned)lcore_id, startQueue, endQueue - 1);
463
464         if (startQueue == endQueue) {
465                 printf("lcore %u has nothing to do\n", lcore_id);
466                 return (0);
467         }
468
469         for (;;) {
470                 struct rte_mbuf *buf[MAX_PKT_BURST];
471                 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
472
473                 for (p = 0; p < num_ports; p++) {
474                         const uint8_t sport = ports[p];
475                         const uint8_t dport = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
476
477                         if ((sport == INVALID_PORT_ID) || (dport == INVALID_PORT_ID))
478                                 continue;
479
480                         for (q = startQueue; q < endQueue; q++) {
481                                 const uint16_t rxCount = rte_eth_rx_burst(sport,
482                                         q, buf, buf_size);
483
484                                 if (unlikely(rxCount == 0))
485                                         continue;
486
487                                 rxPackets[q] += rxCount;
488
489                                 for (i = 0; i < rxCount; i++)
490                                         update_mac_address(buf[i], dport);
491
492                                 const uint16_t txCount = rte_eth_tx_burst(dport,
493                                         core_id, buf, rxCount);
494
495                                 if (txCount != rxCount) {
496                                         for (i = txCount; i < rxCount; i++)
497                                                 rte_pktmbuf_free(buf[i]);
498                                 }
499                         }
500                 }
501         }
502 }
503
504 /*
505  * Update the global var NUM_PORTS and array PORTS according to system ports number
506  * and return valid ports number
507  */
508 static unsigned check_ports_num(unsigned nb_ports)
509 {
510         unsigned valid_num_ports = num_ports;
511         unsigned portid;
512
513         if (num_ports > nb_ports) {
514                 printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
515                         num_ports, nb_ports);
516                 num_ports = nb_ports;
517         }
518
519         for (portid = 0; portid < num_ports; portid ++) {
520                 if (ports[portid] >= nb_ports) {
521                         printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
522                                 ports[portid], (nb_ports - 1));
523                         ports[portid] = INVALID_PORT_ID;
524                         valid_num_ports --;
525                 }
526         }
527         return valid_num_ports;
528 }
529
530 /* Main function, does initialisation and calls the per-lcore functions */
531 int
532 MAIN(int argc, char *argv[])
533 {
534         struct rte_mempool *mbuf_pool;
535         unsigned lcore_id, core_id = 0;
536         int ret;
537         unsigned nb_ports, valid_num_ports;
538         uint8_t portid;
539
540 #ifndef RTE_EXEC_ENV_BAREMETAL
541         signal(SIGHUP, sighup_handler);
542 #endif
543
544         /* init EAL */
545         ret = rte_eal_init(argc, argv);
546         if (ret < 0)
547                 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
548         argc -= ret;
549         argv += ret;
550
551         /* parse app arguments */
552         ret = vmdq_parse_args(argc, argv);
553         if (ret < 0)
554                 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
555
556         for (lcore_id = 0; lcore_id < RTE_MAX_LCORE; lcore_id ++)
557                 if (rte_lcore_is_enabled(lcore_id))
558                         lcore_ids[core_id ++] = lcore_id;
559
560         if (rte_lcore_count() > RTE_MAX_LCORE)
561                 rte_exit(EXIT_FAILURE,"Not enough cores\n");
562
563         nb_ports = rte_eth_dev_count();
564         if (nb_ports > RTE_MAX_ETHPORTS)
565                 nb_ports = RTE_MAX_ETHPORTS;
566
567         /*
568          * Update the global var NUM_PORTS and global array PORTS
569          * and get value of var VALID_NUM_PORTS according to system ports number
570          */
571         valid_num_ports = check_ports_num(nb_ports);
572
573         if (valid_num_ports < 2 || valid_num_ports % 2) {
574                 printf("Current valid ports number is %u\n", valid_num_ports);
575                 rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
576         }
577
578         mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS_PER_PORT * nb_ports,
579                                        MBUF_SIZE, MBUF_CACHE_SIZE,
580                                        sizeof(struct rte_pktmbuf_pool_private),
581                                        rte_pktmbuf_pool_init, NULL,
582                                        rte_pktmbuf_init, NULL,
583                                        rte_socket_id(), 0);
584         if (mbuf_pool == NULL)
585                 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
586
587         /* initialize all ports */
588         for (portid = 0; portid < nb_ports; portid++) {
589                 /* skip ports that are not enabled */
590                 if ((enabled_port_mask & (1 << portid)) == 0) {
591                         printf("\nSkipping disabled port %d\n", portid);
592                         continue;
593                 }
594                 if (port_init(portid, mbuf_pool) != 0)
595                         rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
596         }
597
598         /* call lcore_main() on every lcore */
599         rte_eal_mp_remote_launch(lcore_main, NULL, CALL_MASTER);
600         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
601                 if (rte_eal_wait_lcore(lcore_id) < 0)
602                         return -1;
603         }
604
605         return 0;
606 }