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