]>
Commit | Line | Data |
---|---|---|
9f95a23c TL |
1 | /* SPDX-License-Identifier: BSD-3-Clause |
2 | * Copyright(c) 2010-2016 Intel Corporation | |
7c673cae FG |
3 | */ |
4 | ||
5 | #include <stdio.h> | |
6 | #include <stdlib.h> | |
7 | #include <string.h> | |
8 | #include <stdint.h> | |
9 | #include <inttypes.h> | |
10 | #include <sys/types.h> | |
11 | #include <sys/queue.h> | |
12 | #include <netinet/in.h> | |
13 | #include <setjmp.h> | |
14 | #include <stdarg.h> | |
15 | #include <ctype.h> | |
16 | #include <errno.h> | |
17 | #include <getopt.h> | |
18 | #include <signal.h> | |
19 | #include <stdbool.h> | |
20 | ||
21 | #include <rte_common.h> | |
22 | #include <rte_log.h> | |
23 | #include <rte_malloc.h> | |
24 | #include <rte_memory.h> | |
25 | #include <rte_memcpy.h> | |
7c673cae | 26 | #include <rte_eal.h> |
7c673cae FG |
27 | #include <rte_launch.h> |
28 | #include <rte_atomic.h> | |
29 | #include <rte_cycles.h> | |
30 | #include <rte_prefetch.h> | |
31 | #include <rte_lcore.h> | |
32 | #include <rte_per_lcore.h> | |
33 | #include <rte_branch_prediction.h> | |
34 | #include <rte_interrupts.h> | |
7c673cae FG |
35 | #include <rte_random.h> |
36 | #include <rte_debug.h> | |
37 | #include <rte_ether.h> | |
38 | #include <rte_ethdev.h> | |
39 | #include <rte_mempool.h> | |
40 | #include <rte_mbuf.h> | |
41 | ||
42 | static volatile bool force_quit; | |
43 | ||
44 | /* MAC updating enabled by default */ | |
45 | static int mac_updating = 1; | |
46 | ||
47 | #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1 | |
48 | ||
7c673cae FG |
49 | #define MAX_PKT_BURST 32 |
50 | #define BURST_TX_DRAIN_US 100 /* TX drain every ~100us */ | |
51 | #define MEMPOOL_CACHE_SIZE 256 | |
52 | ||
53 | /* | |
54 | * Configurable number of RX/TX ring descriptors | |
55 | */ | |
9f95a23c TL |
56 | #define RTE_TEST_RX_DESC_DEFAULT 1024 |
57 | #define RTE_TEST_TX_DESC_DEFAULT 1024 | |
7c673cae FG |
58 | static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; |
59 | static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; | |
60 | ||
61 | /* ethernet addresses of ports */ | |
62 | static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS]; | |
63 | ||
64 | /* mask of enabled ports */ | |
65 | static uint32_t l2fwd_enabled_port_mask = 0; | |
66 | ||
67 | /* list of enabled ports */ | |
68 | static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS]; | |
69 | ||
70 | static unsigned int l2fwd_rx_queue_per_lcore = 1; | |
71 | ||
72 | #define MAX_RX_QUEUE_PER_LCORE 16 | |
73 | #define MAX_TX_QUEUE_PER_PORT 16 | |
74 | struct lcore_queue_conf { | |
75 | unsigned n_rx_port; | |
76 | unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; | |
77 | } __rte_cache_aligned; | |
78 | struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; | |
79 | ||
80 | static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; | |
81 | ||
9f95a23c | 82 | static struct rte_eth_conf port_conf = { |
7c673cae FG |
83 | .rxmode = { |
84 | .split_hdr_size = 0, | |
7c673cae FG |
85 | }, |
86 | .txmode = { | |
87 | .mq_mode = ETH_MQ_TX_NONE, | |
88 | }, | |
89 | }; | |
90 | ||
91 | struct rte_mempool * l2fwd_pktmbuf_pool = NULL; | |
92 | ||
93 | /* Per-port statistics struct */ | |
94 | struct l2fwd_port_statistics { | |
95 | uint64_t tx; | |
96 | uint64_t rx; | |
97 | uint64_t dropped; | |
98 | } __rte_cache_aligned; | |
99 | struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS]; | |
100 | ||
101 | #define MAX_TIMER_PERIOD 86400 /* 1 day max */ | |
102 | /* A tsc-based timer responsible for triggering statistics printout */ | |
103 | static uint64_t timer_period = 10; /* default period is 10 seconds */ | |
104 | ||
105 | /* Print out statistics on packets dropped */ | |
106 | static void | |
107 | print_stats(void) | |
108 | { | |
109 | uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; | |
110 | unsigned portid; | |
111 | ||
112 | total_packets_dropped = 0; | |
113 | total_packets_tx = 0; | |
114 | total_packets_rx = 0; | |
115 | ||
116 | const char clr[] = { 27, '[', '2', 'J', '\0' }; | |
117 | const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' }; | |
118 | ||
119 | /* Clear screen and move to top left */ | |
120 | printf("%s%s", clr, topLeft); | |
121 | ||
122 | printf("\nPort statistics ===================================="); | |
123 | ||
124 | for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { | |
125 | /* skip disabled ports */ | |
126 | if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) | |
127 | continue; | |
128 | printf("\nStatistics for port %u ------------------------------" | |
129 | "\nPackets sent: %24"PRIu64 | |
130 | "\nPackets received: %20"PRIu64 | |
131 | "\nPackets dropped: %21"PRIu64, | |
132 | portid, | |
133 | port_statistics[portid].tx, | |
134 | port_statistics[portid].rx, | |
135 | port_statistics[portid].dropped); | |
136 | ||
137 | total_packets_dropped += port_statistics[portid].dropped; | |
138 | total_packets_tx += port_statistics[portid].tx; | |
139 | total_packets_rx += port_statistics[portid].rx; | |
140 | } | |
141 | printf("\nAggregate statistics ===============================" | |
142 | "\nTotal packets sent: %18"PRIu64 | |
143 | "\nTotal packets received: %14"PRIu64 | |
144 | "\nTotal packets dropped: %15"PRIu64, | |
145 | total_packets_tx, | |
146 | total_packets_rx, | |
147 | total_packets_dropped); | |
148 | printf("\n====================================================\n"); | |
149 | } | |
150 | ||
151 | static void | |
152 | l2fwd_mac_updating(struct rte_mbuf *m, unsigned dest_portid) | |
153 | { | |
154 | struct ether_hdr *eth; | |
155 | void *tmp; | |
156 | ||
157 | eth = rte_pktmbuf_mtod(m, struct ether_hdr *); | |
158 | ||
159 | /* 02:00:00:00:00:xx */ | |
160 | tmp = ð->d_addr.addr_bytes[0]; | |
161 | *((uint64_t *)tmp) = 0x000000000002 + ((uint64_t)dest_portid << 40); | |
162 | ||
163 | /* src addr */ | |
164 | ether_addr_copy(&l2fwd_ports_eth_addr[dest_portid], ð->s_addr); | |
165 | } | |
166 | ||
167 | static void | |
168 | l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid) | |
169 | { | |
170 | unsigned dst_port; | |
171 | int sent; | |
172 | struct rte_eth_dev_tx_buffer *buffer; | |
173 | ||
174 | dst_port = l2fwd_dst_ports[portid]; | |
175 | ||
176 | if (mac_updating) | |
177 | l2fwd_mac_updating(m, dst_port); | |
178 | ||
179 | buffer = tx_buffer[dst_port]; | |
180 | sent = rte_eth_tx_buffer(dst_port, 0, buffer, m); | |
181 | if (sent) | |
182 | port_statistics[dst_port].tx += sent; | |
183 | } | |
184 | ||
185 | /* main processing loop */ | |
186 | static void | |
187 | l2fwd_main_loop(void) | |
188 | { | |
189 | struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; | |
190 | struct rte_mbuf *m; | |
191 | int sent; | |
192 | unsigned lcore_id; | |
193 | uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc; | |
194 | unsigned i, j, portid, nb_rx; | |
195 | struct lcore_queue_conf *qconf; | |
196 | const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * | |
197 | BURST_TX_DRAIN_US; | |
198 | struct rte_eth_dev_tx_buffer *buffer; | |
199 | ||
200 | prev_tsc = 0; | |
201 | timer_tsc = 0; | |
202 | ||
203 | lcore_id = rte_lcore_id(); | |
204 | qconf = &lcore_queue_conf[lcore_id]; | |
205 | ||
206 | if (qconf->n_rx_port == 0) { | |
207 | RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id); | |
208 | return; | |
209 | } | |
210 | ||
211 | RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id); | |
212 | ||
213 | for (i = 0; i < qconf->n_rx_port; i++) { | |
214 | ||
215 | portid = qconf->rx_port_list[i]; | |
216 | RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id, | |
217 | portid); | |
218 | ||
219 | } | |
220 | ||
221 | while (!force_quit) { | |
222 | ||
223 | cur_tsc = rte_rdtsc(); | |
224 | ||
225 | /* | |
226 | * TX burst queue drain | |
227 | */ | |
228 | diff_tsc = cur_tsc - prev_tsc; | |
229 | if (unlikely(diff_tsc > drain_tsc)) { | |
230 | ||
231 | for (i = 0; i < qconf->n_rx_port; i++) { | |
232 | ||
233 | portid = l2fwd_dst_ports[qconf->rx_port_list[i]]; | |
234 | buffer = tx_buffer[portid]; | |
235 | ||
236 | sent = rte_eth_tx_buffer_flush(portid, 0, buffer); | |
237 | if (sent) | |
238 | port_statistics[portid].tx += sent; | |
239 | ||
240 | } | |
241 | ||
242 | /* if timer is enabled */ | |
243 | if (timer_period > 0) { | |
244 | ||
245 | /* advance the timer */ | |
246 | timer_tsc += diff_tsc; | |
247 | ||
248 | /* if timer has reached its timeout */ | |
249 | if (unlikely(timer_tsc >= timer_period)) { | |
250 | ||
251 | /* do this only on master core */ | |
252 | if (lcore_id == rte_get_master_lcore()) { | |
253 | print_stats(); | |
254 | /* reset the timer */ | |
255 | timer_tsc = 0; | |
256 | } | |
257 | } | |
258 | } | |
259 | ||
260 | prev_tsc = cur_tsc; | |
261 | } | |
262 | ||
263 | /* | |
264 | * Read packet from RX queues | |
265 | */ | |
266 | for (i = 0; i < qconf->n_rx_port; i++) { | |
267 | ||
268 | portid = qconf->rx_port_list[i]; | |
9f95a23c | 269 | nb_rx = rte_eth_rx_burst(portid, 0, |
7c673cae FG |
270 | pkts_burst, MAX_PKT_BURST); |
271 | ||
272 | port_statistics[portid].rx += nb_rx; | |
273 | ||
274 | for (j = 0; j < nb_rx; j++) { | |
275 | m = pkts_burst[j]; | |
276 | rte_prefetch0(rte_pktmbuf_mtod(m, void *)); | |
277 | l2fwd_simple_forward(m, portid); | |
278 | } | |
279 | } | |
280 | } | |
281 | } | |
282 | ||
283 | static int | |
284 | l2fwd_launch_one_lcore(__attribute__((unused)) void *dummy) | |
285 | { | |
286 | l2fwd_main_loop(); | |
287 | return 0; | |
288 | } | |
289 | ||
290 | /* display usage */ | |
291 | static void | |
292 | l2fwd_usage(const char *prgname) | |
293 | { | |
294 | printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" | |
295 | " -p PORTMASK: hexadecimal bitmask of ports to configure\n" | |
296 | " -q NQ: number of queue (=ports) per lcore (default is 1)\n" | |
297 | " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n" | |
298 | " --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n" | |
299 | " When enabled:\n" | |
300 | " - The source MAC address is replaced by the TX port MAC address\n" | |
301 | " - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n", | |
302 | prgname); | |
303 | } | |
304 | ||
305 | static int | |
306 | l2fwd_parse_portmask(const char *portmask) | |
307 | { | |
308 | char *end = NULL; | |
309 | unsigned long pm; | |
310 | ||
311 | /* parse hexadecimal string */ | |
312 | pm = strtoul(portmask, &end, 16); | |
313 | if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) | |
314 | return -1; | |
315 | ||
316 | if (pm == 0) | |
317 | return -1; | |
318 | ||
319 | return pm; | |
320 | } | |
321 | ||
322 | static unsigned int | |
323 | l2fwd_parse_nqueue(const char *q_arg) | |
324 | { | |
325 | char *end = NULL; | |
326 | unsigned long n; | |
327 | ||
328 | /* parse hexadecimal string */ | |
329 | n = strtoul(q_arg, &end, 10); | |
330 | if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) | |
331 | return 0; | |
332 | if (n == 0) | |
333 | return 0; | |
334 | if (n >= MAX_RX_QUEUE_PER_LCORE) | |
335 | return 0; | |
336 | ||
337 | return n; | |
338 | } | |
339 | ||
340 | static int | |
341 | l2fwd_parse_timer_period(const char *q_arg) | |
342 | { | |
343 | char *end = NULL; | |
344 | int n; | |
345 | ||
346 | /* parse number string */ | |
347 | n = strtol(q_arg, &end, 10); | |
348 | if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) | |
349 | return -1; | |
350 | if (n >= MAX_TIMER_PERIOD) | |
351 | return -1; | |
352 | ||
353 | return n; | |
354 | } | |
355 | ||
11fdf7f2 TL |
356 | static const char short_options[] = |
357 | "p:" /* portmask */ | |
358 | "q:" /* number of queues */ | |
359 | "T:" /* timer period */ | |
360 | ; | |
361 | ||
362 | #define CMD_LINE_OPT_MAC_UPDATING "mac-updating" | |
363 | #define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating" | |
364 | ||
365 | enum { | |
366 | /* long options mapped to a short option */ | |
367 | ||
368 | /* first long only option value must be >= 256, so that we won't | |
369 | * conflict with short options */ | |
370 | CMD_LINE_OPT_MIN_NUM = 256, | |
371 | }; | |
372 | ||
373 | static const struct option lgopts[] = { | |
374 | { CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1}, | |
375 | { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0}, | |
376 | {NULL, 0, 0, 0} | |
377 | }; | |
378 | ||
7c673cae FG |
379 | /* Parse the argument given in the command line of the application */ |
380 | static int | |
381 | l2fwd_parse_args(int argc, char **argv) | |
382 | { | |
383 | int opt, ret, timer_secs; | |
384 | char **argvopt; | |
385 | int option_index; | |
386 | char *prgname = argv[0]; | |
7c673cae FG |
387 | |
388 | argvopt = argv; | |
389 | ||
11fdf7f2 | 390 | while ((opt = getopt_long(argc, argvopt, short_options, |
7c673cae FG |
391 | lgopts, &option_index)) != EOF) { |
392 | ||
393 | switch (opt) { | |
394 | /* portmask */ | |
395 | case 'p': | |
396 | l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg); | |
397 | if (l2fwd_enabled_port_mask == 0) { | |
398 | printf("invalid portmask\n"); | |
399 | l2fwd_usage(prgname); | |
400 | return -1; | |
401 | } | |
402 | break; | |
403 | ||
404 | /* nqueue */ | |
405 | case 'q': | |
406 | l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); | |
407 | if (l2fwd_rx_queue_per_lcore == 0) { | |
408 | printf("invalid queue number\n"); | |
409 | l2fwd_usage(prgname); | |
410 | return -1; | |
411 | } | |
412 | break; | |
413 | ||
414 | /* timer period */ | |
415 | case 'T': | |
416 | timer_secs = l2fwd_parse_timer_period(optarg); | |
417 | if (timer_secs < 0) { | |
418 | printf("invalid timer period\n"); | |
419 | l2fwd_usage(prgname); | |
420 | return -1; | |
421 | } | |
422 | timer_period = timer_secs; | |
423 | break; | |
424 | ||
425 | /* long options */ | |
426 | case 0: | |
427 | break; | |
428 | ||
429 | default: | |
430 | l2fwd_usage(prgname); | |
431 | return -1; | |
432 | } | |
433 | } | |
434 | ||
435 | if (optind >= 0) | |
436 | argv[optind-1] = prgname; | |
437 | ||
438 | ret = optind-1; | |
11fdf7f2 | 439 | optind = 1; /* reset getopt lib */ |
7c673cae FG |
440 | return ret; |
441 | } | |
442 | ||
443 | /* Check the link status of all ports in up to 9s, and print them finally */ | |
444 | static void | |
9f95a23c | 445 | check_all_ports_link_status(uint32_t port_mask) |
7c673cae FG |
446 | { |
447 | #define CHECK_INTERVAL 100 /* 100ms */ | |
448 | #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ | |
9f95a23c TL |
449 | uint16_t portid; |
450 | uint8_t count, all_ports_up, print_flag = 0; | |
7c673cae FG |
451 | struct rte_eth_link link; |
452 | ||
453 | printf("\nChecking link status"); | |
454 | fflush(stdout); | |
455 | for (count = 0; count <= MAX_CHECK_TIME; count++) { | |
456 | if (force_quit) | |
457 | return; | |
458 | all_ports_up = 1; | |
9f95a23c | 459 | RTE_ETH_FOREACH_DEV(portid) { |
7c673cae FG |
460 | if (force_quit) |
461 | return; | |
462 | if ((port_mask & (1 << portid)) == 0) | |
463 | continue; | |
464 | memset(&link, 0, sizeof(link)); | |
465 | rte_eth_link_get_nowait(portid, &link); | |
466 | /* print link status if flag set */ | |
467 | if (print_flag == 1) { | |
468 | if (link.link_status) | |
9f95a23c TL |
469 | printf( |
470 | "Port%d Link Up. Speed %u Mbps - %s\n", | |
471 | portid, link.link_speed, | |
7c673cae FG |
472 | (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? |
473 | ("full-duplex") : ("half-duplex\n")); | |
474 | else | |
9f95a23c | 475 | printf("Port %d Link Down\n", portid); |
7c673cae FG |
476 | continue; |
477 | } | |
478 | /* clear all_ports_up flag if any link down */ | |
479 | if (link.link_status == ETH_LINK_DOWN) { | |
480 | all_ports_up = 0; | |
481 | break; | |
482 | } | |
483 | } | |
484 | /* after finally printing all link status, get out */ | |
485 | if (print_flag == 1) | |
486 | break; | |
487 | ||
488 | if (all_ports_up == 0) { | |
489 | printf("."); | |
490 | fflush(stdout); | |
491 | rte_delay_ms(CHECK_INTERVAL); | |
492 | } | |
493 | ||
494 | /* set the print_flag if all ports up or timeout */ | |
495 | if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { | |
496 | print_flag = 1; | |
497 | printf("done\n"); | |
498 | } | |
499 | } | |
500 | } | |
501 | ||
502 | static void | |
503 | signal_handler(int signum) | |
504 | { | |
505 | if (signum == SIGINT || signum == SIGTERM) { | |
506 | printf("\n\nSignal %d received, preparing to exit...\n", | |
507 | signum); | |
508 | force_quit = true; | |
509 | } | |
510 | } | |
511 | ||
512 | int | |
513 | main(int argc, char **argv) | |
514 | { | |
515 | struct lcore_queue_conf *qconf; | |
7c673cae | 516 | int ret; |
9f95a23c TL |
517 | uint16_t nb_ports; |
518 | uint16_t nb_ports_available = 0; | |
519 | uint16_t portid, last_port; | |
7c673cae FG |
520 | unsigned lcore_id, rx_lcore_id; |
521 | unsigned nb_ports_in_mask = 0; | |
9f95a23c TL |
522 | unsigned int nb_lcores = 0; |
523 | unsigned int nb_mbufs; | |
7c673cae FG |
524 | |
525 | /* init EAL */ | |
526 | ret = rte_eal_init(argc, argv); | |
527 | if (ret < 0) | |
528 | rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); | |
529 | argc -= ret; | |
530 | argv += ret; | |
531 | ||
532 | force_quit = false; | |
533 | signal(SIGINT, signal_handler); | |
534 | signal(SIGTERM, signal_handler); | |
535 | ||
536 | /* parse application arguments (after the EAL ones) */ | |
537 | ret = l2fwd_parse_args(argc, argv); | |
538 | if (ret < 0) | |
539 | rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); | |
540 | ||
541 | printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled"); | |
542 | ||
543 | /* convert to number of cycles */ | |
544 | timer_period *= rte_get_timer_hz(); | |
545 | ||
9f95a23c | 546 | nb_ports = rte_eth_dev_count_avail(); |
7c673cae FG |
547 | if (nb_ports == 0) |
548 | rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); | |
549 | ||
9f95a23c TL |
550 | /* check port mask to possible port mask */ |
551 | if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1)) | |
552 | rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n", | |
553 | (1 << nb_ports) - 1); | |
554 | ||
7c673cae FG |
555 | /* reset l2fwd_dst_ports */ |
556 | for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) | |
557 | l2fwd_dst_ports[portid] = 0; | |
558 | last_port = 0; | |
559 | ||
560 | /* | |
561 | * Each logical core is assigned a dedicated TX queue on each port. | |
562 | */ | |
9f95a23c | 563 | RTE_ETH_FOREACH_DEV(portid) { |
7c673cae FG |
564 | /* skip ports that are not enabled */ |
565 | if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) | |
566 | continue; | |
567 | ||
568 | if (nb_ports_in_mask % 2) { | |
569 | l2fwd_dst_ports[portid] = last_port; | |
570 | l2fwd_dst_ports[last_port] = portid; | |
571 | } | |
572 | else | |
573 | last_port = portid; | |
574 | ||
575 | nb_ports_in_mask++; | |
7c673cae FG |
576 | } |
577 | if (nb_ports_in_mask % 2) { | |
578 | printf("Notice: odd number of ports in portmask.\n"); | |
579 | l2fwd_dst_ports[last_port] = last_port; | |
580 | } | |
581 | ||
582 | rx_lcore_id = 0; | |
583 | qconf = NULL; | |
584 | ||
585 | /* Initialize the port/queue configuration of each logical core */ | |
9f95a23c | 586 | RTE_ETH_FOREACH_DEV(portid) { |
7c673cae FG |
587 | /* skip ports that are not enabled */ |
588 | if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) | |
589 | continue; | |
590 | ||
591 | /* get the lcore_id for this port */ | |
592 | while (rte_lcore_is_enabled(rx_lcore_id) == 0 || | |
593 | lcore_queue_conf[rx_lcore_id].n_rx_port == | |
594 | l2fwd_rx_queue_per_lcore) { | |
595 | rx_lcore_id++; | |
596 | if (rx_lcore_id >= RTE_MAX_LCORE) | |
597 | rte_exit(EXIT_FAILURE, "Not enough cores\n"); | |
598 | } | |
599 | ||
9f95a23c | 600 | if (qconf != &lcore_queue_conf[rx_lcore_id]) { |
7c673cae FG |
601 | /* Assigned a new logical core in the loop above. */ |
602 | qconf = &lcore_queue_conf[rx_lcore_id]; | |
9f95a23c TL |
603 | nb_lcores++; |
604 | } | |
7c673cae FG |
605 | |
606 | qconf->rx_port_list[qconf->n_rx_port] = portid; | |
607 | qconf->n_rx_port++; | |
9f95a23c | 608 | printf("Lcore %u: RX port %u\n", rx_lcore_id, portid); |
7c673cae FG |
609 | } |
610 | ||
9f95a23c TL |
611 | nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST + |
612 | nb_lcores * MEMPOOL_CACHE_SIZE), 8192U); | |
613 | ||
614 | /* create the mbuf pool */ | |
615 | l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs, | |
616 | MEMPOOL_CACHE_SIZE, 0, RTE_MBUF_DEFAULT_BUF_SIZE, | |
617 | rte_socket_id()); | |
618 | if (l2fwd_pktmbuf_pool == NULL) | |
619 | rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); | |
7c673cae FG |
620 | |
621 | /* Initialise each port */ | |
9f95a23c TL |
622 | RTE_ETH_FOREACH_DEV(portid) { |
623 | struct rte_eth_rxconf rxq_conf; | |
624 | struct rte_eth_txconf txq_conf; | |
625 | struct rte_eth_conf local_port_conf = port_conf; | |
626 | struct rte_eth_dev_info dev_info; | |
627 | ||
7c673cae FG |
628 | /* skip ports that are not enabled */ |
629 | if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { | |
9f95a23c | 630 | printf("Skipping disabled port %u\n", portid); |
7c673cae FG |
631 | continue; |
632 | } | |
9f95a23c TL |
633 | nb_ports_available++; |
634 | ||
7c673cae | 635 | /* init port */ |
9f95a23c | 636 | printf("Initializing port %u... ", portid); |
7c673cae | 637 | fflush(stdout); |
9f95a23c TL |
638 | rte_eth_dev_info_get(portid, &dev_info); |
639 | if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) | |
640 | local_port_conf.txmode.offloads |= | |
641 | DEV_TX_OFFLOAD_MBUF_FAST_FREE; | |
642 | ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf); | |
7c673cae FG |
643 | if (ret < 0) |
644 | rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", | |
9f95a23c TL |
645 | ret, portid); |
646 | ||
647 | ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, | |
648 | &nb_txd); | |
649 | if (ret < 0) | |
650 | rte_exit(EXIT_FAILURE, | |
651 | "Cannot adjust number of descriptors: err=%d, port=%u\n", | |
652 | ret, portid); | |
7c673cae FG |
653 | |
654 | rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]); | |
655 | ||
656 | /* init one RX queue */ | |
657 | fflush(stdout); | |
9f95a23c TL |
658 | rxq_conf = dev_info.default_rxconf; |
659 | rxq_conf.offloads = local_port_conf.rxmode.offloads; | |
7c673cae FG |
660 | ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, |
661 | rte_eth_dev_socket_id(portid), | |
9f95a23c | 662 | &rxq_conf, |
7c673cae FG |
663 | l2fwd_pktmbuf_pool); |
664 | if (ret < 0) | |
665 | rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", | |
9f95a23c | 666 | ret, portid); |
7c673cae FG |
667 | |
668 | /* init one TX queue on each port */ | |
669 | fflush(stdout); | |
9f95a23c TL |
670 | txq_conf = dev_info.default_txconf; |
671 | txq_conf.offloads = local_port_conf.txmode.offloads; | |
7c673cae FG |
672 | ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, |
673 | rte_eth_dev_socket_id(portid), | |
9f95a23c | 674 | &txq_conf); |
7c673cae FG |
675 | if (ret < 0) |
676 | rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n", | |
9f95a23c | 677 | ret, portid); |
7c673cae FG |
678 | |
679 | /* Initialize TX buffers */ | |
680 | tx_buffer[portid] = rte_zmalloc_socket("tx_buffer", | |
681 | RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, | |
682 | rte_eth_dev_socket_id(portid)); | |
683 | if (tx_buffer[portid] == NULL) | |
684 | rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n", | |
9f95a23c | 685 | portid); |
7c673cae FG |
686 | |
687 | rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST); | |
688 | ||
689 | ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid], | |
690 | rte_eth_tx_buffer_count_callback, | |
691 | &port_statistics[portid].dropped); | |
692 | if (ret < 0) | |
9f95a23c TL |
693 | rte_exit(EXIT_FAILURE, |
694 | "Cannot set error callback for tx buffer on port %u\n", | |
695 | portid); | |
7c673cae FG |
696 | |
697 | /* Start device */ | |
698 | ret = rte_eth_dev_start(portid); | |
699 | if (ret < 0) | |
700 | rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", | |
9f95a23c | 701 | ret, portid); |
7c673cae FG |
702 | |
703 | printf("done: \n"); | |
704 | ||
705 | rte_eth_promiscuous_enable(portid); | |
706 | ||
707 | printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", | |
9f95a23c | 708 | portid, |
7c673cae FG |
709 | l2fwd_ports_eth_addr[portid].addr_bytes[0], |
710 | l2fwd_ports_eth_addr[portid].addr_bytes[1], | |
711 | l2fwd_ports_eth_addr[portid].addr_bytes[2], | |
712 | l2fwd_ports_eth_addr[portid].addr_bytes[3], | |
713 | l2fwd_ports_eth_addr[portid].addr_bytes[4], | |
714 | l2fwd_ports_eth_addr[portid].addr_bytes[5]); | |
715 | ||
716 | /* initialize port stats */ | |
717 | memset(&port_statistics, 0, sizeof(port_statistics)); | |
718 | } | |
719 | ||
720 | if (!nb_ports_available) { | |
721 | rte_exit(EXIT_FAILURE, | |
722 | "All available ports are disabled. Please set portmask.\n"); | |
723 | } | |
724 | ||
9f95a23c | 725 | check_all_ports_link_status(l2fwd_enabled_port_mask); |
7c673cae FG |
726 | |
727 | ret = 0; | |
728 | /* launch per-lcore init on every lcore */ | |
729 | rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, NULL, CALL_MASTER); | |
730 | RTE_LCORE_FOREACH_SLAVE(lcore_id) { | |
731 | if (rte_eal_wait_lcore(lcore_id) < 0) { | |
732 | ret = -1; | |
733 | break; | |
734 | } | |
735 | } | |
736 | ||
9f95a23c | 737 | RTE_ETH_FOREACH_DEV(portid) { |
7c673cae FG |
738 | if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) |
739 | continue; | |
740 | printf("Closing port %d...", portid); | |
741 | rte_eth_dev_stop(portid); | |
742 | rte_eth_dev_close(portid); | |
743 | printf(" Done\n"); | |
744 | } | |
745 | printf("Bye...\n"); | |
746 | ||
747 | return ret; | |
748 | } |