/* license: to be defined */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "low.h" // HEADER DEFINITION #define ANT_NUM buf[23] #define PAYLOAD_1 buf[20] #define PAYLOAD_2 buf[21] #define ETH_TYPE buf[17] #define SYMBOL buf[29] #define SUBFRAME buf[28] #define FRAME buf[27] static volatile bool force_quit; unsigned short iq[33600]; unsigned char iq_swap[67200]; unsigned short *iq_ptr[14]; unsigned int dl_start = 0; /* MAC updating enabled by default */ static int mac_updating = 1; #define RTE_LOGTYPE_L2FWD RTE_LOGTYPE_USER1 #define MAX_PKT_BURST 32 #define BURST_TX_DRAIN_US 5 /* TX drain every ~100us */ #define MEMPOOL_CACHE_SIZE 256 /* * Configurable number of RX/TX ring descriptors */ #define RTE_TEST_RX_DESC_DEFAULT 1024 #define RTE_TEST_TX_DESC_DEFAULT 1024 static uint16_t nb_rxd = RTE_TEST_RX_DESC_DEFAULT; static uint16_t nb_txd = RTE_TEST_TX_DESC_DEFAULT; /* ethernet addresses of ports */ static struct ether_addr l2fwd_ports_eth_addr[RTE_MAX_ETHPORTS]; /* mask of enabled ports */ static uint32_t l2fwd_enabled_port_mask = 0; /* list of enabled ports */ static uint32_t l2fwd_dst_ports[RTE_MAX_ETHPORTS]; static unsigned int l2fwd_rx_queue_per_lcore = 1; #define MAX_RX_QUEUE_PER_LCORE 16 #define MAX_TX_QUEUE_PER_PORT 16 struct lcore_queue_conf { unsigned n_rx_port; unsigned rx_port_list[MAX_RX_QUEUE_PER_LCORE]; } __rte_cache_aligned; struct lcore_queue_conf lcore_queue_conf[RTE_MAX_LCORE]; static struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; static struct rte_eth_conf port_conf = { .rxmode = { .split_hdr_size = 0, .offloads = DEV_RX_OFFLOAD_JUMBO_FRAME, .split_hdr_size = 0, .max_rx_pkt_len = 9500, }, .txmode = { .mq_mode = ETH_MQ_TX_NONE, }, }; struct rte_mempool * l2fwd_pktmbuf_pool = NULL; /* Per-port statistics struct */ struct l2fwd_port_statistics { uint64_t tx; uint64_t rx; uint64_t dropped; } __rte_cache_aligned; struct l2fwd_port_statistics port_statistics[RTE_MAX_ETHPORTS]; #define MAX_TIMER_PERIOD 86400 /* 1 day max */ /* A tsc-based timer responsible for triggering statistics printout */ static uint64_t timer_period = 10; /* default period is 10 seconds */ /* Print out statistics on packets dropped */ static void print_stats(void) { uint64_t total_packets_dropped, total_packets_tx, total_packets_rx; unsigned portid; total_packets_dropped = 0; total_packets_tx = 0; total_packets_rx = 0; const char clr[] = { 27, '[', '2', 'J', '\0' }; const char topLeft[] = { 27, '[', '1', ';', '1', 'H','\0' }; /* Clear screen and move to top left */ printf("%s%s", clr, topLeft); printf("\nPort statistics ===================================="); for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) { /* skip disabled ports */ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) continue; printf("\nStatistics for port %u ------------------------------" "\nPackets sent: %24"PRIu64 "\nPackets received: %20"PRIu64 "\nPackets dropped: %21"PRIu64, portid, port_statistics[portid].tx, port_statistics[portid].rx, port_statistics[portid].dropped); total_packets_dropped += port_statistics[portid].dropped; total_packets_tx += port_statistics[portid].tx; total_packets_rx += port_statistics[portid].rx; } printf("\nAggregate statistics ===============================" "\nTotal packets sent: %18"PRIu64 "\nTotal packets received: %14"PRIu64 "\nTotal packets dropped: %15"PRIu64, total_packets_tx, total_packets_rx, total_packets_dropped); printf("\n====================================================\n"); } static void l2fwd_simple_forward(struct rte_mbuf *m, unsigned portid, benetel_t *bs) { unsigned char *buf, *buf_tx; unsigned int len; struct ether_hdr *eth; unsigned dst_port; int sent, prach_ctrl = 0; struct rte_eth_dev_tx_buffer *buffer; unsigned char * IQ_ptr; ul_packet_t p; buf = rte_pktmbuf_mtod(m, unsigned char *); //rte_memdump(stdout, "Rx Packet",buf ,34); eth = rte_pktmbuf_mtod(m, struct ether_hdr *); len = rte_pktmbuf_data_len(m); IQ_ptr = &buf[34]; //destination mac address (RRU MAC) eth->d_addr.addr_bytes[0] = 0x02; eth->d_addr.addr_bytes[1] = 0x00; eth->d_addr.addr_bytes[2] = 0x5e; eth->d_addr.addr_bytes[3] = 0x01; eth->d_addr.addr_bytes[4] = 0x01; eth->d_addr.addr_bytes[5] = 0x01; //source mac address (DU MAC) eth->s_addr.addr_bytes[0] = 0xdd; eth->s_addr.addr_bytes[1] = 0xdd; eth->s_addr.addr_bytes[2] = 0xdd; eth->s_addr.addr_bytes[3] = 0xdd; eth->s_addr.addr_bytes[4] = 0xdd; eth->s_addr.addr_bytes[5] = 0xdd; dst_port = l2fwd_dst_ports[portid]; #if 1 if (buf[18] == 0xAA) //msg1 check { printf("\nHandshake MSG 1 Received\n"); printf("\n====================================================\n"); buf[18] = 0xBB;//change to msg2 after receive msg1 printf("Handshake MSG 2 Sent\n"); printf("\n====================================================\n"); } #else // Handshake Condition if (buf[18] == 0x01 || buf[18] == 0x03) // ORAN handshake msgs. { if (buf[18] == 0x01) //msg1 check { printf("\nHandshake MSG 1 Received\n"); printf("\n====================================================\n"); buf[18] = 0x02;//change to msg2 after receive msg1 printf("Handshake MSG 2 Sent\n"); printf("\n====================================================\n"); } else if(buf[18] == 0x03) //msg3 check { printf("Handshake MSG 3 Sent\n"); printf("\n====================================================\n"); buf[18] = 0x04; printf("Handshake MSG 4 Sent\n"); printf("\n====================================================\n"); } } #endif // Trigger start send DL packets if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && SYMBOL == 0x09 && ANT_NUM == 0x00 && dl_start == 0){ printf("\nU-Plane Started\n"); printf("\n====================================================\n"); dl_start = 1; } if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && ANT_NUM == 0x00) { p.frame = FRAME; p.subframe = SUBFRAME >> 4; p.slot = 0; /* unused */ p.symbol = SYMBOL; p.antenna = 0; memcpy(p.iq, IQ_ptr, 4800); store_ul(bs, &p); } // U-PLANE UL ANT_0 PROCESSING if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && ANT_NUM == 0x00 && dl_start == 1) { int tx_frame = FRAME; int tx_subframe = SUBFRAME >> 4; int tx_symbol = SYMBOL + 5; if (tx_symbol > 13) { tx_symbol -= 14; tx_subframe++; if (tx_subframe == 10) { tx_subframe = 0; tx_frame = (tx_frame + 1) & 255; } } // ANT_NUM = 0x00; // SYMBOL = (SYMBOL + 5) % 14; PAYLOAD_2 = 0xc8; FRAME = tx_frame; SUBFRAME = tx_subframe << 4; SYMBOL = tx_symbol; /* antenna 0 - send actual DL data (if available) */ lock_dl_buffer(bs->buffers, tx_subframe); if (!(bs->buffers->dl_busy[tx_subframe] & (1 << tx_symbol))) { printf("%s: warning, DL underflow (sf.symbol %d.%d)\n", __FUNCTION__, tx_subframe, tx_symbol); memset(IQ_ptr, 0, 1200 * 4); } else { memcpy(IQ_ptr, bs->buffers->dl[tx_subframe] + tx_symbol * 1200*4, 1200*4); } bs->buffers->dl_busy[tx_subframe] &= ~(1 << tx_symbol); unlock_dl_buffer(bs->buffers, tx_subframe); // fill DL Data for ant 0 with 0 value // memset(IQ_ptr, 0, 4800); } // U-PLANE UL ANT_1 PROCESSING else if(PAYLOAD_1 == 0x12 && PAYLOAD_2 == 0xce && ANT_NUM == 0x01 && dl_start == 1) { // ANT_NUM = 0x01; SYMBOL = (SYMBOL + 5) % 14; PAYLOAD_2 = 0xc8; // fill DL Data for ant 1 with 0 value memset(IQ_ptr, 0, 4800); } // U-PLANE PRACH PROCESSING else if(PAYLOAD_1 == 0x0d && PAYLOAD_2 == 0x28){ if (ANT_NUM == 0) { store_prach(bs, FRAME, SUBFRAME>>4, IQ_ptr); } rte_pktmbuf_free(m); return; } // Send Packets buffer = tx_buffer[dst_port]; sent = rte_eth_tx_buffer(dst_port, 0, buffer, m); if (sent) port_statistics[dst_port].tx += sent; } /* main processing loop */ static void l2fwd_main_loop(benetel_t *bs) { struct rte_mbuf *pkts_burst[MAX_PKT_BURST]; struct rte_mbuf *m; int sent; unsigned lcore_id; uint64_t prev_tsc, diff_tsc, cur_tsc, timer_tsc; unsigned i, j, portid, nb_rx; struct lcore_queue_conf *qconf; const uint64_t drain_tsc = (rte_get_tsc_hz() + US_PER_S - 1) / US_PER_S * BURST_TX_DRAIN_US; struct rte_eth_dev_tx_buffer *buffer; prev_tsc = 0; timer_tsc = 0; lcore_id = rte_lcore_id(); qconf = &lcore_queue_conf[lcore_id]; if (qconf->n_rx_port == 0) { RTE_LOG(INFO, L2FWD, "lcore %u has nothing to do\n", lcore_id); return; } RTE_LOG(INFO, L2FWD, "entering main loop on lcore %u\n", lcore_id); for (i = 0; i < qconf->n_rx_port; i++) { portid = qconf->rx_port_list[i]; RTE_LOG(INFO, L2FWD, " -- lcoreid=%u portid=%u\n", lcore_id, portid); } while (!force_quit) { cur_tsc = rte_rdtsc(); /* * TX burst queue drain */ diff_tsc = cur_tsc - prev_tsc; if (unlikely(diff_tsc > drain_tsc)) { for (i = 0; i < qconf->n_rx_port; i++) { portid = l2fwd_dst_ports[qconf->rx_port_list[i]]; buffer = tx_buffer[portid]; sent = rte_eth_tx_buffer_flush(portid, 0, buffer); if (sent) port_statistics[portid].tx += sent; } /* if timer is enabled */ if (timer_period > 0) { /* advance the timer */ timer_tsc += diff_tsc; /* if timer has reached its timeout */ if (unlikely(timer_tsc >= timer_period)) { /* do this only on master core */ if (lcore_id == rte_get_master_lcore()) { //print_stats(); /* reset the timer */ timer_tsc = 0; } } } prev_tsc = cur_tsc; } /* * Read packet from RX queues */ for (i = 0; i < qconf->n_rx_port; i++) { portid = qconf->rx_port_list[i]; nb_rx = rte_eth_rx_burst(portid, 0, pkts_burst, MAX_PKT_BURST); port_statistics[portid].rx += nb_rx; for (j = 0; j < nb_rx; j++) { m = pkts_burst[j]; rte_prefetch0(rte_pktmbuf_mtod(m, void *)); l2fwd_simple_forward(m, portid, bs); } } } } static int l2fwd_launch_one_lcore(void *bs) { l2fwd_main_loop(bs); return 0; } /* display usage */ static void l2fwd_usage(const char *prgname) { printf("%s [EAL options] -- -p PORTMASK [-q NQ]\n" " -p PORTMASK: hexadecimal bitmask of ports to configure\n" " -q NQ: number of queue (=ports) per lcore (default is 1)\n" " -T PERIOD: statistics will be refreshed each PERIOD seconds (0 to disable, 10 default, 86400 maximum)\n" " --[no-]mac-updating: Enable or disable MAC addresses updating (enabled by default)\n" " When enabled:\n" " - The source MAC address is replaced by the TX port MAC address\n" " - The destination MAC address is replaced by 02:00:00:00:00:TX_PORT_ID\n", prgname); } static int l2fwd_parse_portmask(const char *portmask) { char *end = NULL; unsigned long pm; /* parse hexadecimal string */ pm = strtoul(portmask, &end, 16); if ((portmask[0] == '\0') || (end == NULL) || (*end != '\0')) return -1; if (pm == 0) return -1; return pm; } static unsigned int l2fwd_parse_nqueue(const char *q_arg) { char *end = NULL; unsigned long n; /* parse hexadecimal string */ n = strtoul(q_arg, &end, 10); if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) return 0; if (n == 0) return 0; if (n >= MAX_RX_QUEUE_PER_LCORE) return 0; return n; } static int l2fwd_parse_timer_period(const char *q_arg) { char *end = NULL; int n; /* parse number string */ n = strtol(q_arg, &end, 10); if ((q_arg[0] == '\0') || (end == NULL) || (*end != '\0')) return -1; if (n >= MAX_TIMER_PERIOD) return -1; return n; } static const char short_options[] = "p:" /* portmask */ "q:" /* number of queues */ "T:" /* timer period */ ; #define CMD_LINE_OPT_MAC_UPDATING "mac-updating" #define CMD_LINE_OPT_NO_MAC_UPDATING "no-mac-updating" enum { /* long options mapped to a short option */ /* first long only option value must be >= 256, so that we won't * conflict with short options */ CMD_LINE_OPT_MIN_NUM = 256, }; static const struct option lgopts[] = { { CMD_LINE_OPT_MAC_UPDATING, no_argument, &mac_updating, 1}, { CMD_LINE_OPT_NO_MAC_UPDATING, no_argument, &mac_updating, 0}, {NULL, 0, 0, 0} }; /* Parse the argument given in the command line of the application */ static int l2fwd_parse_args(int argc, char **argv) { int opt, ret, timer_secs; char **argvopt; int option_index; char *prgname = argv[0]; argvopt = argv; while ((opt = getopt_long(argc, argvopt, short_options, lgopts, &option_index)) != EOF) { switch (opt) { /* portmask */ case 'p': l2fwd_enabled_port_mask = l2fwd_parse_portmask(optarg); if (l2fwd_enabled_port_mask == 0) { printf("invalid portmask\n"); l2fwd_usage(prgname); return -1; } break; /* nqueue */ case 'q': l2fwd_rx_queue_per_lcore = l2fwd_parse_nqueue(optarg); if (l2fwd_rx_queue_per_lcore == 0) { printf("invalid queue number\n"); l2fwd_usage(prgname); return -1; } break; /* timer period */ case 'T': timer_secs = l2fwd_parse_timer_period(optarg); if (timer_secs < 0) { printf("invalid timer period\n"); l2fwd_usage(prgname); return -1; } timer_period = timer_secs; break; /* long options */ case 0: break; default: l2fwd_usage(prgname); return -1; } } if (optind >= 0) argv[optind-1] = prgname; ret = optind-1; optind = 1; /* reset getopt lib */ return ret; } /* Check the link status of all ports in up to 9s, and print them finally */ static void check_all_ports_link_status(uint32_t port_mask) { #define CHECK_INTERVAL 100 /* 100ms */ #define MAX_CHECK_TIME 90 /* 9s (90 * 100ms) in total */ uint16_t portid; uint8_t count, all_ports_up, print_flag = 0; struct rte_eth_link link; printf("\nChecking link status"); fflush(stdout); for (count = 0; count <= MAX_CHECK_TIME; count++) { if (force_quit) return; all_ports_up = 1; RTE_ETH_FOREACH_DEV(portid) { if (force_quit) return; if ((port_mask & (1 << portid)) == 0) continue; memset(&link, 0, sizeof(link)); rte_eth_link_get_nowait(portid, &link); /* print link status if flag set */ if (print_flag == 1) { if (link.link_status) printf( "Port%d Link Up. Speed %u Mbps - %s\n", portid, link.link_speed, (link.link_duplex == ETH_LINK_FULL_DUPLEX) ? ("full-duplex") : ("half-duplex\n")); else printf("Port %d Link Down\n", portid); continue; } /* clear all_ports_up flag if any link down */ if (link.link_status == ETH_LINK_DOWN) { all_ports_up = 0; break; } } /* after finally printing all link status, get out */ if (print_flag == 1) break; if (all_ports_up == 0) { printf("."); fflush(stdout); rte_delay_ms(CHECK_INTERVAL); } /* set the print_flag if all ports up or timeout */ if (all_ports_up == 1 || count == (MAX_CHECK_TIME - 1)) { print_flag = 1; printf("done\n"); } } } static void signal_handler(int signum) { if (signum == SIGINT || signum == SIGTERM) { printf("\n\nSignal %d received, preparing to exit...\n", signum); force_quit = true; } } int dpdk_main(int argc, char **argv, benetel_t *bs) { struct lcore_queue_conf *qconf; int ret; uint16_t nb_ports; uint16_t nb_ports_available = 0; uint16_t portid, last_port; unsigned lcore_id, rx_lcore_id; unsigned nb_ports_in_mask = 0; unsigned int nb_lcores = 0; unsigned int nb_mbufs; /* init EAL */ ret = rte_eal_init(argc, argv); if (ret < 0) rte_exit(EXIT_FAILURE, "Invalid EAL arguments\n"); argc -= ret; argv += ret; force_quit = false; signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); /* parse application arguments (after the EAL ones) */ ret = l2fwd_parse_args(argc, argv); if (ret < 0) rte_exit(EXIT_FAILURE, "Invalid L2FWD arguments\n"); printf("MAC updating %s\n", mac_updating ? "enabled" : "disabled"); /* convert to number of cycles */ timer_period *= rte_get_timer_hz(); nb_ports = rte_eth_dev_count_avail(); if (nb_ports == 0) rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); /* check port mask to possible port mask */ if (l2fwd_enabled_port_mask & ~((1 << nb_ports) - 1)) rte_exit(EXIT_FAILURE, "Invalid portmask; possible (0x%x)\n", (1 << nb_ports) - 1); /* reset l2fwd_dst_ports */ for (portid = 0; portid < RTE_MAX_ETHPORTS; portid++) l2fwd_dst_ports[portid] = 0; last_port = 0; /* * Each logical core is assigned a dedicated TX queue on each port. */ RTE_ETH_FOREACH_DEV(portid) { /* skip ports that are not enabled */ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) continue; if (nb_ports_in_mask % 2) { l2fwd_dst_ports[portid] = last_port; l2fwd_dst_ports[last_port] = portid; } else last_port = portid; nb_ports_in_mask++; } if (nb_ports_in_mask % 2) { printf("Notice: odd number of ports in portmask.\n"); l2fwd_dst_ports[last_port] = last_port; } rx_lcore_id = 0; qconf = NULL; /* Initialize the port/queue configuration of each logical core */ RTE_ETH_FOREACH_DEV(portid) { /* skip ports that are not enabled */ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) continue; /* get the lcore_id for this port */ while (rte_lcore_is_enabled(rx_lcore_id) == 0 || lcore_queue_conf[rx_lcore_id].n_rx_port == l2fwd_rx_queue_per_lcore) { rx_lcore_id++; if (rx_lcore_id >= RTE_MAX_LCORE) rte_exit(EXIT_FAILURE, "Not enough cores\n"); } if (qconf != &lcore_queue_conf[rx_lcore_id]) { /* Assigned a new logical core in the loop above. */ qconf = &lcore_queue_conf[rx_lcore_id]; nb_lcores++; } qconf->rx_port_list[qconf->n_rx_port] = portid; qconf->n_rx_port++; printf("Lcore %u: RX port %u\n", rx_lcore_id, portid); } nb_mbufs = RTE_MAX(nb_ports * (nb_rxd + nb_txd + MAX_PKT_BURST + nb_lcores * MEMPOOL_CACHE_SIZE), 8192U); /* create the mbuf pool */ l2fwd_pktmbuf_pool = rte_pktmbuf_pool_create("mbuf_pool", nb_mbufs, MEMPOOL_CACHE_SIZE, 0, 9680, rte_socket_id()); if (l2fwd_pktmbuf_pool == NULL) rte_exit(EXIT_FAILURE, "Cannot init mbuf pool\n"); /* Initialise each port */ RTE_ETH_FOREACH_DEV(portid) { struct rte_eth_rxconf rxq_conf; struct rte_eth_txconf txq_conf; struct rte_eth_conf local_port_conf = port_conf; struct rte_eth_dev_info dev_info; /* skip ports that are not enabled */ if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) { printf("Skipping disabled port %u\n", portid); continue; } nb_ports_available++; /* init port */ printf("Initializing port %u... ", portid); fflush(stdout); rte_eth_dev_info_get(portid, &dev_info); if (dev_info.tx_offload_capa & DEV_TX_OFFLOAD_MBUF_FAST_FREE) local_port_conf.txmode.offloads |= DEV_TX_OFFLOAD_MBUF_FAST_FREE; ret = rte_eth_dev_configure(portid, 1, 1, &local_port_conf); if (ret < 0) rte_exit(EXIT_FAILURE, "Cannot configure device: err=%d, port=%u\n", ret, portid); ret = rte_eth_dev_adjust_nb_rx_tx_desc(portid, &nb_rxd, &nb_txd); if (ret < 0) rte_exit(EXIT_FAILURE, "Cannot adjust number of descriptors: err=%d, port=%u\n", ret, portid); rte_eth_macaddr_get(portid,&l2fwd_ports_eth_addr[portid]); /* init one RX queue */ fflush(stdout); rxq_conf = dev_info.default_rxconf; rxq_conf.offloads = local_port_conf.rxmode.offloads; ret = rte_eth_rx_queue_setup(portid, 0, nb_rxd, rte_eth_dev_socket_id(portid), &rxq_conf, l2fwd_pktmbuf_pool); if (ret < 0) rte_exit(EXIT_FAILURE, "rte_eth_rx_queue_setup:err=%d, port=%u\n", ret, portid); /* init one TX queue on each port */ fflush(stdout); txq_conf = dev_info.default_txconf; txq_conf.offloads = local_port_conf.txmode.offloads; ret = rte_eth_tx_queue_setup(portid, 0, nb_txd, rte_eth_dev_socket_id(portid), &txq_conf); if (ret < 0) rte_exit(EXIT_FAILURE, "rte_eth_tx_queue_setup:err=%d, port=%u\n", ret, portid); /* Initialize TX buffers */ tx_buffer[portid] = rte_zmalloc_socket("tx_buffer", RTE_ETH_TX_BUFFER_SIZE(MAX_PKT_BURST), 0, rte_eth_dev_socket_id(portid)); if (tx_buffer[portid] == NULL) rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n", portid); rte_eth_tx_buffer_init(tx_buffer[portid], MAX_PKT_BURST); ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[portid], rte_eth_tx_buffer_count_callback, &port_statistics[portid].dropped); if (ret < 0) rte_exit(EXIT_FAILURE, "Cannot set error callback for tx buffer on port %u\n", portid); /* Start device */ ret = rte_eth_dev_start(portid); if (ret < 0) rte_exit(EXIT_FAILURE, "rte_eth_dev_start:err=%d, port=%u\n", ret, portid); printf("done: \n"); rte_eth_promiscuous_enable(portid); printf("Port %u, MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n\n", portid, l2fwd_ports_eth_addr[portid].addr_bytes[0], l2fwd_ports_eth_addr[portid].addr_bytes[1], l2fwd_ports_eth_addr[portid].addr_bytes[2], l2fwd_ports_eth_addr[portid].addr_bytes[3], l2fwd_ports_eth_addr[portid].addr_bytes[4], l2fwd_ports_eth_addr[portid].addr_bytes[5]); /* initialize port stats */ memset(&port_statistics, 0, sizeof(port_statistics)); } if (!nb_ports_available) { rte_exit(EXIT_FAILURE, "All available ports are disabled. Please set portmask.\n"); } check_all_ports_link_status(l2fwd_enabled_port_mask); ret = 0; /* launch per-lcore init on every lcore */ rte_eal_mp_remote_launch(l2fwd_launch_one_lcore, bs, CALL_MASTER); RTE_LCORE_FOREACH_SLAVE(lcore_id) { if (rte_eal_wait_lcore(lcore_id) < 0) { ret = -1; break; } } RTE_ETH_FOREACH_DEV(portid) { if ((l2fwd_enabled_port_mask & (1 << portid)) == 0) continue; printf("Closing port %d...", portid); rte_eth_dev_stop(portid); rte_eth_dev_close(portid); printf(" Done\n"); } printf("Bye...\n"); return ret; }