xref: /dpdk/examples/ethtool/ethtool-app/main.c (revision 008ee817dfbe133e03717a37743f115d21e1a479)
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
23bda68ab9SRemy Horton #define PORT_RX_QUEUE_SIZE 128
24bda68ab9SRemy Horton #define PORT_TX_QUEUE_SIZE 256
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 {
35bda68ab9SRemy Horton 	struct 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 
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 
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 
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 
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 
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 
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;
98*008ee817SShahaf Shuler 	struct rte_eth_txconf txconf;
99bda68ab9SRemy Horton 
100bda68ab9SRemy Horton 	memset(&cfg_port, 0, sizeof(cfg_port));
101bda68ab9SRemy Horton 	cfg_port.txmode.mq_mode = ETH_MQ_TX_NONE;
102*008ee817SShahaf Shuler 	cfg_port.rxmode.ignore_offload_bitfield = 1;
103bda68ab9SRemy Horton 
104bda68ab9SRemy Horton 	for (idx_port = 0; idx_port < cnt_ports; idx_port++) {
105bda68ab9SRemy Horton 		struct app_port *ptr_port = &app_cfg->ports[idx_port];
106bda68ab9SRemy Horton 
107bda68ab9SRemy Horton 		rte_eth_dev_info_get(idx_port, &dev_info);
108bda68ab9SRemy Horton 		size_pktpool = dev_info.rx_desc_lim.nb_max +
109bda68ab9SRemy Horton 			dev_info.tx_desc_lim.nb_max + PKTPOOL_EXTRA_SIZE;
110bda68ab9SRemy Horton 
111bda68ab9SRemy Horton 		snprintf(str_name, 16, "pkt_pool%i", idx_port);
112bda68ab9SRemy Horton 		ptr_port->pkt_pool = rte_pktmbuf_pool_create(
113bda68ab9SRemy Horton 			str_name,
114bda68ab9SRemy Horton 			size_pktpool, PKTPOOL_CACHE,
115bda68ab9SRemy Horton 			0,
116bda68ab9SRemy Horton 			RTE_MBUF_DEFAULT_BUF_SIZE,
117bda68ab9SRemy Horton 			rte_socket_id()
118bda68ab9SRemy Horton 			);
119bda68ab9SRemy Horton 		if (ptr_port->pkt_pool == NULL)
120bda68ab9SRemy Horton 			rte_exit(EXIT_FAILURE,
121bda68ab9SRemy Horton 				"rte_pktmbuf_pool_create failed"
122bda68ab9SRemy Horton 				);
123bda68ab9SRemy Horton 
124bda68ab9SRemy Horton 		printf("Init port %i..\n", idx_port);
125bda68ab9SRemy Horton 		ptr_port->port_active = 1;
126bda68ab9SRemy Horton 		ptr_port->port_dirty = 0;
127bda68ab9SRemy Horton 		ptr_port->idx_port = idx_port;
128bda68ab9SRemy Horton 
129bda68ab9SRemy Horton 		if (rte_eth_dev_configure(idx_port, 1, 1, &cfg_port) < 0)
130bda68ab9SRemy Horton 			rte_exit(EXIT_FAILURE,
131bda68ab9SRemy Horton 				 "rte_eth_dev_configure failed");
13260efb44fSRoman Zhukov 		if (rte_eth_dev_adjust_nb_rx_tx_desc(idx_port, &nb_rxd,
13360efb44fSRoman Zhukov 						     &nb_txd) < 0)
13460efb44fSRoman Zhukov 			rte_exit(EXIT_FAILURE,
13560efb44fSRoman Zhukov 				 "rte_eth_dev_adjust_nb_rx_tx_desc failed");
136*008ee817SShahaf Shuler 
137bda68ab9SRemy Horton 		if (rte_eth_rx_queue_setup(
13860efb44fSRoman Zhukov 			    idx_port, 0, nb_rxd,
139bda68ab9SRemy Horton 			    rte_eth_dev_socket_id(idx_port), NULL,
140bda68ab9SRemy Horton 			    ptr_port->pkt_pool) < 0)
141bda68ab9SRemy Horton 			rte_exit(EXIT_FAILURE,
142bda68ab9SRemy Horton 				 "rte_eth_rx_queue_setup failed"
143bda68ab9SRemy Horton 				);
144*008ee817SShahaf Shuler 		txconf = dev_info.default_txconf;
145*008ee817SShahaf Shuler 		txconf.txq_flags = ETH_TXQ_FLAGS_IGNORE;
146bda68ab9SRemy Horton 		if (rte_eth_tx_queue_setup(
14760efb44fSRoman Zhukov 			    idx_port, 0, nb_txd,
148*008ee817SShahaf Shuler 			    rte_eth_dev_socket_id(idx_port), &txconf) < 0)
149bda68ab9SRemy Horton 			rte_exit(EXIT_FAILURE,
150bda68ab9SRemy Horton 				 "rte_eth_tx_queue_setup failed"
151bda68ab9SRemy Horton 				);
152bda68ab9SRemy Horton 		if (rte_eth_dev_start(idx_port) < 0)
153bda68ab9SRemy Horton 			rte_exit(EXIT_FAILURE,
154bda68ab9SRemy Horton 				 "%s:%i: rte_eth_dev_start failed",
155bda68ab9SRemy Horton 				 __FILE__, __LINE__
156bda68ab9SRemy Horton 				);
157bda68ab9SRemy Horton 		rte_eth_macaddr_get(idx_port, &ptr_port->mac_addr);
158bda68ab9SRemy Horton 		rte_spinlock_init(&ptr_port->lock);
159bda68ab9SRemy Horton 	}
160bda68ab9SRemy Horton }
161bda68ab9SRemy Horton 
162bda68ab9SRemy Horton static void process_frame(struct app_port *ptr_port,
163bda68ab9SRemy Horton 	struct rte_mbuf *ptr_frame)
164bda68ab9SRemy Horton {
165bda68ab9SRemy Horton 	struct ether_hdr *ptr_mac_hdr;
166bda68ab9SRemy Horton 
167bda68ab9SRemy Horton 	ptr_mac_hdr = rte_pktmbuf_mtod(ptr_frame, struct ether_hdr *);
168bda68ab9SRemy Horton 	ether_addr_copy(&ptr_mac_hdr->s_addr, &ptr_mac_hdr->d_addr);
169bda68ab9SRemy Horton 	ether_addr_copy(&ptr_port->mac_addr, &ptr_mac_hdr->s_addr);
170bda68ab9SRemy Horton }
171bda68ab9SRemy Horton 
172bda68ab9SRemy Horton static int slave_main(__attribute__((unused)) void *ptr_data)
173bda68ab9SRemy Horton {
174bda68ab9SRemy Horton 	struct app_port *ptr_port;
175bda68ab9SRemy Horton 	struct rte_mbuf *ptr_frame;
176bda68ab9SRemy Horton 	struct txq_port *txq;
177bda68ab9SRemy Horton 
178bda68ab9SRemy Horton 	uint16_t cnt_recv_frames;
179bda68ab9SRemy Horton 	uint16_t idx_frame;
180bda68ab9SRemy Horton 	uint16_t cnt_sent;
181bda68ab9SRemy Horton 	uint16_t idx_port;
182bda68ab9SRemy Horton 	uint16_t lock_result;
183bda68ab9SRemy Horton 
184bda68ab9SRemy Horton 	while (app_cfg.exit_now == 0) {
185bda68ab9SRemy Horton 		for (idx_port = 0; idx_port < app_cfg.cnt_ports; idx_port++) {
186bda68ab9SRemy Horton 			/* Check that port is active and unlocked */
187bda68ab9SRemy Horton 			ptr_port = &app_cfg.ports[idx_port];
188bda68ab9SRemy Horton 			lock_result = rte_spinlock_trylock(&ptr_port->lock);
189bda68ab9SRemy Horton 			if (lock_result == 0)
190bda68ab9SRemy Horton 				continue;
191bda68ab9SRemy Horton 			if (ptr_port->port_active == 0) {
192bda68ab9SRemy Horton 				rte_spinlock_unlock(&ptr_port->lock);
193bda68ab9SRemy Horton 				continue;
194bda68ab9SRemy Horton 			}
195bda68ab9SRemy Horton 			txq = &ptr_port->txq;
196bda68ab9SRemy Horton 
197bda68ab9SRemy Horton 			/* MAC address was updated */
198bda68ab9SRemy Horton 			if (ptr_port->port_dirty == 1) {
199bda68ab9SRemy Horton 				rte_eth_macaddr_get(ptr_port->idx_port,
200bda68ab9SRemy Horton 					&ptr_port->mac_addr);
201bda68ab9SRemy Horton 				ptr_port->port_dirty = 0;
202bda68ab9SRemy Horton 			}
203bda68ab9SRemy Horton 
204bda68ab9SRemy Horton 			/* Incoming frames */
205bda68ab9SRemy Horton 			cnt_recv_frames = rte_eth_rx_burst(
206bda68ab9SRemy Horton 				ptr_port->idx_port, 0,
207bda68ab9SRemy Horton 				&txq->buf_frames[txq->cnt_unsent],
208bda68ab9SRemy Horton 				RTE_DIM(txq->buf_frames) - txq->cnt_unsent
209bda68ab9SRemy Horton 				);
210bda68ab9SRemy Horton 			if (cnt_recv_frames > 0) {
211bda68ab9SRemy Horton 				for (idx_frame = 0;
212bda68ab9SRemy Horton 					idx_frame < cnt_recv_frames;
213bda68ab9SRemy Horton 					idx_frame++) {
214bda68ab9SRemy Horton 					ptr_frame = txq->buf_frames[
215bda68ab9SRemy Horton 						idx_frame + txq->cnt_unsent];
216bda68ab9SRemy Horton 					process_frame(ptr_port, ptr_frame);
217bda68ab9SRemy Horton 				}
218bda68ab9SRemy Horton 				txq->cnt_unsent += cnt_recv_frames;
219bda68ab9SRemy Horton 			}
220bda68ab9SRemy Horton 
221bda68ab9SRemy Horton 			/* Outgoing frames */
222bda68ab9SRemy Horton 			if (txq->cnt_unsent > 0) {
223bda68ab9SRemy Horton 				cnt_sent = rte_eth_tx_burst(
224bda68ab9SRemy Horton 					ptr_port->idx_port, 0,
225bda68ab9SRemy Horton 					txq->buf_frames,
226bda68ab9SRemy Horton 					txq->cnt_unsent
227bda68ab9SRemy Horton 					);
228bda68ab9SRemy Horton 				/* Shuffle up unsent frame pointers */
229bda68ab9SRemy Horton 				for (idx_frame = cnt_sent;
230bda68ab9SRemy Horton 					idx_frame < txq->cnt_unsent;
231bda68ab9SRemy Horton 					idx_frame++)
232bda68ab9SRemy Horton 					txq->buf_frames[idx_frame - cnt_sent] =
233bda68ab9SRemy Horton 						txq->buf_frames[idx_frame];
234bda68ab9SRemy Horton 				txq->cnt_unsent -= cnt_sent;
235bda68ab9SRemy Horton 			}
236bda68ab9SRemy Horton 			rte_spinlock_unlock(&ptr_port->lock);
237bda68ab9SRemy Horton 		} /* end for( idx_port ) */
238bda68ab9SRemy Horton 	} /* end for(;;) */
239bda68ab9SRemy Horton 
240bda68ab9SRemy Horton 	return 0;
241bda68ab9SRemy Horton }
242bda68ab9SRemy Horton 
243bda68ab9SRemy Horton int main(int argc, char **argv)
244bda68ab9SRemy Horton {
245bda68ab9SRemy Horton 	int cnt_args_parsed;
246bda68ab9SRemy Horton 	uint32_t id_core;
247bda68ab9SRemy Horton 	uint32_t cnt_ports;
248bda68ab9SRemy Horton 
24998a7ea33SJerin Jacob 	/* Init runtime environment */
250bda68ab9SRemy Horton 	cnt_args_parsed = rte_eal_init(argc, argv);
251bda68ab9SRemy Horton 	if (cnt_args_parsed < 0)
252bda68ab9SRemy Horton 		rte_exit(EXIT_FAILURE, "rte_eal_init(): Failed");
253bda68ab9SRemy Horton 
254bda68ab9SRemy Horton 	cnt_ports = rte_eth_dev_count();
255bda68ab9SRemy Horton 	printf("Number of NICs: %i\n", cnt_ports);
256bda68ab9SRemy Horton 	if (cnt_ports == 0)
257bda68ab9SRemy Horton 		rte_exit(EXIT_FAILURE, "No available NIC ports!\n");
258bda68ab9SRemy Horton 	if (cnt_ports > MAX_PORTS) {
259bda68ab9SRemy Horton 		printf("Info: Using only %i of %i ports\n",
260bda68ab9SRemy Horton 			cnt_ports, MAX_PORTS
261bda68ab9SRemy Horton 			);
262bda68ab9SRemy Horton 		cnt_ports = MAX_PORTS;
263bda68ab9SRemy Horton 	}
264bda68ab9SRemy Horton 
265bda68ab9SRemy Horton 	setup_ports(&app_cfg, cnt_ports);
266bda68ab9SRemy Horton 
267bda68ab9SRemy Horton 	app_cfg.exit_now = 0;
268bda68ab9SRemy Horton 	app_cfg.cnt_ports = cnt_ports;
269bda68ab9SRemy Horton 
270bda68ab9SRemy Horton 	if (rte_lcore_count() < 2)
271bda68ab9SRemy Horton 		rte_exit(EXIT_FAILURE, "No available slave core!\n");
272bda68ab9SRemy Horton 	/* Assume there is an available slave.. */
273bda68ab9SRemy Horton 	id_core = rte_lcore_id();
274bda68ab9SRemy Horton 	id_core = rte_get_next_lcore(id_core, 1, 1);
275bda68ab9SRemy Horton 	rte_eal_remote_launch(slave_main, NULL, id_core);
276bda68ab9SRemy Horton 
277bda68ab9SRemy Horton 	ethapp_main();
278bda68ab9SRemy Horton 
279bda68ab9SRemy Horton 	app_cfg.exit_now = 1;
280bda68ab9SRemy Horton 	RTE_LCORE_FOREACH_SLAVE(id_core) {
281bda68ab9SRemy Horton 		if (rte_eal_wait_lcore(id_core) < 0)
282bda68ab9SRemy Horton 			return -1;
283bda68ab9SRemy Horton 	}
284bda68ab9SRemy Horton 
285bda68ab9SRemy Horton 	return 0;
286bda68ab9SRemy Horton }
287