]> git.proxmox.com Git - ceph.git/blob - ceph/src/dpdk/examples/vmdq_dcb/main.c
bump version to 12.2.12-pve1
[ceph.git] / ceph / src / dpdk / 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 }