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