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