13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 23998e2a0SBruce Richardson * Copyright(c) 2016-2017 Intel Corporation 3ed2a80fdSPablo de Lara */ 4ed2a80fdSPablo de Lara 5ed2a80fdSPablo de Lara #include <stdint.h> 6ed2a80fdSPablo de Lara #include <stdio.h> 7ed2a80fdSPablo de Lara #include <inttypes.h> 8ed2a80fdSPablo de Lara #include <stdarg.h> 9ed2a80fdSPablo de Lara #include <errno.h> 10ed2a80fdSPablo de Lara #include <sys/queue.h> 11ed2a80fdSPablo de Lara #include <stdlib.h> 12ed2a80fdSPablo de Lara #include <getopt.h> 13ed2a80fdSPablo de Lara #include <string.h> 14ed2a80fdSPablo de Lara 15ed2a80fdSPablo de Lara #include <rte_common.h> 16ed2a80fdSPablo de Lara #include <rte_malloc.h> 17ed2a80fdSPablo de Lara #include <rte_memory.h> 18ed2a80fdSPablo de Lara #include <rte_memzone.h> 19ed2a80fdSPablo de Lara #include <rte_eal.h> 20ed2a80fdSPablo de Lara #include <rte_atomic.h> 21ed2a80fdSPablo de Lara #include <rte_branch_prediction.h> 22ed2a80fdSPablo de Lara #include <rte_log.h> 23ed2a80fdSPablo de Lara #include <rte_per_lcore.h> 24ed2a80fdSPablo de Lara #include <rte_launch.h> 25ed2a80fdSPablo de Lara #include <rte_lcore.h> 26ed2a80fdSPablo de Lara #include <rte_ring.h> 27ed2a80fdSPablo de Lara #include <rte_debug.h> 28ed2a80fdSPablo de Lara #include <rte_mempool.h> 29ed2a80fdSPablo de Lara #include <rte_mbuf.h> 30ed2a80fdSPablo de Lara #include <rte_interrupts.h> 31ed2a80fdSPablo de Lara #include <rte_ether.h> 32ed2a80fdSPablo de Lara #include <rte_ethdev.h> 33ed2a80fdSPablo de Lara #include <rte_string_fns.h> 34ed2a80fdSPablo de Lara #include <rte_ip.h> 35ed2a80fdSPablo de Lara 36ed2a80fdSPablo de Lara #include "common.h" 37ed2a80fdSPablo de Lara 38ed2a80fdSPablo de Lara /* Number of packets to attempt to read from queue */ 39ed2a80fdSPablo de Lara #define PKT_READ_SIZE ((uint16_t)32) 40ed2a80fdSPablo de Lara 41ed2a80fdSPablo de Lara /* 42ed2a80fdSPablo de Lara * Our node id number - tells us which rx queue to read, and NIC TX 43ed2a80fdSPablo de Lara * queue to write to. 44ed2a80fdSPablo de Lara */ 45ed2a80fdSPablo de Lara static uint8_t node_id; 46ed2a80fdSPablo de Lara 47ed2a80fdSPablo de Lara #define MBQ_CAPACITY 32 48ed2a80fdSPablo de Lara 49ed2a80fdSPablo de Lara /* maps input ports to output ports for packets */ 5047523597SZhiyong Yang static uint16_t output_ports[RTE_MAX_ETHPORTS]; 51ed2a80fdSPablo de Lara 52ed2a80fdSPablo de Lara /* buffers up a set of packet that are ready to send */ 53ed2a80fdSPablo de Lara struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; 54ed2a80fdSPablo de Lara 55ed2a80fdSPablo de Lara /* shared data from server. We update statistics here */ 56ed2a80fdSPablo de Lara static struct tx_stats *tx_stats; 57ed2a80fdSPablo de Lara 58ed2a80fdSPablo de Lara static struct filter_stats *filter_stats; 59ed2a80fdSPablo de Lara 60ed2a80fdSPablo de Lara /* 61ed2a80fdSPablo de Lara * print a usage message 62ed2a80fdSPablo de Lara */ 63ed2a80fdSPablo de Lara static void 64ed2a80fdSPablo de Lara usage(const char *progname) 65ed2a80fdSPablo de Lara { 66ed2a80fdSPablo de Lara printf("Usage: %s [EAL args] -- -n <node_id>\n\n", progname); 67ed2a80fdSPablo de Lara } 68ed2a80fdSPablo de Lara 69ed2a80fdSPablo de Lara /* 70ed2a80fdSPablo de Lara * Convert the node id number from a string to an int. 71ed2a80fdSPablo de Lara */ 72ed2a80fdSPablo de Lara static int 73ed2a80fdSPablo de Lara parse_node_num(const char *node) 74ed2a80fdSPablo de Lara { 75ed2a80fdSPablo de Lara char *end = NULL; 76ed2a80fdSPablo de Lara unsigned long temp; 77ed2a80fdSPablo de Lara 78ed2a80fdSPablo de Lara if (node == NULL || *node == '\0') 79ed2a80fdSPablo de Lara return -1; 80ed2a80fdSPablo de Lara 81ed2a80fdSPablo de Lara temp = strtoul(node, &end, 10); 82ed2a80fdSPablo de Lara if (end == NULL || *end != '\0') 83ed2a80fdSPablo de Lara return -1; 84ed2a80fdSPablo de Lara 85ed2a80fdSPablo de Lara node_id = (uint8_t)temp; 86ed2a80fdSPablo de Lara return 0; 87ed2a80fdSPablo de Lara } 88ed2a80fdSPablo de Lara 89ed2a80fdSPablo de Lara /* 90ed2a80fdSPablo de Lara * Parse the application arguments to the node app. 91ed2a80fdSPablo de Lara */ 92ed2a80fdSPablo de Lara static int 93ed2a80fdSPablo de Lara parse_app_args(int argc, char *argv[]) 94ed2a80fdSPablo de Lara { 95ed2a80fdSPablo de Lara int option_index, opt; 96ed2a80fdSPablo de Lara char **argvopt = argv; 97ed2a80fdSPablo de Lara const char *progname = NULL; 98ed2a80fdSPablo de Lara static struct option lgopts[] = { /* no long options */ 99ed2a80fdSPablo de Lara {NULL, 0, 0, 0 } 100ed2a80fdSPablo de Lara }; 101ed2a80fdSPablo de Lara progname = argv[0]; 102ed2a80fdSPablo de Lara 103ed2a80fdSPablo de Lara while ((opt = getopt_long(argc, argvopt, "n:", lgopts, 104ed2a80fdSPablo de Lara &option_index)) != EOF) { 105ed2a80fdSPablo de Lara switch (opt) { 106ed2a80fdSPablo de Lara case 'n': 107ed2a80fdSPablo de Lara if (parse_node_num(optarg) != 0) { 108ed2a80fdSPablo de Lara usage(progname); 109ed2a80fdSPablo de Lara return -1; 110ed2a80fdSPablo de Lara } 111ed2a80fdSPablo de Lara break; 112ed2a80fdSPablo de Lara default: 113ed2a80fdSPablo de Lara usage(progname); 114ed2a80fdSPablo de Lara return -1; 115ed2a80fdSPablo de Lara } 116ed2a80fdSPablo de Lara } 117ed2a80fdSPablo de Lara return 0; 118ed2a80fdSPablo de Lara } 119ed2a80fdSPablo de Lara 120ed2a80fdSPablo de Lara /* 121ed2a80fdSPablo de Lara * Tx buffer error callback 122ed2a80fdSPablo de Lara */ 123ed2a80fdSPablo de Lara static void 124ed2a80fdSPablo de Lara flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count, 125ed2a80fdSPablo de Lara void *userdata) { 126ed2a80fdSPablo de Lara int i; 12747523597SZhiyong Yang uint16_t port_id = (uintptr_t)userdata; 128ed2a80fdSPablo de Lara 129ed2a80fdSPablo de Lara tx_stats->tx_drop[port_id] += count; 130ed2a80fdSPablo de Lara 131ed2a80fdSPablo de Lara /* free the mbufs which failed from transmit */ 132ed2a80fdSPablo de Lara for (i = 0; i < count; i++) 133ed2a80fdSPablo de Lara rte_pktmbuf_free(unsent[i]); 134ed2a80fdSPablo de Lara 135ed2a80fdSPablo de Lara } 136ed2a80fdSPablo de Lara 137ed2a80fdSPablo de Lara static void 13847523597SZhiyong Yang configure_tx_buffer(uint16_t port_id, uint16_t size) 139ed2a80fdSPablo de Lara { 140ed2a80fdSPablo de Lara int ret; 141ed2a80fdSPablo de Lara 142ed2a80fdSPablo de Lara /* Initialize TX buffers */ 143ed2a80fdSPablo de Lara tx_buffer[port_id] = rte_zmalloc_socket("tx_buffer", 144ed2a80fdSPablo de Lara RTE_ETH_TX_BUFFER_SIZE(size), 0, 145ed2a80fdSPablo de Lara rte_eth_dev_socket_id(port_id)); 146ed2a80fdSPablo de Lara if (tx_buffer[port_id] == NULL) 14747523597SZhiyong Yang rte_exit(EXIT_FAILURE, 14847523597SZhiyong Yang "Cannot allocate buffer for tx on port %u\n", port_id); 149ed2a80fdSPablo de Lara 150ed2a80fdSPablo de Lara rte_eth_tx_buffer_init(tx_buffer[port_id], size); 151ed2a80fdSPablo de Lara 152ed2a80fdSPablo de Lara ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[port_id], 153ed2a80fdSPablo de Lara flush_tx_error_callback, (void *)(intptr_t)port_id); 154ed2a80fdSPablo de Lara if (ret < 0) 15547523597SZhiyong Yang rte_exit(EXIT_FAILURE, 15647523597SZhiyong Yang "Cannot set error callback for tx buffer on port %u\n", 15747523597SZhiyong Yang port_id); 158ed2a80fdSPablo de Lara } 159ed2a80fdSPablo de Lara 160ed2a80fdSPablo de Lara /* 161ed2a80fdSPablo de Lara * set up output ports so that all traffic on port gets sent out 162ed2a80fdSPablo de Lara * its paired port. Index using actual port numbers since that is 163ed2a80fdSPablo de Lara * what comes in the mbuf structure. 164ed2a80fdSPablo de Lara */ 165ed2a80fdSPablo de Lara static void 166ed2a80fdSPablo de Lara configure_output_ports(const struct shared_info *info) 167ed2a80fdSPablo de Lara { 168ed2a80fdSPablo de Lara int i; 169ed2a80fdSPablo de Lara 170ed2a80fdSPablo de Lara if (info->num_ports > RTE_MAX_ETHPORTS) 171ed2a80fdSPablo de Lara rte_exit(EXIT_FAILURE, "Too many ethernet ports. " 172ed2a80fdSPablo de Lara "RTE_MAX_ETHPORTS = %u\n", 173ed2a80fdSPablo de Lara (unsigned int)RTE_MAX_ETHPORTS); 174ed2a80fdSPablo de Lara for (i = 0; i < info->num_ports - 1; i += 2) { 175ed2a80fdSPablo de Lara uint8_t p1 = info->id[i]; 176ed2a80fdSPablo de Lara uint8_t p2 = info->id[i+1]; 177ed2a80fdSPablo de Lara 178ed2a80fdSPablo de Lara output_ports[p1] = p2; 179ed2a80fdSPablo de Lara output_ports[p2] = p1; 180ed2a80fdSPablo de Lara 181ed2a80fdSPablo de Lara configure_tx_buffer(p1, MBQ_CAPACITY); 182ed2a80fdSPablo de Lara configure_tx_buffer(p2, MBQ_CAPACITY); 183ed2a80fdSPablo de Lara 184ed2a80fdSPablo de Lara } 185ed2a80fdSPablo de Lara } 186ed2a80fdSPablo de Lara 187ed2a80fdSPablo de Lara /* 188ed2a80fdSPablo de Lara * Create the hash table that will contain the flows that 189ed2a80fdSPablo de Lara * the node will handle, which will be used to decide if packet 190ed2a80fdSPablo de Lara * is transmitted or dropped. 191ed2a80fdSPablo de Lara */ 192ed2a80fdSPablo de Lara static struct rte_hash * 193ed2a80fdSPablo de Lara create_hash_table(const struct shared_info *info) 194ed2a80fdSPablo de Lara { 195ed2a80fdSPablo de Lara uint32_t num_flows_node = info->num_flows / info->num_nodes; 196ed2a80fdSPablo de Lara char name[RTE_HASH_NAMESIZE]; 197ed2a80fdSPablo de Lara struct rte_hash *h; 198ed2a80fdSPablo de Lara 199ed2a80fdSPablo de Lara /* create table */ 200ed2a80fdSPablo de Lara struct rte_hash_parameters hash_params = { 201ed2a80fdSPablo de Lara .entries = num_flows_node * 2, /* table load = 50% */ 202ed2a80fdSPablo de Lara .key_len = sizeof(uint32_t), /* Store IPv4 dest IP address */ 203ed2a80fdSPablo de Lara .socket_id = rte_socket_id(), 204ed2a80fdSPablo de Lara .hash_func_init_val = 0, 205ed2a80fdSPablo de Lara }; 206ed2a80fdSPablo de Lara 207ed2a80fdSPablo de Lara snprintf(name, sizeof(name), "hash_table_%d", node_id); 208ed2a80fdSPablo de Lara hash_params.name = name; 209ed2a80fdSPablo de Lara h = rte_hash_create(&hash_params); 210ed2a80fdSPablo de Lara 211ed2a80fdSPablo de Lara if (h == NULL) 212ed2a80fdSPablo de Lara rte_exit(EXIT_FAILURE, 213ed2a80fdSPablo de Lara "Problem creating the hash table for node %d\n", 214ed2a80fdSPablo de Lara node_id); 215ed2a80fdSPablo de Lara return h; 216ed2a80fdSPablo de Lara } 217ed2a80fdSPablo de Lara 218ed2a80fdSPablo de Lara static void 219ed2a80fdSPablo de Lara populate_hash_table(const struct rte_hash *h, const struct shared_info *info) 220ed2a80fdSPablo de Lara { 221ed2a80fdSPablo de Lara unsigned int i; 222ed2a80fdSPablo de Lara int32_t ret; 223ed2a80fdSPablo de Lara uint32_t ip_dst; 224ed2a80fdSPablo de Lara uint32_t num_flows_node = 0; 225ed2a80fdSPablo de Lara uint64_t target_node; 226ed2a80fdSPablo de Lara 227ed2a80fdSPablo de Lara /* Add flows in table */ 228ed2a80fdSPablo de Lara for (i = 0; i < info->num_flows; i++) { 229ed2a80fdSPablo de Lara target_node = i % info->num_nodes; 230ed2a80fdSPablo de Lara if (target_node != node_id) 231ed2a80fdSPablo de Lara continue; 232ed2a80fdSPablo de Lara 233ed2a80fdSPablo de Lara ip_dst = rte_cpu_to_be_32(i); 234ed2a80fdSPablo de Lara 235ed2a80fdSPablo de Lara ret = rte_hash_add_key(h, (void *) &ip_dst); 236ed2a80fdSPablo de Lara if (ret < 0) 237ed2a80fdSPablo de Lara rte_exit(EXIT_FAILURE, "Unable to add entry %u " 238ed2a80fdSPablo de Lara "in hash table\n", i); 239ed2a80fdSPablo de Lara else 240ed2a80fdSPablo de Lara num_flows_node++; 241ed2a80fdSPablo de Lara 242ed2a80fdSPablo de Lara } 243ed2a80fdSPablo de Lara 244ed2a80fdSPablo de Lara printf("Hash table: Adding 0x%x keys\n", num_flows_node); 245ed2a80fdSPablo de Lara } 246ed2a80fdSPablo de Lara 247ed2a80fdSPablo de Lara /* 248ed2a80fdSPablo de Lara * This function performs routing of packets 249ed2a80fdSPablo de Lara * Just sends each input packet out an output port based solely on the input 250ed2a80fdSPablo de Lara * port it arrived on. 251ed2a80fdSPablo de Lara */ 252ed2a80fdSPablo de Lara static inline void 253ed2a80fdSPablo de Lara transmit_packet(struct rte_mbuf *buf) 254ed2a80fdSPablo de Lara { 255ed2a80fdSPablo de Lara int sent; 25647523597SZhiyong Yang const uint16_t in_port = buf->port; 25747523597SZhiyong Yang const uint16_t out_port = output_ports[in_port]; 258ed2a80fdSPablo de Lara struct rte_eth_dev_tx_buffer *buffer = tx_buffer[out_port]; 259ed2a80fdSPablo de Lara 260ed2a80fdSPablo de Lara sent = rte_eth_tx_buffer(out_port, node_id, buffer, buf); 261ed2a80fdSPablo de Lara if (sent) 262ed2a80fdSPablo de Lara tx_stats->tx[out_port] += sent; 263ed2a80fdSPablo de Lara 264ed2a80fdSPablo de Lara } 265ed2a80fdSPablo de Lara 266ed2a80fdSPablo de Lara static inline void 267ed2a80fdSPablo de Lara handle_packets(struct rte_hash *h, struct rte_mbuf **bufs, uint16_t num_packets) 268ed2a80fdSPablo de Lara { 269a7c528e5SOlivier Matz struct rte_ipv4_hdr *ipv4_hdr; 270ed2a80fdSPablo de Lara uint32_t ipv4_dst_ip[PKT_READ_SIZE]; 271ed2a80fdSPablo de Lara const void *key_ptrs[PKT_READ_SIZE]; 272ed2a80fdSPablo de Lara unsigned int i; 273ed2a80fdSPablo de Lara int32_t positions[PKT_READ_SIZE] = {0}; 274ed2a80fdSPablo de Lara 275ed2a80fdSPablo de Lara for (i = 0; i < num_packets; i++) { 276ed2a80fdSPablo de Lara /* Handle IPv4 header.*/ 277a7c528e5SOlivier Matz ipv4_hdr = rte_pktmbuf_mtod_offset(bufs[i], 278a7c528e5SOlivier Matz struct rte_ipv4_hdr *, sizeof(struct rte_ether_hdr)); 279ed2a80fdSPablo de Lara ipv4_dst_ip[i] = ipv4_hdr->dst_addr; 280ed2a80fdSPablo de Lara key_ptrs[i] = &ipv4_dst_ip[i]; 281ed2a80fdSPablo de Lara } 282ed2a80fdSPablo de Lara /* Check if packets belongs to any flows handled by this node */ 283ed2a80fdSPablo de Lara rte_hash_lookup_bulk(h, key_ptrs, num_packets, positions); 284ed2a80fdSPablo de Lara 285ed2a80fdSPablo de Lara for (i = 0; i < num_packets; i++) { 286ed2a80fdSPablo de Lara if (likely(positions[i] >= 0)) { 287ed2a80fdSPablo de Lara filter_stats->passed++; 288ed2a80fdSPablo de Lara transmit_packet(bufs[i]); 289ed2a80fdSPablo de Lara } else { 290ed2a80fdSPablo de Lara filter_stats->drop++; 291ed2a80fdSPablo de Lara /* Drop packet, as flow is not handled by this node */ 292ed2a80fdSPablo de Lara rte_pktmbuf_free(bufs[i]); 293ed2a80fdSPablo de Lara } 294ed2a80fdSPablo de Lara } 295ed2a80fdSPablo de Lara } 296ed2a80fdSPablo de Lara 297ed2a80fdSPablo de Lara /* 298ed2a80fdSPablo de Lara * Application main function - loops through 299ed2a80fdSPablo de Lara * receiving and processing packets. Never returns 300ed2a80fdSPablo de Lara */ 301ed2a80fdSPablo de Lara int 302ed2a80fdSPablo de Lara main(int argc, char *argv[]) 303ed2a80fdSPablo de Lara { 304ed2a80fdSPablo de Lara const struct rte_memzone *mz; 305ed2a80fdSPablo de Lara struct rte_ring *rx_ring; 306ed2a80fdSPablo de Lara struct rte_hash *h; 307ed2a80fdSPablo de Lara struct rte_mempool *mp; 308ed2a80fdSPablo de Lara struct shared_info *info; 309ed2a80fdSPablo de Lara int need_flush = 0; /* indicates whether we have unsent packets */ 310ed2a80fdSPablo de Lara int retval; 311ed2a80fdSPablo de Lara void *pkts[PKT_READ_SIZE]; 312ed2a80fdSPablo de Lara uint16_t sent; 313ed2a80fdSPablo de Lara 314ed2a80fdSPablo de Lara retval = rte_eal_init(argc, argv); 315ed2a80fdSPablo de Lara if (retval < 0) 316ed2a80fdSPablo de Lara return -1; 317ed2a80fdSPablo de Lara argc -= retval; 318ed2a80fdSPablo de Lara argv += retval; 319ed2a80fdSPablo de Lara 320ed2a80fdSPablo de Lara if (parse_app_args(argc, argv) < 0) 321ed2a80fdSPablo de Lara rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n"); 322ed2a80fdSPablo de Lara 323d9a42a69SThomas Monjalon if (rte_eth_dev_count_avail() == 0) 324ed2a80fdSPablo de Lara rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); 325ed2a80fdSPablo de Lara 326ed2a80fdSPablo de Lara rx_ring = rte_ring_lookup(get_rx_queue_name(node_id)); 327ed2a80fdSPablo de Lara if (rx_ring == NULL) 328ed2a80fdSPablo de Lara rte_exit(EXIT_FAILURE, "Cannot get RX ring - " 329ed2a80fdSPablo de Lara "is server process running?\n"); 330ed2a80fdSPablo de Lara 331ed2a80fdSPablo de Lara mp = rte_mempool_lookup(PKTMBUF_POOL_NAME); 332ed2a80fdSPablo de Lara if (mp == NULL) 333ed2a80fdSPablo de Lara rte_exit(EXIT_FAILURE, "Cannot get mempool for mbufs\n"); 334ed2a80fdSPablo de Lara 335ed2a80fdSPablo de Lara mz = rte_memzone_lookup(MZ_SHARED_INFO); 336ed2a80fdSPablo de Lara if (mz == NULL) 337ed2a80fdSPablo de Lara rte_exit(EXIT_FAILURE, "Cannot get port info structure\n"); 338ed2a80fdSPablo de Lara info = mz->addr; 339ed2a80fdSPablo de Lara tx_stats = &(info->tx_stats[node_id]); 340ed2a80fdSPablo de Lara filter_stats = &(info->filter_stats[node_id]); 341ed2a80fdSPablo de Lara 342ed2a80fdSPablo de Lara configure_output_ports(info); 343ed2a80fdSPablo de Lara 344ed2a80fdSPablo de Lara h = create_hash_table(info); 345ed2a80fdSPablo de Lara 346ed2a80fdSPablo de Lara populate_hash_table(h, info); 347ed2a80fdSPablo de Lara 348ed2a80fdSPablo de Lara RTE_LOG(INFO, APP, "Finished Process Init.\n"); 349ed2a80fdSPablo de Lara 350ed2a80fdSPablo de Lara printf("\nNode process %d handling packets\n", node_id); 351ed2a80fdSPablo de Lara printf("[Press Ctrl-C to quit ...]\n"); 352ed2a80fdSPablo de Lara 353ed2a80fdSPablo de Lara for (;;) { 354ed2a80fdSPablo de Lara uint16_t rx_pkts = PKT_READ_SIZE; 35547523597SZhiyong Yang uint16_t port; 356ed2a80fdSPablo de Lara 357ed2a80fdSPablo de Lara /* 358ed2a80fdSPablo de Lara * Try dequeuing max possible packets first, if that fails, 359ed2a80fdSPablo de Lara * get the most we can. Loop body should only execute once, 360ed2a80fdSPablo de Lara * maximum 361ed2a80fdSPablo de Lara */ 362ed2a80fdSPablo de Lara while (rx_pkts > 0 && 363ed2a80fdSPablo de Lara unlikely(rte_ring_dequeue_bulk(rx_ring, pkts, 364ecaed092SBruce Richardson rx_pkts, NULL) == 0)) 365ed2a80fdSPablo de Lara rx_pkts = (uint16_t)RTE_MIN(rte_ring_count(rx_ring), 366ed2a80fdSPablo de Lara PKT_READ_SIZE); 367ed2a80fdSPablo de Lara 368ed2a80fdSPablo de Lara if (unlikely(rx_pkts == 0)) { 369ed2a80fdSPablo de Lara if (need_flush) 370ed2a80fdSPablo de Lara for (port = 0; port < info->num_ports; port++) { 371ed2a80fdSPablo de Lara sent = rte_eth_tx_buffer_flush( 372ed2a80fdSPablo de Lara info->id[port], 373ed2a80fdSPablo de Lara node_id, 374ed2a80fdSPablo de Lara tx_buffer[port]); 375ed2a80fdSPablo de Lara if (unlikely(sent)) 376ed2a80fdSPablo de Lara tx_stats->tx[port] += sent; 377ed2a80fdSPablo de Lara } 378ed2a80fdSPablo de Lara need_flush = 0; 379ed2a80fdSPablo de Lara continue; 380ed2a80fdSPablo de Lara } 381ed2a80fdSPablo de Lara 382ed2a80fdSPablo de Lara handle_packets(h, (struct rte_mbuf **)pkts, rx_pkts); 383ed2a80fdSPablo de Lara 384ed2a80fdSPablo de Lara need_flush = 1; 385ed2a80fdSPablo de Lara } 386*10aa3757SChengchang Tang 387*10aa3757SChengchang Tang /* clean up the EAL */ 388*10aa3757SChengchang Tang rte_eal_cleanup(); 389ed2a80fdSPablo de Lara } 390