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