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