13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
23998e2a0SBruce Richardson * Copyright(c) 2015 Intel Corporation
3bda68ab9SRemy Horton */
4bda68ab9SRemy Horton
5bda68ab9SRemy Horton
6bda68ab9SRemy Horton #include <stdio.h>
7bda68ab9SRemy Horton #include <stdlib.h>
8bda68ab9SRemy Horton
9bda68ab9SRemy Horton #include <rte_common.h>
1071e6e8c5SThomas Monjalon #include <rte_spinlock.h>
11bda68ab9SRemy Horton #include <rte_eal.h>
12bda68ab9SRemy Horton #include <rte_ethdev.h>
13bda68ab9SRemy Horton #include <rte_ether.h>
14bda68ab9SRemy Horton #include <rte_ip.h>
15bda68ab9SRemy Horton #include <rte_memory.h>
16bda68ab9SRemy Horton #include <rte_mempool.h>
17bda68ab9SRemy Horton #include <rte_mbuf.h>
18bda68ab9SRemy Horton
19bda68ab9SRemy Horton #include "ethapp.h"
20bda68ab9SRemy Horton
21bda68ab9SRemy Horton #define MAX_PORTS RTE_MAX_ETHPORTS
22bda68ab9SRemy Horton #define MAX_BURST_LENGTH 32
23867a6c66SKevin Laatz #define PORT_RX_QUEUE_SIZE 1024
24867a6c66SKevin Laatz #define PORT_TX_QUEUE_SIZE 1024
25bda68ab9SRemy Horton #define PKTPOOL_EXTRA_SIZE 512
26bda68ab9SRemy Horton #define PKTPOOL_CACHE 32
27bda68ab9SRemy Horton
28bda68ab9SRemy Horton
29bda68ab9SRemy Horton struct txq_port {
30bda68ab9SRemy Horton uint16_t cnt_unsent;
31bda68ab9SRemy Horton struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
32bda68ab9SRemy Horton };
33bda68ab9SRemy Horton
34bda68ab9SRemy Horton struct app_port {
356d13ea8eSOlivier Matz struct rte_ether_addr mac_addr;
36bda68ab9SRemy Horton struct txq_port txq;
37bda68ab9SRemy Horton rte_spinlock_t lock;
38bda68ab9SRemy Horton int port_active;
39bda68ab9SRemy Horton int port_dirty;
40bda68ab9SRemy Horton int idx_port;
41bda68ab9SRemy Horton struct rte_mempool *pkt_pool;
42bda68ab9SRemy Horton };
43bda68ab9SRemy Horton
44bda68ab9SRemy Horton struct app_config {
45bda68ab9SRemy Horton struct app_port ports[MAX_PORTS];
46bda68ab9SRemy Horton int cnt_ports;
47bda68ab9SRemy Horton int exit_now;
48bda68ab9SRemy Horton };
49bda68ab9SRemy Horton
50bda68ab9SRemy Horton
51bda68ab9SRemy Horton struct app_config app_cfg;
52bda68ab9SRemy Horton
53bda68ab9SRemy Horton
lock_port(int idx_port)54bda68ab9SRemy Horton void lock_port(int idx_port)
55bda68ab9SRemy Horton {
56bda68ab9SRemy Horton struct app_port *ptr_port = &app_cfg.ports[idx_port];
57bda68ab9SRemy Horton
58bda68ab9SRemy Horton rte_spinlock_lock(&ptr_port->lock);
59bda68ab9SRemy Horton }
60bda68ab9SRemy Horton
unlock_port(int idx_port)61bda68ab9SRemy Horton void unlock_port(int idx_port)
62bda68ab9SRemy Horton {
63bda68ab9SRemy Horton struct app_port *ptr_port = &app_cfg.ports[idx_port];
64bda68ab9SRemy Horton
65bda68ab9SRemy Horton rte_spinlock_unlock(&ptr_port->lock);
66bda68ab9SRemy Horton }
67bda68ab9SRemy Horton
mark_port_active(int idx_port)68bda68ab9SRemy Horton void mark_port_active(int idx_port)
69bda68ab9SRemy Horton {
70bda68ab9SRemy Horton struct app_port *ptr_port = &app_cfg.ports[idx_port];
71bda68ab9SRemy Horton
72bda68ab9SRemy Horton ptr_port->port_active = 1;
73bda68ab9SRemy Horton }
74bda68ab9SRemy Horton
mark_port_inactive(int idx_port)75bda68ab9SRemy Horton void mark_port_inactive(int idx_port)
76bda68ab9SRemy Horton {
77bda68ab9SRemy Horton struct app_port *ptr_port = &app_cfg.ports[idx_port];
78bda68ab9SRemy Horton
79bda68ab9SRemy Horton ptr_port->port_active = 0;
80bda68ab9SRemy Horton }
81bda68ab9SRemy Horton
mark_port_newmac(int idx_port)82bda68ab9SRemy Horton void mark_port_newmac(int idx_port)
83bda68ab9SRemy Horton {
84bda68ab9SRemy Horton struct app_port *ptr_port = &app_cfg.ports[idx_port];
85bda68ab9SRemy Horton
86bda68ab9SRemy Horton ptr_port->port_dirty = 1;
87bda68ab9SRemy Horton }
88bda68ab9SRemy Horton
setup_ports(struct app_config * app_cfg,int cnt_ports)89bda68ab9SRemy Horton static void setup_ports(struct app_config *app_cfg, int cnt_ports)
90bda68ab9SRemy Horton {
91bda68ab9SRemy Horton int idx_port;
92bda68ab9SRemy Horton int size_pktpool;
93bda68ab9SRemy Horton struct rte_eth_conf cfg_port;
94bda68ab9SRemy Horton struct rte_eth_dev_info dev_info;
95bda68ab9SRemy Horton char str_name[16];
9660efb44fSRoman Zhukov uint16_t nb_rxd = PORT_RX_QUEUE_SIZE;
9760efb44fSRoman Zhukov uint16_t nb_txd = PORT_TX_QUEUE_SIZE;
98089e5ed7SIvan Ilchenko int ret;
99bda68ab9SRemy Horton
100bda68ab9SRemy Horton memset(&cfg_port, 0, sizeof(cfg_port));
101295968d1SFerruh Yigit cfg_port.txmode.mq_mode = RTE_ETH_MQ_TX_NONE;
102bda68ab9SRemy Horton
103bda68ab9SRemy Horton for (idx_port = 0; idx_port < cnt_ports; idx_port++) {
104bda68ab9SRemy Horton struct app_port *ptr_port = &app_cfg->ports[idx_port];
105bda68ab9SRemy Horton
106089e5ed7SIvan Ilchenko ret = rte_eth_dev_info_get(idx_port, &dev_info);
107089e5ed7SIvan Ilchenko if (ret != 0)
108089e5ed7SIvan Ilchenko rte_exit(EXIT_FAILURE,
109089e5ed7SIvan Ilchenko "Error during getting device (port %u) info: %s\n",
110089e5ed7SIvan Ilchenko idx_port, strerror(-ret));
111089e5ed7SIvan Ilchenko
112bda68ab9SRemy Horton size_pktpool = dev_info.rx_desc_lim.nb_max +
113bda68ab9SRemy Horton dev_info.tx_desc_lim.nb_max + PKTPOOL_EXTRA_SIZE;
114bda68ab9SRemy Horton
115bda68ab9SRemy Horton snprintf(str_name, 16, "pkt_pool%i", idx_port);
116bda68ab9SRemy Horton ptr_port->pkt_pool = rte_pktmbuf_pool_create(
117bda68ab9SRemy Horton str_name,
118bda68ab9SRemy Horton size_pktpool, PKTPOOL_CACHE,
119bda68ab9SRemy Horton 0,
120bda68ab9SRemy Horton RTE_MBUF_DEFAULT_BUF_SIZE,
121bda68ab9SRemy Horton rte_socket_id()
122bda68ab9SRemy Horton );
123bda68ab9SRemy Horton if (ptr_port->pkt_pool == NULL)
124bda68ab9SRemy Horton rte_exit(EXIT_FAILURE,
125bda68ab9SRemy Horton "rte_pktmbuf_pool_create failed"
126bda68ab9SRemy Horton );
127bda68ab9SRemy Horton
128bda68ab9SRemy Horton printf("Init port %i..\n", idx_port);
129bda68ab9SRemy Horton ptr_port->port_active = 1;
130bda68ab9SRemy Horton ptr_port->port_dirty = 0;
131bda68ab9SRemy Horton ptr_port->idx_port = idx_port;
132bda68ab9SRemy Horton
133bda68ab9SRemy Horton if (rte_eth_dev_configure(idx_port, 1, 1, &cfg_port) < 0)
134bda68ab9SRemy Horton rte_exit(EXIT_FAILURE,
135bda68ab9SRemy Horton "rte_eth_dev_configure failed");
13660efb44fSRoman Zhukov if (rte_eth_dev_adjust_nb_rx_tx_desc(idx_port, &nb_rxd,
13760efb44fSRoman Zhukov &nb_txd) < 0)
13860efb44fSRoman Zhukov rte_exit(EXIT_FAILURE,
13960efb44fSRoman Zhukov "rte_eth_dev_adjust_nb_rx_tx_desc failed");
140008ee817SShahaf Shuler
141bda68ab9SRemy Horton if (rte_eth_rx_queue_setup(
14260efb44fSRoman Zhukov idx_port, 0, nb_rxd,
143bda68ab9SRemy Horton rte_eth_dev_socket_id(idx_port), NULL,
144bda68ab9SRemy Horton ptr_port->pkt_pool) < 0)
145bda68ab9SRemy Horton rte_exit(EXIT_FAILURE,
146bda68ab9SRemy Horton "rte_eth_rx_queue_setup failed"
147bda68ab9SRemy Horton );
148bda68ab9SRemy Horton if (rte_eth_tx_queue_setup(
14960efb44fSRoman Zhukov idx_port, 0, nb_txd,
150e00a5eaaSThomas Monjalon rte_eth_dev_socket_id(idx_port), NULL) < 0)
151bda68ab9SRemy Horton rte_exit(EXIT_FAILURE,
152bda68ab9SRemy Horton "rte_eth_tx_queue_setup failed"
153bda68ab9SRemy Horton );
154bda68ab9SRemy Horton if (rte_eth_dev_start(idx_port) < 0)
155bda68ab9SRemy Horton rte_exit(EXIT_FAILURE,
156bda68ab9SRemy Horton "%s:%i: rte_eth_dev_start failed",
157bda68ab9SRemy Horton __FILE__, __LINE__
158bda68ab9SRemy Horton );
15970febdcfSIgor Romanov ret = rte_eth_macaddr_get(idx_port, &ptr_port->mac_addr);
16070febdcfSIgor Romanov if (ret != 0)
16170febdcfSIgor Romanov rte_exit(EXIT_FAILURE,
16270febdcfSIgor Romanov "rte_eth_macaddr_get failed (port %u): %s\n",
16370febdcfSIgor Romanov idx_port, rte_strerror(-ret));
16470febdcfSIgor Romanov
165bda68ab9SRemy Horton rte_spinlock_init(&ptr_port->lock);
166bda68ab9SRemy Horton }
167bda68ab9SRemy Horton }
168bda68ab9SRemy Horton
process_frame(struct app_port * ptr_port,struct rte_mbuf * ptr_frame)169bda68ab9SRemy Horton static void process_frame(struct app_port *ptr_port,
170bda68ab9SRemy Horton struct rte_mbuf *ptr_frame)
171bda68ab9SRemy Horton {
1726d13ea8eSOlivier Matz struct rte_ether_hdr *ptr_mac_hdr;
173bda68ab9SRemy Horton
1746d13ea8eSOlivier Matz ptr_mac_hdr = rte_pktmbuf_mtod(ptr_frame, struct rte_ether_hdr *);
17504d43857SDmitry Kozlyuk rte_ether_addr_copy(&ptr_mac_hdr->src_addr, &ptr_mac_hdr->dst_addr);
17604d43857SDmitry Kozlyuk rte_ether_addr_copy(&ptr_port->mac_addr, &ptr_mac_hdr->src_addr);
177bda68ab9SRemy Horton }
178bda68ab9SRemy Horton
worker_main(__rte_unused void * ptr_data)179cb056611SStephen Hemminger static int worker_main(__rte_unused void *ptr_data)
180bda68ab9SRemy Horton {
181bda68ab9SRemy Horton struct app_port *ptr_port;
182bda68ab9SRemy Horton struct rte_mbuf *ptr_frame;
183bda68ab9SRemy Horton struct txq_port *txq;
184bda68ab9SRemy Horton
185bda68ab9SRemy Horton uint16_t cnt_recv_frames;
186bda68ab9SRemy Horton uint16_t idx_frame;
187bda68ab9SRemy Horton uint16_t cnt_sent;
188bda68ab9SRemy Horton uint16_t idx_port;
189bda68ab9SRemy Horton uint16_t lock_result;
19070febdcfSIgor Romanov int ret;
191bda68ab9SRemy Horton
192bda68ab9SRemy Horton while (app_cfg.exit_now == 0) {
193bda68ab9SRemy Horton for (idx_port = 0; idx_port < app_cfg.cnt_ports; idx_port++) {
194bda68ab9SRemy Horton /* Check that port is active and unlocked */
195bda68ab9SRemy Horton ptr_port = &app_cfg.ports[idx_port];
196bda68ab9SRemy Horton lock_result = rte_spinlock_trylock(&ptr_port->lock);
197bda68ab9SRemy Horton if (lock_result == 0)
198bda68ab9SRemy Horton continue;
199bda68ab9SRemy Horton if (ptr_port->port_active == 0) {
200bda68ab9SRemy Horton rte_spinlock_unlock(&ptr_port->lock);
201bda68ab9SRemy Horton continue;
202bda68ab9SRemy Horton }
203bda68ab9SRemy Horton txq = &ptr_port->txq;
204bda68ab9SRemy Horton
205bda68ab9SRemy Horton /* MAC address was updated */
206bda68ab9SRemy Horton if (ptr_port->port_dirty == 1) {
20770febdcfSIgor Romanov ret = rte_eth_macaddr_get(ptr_port->idx_port,
208bda68ab9SRemy Horton &ptr_port->mac_addr);
20970febdcfSIgor Romanov if (ret != 0) {
21070febdcfSIgor Romanov rte_spinlock_unlock(&ptr_port->lock);
21170febdcfSIgor Romanov printf("Failed to get MAC address (port %u): %s",
21270febdcfSIgor Romanov ptr_port->idx_port,
21370febdcfSIgor Romanov rte_strerror(-ret));
21470febdcfSIgor Romanov return ret;
21570febdcfSIgor Romanov }
21670febdcfSIgor Romanov
217bda68ab9SRemy Horton ptr_port->port_dirty = 0;
218bda68ab9SRemy Horton }
219bda68ab9SRemy Horton
220bda68ab9SRemy Horton /* Incoming frames */
221bda68ab9SRemy Horton cnt_recv_frames = rte_eth_rx_burst(
222bda68ab9SRemy Horton ptr_port->idx_port, 0,
223bda68ab9SRemy Horton &txq->buf_frames[txq->cnt_unsent],
224bda68ab9SRemy Horton RTE_DIM(txq->buf_frames) - txq->cnt_unsent
225bda68ab9SRemy Horton );
226bda68ab9SRemy Horton if (cnt_recv_frames > 0) {
227bda68ab9SRemy Horton for (idx_frame = 0;
228bda68ab9SRemy Horton idx_frame < cnt_recv_frames;
229bda68ab9SRemy Horton idx_frame++) {
230bda68ab9SRemy Horton ptr_frame = txq->buf_frames[
231bda68ab9SRemy Horton idx_frame + txq->cnt_unsent];
232bda68ab9SRemy Horton process_frame(ptr_port, ptr_frame);
233bda68ab9SRemy Horton }
234bda68ab9SRemy Horton txq->cnt_unsent += cnt_recv_frames;
235bda68ab9SRemy Horton }
236bda68ab9SRemy Horton
237bda68ab9SRemy Horton /* Outgoing frames */
238bda68ab9SRemy Horton if (txq->cnt_unsent > 0) {
239bda68ab9SRemy Horton cnt_sent = rte_eth_tx_burst(
240bda68ab9SRemy Horton ptr_port->idx_port, 0,
241bda68ab9SRemy Horton txq->buf_frames,
242bda68ab9SRemy Horton txq->cnt_unsent
243bda68ab9SRemy Horton );
244bda68ab9SRemy Horton /* Shuffle up unsent frame pointers */
245bda68ab9SRemy Horton for (idx_frame = cnt_sent;
246bda68ab9SRemy Horton idx_frame < txq->cnt_unsent;
247bda68ab9SRemy Horton idx_frame++)
248bda68ab9SRemy Horton txq->buf_frames[idx_frame - cnt_sent] =
249bda68ab9SRemy Horton txq->buf_frames[idx_frame];
250bda68ab9SRemy Horton txq->cnt_unsent -= cnt_sent;
251bda68ab9SRemy Horton }
252bda68ab9SRemy Horton rte_spinlock_unlock(&ptr_port->lock);
253bda68ab9SRemy Horton } /* end for( idx_port ) */
254bda68ab9SRemy Horton } /* end for(;;) */
255bda68ab9SRemy Horton
256bda68ab9SRemy Horton return 0;
257bda68ab9SRemy Horton }
258bda68ab9SRemy Horton
close_ports(void)259*497025daSHuisong Li static void close_ports(void)
260*497025daSHuisong Li {
261*497025daSHuisong Li uint16_t portid;
262*497025daSHuisong Li int ret;
263*497025daSHuisong Li
264*497025daSHuisong Li for (portid = 0; portid < app_cfg.cnt_ports; portid++) {
265*497025daSHuisong Li printf("Closing port %d...", portid);
266*497025daSHuisong Li ret = rte_eth_dev_stop(portid);
267*497025daSHuisong Li if (ret != 0)
268*497025daSHuisong Li rte_exit(EXIT_FAILURE, "rte_eth_dev_stop: err=%s, port=%u\n",
269*497025daSHuisong Li strerror(-ret), portid);
270*497025daSHuisong Li rte_eth_dev_close(portid);
271*497025daSHuisong Li printf(" Done\n");
272*497025daSHuisong Li }
273*497025daSHuisong Li }
274*497025daSHuisong Li
main(int argc,char ** argv)275bda68ab9SRemy Horton int main(int argc, char **argv)
276bda68ab9SRemy Horton {
277bda68ab9SRemy Horton int cnt_args_parsed;
278bda68ab9SRemy Horton uint32_t id_core;
279bda68ab9SRemy Horton uint32_t cnt_ports;
280bda68ab9SRemy Horton
28198a7ea33SJerin Jacob /* Init runtime environment */
282bda68ab9SRemy Horton cnt_args_parsed = rte_eal_init(argc, argv);
283bda68ab9SRemy Horton if (cnt_args_parsed < 0)
284bda68ab9SRemy Horton rte_exit(EXIT_FAILURE, "rte_eal_init(): Failed");
285bda68ab9SRemy Horton
286d9a42a69SThomas Monjalon cnt_ports = rte_eth_dev_count_avail();
287bda68ab9SRemy Horton printf("Number of NICs: %i\n", cnt_ports);
288bda68ab9SRemy Horton if (cnt_ports == 0)
289bda68ab9SRemy Horton rte_exit(EXIT_FAILURE, "No available NIC ports!\n");
290bda68ab9SRemy Horton if (cnt_ports > MAX_PORTS) {
291bda68ab9SRemy Horton printf("Info: Using only %i of %i ports\n",
292bda68ab9SRemy Horton cnt_ports, MAX_PORTS
293bda68ab9SRemy Horton );
294bda68ab9SRemy Horton cnt_ports = MAX_PORTS;
295bda68ab9SRemy Horton }
296bda68ab9SRemy Horton
297bda68ab9SRemy Horton setup_ports(&app_cfg, cnt_ports);
298bda68ab9SRemy Horton
299bda68ab9SRemy Horton app_cfg.exit_now = 0;
300bda68ab9SRemy Horton app_cfg.cnt_ports = cnt_ports;
301bda68ab9SRemy Horton
302bda68ab9SRemy Horton if (rte_lcore_count() < 2)
303cb056611SStephen Hemminger rte_exit(EXIT_FAILURE, "No available worker core!\n");
304cb056611SStephen Hemminger
305cb056611SStephen Hemminger /* Assume there is an available worker.. */
306bda68ab9SRemy Horton id_core = rte_lcore_id();
307bda68ab9SRemy Horton id_core = rte_get_next_lcore(id_core, 1, 1);
308cb056611SStephen Hemminger rte_eal_remote_launch(worker_main, NULL, id_core);
309bda68ab9SRemy Horton
310bda68ab9SRemy Horton ethapp_main();
311bda68ab9SRemy Horton
312bda68ab9SRemy Horton app_cfg.exit_now = 1;
313cb056611SStephen Hemminger RTE_LCORE_FOREACH_WORKER(id_core) {
314bda68ab9SRemy Horton if (rte_eal_wait_lcore(id_core) < 0)
315bda68ab9SRemy Horton return -1;
316bda68ab9SRemy Horton }
317bda68ab9SRemy Horton
318*497025daSHuisong Li close_ports();
319*497025daSHuisong Li
32010aa3757SChengchang Tang /* clean up the EAL */
32110aa3757SChengchang Tang rte_eal_cleanup();
32210aa3757SChengchang Tang
323bda68ab9SRemy Horton return 0;
324bda68ab9SRemy Horton }
325