1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2016 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_lcore.h> 25 #include <rte_ring.h> 26 #include <rte_launch.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 35 #include "common.h" 36 37 /* Number of packets to attempt to read from queue */ 38 #define PKT_READ_SIZE ((uint16_t)32) 39 40 /* our client id number - tells us which rx queue to read, and NIC TX 41 * queue to write to. */ 42 static uint8_t client_id = 0; 43 44 #define MBQ_CAPACITY 32 45 46 /* maps input ports to output ports for packets */ 47 static uint16_t output_ports[RTE_MAX_ETHPORTS]; 48 49 /* buffers up a set of packet that are ready to send */ 50 struct rte_eth_dev_tx_buffer *tx_buffer[RTE_MAX_ETHPORTS]; 51 52 /* shared data from server. We update statistics here */ 53 static volatile struct tx_stats *tx_stats; 54 55 56 /* 57 * print a usage message 58 */ 59 static void 60 usage(const char *progname) 61 { 62 printf("Usage: %s [EAL args] -- -n <client_id>\n\n", progname); 63 } 64 65 /* 66 * Convert the client id number from a string to an int. 67 */ 68 static int 69 parse_client_num(const char *client) 70 { 71 char *end = NULL; 72 unsigned long temp; 73 74 if (client == NULL || *client == '\0') 75 return -1; 76 77 temp = strtoul(client, &end, 10); 78 if (end == NULL || *end != '\0') 79 return -1; 80 81 client_id = (uint8_t)temp; 82 return 0; 83 } 84 85 /* 86 * Parse the application arguments to the client app. 87 */ 88 static int 89 parse_app_args(int argc, char *argv[]) 90 { 91 int option_index, opt; 92 char **argvopt = argv; 93 const char *progname = NULL; 94 static struct option lgopts[] = { /* no long options */ 95 {NULL, 0, 0, 0 } 96 }; 97 progname = argv[0]; 98 99 while ((opt = getopt_long(argc, argvopt, "n:", lgopts, 100 &option_index)) != EOF){ 101 switch (opt){ 102 case 'n': 103 if (parse_client_num(optarg) != 0){ 104 usage(progname); 105 return -1; 106 } 107 break; 108 default: 109 usage(progname); 110 return -1; 111 } 112 } 113 return 0; 114 } 115 116 /* 117 * Tx buffer error callback 118 */ 119 static void 120 flush_tx_error_callback(struct rte_mbuf **unsent, uint16_t count, 121 void *userdata) { 122 int i; 123 uint16_t port_id = (uintptr_t)userdata; 124 125 tx_stats->tx_drop[port_id] += count; 126 127 /* free the mbufs which failed from transmit */ 128 for (i = 0; i < count; i++) 129 rte_pktmbuf_free(unsent[i]); 130 131 } 132 133 static void 134 configure_tx_buffer(uint16_t port_id, uint16_t size) 135 { 136 int ret; 137 138 /* Initialize TX buffers */ 139 tx_buffer[port_id] = rte_zmalloc_socket("tx_buffer", 140 RTE_ETH_TX_BUFFER_SIZE(size), 0, 141 rte_eth_dev_socket_id(port_id)); 142 if (tx_buffer[port_id] == NULL) 143 rte_exit(EXIT_FAILURE, "Cannot allocate buffer for tx on port %u\n", 144 port_id); 145 146 rte_eth_tx_buffer_init(tx_buffer[port_id], size); 147 148 ret = rte_eth_tx_buffer_set_err_callback(tx_buffer[port_id], 149 flush_tx_error_callback, (void *)(intptr_t)port_id); 150 if (ret < 0) 151 rte_exit(EXIT_FAILURE, 152 "Cannot set error callback for tx buffer on port %u\n", 153 port_id); 154 } 155 156 /* 157 * set up output ports so that all traffic on port gets sent out 158 * its paired port. Index using actual port numbers since that is 159 * what comes in the mbuf structure. 160 */ 161 static void 162 configure_output_ports(const struct port_info *ports) 163 { 164 int i; 165 if (ports->num_ports > RTE_MAX_ETHPORTS) 166 rte_exit(EXIT_FAILURE, "Too many ethernet ports. RTE_MAX_ETHPORTS = %u\n", 167 (unsigned)RTE_MAX_ETHPORTS); 168 for (i = 0; i < ports->num_ports - 1; i+=2){ 169 uint16_t p1 = ports->id[i]; 170 uint16_t p2 = ports->id[i+1]; 171 output_ports[p1] = p2; 172 output_ports[p2] = p1; 173 174 configure_tx_buffer(p1, MBQ_CAPACITY); 175 configure_tx_buffer(p2, MBQ_CAPACITY); 176 177 } 178 } 179 180 /* 181 * This function performs routing of packets 182 * Just sends each input packet out an output port based solely on the input 183 * port it arrived on. 184 */ 185 static void 186 handle_packet(struct rte_mbuf *buf) 187 { 188 int sent; 189 const uint16_t in_port = buf->port; 190 const uint16_t out_port = output_ports[in_port]; 191 struct rte_eth_dev_tx_buffer *buffer = tx_buffer[out_port]; 192 193 sent = rte_eth_tx_buffer(out_port, client_id, buffer, buf); 194 if (sent) 195 tx_stats->tx[out_port] += sent; 196 197 } 198 199 /* 200 * Application main function - loops through 201 * receiving and processing packets. Never returns 202 */ 203 int 204 main(int argc, char *argv[]) 205 { 206 const struct rte_memzone *mz; 207 struct rte_ring *rx_ring; 208 struct rte_mempool *mp; 209 struct port_info *ports; 210 int need_flush = 0; /* indicates whether we have unsent packets */ 211 int retval; 212 void *pkts[PKT_READ_SIZE]; 213 uint16_t sent; 214 215 if ((retval = rte_eal_init(argc, argv)) < 0) 216 return -1; 217 argc -= retval; 218 argv += retval; 219 220 if (parse_app_args(argc, argv) < 0) 221 rte_exit(EXIT_FAILURE, "Invalid command-line arguments\n"); 222 223 if (rte_eth_dev_count_avail() == 0) 224 rte_exit(EXIT_FAILURE, "No Ethernet ports - bye\n"); 225 226 rx_ring = rte_ring_lookup(get_rx_queue_name(client_id)); 227 if (rx_ring == NULL) 228 rte_exit(EXIT_FAILURE, "Cannot get RX ring - is server process running?\n"); 229 230 mp = rte_mempool_lookup(PKTMBUF_POOL_NAME); 231 if (mp == NULL) 232 rte_exit(EXIT_FAILURE, "Cannot get mempool for mbufs\n"); 233 234 mz = rte_memzone_lookup(MZ_PORT_INFO); 235 if (mz == NULL) 236 rte_exit(EXIT_FAILURE, "Cannot get port info structure\n"); 237 ports = mz->addr; 238 tx_stats = &(ports->tx_stats[client_id]); 239 240 configure_output_ports(ports); 241 242 RTE_LOG(INFO, APP, "Finished Process Init.\n"); 243 244 printf("\nClient process %d handling packets\n", client_id); 245 printf("[Press Ctrl-C to quit ...]\n"); 246 247 for (;;) { 248 uint16_t i, rx_pkts; 249 250 rx_pkts = rte_ring_dequeue_burst(rx_ring, pkts, 251 PKT_READ_SIZE, NULL); 252 253 if (rx_pkts == 0 && need_flush) { 254 for (i = 0; i < ports->num_ports; i++) { 255 uint16_t port = ports->id[i]; 256 257 sent = rte_eth_tx_buffer_flush(port, 258 client_id, 259 tx_buffer[port]); 260 tx_stats->tx[port] += sent; 261 } 262 need_flush = 0; 263 continue; 264 } 265 266 for (i = 0; i < rx_pkts; i++) 267 handle_packet(pkts[i]); 268 269 need_flush = 1; 270 } 271 } 272