Imported Upstream version 16.11
[deb_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_eal.h>
52 #include <rte_per_lcore.h>
53 #include <rte_launch.h>
54 #include <rte_atomic.h>
55 #include <rte_cycles.h>
56 #include <rte_prefetch.h>
57 #include <rte_lcore.h>
58 #include <rte_per_lcore.h>
59 #include <rte_branch_prediction.h>
60 #include <rte_interrupts.h>
61 #include <rte_pci.h>
62 #include <rte_random.h>
63 #include <rte_debug.h>
64 #include <rte_ether.h>
65 #include <rte_ethdev.h>
66 #include <rte_log.h>
67 #include <rte_mempool.h>
68 #include <rte_mbuf.h>
69 #include <rte_memcpy.h>
70
71 /* basic constants used in application */
72 #define MAX_QUEUES 1024
73 /*
74  * 1024 queues require to meet the needs of a large number of vmdq_pools.
75  * (RX/TX_queue_nb * RX/TX_ring_descriptors_nb) per port.
76  */
77 #define NUM_MBUFS_PER_PORT (MAX_QUEUES * RTE_MAX(RTE_TEST_RX_DESC_DEFAULT, \
78                                                 RTE_TEST_TX_DESC_DEFAULT))
79 #define MBUF_CACHE_SIZE 64
80
81 #define MAX_PKT_BURST 32
82
83 /*
84  * Configurable number of RX/TX ring descriptors
85  */
86 #define RTE_TEST_RX_DESC_DEFAULT 128
87 #define RTE_TEST_TX_DESC_DEFAULT 512
88
89 #define INVALID_PORT_ID 0xFF
90
91 /* mask of enabled ports */
92 static uint32_t enabled_port_mask;
93 static uint8_t ports[RTE_MAX_ETHPORTS];
94 static unsigned num_ports;
95
96 /* number of pools (if user does not specify any, 32 by default */
97 static enum rte_eth_nb_pools num_pools = ETH_32_POOLS;
98 static enum rte_eth_nb_tcs   num_tcs   = ETH_4_TCS;
99 static uint16_t num_queues, num_vmdq_queues;
100 static uint16_t vmdq_pool_base, vmdq_queue_base;
101 static uint8_t rss_enable;
102
103 /* empty vmdq+dcb configuration structure. Filled in programatically */
104 static const struct rte_eth_conf vmdq_dcb_conf_default = {
105         .rxmode = {
106                 .mq_mode        = ETH_MQ_RX_VMDQ_DCB,
107                 .split_hdr_size = 0,
108                 .header_split   = 0, /**< Header Split disabled */
109                 .hw_ip_checksum = 0, /**< IP checksum offload disabled */
110                 .hw_vlan_filter = 0, /**< VLAN filtering disabled */
111                 .jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
112         },
113         .txmode = {
114                 .mq_mode = ETH_MQ_TX_VMDQ_DCB,
115         },
116         /*
117          * should be overridden separately in code with
118          * appropriate values
119          */
120         .rx_adv_conf = {
121                 .vmdq_dcb_conf = {
122                         .nb_queue_pools = ETH_32_POOLS,
123                         .enable_default_pool = 0,
124                         .default_pool = 0,
125                         .nb_pool_maps = 0,
126                         .pool_map = {{0, 0},},
127                         .dcb_tc = {0},
128                 },
129                 .dcb_rx_conf = {
130                                 .nb_tcs = ETH_4_TCS,
131                                 /** Traffic class each UP mapped to. */
132                                 .dcb_tc = {0},
133                 },
134                 .vmdq_rx_conf = {
135                         .nb_queue_pools = ETH_32_POOLS,
136                         .enable_default_pool = 0,
137                         .default_pool = 0,
138                         .nb_pool_maps = 0,
139                         .pool_map = {{0, 0},},
140                 },
141         },
142         .tx_adv_conf = {
143                 .vmdq_dcb_tx_conf = {
144                         .nb_queue_pools = ETH_32_POOLS,
145                         .dcb_tc = {0},
146                 },
147         },
148 };
149
150 /* array used for printing out statistics */
151 volatile unsigned long rxPackets[MAX_QUEUES] = {0};
152
153 const uint16_t vlan_tags[] = {
154         0,  1,  2,  3,  4,  5,  6,  7,
155         8,  9, 10, 11,  12, 13, 14, 15,
156         16, 17, 18, 19, 20, 21, 22, 23,
157         24, 25, 26, 27, 28, 29, 30, 31
158 };
159
160 const uint16_t num_vlans = RTE_DIM(vlan_tags);
161 /* pool mac addr template, pool mac addr is like: 52 54 00 12 port# pool# */
162 static struct ether_addr pool_addr_template = {
163         .addr_bytes = {0x52, 0x54, 0x00, 0x12, 0x00, 0x00}
164 };
165
166 /* ethernet addresses of ports */
167 static struct ether_addr vmdq_ports_eth_addr[RTE_MAX_ETHPORTS];
168
169 /* Builds up the correct configuration for vmdq+dcb based on the vlan tags array
170  * given above, and the number of traffic classes available for use. */
171 static inline int
172 get_eth_conf(struct rte_eth_conf *eth_conf)
173 {
174         struct rte_eth_vmdq_dcb_conf conf;
175         struct rte_eth_vmdq_rx_conf  vmdq_conf;
176         struct rte_eth_dcb_rx_conf   dcb_conf;
177         struct rte_eth_vmdq_dcb_tx_conf tx_conf;
178         uint8_t i;
179
180         conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
181         vmdq_conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
182         tx_conf.nb_queue_pools = (enum rte_eth_nb_pools)num_pools;
183         conf.nb_pool_maps = num_pools;
184         vmdq_conf.nb_pool_maps = num_pools;
185         conf.enable_default_pool = 0;
186         vmdq_conf.enable_default_pool = 0;
187         conf.default_pool = 0; /* set explicit value, even if not used */
188         vmdq_conf.default_pool = 0;
189
190         for (i = 0; i < conf.nb_pool_maps; i++) {
191                 conf.pool_map[i].vlan_id = vlan_tags[i];
192                 vmdq_conf.pool_map[i].vlan_id = vlan_tags[i];
193                 conf.pool_map[i].pools = 1UL << i;
194                 vmdq_conf.pool_map[i].pools = 1UL << i;
195         }
196         for (i = 0; i < ETH_DCB_NUM_USER_PRIORITIES; i++){
197                 conf.dcb_tc[i] = i % num_tcs;
198                 dcb_conf.dcb_tc[i] = i % num_tcs;
199                 tx_conf.dcb_tc[i] = i % num_tcs;
200         }
201         dcb_conf.nb_tcs = (enum rte_eth_nb_tcs)num_tcs;
202         (void)(rte_memcpy(eth_conf, &vmdq_dcb_conf_default, sizeof(*eth_conf)));
203         (void)(rte_memcpy(&eth_conf->rx_adv_conf.vmdq_dcb_conf, &conf,
204                           sizeof(conf)));
205         (void)(rte_memcpy(&eth_conf->rx_adv_conf.dcb_rx_conf, &dcb_conf,
206                           sizeof(dcb_conf)));
207         (void)(rte_memcpy(&eth_conf->rx_adv_conf.vmdq_rx_conf, &vmdq_conf,
208                           sizeof(vmdq_conf)));
209         (void)(rte_memcpy(&eth_conf->tx_adv_conf.vmdq_dcb_tx_conf, &tx_conf,
210                           sizeof(tx_conf)));
211         if (rss_enable) {
212                 eth_conf->rxmode.mq_mode = ETH_MQ_RX_VMDQ_DCB_RSS;
213                 eth_conf->rx_adv_conf.rss_conf.rss_hf = ETH_RSS_IP |
214                                                         ETH_RSS_UDP |
215                                                         ETH_RSS_TCP |
216                                                         ETH_RSS_SCTP;
217         }
218         return 0;
219 }
220
221 /*
222  * Initialises a given port using global settings and with the rx buffers
223  * coming from the mbuf_pool passed as parameter
224  */
225 static inline int
226 port_init(uint8_t port, struct rte_mempool *mbuf_pool)
227 {
228         struct rte_eth_dev_info dev_info;
229         struct rte_eth_conf port_conf = {0};
230         const uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT;
231         const uint16_t txRingSize = RTE_TEST_TX_DESC_DEFAULT;
232         int retval;
233         uint16_t q;
234         uint16_t queues_per_pool;
235         uint32_t max_nb_pools;
236
237         /*
238          * The max pool number from dev_info will be used to validate the pool
239          * number specified in cmd line
240          */
241         rte_eth_dev_info_get(port, &dev_info);
242         max_nb_pools = (uint32_t)dev_info.max_vmdq_pools;
243         /*
244          * We allow to process part of VMDQ pools specified by num_pools in
245          * command line.
246          */
247         if (num_pools > max_nb_pools) {
248                 printf("num_pools %d >max_nb_pools %d\n",
249                         num_pools, max_nb_pools);
250                 return -1;
251         }
252
253         /*
254          * NIC queues are divided into pf queues and vmdq queues.
255          * There is assumption here all ports have the same configuration!
256         */
257         vmdq_queue_base = dev_info.vmdq_queue_base;
258         vmdq_pool_base  = dev_info.vmdq_pool_base;
259         printf("vmdq queue base: %d pool base %d\n",
260                 vmdq_queue_base, vmdq_pool_base);
261         if (vmdq_pool_base == 0) {
262                 num_vmdq_queues = dev_info.max_rx_queues;
263                 num_queues = dev_info.max_rx_queues;
264                 if (num_tcs != num_vmdq_queues / num_pools) {
265                         printf("nb_tcs %d is invalid considering with"
266                                 " nb_pools %d, nb_tcs * nb_pools should = %d\n",
267                                 num_tcs, num_pools, num_vmdq_queues);
268                         return -1;
269                 }
270         } else {
271                 queues_per_pool = dev_info.vmdq_queue_num /
272                                   dev_info.max_vmdq_pools;
273                 if (num_tcs > queues_per_pool) {
274                         printf("num_tcs %d > num of queues per pool %d\n",
275                                 num_tcs, queues_per_pool);
276                         return -1;
277                 }
278                 num_vmdq_queues = num_pools * queues_per_pool;
279                 num_queues = vmdq_queue_base + num_vmdq_queues;
280                 printf("Configured vmdq pool num: %u,"
281                         " each vmdq pool has %u queues\n",
282                         num_pools, queues_per_pool);
283         }
284
285         if (port >= rte_eth_dev_count())
286                 return -1;
287
288         retval = get_eth_conf(&port_conf);
289         if (retval < 0)
290                 return retval;
291
292         /*
293          * Though in this example, all queues including pf queues are setup.
294          * This is because VMDQ queues doesn't always start from zero, and the
295          * PMD layer doesn't support selectively initialising part of rx/tx
296          * queues.
297          */
298         retval = rte_eth_dev_configure(port, num_queues, num_queues, &port_conf);
299         if (retval != 0)
300                 return retval;
301
302         for (q = 0; q < num_queues; q++) {
303                 retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
304                                         rte_eth_dev_socket_id(port),
305                                         NULL,
306                                         mbuf_pool);
307                 if (retval < 0) {
308                         printf("initialize rx queue %d failed\n", q);
309                         return retval;
310                 }
311         }
312
313         for (q = 0; q < num_queues; q++) {
314                 retval = rte_eth_tx_queue_setup(port, q, txRingSize,
315                                         rte_eth_dev_socket_id(port),
316                                         NULL);
317                 if (retval < 0) {
318                         printf("initialize tx queue %d failed\n", q);
319                         return retval;
320                 }
321         }
322
323         retval  = rte_eth_dev_start(port);
324         if (retval < 0) {
325                 printf("port %d start failed\n", port);
326                 return retval;
327         }
328
329         rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]);
330         printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
331                         " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
332                         (unsigned)port,
333                         vmdq_ports_eth_addr[port].addr_bytes[0],
334                         vmdq_ports_eth_addr[port].addr_bytes[1],
335                         vmdq_ports_eth_addr[port].addr_bytes[2],
336                         vmdq_ports_eth_addr[port].addr_bytes[3],
337                         vmdq_ports_eth_addr[port].addr_bytes[4],
338                         vmdq_ports_eth_addr[port].addr_bytes[5]);
339
340         /* Set mac for each pool.*/
341         for (q = 0; q < num_pools; q++) {
342                 struct ether_addr mac;
343
344                 mac = pool_addr_template;
345                 mac.addr_bytes[4] = port;
346                 mac.addr_bytes[5] = q;
347                 printf("Port %u vmdq pool %u set mac %02x:%02x:%02x:%02x:%02x:%02x\n",
348                         port, q,
349                         mac.addr_bytes[0], mac.addr_bytes[1],
350                         mac.addr_bytes[2], mac.addr_bytes[3],
351                         mac.addr_bytes[4], mac.addr_bytes[5]);
352                 retval = rte_eth_dev_mac_addr_add(port, &mac,
353                                 q + vmdq_pool_base);
354                 if (retval) {
355                         printf("mac addr add failed at pool %d\n", q);
356                         return retval;
357                 }
358         }
359
360         return 0;
361 }
362
363 /* Check num_pools parameter and set it if OK*/
364 static int
365 vmdq_parse_num_pools(const char *q_arg)
366 {
367         char *end = NULL;
368         int n;
369
370         /* parse number string */
371         n = strtol(q_arg, &end, 10);
372         if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
373                 return -1;
374         if (n != 16 && n != 32)
375                 return -1;
376         if (n == 16)
377                 num_pools = ETH_16_POOLS;
378         else
379                 num_pools = ETH_32_POOLS;
380
381         return 0;
382 }
383
384 /* Check num_tcs parameter and set it if OK*/
385 static int
386 vmdq_parse_num_tcs(const char *q_arg)
387 {
388         char *end = NULL;
389         int n;
390
391         /* parse number string */
392         n = strtol(q_arg, &end, 10);
393         if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
394                 return -1;
395
396         if (n != 4 && n != 8)
397                 return -1;
398         if (n == 4)
399                 num_tcs = ETH_4_TCS;
400         else
401                 num_tcs = ETH_8_TCS;
402
403         return 0;
404 }
405
406 static int
407 parse_portmask(const char *portmask)
408 {
409         char *end = NULL;
410         unsigned long pm;
411
412         /* parse hexadecimal string */
413         pm = strtoul(portmask, &end, 16);
414         if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
415                 return -1;
416
417         if (pm == 0)
418                 return -1;
419
420         return pm;
421 }
422
423 /* Display usage */
424 static void
425 vmdq_usage(const char *prgname)
426 {
427         printf("%s [EAL options] -- -p PORTMASK]\n"
428         "  --nb-pools NP: number of pools (32 default, 16)\n"
429         "  --nb-tcs NP: number of TCs (4 default, 8)\n"
430         "  --enable-rss: enable RSS (disabled by default)\n",
431                prgname);
432 }
433
434 /*  Parse the argument (num_pools) given in the command line of the application */
435 static int
436 vmdq_parse_args(int argc, char **argv)
437 {
438         int opt;
439         int option_index;
440         unsigned i;
441         const char *prgname = argv[0];
442         static struct option long_option[] = {
443                 {"nb-pools", required_argument, NULL, 0},
444                 {"nb-tcs", required_argument, NULL, 0},
445                 {"enable-rss", 0, NULL, 0},
446                 {NULL, 0, 0, 0}
447         };
448
449         /* Parse command line */
450         while ((opt = getopt_long(argc, argv, "p:", long_option,
451                 &option_index)) != EOF) {
452                 switch (opt) {
453                 /* portmask */
454                 case 'p':
455                         enabled_port_mask = parse_portmask(optarg);
456                         if (enabled_port_mask == 0) {
457                                 printf("invalid portmask\n");
458                                 vmdq_usage(prgname);
459                                 return -1;
460                         }
461                         break;
462                 case 0:
463                         if (!strcmp(long_option[option_index].name, "nb-pools")) {
464                                 if (vmdq_parse_num_pools(optarg) == -1) {
465                                         printf("invalid number of pools\n");
466                                         return -1;
467                                 }
468                         }
469
470                         if (!strcmp(long_option[option_index].name, "nb-tcs")) {
471                                 if (vmdq_parse_num_tcs(optarg) == -1) {
472                                         printf("invalid number of tcs\n");
473                                         return -1;
474                                 }
475                         }
476
477                         if (!strcmp(long_option[option_index].name, "enable-rss"))
478                                 rss_enable = 1;
479                         break;
480
481                 default:
482                         vmdq_usage(prgname);
483                         return -1;
484                 }
485         }
486
487         for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
488                 if (enabled_port_mask & (1 << i))
489                         ports[num_ports++] = (uint8_t)i;
490         }
491
492         if (num_ports < 2 || num_ports % 2) {
493                 printf("Current enabled port number is %u,"
494                         " but it should be even and at least 2\n", num_ports);
495                 return -1;
496         }
497
498         return 0;
499 }
500
501 static void
502 update_mac_address(struct rte_mbuf *m, unsigned dst_port)
503 {
504         struct ether_hdr *eth;
505         void *tmp;
506
507         eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
508
509         /* 02:00:00:00:00:xx */
510         tmp = &eth->d_addr.addr_bytes[0];
511         *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
512
513         /* src addr */
514         ether_addr_copy(&vmdq_ports_eth_addr[dst_port], &eth->s_addr);
515 }
516
517 /* When we receive a HUP signal, print out our stats */
518 static void
519 sighup_handler(int signum)
520 {
521         unsigned q = vmdq_queue_base;
522
523         for (; q < num_queues; q++) {
524                 if (q % (num_vmdq_queues / num_pools) == 0)
525                         printf("\nPool %u: ", (q - vmdq_queue_base) /
526                                               (num_vmdq_queues / num_pools));
527                 printf("%lu ", rxPackets[q]);
528         }
529         printf("\nFinished handling signal %d\n", signum);
530 }
531
532 /*
533  * Main thread that does the work, reading from INPUT_PORT
534  * and writing to OUTPUT_PORT
535  */
536 static int
537 lcore_main(void *arg)
538 {
539         const uintptr_t core_num = (uintptr_t)arg;
540         const unsigned num_cores = rte_lcore_count();
541         uint16_t startQueue, endQueue;
542         uint16_t q, i, p;
543         const uint16_t quot = (uint16_t)(num_vmdq_queues / num_cores);
544         const uint16_t remainder = (uint16_t)(num_vmdq_queues % num_cores);
545
546
547         if (remainder) {
548                 if (core_num < remainder) {
549                         startQueue = (uint16_t)(core_num * (quot + 1));
550                         endQueue = (uint16_t)(startQueue + quot + 1);
551                 } else {
552                         startQueue = (uint16_t)(core_num * quot + remainder);
553                         endQueue = (uint16_t)(startQueue + quot);
554                 }
555         } else {
556                 startQueue = (uint16_t)(core_num * quot);
557                 endQueue = (uint16_t)(startQueue + quot);
558         }
559
560         /* vmdq queue idx doesn't always start from zero.*/
561         startQueue += vmdq_queue_base;
562         endQueue   += vmdq_queue_base;
563         printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num,
564                rte_lcore_id(), startQueue, endQueue - 1);
565
566         if (startQueue == endQueue) {
567                 printf("lcore %u has nothing to do\n", (unsigned)core_num);
568                 return 0;
569         }
570
571         for (;;) {
572                 struct rte_mbuf *buf[MAX_PKT_BURST];
573                 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
574                 for (p = 0; p < num_ports; p++) {
575                         const uint8_t src = ports[p];
576                         const uint8_t dst = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
577
578                         if ((src == INVALID_PORT_ID) || (dst == INVALID_PORT_ID))
579                                 continue;
580
581                         for (q = startQueue; q < endQueue; q++) {
582                                 const uint16_t rxCount = rte_eth_rx_burst(src,
583                                         q, buf, buf_size);
584
585                                 if (unlikely(rxCount == 0))
586                                         continue;
587
588                                 rxPackets[q] += rxCount;
589
590                                 for (i = 0; i < rxCount; i++)
591                                         update_mac_address(buf[i], dst);
592
593                                 const uint16_t txCount = rte_eth_tx_burst(dst,
594                                         q, buf, rxCount);
595                                 if (txCount != rxCount) {
596                                         for (i = txCount; i < rxCount; i++)
597                                                 rte_pktmbuf_free(buf[i]);
598                                 }
599                         }
600                 }
601         }
602 }
603
604 /*
605  * Update the global var NUM_PORTS and array PORTS according to system ports number
606  * and return valid ports number
607  */
608 static unsigned check_ports_num(unsigned nb_ports)
609 {
610         unsigned valid_num_ports = num_ports;
611         unsigned portid;
612
613         if (num_ports > nb_ports) {
614                 printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
615                         num_ports, nb_ports);
616                 num_ports = nb_ports;
617         }
618
619         for (portid = 0; portid < num_ports; portid++) {
620                 if (ports[portid] >= nb_ports) {
621                         printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
622                                 ports[portid], (nb_ports - 1));
623                         ports[portid] = INVALID_PORT_ID;
624                         valid_num_ports--;
625                 }
626         }
627         return valid_num_ports;
628 }
629
630
631 /* Main function, does initialisation and calls the per-lcore functions */
632 int
633 main(int argc, char *argv[])
634 {
635         unsigned cores;
636         struct rte_mempool *mbuf_pool;
637         unsigned lcore_id;
638         uintptr_t i;
639         int ret;
640         unsigned nb_ports, valid_num_ports;
641         uint8_t portid;
642
643         signal(SIGHUP, sighup_handler);
644
645         /* init EAL */
646         ret = rte_eal_init(argc, argv);
647         if (ret < 0)
648                 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
649         argc -= ret;
650         argv += ret;
651
652         /* parse app arguments */
653         ret = vmdq_parse_args(argc, argv);
654         if (ret < 0)
655                 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
656
657         cores = rte_lcore_count();
658         if ((cores & (cores - 1)) != 0 || cores > RTE_MAX_LCORE) {
659                 rte_exit(EXIT_FAILURE,"This program can only run on an even"
660                                 " number of cores(1-%d)\n\n", RTE_MAX_LCORE);
661         }
662
663         nb_ports = rte_eth_dev_count();
664
665         /*
666          * Update the global var NUM_PORTS and global array PORTS
667          * and get value of var VALID_NUM_PORTS according to system ports number
668          */
669         valid_num_ports = check_ports_num(nb_ports);
670
671         if (valid_num_ports < 2 || valid_num_ports % 2) {
672                 printf("Current valid ports number is %u\n", valid_num_ports);
673                 rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
674         }
675
676         mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL",
677                 NUM_MBUFS_PER_PORT * nb_ports, MBUF_CACHE_SIZE,
678                 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
679         if (mbuf_pool == NULL)
680                 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
681
682         /* initialize all ports */
683         for (portid = 0; portid < nb_ports; portid++) {
684                 /* skip ports that are not enabled */
685                 if ((enabled_port_mask & (1 << portid)) == 0) {
686                         printf("\nSkipping disabled port %d\n", portid);
687                         continue;
688                 }
689                 if (port_init(portid, mbuf_pool) != 0)
690                         rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
691         }
692
693         /* call lcore_main() on every slave lcore */
694         i = 0;
695         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
696                 rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id);
697         }
698         /* call on master too */
699         (void) lcore_main((void*)i);
700
701         return 0;
702 }