4f6d47e44935962581e172bbe984b98b709c6fab
[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         uint16_t rxRingSize = RTE_TEST_RX_DESC_DEFAULT;
231         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         retval = rte_eth_dev_adjust_nb_rx_tx_desc(port, &rxRingSize,
303                                 &txRingSize);
304         if (retval != 0)
305                 return retval;
306         if (RTE_MAX(rxRingSize, txRingSize) >
307             RTE_MAX(RTE_TEST_RX_DESC_DEFAULT, RTE_TEST_TX_DESC_DEFAULT)) {
308                 printf("Mbuf pool has an insufficient size for port %u.\n",
309                         port);
310                 return -1;
311         }
312
313         for (q = 0; q < num_queues; q++) {
314                 retval = rte_eth_rx_queue_setup(port, q, rxRingSize,
315                                         rte_eth_dev_socket_id(port),
316                                         NULL,
317                                         mbuf_pool);
318                 if (retval < 0) {
319                         printf("initialize rx queue %d failed\n", q);
320                         return retval;
321                 }
322         }
323
324         for (q = 0; q < num_queues; q++) {
325                 retval = rte_eth_tx_queue_setup(port, q, txRingSize,
326                                         rte_eth_dev_socket_id(port),
327                                         NULL);
328                 if (retval < 0) {
329                         printf("initialize tx queue %d failed\n", q);
330                         return retval;
331                 }
332         }
333
334         retval  = rte_eth_dev_start(port);
335         if (retval < 0) {
336                 printf("port %d start failed\n", port);
337                 return retval;
338         }
339
340         rte_eth_macaddr_get(port, &vmdq_ports_eth_addr[port]);
341         printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
342                         " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
343                         (unsigned)port,
344                         vmdq_ports_eth_addr[port].addr_bytes[0],
345                         vmdq_ports_eth_addr[port].addr_bytes[1],
346                         vmdq_ports_eth_addr[port].addr_bytes[2],
347                         vmdq_ports_eth_addr[port].addr_bytes[3],
348                         vmdq_ports_eth_addr[port].addr_bytes[4],
349                         vmdq_ports_eth_addr[port].addr_bytes[5]);
350
351         /* Set mac for each pool.*/
352         for (q = 0; q < num_pools; q++) {
353                 struct ether_addr mac;
354
355                 mac = pool_addr_template;
356                 mac.addr_bytes[4] = port;
357                 mac.addr_bytes[5] = q;
358                 printf("Port %u vmdq pool %u set mac %02x:%02x:%02x:%02x:%02x:%02x\n",
359                         port, q,
360                         mac.addr_bytes[0], mac.addr_bytes[1],
361                         mac.addr_bytes[2], mac.addr_bytes[3],
362                         mac.addr_bytes[4], mac.addr_bytes[5]);
363                 retval = rte_eth_dev_mac_addr_add(port, &mac,
364                                 q + vmdq_pool_base);
365                 if (retval) {
366                         printf("mac addr add failed at pool %d\n", q);
367                         return retval;
368                 }
369         }
370
371         return 0;
372 }
373
374 /* Check num_pools parameter and set it if OK*/
375 static int
376 vmdq_parse_num_pools(const char *q_arg)
377 {
378         char *end = NULL;
379         int n;
380
381         /* parse number string */
382         n = strtol(q_arg, &end, 10);
383         if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
384                 return -1;
385         if (n != 16 && n != 32)
386                 return -1;
387         if (n == 16)
388                 num_pools = ETH_16_POOLS;
389         else
390                 num_pools = ETH_32_POOLS;
391
392         return 0;
393 }
394
395 /* Check num_tcs parameter and set it if OK*/
396 static int
397 vmdq_parse_num_tcs(const char *q_arg)
398 {
399         char *end = NULL;
400         int n;
401
402         /* parse number string */
403         n = strtol(q_arg, &end, 10);
404         if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0'))
405                 return -1;
406
407         if (n != 4 && n != 8)
408                 return -1;
409         if (n == 4)
410                 num_tcs = ETH_4_TCS;
411         else
412                 num_tcs = ETH_8_TCS;
413
414         return 0;
415 }
416
417 static int
418 parse_portmask(const char *portmask)
419 {
420         char *end = NULL;
421         unsigned long pm;
422
423         /* parse hexadecimal string */
424         pm = strtoul(portmask, &end, 16);
425         if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0'))
426                 return -1;
427
428         if (pm == 0)
429                 return -1;
430
431         return pm;
432 }
433
434 /* Display usage */
435 static void
436 vmdq_usage(const char *prgname)
437 {
438         printf("%s [EAL options] -- -p PORTMASK]\n"
439         "  --nb-pools NP: number of pools (32 default, 16)\n"
440         "  --nb-tcs NP: number of TCs (4 default, 8)\n"
441         "  --enable-rss: enable RSS (disabled by default)\n",
442                prgname);
443 }
444
445 /*  Parse the argument (num_pools) given in the command line of the application */
446 static int
447 vmdq_parse_args(int argc, char **argv)
448 {
449         int opt;
450         int option_index;
451         unsigned i;
452         const char *prgname = argv[0];
453         static struct option long_option[] = {
454                 {"nb-pools", required_argument, NULL, 0},
455                 {"nb-tcs", required_argument, NULL, 0},
456                 {"enable-rss", 0, NULL, 0},
457                 {NULL, 0, 0, 0}
458         };
459
460         /* Parse command line */
461         while ((opt = getopt_long(argc, argv, "p:", long_option,
462                 &option_index)) != EOF) {
463                 switch (opt) {
464                 /* portmask */
465                 case 'p':
466                         enabled_port_mask = parse_portmask(optarg);
467                         if (enabled_port_mask == 0) {
468                                 printf("invalid portmask\n");
469                                 vmdq_usage(prgname);
470                                 return -1;
471                         }
472                         break;
473                 case 0:
474                         if (!strcmp(long_option[option_index].name, "nb-pools")) {
475                                 if (vmdq_parse_num_pools(optarg) == -1) {
476                                         printf("invalid number of pools\n");
477                                         return -1;
478                                 }
479                         }
480
481                         if (!strcmp(long_option[option_index].name, "nb-tcs")) {
482                                 if (vmdq_parse_num_tcs(optarg) == -1) {
483                                         printf("invalid number of tcs\n");
484                                         return -1;
485                                 }
486                         }
487
488                         if (!strcmp(long_option[option_index].name, "enable-rss"))
489                                 rss_enable = 1;
490                         break;
491
492                 default:
493                         vmdq_usage(prgname);
494                         return -1;
495                 }
496         }
497
498         for (i = 0; i < RTE_MAX_ETHPORTS; i++) {
499                 if (enabled_port_mask & (1 << i))
500                         ports[num_ports++] = (uint8_t)i;
501         }
502
503         if (num_ports < 2 || num_ports % 2) {
504                 printf("Current enabled port number is %u,"
505                         " but it should be even and at least 2\n", num_ports);
506                 return -1;
507         }
508
509         return 0;
510 }
511
512 static void
513 update_mac_address(struct rte_mbuf *m, unsigned dst_port)
514 {
515         struct ether_hdr *eth;
516         void *tmp;
517
518         eth = rte_pktmbuf_mtod(m, struct ether_hdr *);
519
520         /* 02:00:00:00:00:xx */
521         tmp = &eth->d_addr.addr_bytes[0];
522         *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dst_port << 40);
523
524         /* src addr */
525         ether_addr_copy(&vmdq_ports_eth_addr[dst_port], &eth->s_addr);
526 }
527
528 /* When we receive a HUP signal, print out our stats */
529 static void
530 sighup_handler(int signum)
531 {
532         unsigned q = vmdq_queue_base;
533
534         for (; q < num_queues; q++) {
535                 if (q % (num_vmdq_queues / num_pools) == 0)
536                         printf("\nPool %u: ", (q - vmdq_queue_base) /
537                                               (num_vmdq_queues / num_pools));
538                 printf("%lu ", rxPackets[q]);
539         }
540         printf("\nFinished handling signal %d\n", signum);
541 }
542
543 /*
544  * Main thread that does the work, reading from INPUT_PORT
545  * and writing to OUTPUT_PORT
546  */
547 static int
548 lcore_main(void *arg)
549 {
550         const uintptr_t core_num = (uintptr_t)arg;
551         const unsigned num_cores = rte_lcore_count();
552         uint16_t startQueue, endQueue;
553         uint16_t q, i, p;
554         const uint16_t quot = (uint16_t)(num_vmdq_queues / num_cores);
555         const uint16_t remainder = (uint16_t)(num_vmdq_queues % num_cores);
556
557
558         if (remainder) {
559                 if (core_num < remainder) {
560                         startQueue = (uint16_t)(core_num * (quot + 1));
561                         endQueue = (uint16_t)(startQueue + quot + 1);
562                 } else {
563                         startQueue = (uint16_t)(core_num * quot + remainder);
564                         endQueue = (uint16_t)(startQueue + quot);
565                 }
566         } else {
567                 startQueue = (uint16_t)(core_num * quot);
568                 endQueue = (uint16_t)(startQueue + quot);
569         }
570
571         /* vmdq queue idx doesn't always start from zero.*/
572         startQueue += vmdq_queue_base;
573         endQueue   += vmdq_queue_base;
574         printf("Core %u(lcore %u) reading queues %i-%i\n", (unsigned)core_num,
575                rte_lcore_id(), startQueue, endQueue - 1);
576
577         if (startQueue == endQueue) {
578                 printf("lcore %u has nothing to do\n", (unsigned)core_num);
579                 return 0;
580         }
581
582         for (;;) {
583                 struct rte_mbuf *buf[MAX_PKT_BURST];
584                 const uint16_t buf_size = sizeof(buf) / sizeof(buf[0]);
585                 for (p = 0; p < num_ports; p++) {
586                         const uint8_t src = ports[p];
587                         const uint8_t dst = ports[p ^ 1]; /* 0 <-> 1, 2 <-> 3 etc */
588
589                         if ((src == INVALID_PORT_ID) || (dst == INVALID_PORT_ID))
590                                 continue;
591
592                         for (q = startQueue; q < endQueue; q++) {
593                                 const uint16_t rxCount = rte_eth_rx_burst(src,
594                                         q, buf, buf_size);
595
596                                 if (unlikely(rxCount == 0))
597                                         continue;
598
599                                 rxPackets[q] += rxCount;
600
601                                 for (i = 0; i < rxCount; i++)
602                                         update_mac_address(buf[i], dst);
603
604                                 const uint16_t txCount = rte_eth_tx_burst(dst,
605                                         q, buf, rxCount);
606                                 if (txCount != rxCount) {
607                                         for (i = txCount; i < rxCount; i++)
608                                                 rte_pktmbuf_free(buf[i]);
609                                 }
610                         }
611                 }
612         }
613 }
614
615 /*
616  * Update the global var NUM_PORTS and array PORTS according to system ports number
617  * and return valid ports number
618  */
619 static unsigned check_ports_num(unsigned nb_ports)
620 {
621         unsigned valid_num_ports = num_ports;
622         unsigned portid;
623
624         if (num_ports > nb_ports) {
625                 printf("\nSpecified port number(%u) exceeds total system port number(%u)\n",
626                         num_ports, nb_ports);
627                 num_ports = nb_ports;
628         }
629
630         for (portid = 0; portid < num_ports; portid++) {
631                 if (ports[portid] >= nb_ports) {
632                         printf("\nSpecified port ID(%u) exceeds max system port ID(%u)\n",
633                                 ports[portid], (nb_ports - 1));
634                         ports[portid] = INVALID_PORT_ID;
635                         valid_num_ports--;
636                 }
637         }
638         return valid_num_ports;
639 }
640
641
642 /* Main function, does initialisation and calls the per-lcore functions */
643 int
644 main(int argc, char *argv[])
645 {
646         unsigned cores;
647         struct rte_mempool *mbuf_pool;
648         unsigned lcore_id;
649         uintptr_t i;
650         int ret;
651         unsigned nb_ports, valid_num_ports;
652         uint8_t portid;
653
654         signal(SIGHUP, sighup_handler);
655
656         /* init EAL */
657         ret = rte_eal_init(argc, argv);
658         if (ret < 0)
659                 rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
660         argc -= ret;
661         argv += ret;
662
663         /* parse app arguments */
664         ret = vmdq_parse_args(argc, argv);
665         if (ret < 0)
666                 rte_exit(EXIT_FAILURE, "Invalid VMDQ argument\n");
667
668         cores = rte_lcore_count();
669         if ((cores & (cores - 1)) != 0 || cores > RTE_MAX_LCORE) {
670                 rte_exit(EXIT_FAILURE,"This program can only run on an even"
671                                 " number of cores(1-%d)\n\n", RTE_MAX_LCORE);
672         }
673
674         nb_ports = rte_eth_dev_count();
675
676         /*
677          * Update the global var NUM_PORTS and global array PORTS
678          * and get value of var VALID_NUM_PORTS according to system ports number
679          */
680         valid_num_ports = check_ports_num(nb_ports);
681
682         if (valid_num_ports < 2 || valid_num_ports % 2) {
683                 printf("Current valid ports number is %u\n", valid_num_ports);
684                 rte_exit(EXIT_FAILURE, "Error with valid ports number is not even or less than 2\n");
685         }
686
687         mbuf_pool = rte_pktmbuf_pool_create("MBUF_POOL",
688                 NUM_MBUFS_PER_PORT * nb_ports, MBUF_CACHE_SIZE,
689                 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id());
690         if (mbuf_pool == NULL)
691                 rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
692
693         /* initialize all ports */
694         for (portid = 0; portid < nb_ports; portid++) {
695                 /* skip ports that are not enabled */
696                 if ((enabled_port_mask & (1 << portid)) == 0) {
697                         printf("\nSkipping disabled port %d\n", portid);
698                         continue;
699                 }
700                 if (port_init(portid, mbuf_pool) != 0)
701                         rte_exit(EXIT_FAILURE, "Cannot initialize network ports\n");
702         }
703
704         /* call lcore_main() on every slave lcore */
705         i = 0;
706         RTE_LCORE_FOREACH_SLAVE(lcore_id) {
707                 rte_eal_remote_launch(lcore_main, (void*)i++, lcore_id);
708         }
709         /* call on master too */
710         (void) lcore_main((void*)i);
711
712         return 0;
713 }