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