1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
2d30ea906Sjfb8856606 * Copyright(c) 2015 Intel Corporation
3a9643ea8Slogwang */
4a9643ea8Slogwang
5a9643ea8Slogwang
6a9643ea8Slogwang #include <stdio.h>
7a9643ea8Slogwang #include <stdlib.h>
8a9643ea8Slogwang
9a9643ea8Slogwang #include <rte_common.h>
10a9643ea8Slogwang #include <rte_spinlock.h>
11a9643ea8Slogwang #include <rte_eal.h>
12a9643ea8Slogwang #include <rte_ethdev.h>
13a9643ea8Slogwang #include <rte_ether.h>
14a9643ea8Slogwang #include <rte_ip.h>
15a9643ea8Slogwang #include <rte_memory.h>
16a9643ea8Slogwang #include <rte_mempool.h>
17a9643ea8Slogwang #include <rte_mbuf.h>
18a9643ea8Slogwang
19a9643ea8Slogwang #include "ethapp.h"
20a9643ea8Slogwang
21a9643ea8Slogwang #define MAX_PORTS RTE_MAX_ETHPORTS
22a9643ea8Slogwang #define MAX_BURST_LENGTH 32
23d30ea906Sjfb8856606 #define PORT_RX_QUEUE_SIZE 1024
24d30ea906Sjfb8856606 #define PORT_TX_QUEUE_SIZE 1024
25a9643ea8Slogwang #define PKTPOOL_EXTRA_SIZE 512
26a9643ea8Slogwang #define PKTPOOL_CACHE 32
27a9643ea8Slogwang
28a9643ea8Slogwang
29a9643ea8Slogwang struct txq_port {
30a9643ea8Slogwang uint16_t cnt_unsent;
31a9643ea8Slogwang struct rte_mbuf *buf_frames[MAX_BURST_LENGTH];
32a9643ea8Slogwang };
33a9643ea8Slogwang
34a9643ea8Slogwang struct app_port {
354418919fSjohnjiang struct rte_ether_addr mac_addr;
36a9643ea8Slogwang struct txq_port txq;
37a9643ea8Slogwang rte_spinlock_t lock;
38a9643ea8Slogwang int port_active;
39a9643ea8Slogwang int port_dirty;
40a9643ea8Slogwang int idx_port;
41a9643ea8Slogwang struct rte_mempool *pkt_pool;
42a9643ea8Slogwang };
43a9643ea8Slogwang
44a9643ea8Slogwang struct app_config {
45a9643ea8Slogwang struct app_port ports[MAX_PORTS];
46a9643ea8Slogwang int cnt_ports;
47a9643ea8Slogwang int exit_now;
48a9643ea8Slogwang };
49a9643ea8Slogwang
50a9643ea8Slogwang
51a9643ea8Slogwang struct app_config app_cfg;
52a9643ea8Slogwang
53a9643ea8Slogwang
lock_port(int idx_port)54a9643ea8Slogwang void lock_port(int idx_port)
55a9643ea8Slogwang {
56a9643ea8Slogwang struct app_port *ptr_port = &app_cfg.ports[idx_port];
57a9643ea8Slogwang
58a9643ea8Slogwang rte_spinlock_lock(&ptr_port->lock);
59a9643ea8Slogwang }
60a9643ea8Slogwang
unlock_port(int idx_port)61a9643ea8Slogwang void unlock_port(int idx_port)
62a9643ea8Slogwang {
63a9643ea8Slogwang struct app_port *ptr_port = &app_cfg.ports[idx_port];
64a9643ea8Slogwang
65a9643ea8Slogwang rte_spinlock_unlock(&ptr_port->lock);
66a9643ea8Slogwang }
67a9643ea8Slogwang
mark_port_active(int idx_port)68a9643ea8Slogwang void mark_port_active(int idx_port)
69a9643ea8Slogwang {
70a9643ea8Slogwang struct app_port *ptr_port = &app_cfg.ports[idx_port];
71a9643ea8Slogwang
72a9643ea8Slogwang ptr_port->port_active = 1;
73a9643ea8Slogwang }
74a9643ea8Slogwang
mark_port_inactive(int idx_port)75a9643ea8Slogwang void mark_port_inactive(int idx_port)
76a9643ea8Slogwang {
77a9643ea8Slogwang struct app_port *ptr_port = &app_cfg.ports[idx_port];
78a9643ea8Slogwang
79a9643ea8Slogwang ptr_port->port_active = 0;
80a9643ea8Slogwang }
81a9643ea8Slogwang
mark_port_newmac(int idx_port)82a9643ea8Slogwang void mark_port_newmac(int idx_port)
83a9643ea8Slogwang {
84a9643ea8Slogwang struct app_port *ptr_port = &app_cfg.ports[idx_port];
85a9643ea8Slogwang
86a9643ea8Slogwang ptr_port->port_dirty = 1;
87a9643ea8Slogwang }
88a9643ea8Slogwang
setup_ports(struct app_config * app_cfg,int cnt_ports)89a9643ea8Slogwang static void setup_ports(struct app_config *app_cfg, int cnt_ports)
90a9643ea8Slogwang {
91a9643ea8Slogwang int idx_port;
92a9643ea8Slogwang int size_pktpool;
93a9643ea8Slogwang struct rte_eth_conf cfg_port;
94a9643ea8Slogwang struct rte_eth_dev_info dev_info;
95a9643ea8Slogwang char str_name[16];
962bfe3f2eSlogwang uint16_t nb_rxd = PORT_RX_QUEUE_SIZE;
972bfe3f2eSlogwang uint16_t nb_txd = PORT_TX_QUEUE_SIZE;
984418919fSjohnjiang int ret;
99a9643ea8Slogwang
100a9643ea8Slogwang memset(&cfg_port, 0, sizeof(cfg_port));
101a9643ea8Slogwang cfg_port.txmode.mq_mode = ETH_MQ_TX_NONE;
102a9643ea8Slogwang
103a9643ea8Slogwang for (idx_port = 0; idx_port < cnt_ports; idx_port++) {
104a9643ea8Slogwang struct app_port *ptr_port = &app_cfg->ports[idx_port];
105a9643ea8Slogwang
1064418919fSjohnjiang ret = rte_eth_dev_info_get(idx_port, &dev_info);
1074418919fSjohnjiang if (ret != 0)
1084418919fSjohnjiang rte_exit(EXIT_FAILURE,
1094418919fSjohnjiang "Error during getting device (port %u) info: %s\n",
1104418919fSjohnjiang idx_port, strerror(-ret));
1114418919fSjohnjiang
112a9643ea8Slogwang size_pktpool = dev_info.rx_desc_lim.nb_max +
113a9643ea8Slogwang dev_info.tx_desc_lim.nb_max + PKTPOOL_EXTRA_SIZE;
114a9643ea8Slogwang
115a9643ea8Slogwang snprintf(str_name, 16, "pkt_pool%i", idx_port);
116a9643ea8Slogwang ptr_port->pkt_pool = rte_pktmbuf_pool_create(
117a9643ea8Slogwang str_name,
118a9643ea8Slogwang size_pktpool, PKTPOOL_CACHE,
119a9643ea8Slogwang 0,
120a9643ea8Slogwang RTE_MBUF_DEFAULT_BUF_SIZE,
121a9643ea8Slogwang rte_socket_id()
122a9643ea8Slogwang );
123a9643ea8Slogwang if (ptr_port->pkt_pool == NULL)
124a9643ea8Slogwang rte_exit(EXIT_FAILURE,
125a9643ea8Slogwang "rte_pktmbuf_pool_create failed"
126a9643ea8Slogwang );
127a9643ea8Slogwang
128a9643ea8Slogwang printf("Init port %i..\n", idx_port);
129a9643ea8Slogwang ptr_port->port_active = 1;
130a9643ea8Slogwang ptr_port->port_dirty = 0;
131a9643ea8Slogwang ptr_port->idx_port = idx_port;
132a9643ea8Slogwang
133a9643ea8Slogwang if (rte_eth_dev_configure(idx_port, 1, 1, &cfg_port) < 0)
134a9643ea8Slogwang rte_exit(EXIT_FAILURE,
135a9643ea8Slogwang "rte_eth_dev_configure failed");
1362bfe3f2eSlogwang if (rte_eth_dev_adjust_nb_rx_tx_desc(idx_port, &nb_rxd,
1372bfe3f2eSlogwang &nb_txd) < 0)
1382bfe3f2eSlogwang rte_exit(EXIT_FAILURE,
1392bfe3f2eSlogwang "rte_eth_dev_adjust_nb_rx_tx_desc failed");
140d30ea906Sjfb8856606
141a9643ea8Slogwang if (rte_eth_rx_queue_setup(
1422bfe3f2eSlogwang idx_port, 0, nb_rxd,
143a9643ea8Slogwang rte_eth_dev_socket_id(idx_port), NULL,
144a9643ea8Slogwang ptr_port->pkt_pool) < 0)
145a9643ea8Slogwang rte_exit(EXIT_FAILURE,
146a9643ea8Slogwang "rte_eth_rx_queue_setup failed"
147a9643ea8Slogwang );
148a9643ea8Slogwang if (rte_eth_tx_queue_setup(
1492bfe3f2eSlogwang idx_port, 0, nb_txd,
1504418919fSjohnjiang rte_eth_dev_socket_id(idx_port), NULL) < 0)
151a9643ea8Slogwang rte_exit(EXIT_FAILURE,
152a9643ea8Slogwang "rte_eth_tx_queue_setup failed"
153a9643ea8Slogwang );
154a9643ea8Slogwang if (rte_eth_dev_start(idx_port) < 0)
155a9643ea8Slogwang rte_exit(EXIT_FAILURE,
156a9643ea8Slogwang "%s:%i: rte_eth_dev_start failed",
157a9643ea8Slogwang __FILE__, __LINE__
158a9643ea8Slogwang );
1594418919fSjohnjiang ret = rte_eth_macaddr_get(idx_port, &ptr_port->mac_addr);
1604418919fSjohnjiang if (ret != 0)
1614418919fSjohnjiang rte_exit(EXIT_FAILURE,
1624418919fSjohnjiang "rte_eth_macaddr_get failed (port %u): %s\n",
1634418919fSjohnjiang idx_port, rte_strerror(-ret));
1644418919fSjohnjiang
165a9643ea8Slogwang rte_spinlock_init(&ptr_port->lock);
166a9643ea8Slogwang }
167a9643ea8Slogwang }
168a9643ea8Slogwang
process_frame(struct app_port * ptr_port,struct rte_mbuf * ptr_frame)169a9643ea8Slogwang static void process_frame(struct app_port *ptr_port,
170a9643ea8Slogwang struct rte_mbuf *ptr_frame)
171a9643ea8Slogwang {
1724418919fSjohnjiang struct rte_ether_hdr *ptr_mac_hdr;
173a9643ea8Slogwang
1744418919fSjohnjiang ptr_mac_hdr = rte_pktmbuf_mtod(ptr_frame, struct rte_ether_hdr *);
1754418919fSjohnjiang rte_ether_addr_copy(&ptr_mac_hdr->s_addr, &ptr_mac_hdr->d_addr);
1764418919fSjohnjiang rte_ether_addr_copy(&ptr_port->mac_addr, &ptr_mac_hdr->s_addr);
177a9643ea8Slogwang }
178a9643ea8Slogwang
worker_main(__rte_unused void * ptr_data)179*2d9fd380Sjfb8856606 static int worker_main(__rte_unused void *ptr_data)
180a9643ea8Slogwang {
181a9643ea8Slogwang struct app_port *ptr_port;
182a9643ea8Slogwang struct rte_mbuf *ptr_frame;
183a9643ea8Slogwang struct txq_port *txq;
184a9643ea8Slogwang
185a9643ea8Slogwang uint16_t cnt_recv_frames;
186a9643ea8Slogwang uint16_t idx_frame;
187a9643ea8Slogwang uint16_t cnt_sent;
188a9643ea8Slogwang uint16_t idx_port;
189a9643ea8Slogwang uint16_t lock_result;
1904418919fSjohnjiang int ret;
191a9643ea8Slogwang
192a9643ea8Slogwang while (app_cfg.exit_now == 0) {
193a9643ea8Slogwang for (idx_port = 0; idx_port < app_cfg.cnt_ports; idx_port++) {
194a9643ea8Slogwang /* Check that port is active and unlocked */
195a9643ea8Slogwang ptr_port = &app_cfg.ports[idx_port];
196a9643ea8Slogwang lock_result = rte_spinlock_trylock(&ptr_port->lock);
197a9643ea8Slogwang if (lock_result == 0)
198a9643ea8Slogwang continue;
199a9643ea8Slogwang if (ptr_port->port_active == 0) {
200a9643ea8Slogwang rte_spinlock_unlock(&ptr_port->lock);
201a9643ea8Slogwang continue;
202a9643ea8Slogwang }
203a9643ea8Slogwang txq = &ptr_port->txq;
204a9643ea8Slogwang
205a9643ea8Slogwang /* MAC address was updated */
206a9643ea8Slogwang if (ptr_port->port_dirty == 1) {
2074418919fSjohnjiang ret = rte_eth_macaddr_get(ptr_port->idx_port,
208a9643ea8Slogwang &ptr_port->mac_addr);
2094418919fSjohnjiang if (ret != 0) {
2104418919fSjohnjiang rte_spinlock_unlock(&ptr_port->lock);
2114418919fSjohnjiang printf("Failed to get MAC address (port %u): %s",
2124418919fSjohnjiang ptr_port->idx_port,
2134418919fSjohnjiang rte_strerror(-ret));
2144418919fSjohnjiang return ret;
2154418919fSjohnjiang }
2164418919fSjohnjiang
217a9643ea8Slogwang ptr_port->port_dirty = 0;
218a9643ea8Slogwang }
219a9643ea8Slogwang
220a9643ea8Slogwang /* Incoming frames */
221a9643ea8Slogwang cnt_recv_frames = rte_eth_rx_burst(
222a9643ea8Slogwang ptr_port->idx_port, 0,
223a9643ea8Slogwang &txq->buf_frames[txq->cnt_unsent],
224a9643ea8Slogwang RTE_DIM(txq->buf_frames) - txq->cnt_unsent
225a9643ea8Slogwang );
226a9643ea8Slogwang if (cnt_recv_frames > 0) {
227a9643ea8Slogwang for (idx_frame = 0;
228a9643ea8Slogwang idx_frame < cnt_recv_frames;
229a9643ea8Slogwang idx_frame++) {
230a9643ea8Slogwang ptr_frame = txq->buf_frames[
231a9643ea8Slogwang idx_frame + txq->cnt_unsent];
232a9643ea8Slogwang process_frame(ptr_port, ptr_frame);
233a9643ea8Slogwang }
234a9643ea8Slogwang txq->cnt_unsent += cnt_recv_frames;
235a9643ea8Slogwang }
236a9643ea8Slogwang
237a9643ea8Slogwang /* Outgoing frames */
238a9643ea8Slogwang if (txq->cnt_unsent > 0) {
239a9643ea8Slogwang cnt_sent = rte_eth_tx_burst(
240a9643ea8Slogwang ptr_port->idx_port, 0,
241a9643ea8Slogwang txq->buf_frames,
242a9643ea8Slogwang txq->cnt_unsent
243a9643ea8Slogwang );
244a9643ea8Slogwang /* Shuffle up unsent frame pointers */
245a9643ea8Slogwang for (idx_frame = cnt_sent;
246a9643ea8Slogwang idx_frame < txq->cnt_unsent;
247a9643ea8Slogwang idx_frame++)
248a9643ea8Slogwang txq->buf_frames[idx_frame - cnt_sent] =
249a9643ea8Slogwang txq->buf_frames[idx_frame];
250a9643ea8Slogwang txq->cnt_unsent -= cnt_sent;
251a9643ea8Slogwang }
252a9643ea8Slogwang rte_spinlock_unlock(&ptr_port->lock);
253a9643ea8Slogwang } /* end for( idx_port ) */
254a9643ea8Slogwang } /* end for(;;) */
255a9643ea8Slogwang
256a9643ea8Slogwang return 0;
257a9643ea8Slogwang }
258a9643ea8Slogwang
main(int argc,char ** argv)259a9643ea8Slogwang int main(int argc, char **argv)
260a9643ea8Slogwang {
261a9643ea8Slogwang int cnt_args_parsed;
262a9643ea8Slogwang uint32_t id_core;
263a9643ea8Slogwang uint32_t cnt_ports;
264a9643ea8Slogwang
2652bfe3f2eSlogwang /* Init runtime environment */
266a9643ea8Slogwang cnt_args_parsed = rte_eal_init(argc, argv);
267a9643ea8Slogwang if (cnt_args_parsed < 0)
268a9643ea8Slogwang rte_exit(EXIT_FAILURE, "rte_eal_init(): Failed");
269a9643ea8Slogwang
270d30ea906Sjfb8856606 cnt_ports = rte_eth_dev_count_avail();
271a9643ea8Slogwang printf("Number of NICs: %i\n", cnt_ports);
272a9643ea8Slogwang if (cnt_ports == 0)
273a9643ea8Slogwang rte_exit(EXIT_FAILURE, "No available NIC ports!\n");
274a9643ea8Slogwang if (cnt_ports > MAX_PORTS) {
275a9643ea8Slogwang printf("Info: Using only %i of %i ports\n",
276a9643ea8Slogwang cnt_ports, MAX_PORTS
277a9643ea8Slogwang );
278a9643ea8Slogwang cnt_ports = MAX_PORTS;
279a9643ea8Slogwang }
280a9643ea8Slogwang
281a9643ea8Slogwang setup_ports(&app_cfg, cnt_ports);
282a9643ea8Slogwang
283a9643ea8Slogwang app_cfg.exit_now = 0;
284a9643ea8Slogwang app_cfg.cnt_ports = cnt_ports;
285a9643ea8Slogwang
286a9643ea8Slogwang if (rte_lcore_count() < 2)
287*2d9fd380Sjfb8856606 rte_exit(EXIT_FAILURE, "No available worker core!\n");
288*2d9fd380Sjfb8856606
289*2d9fd380Sjfb8856606 /* Assume there is an available worker.. */
290a9643ea8Slogwang id_core = rte_lcore_id();
291a9643ea8Slogwang id_core = rte_get_next_lcore(id_core, 1, 1);
292*2d9fd380Sjfb8856606 rte_eal_remote_launch(worker_main, NULL, id_core);
293a9643ea8Slogwang
294a9643ea8Slogwang ethapp_main();
295a9643ea8Slogwang
296a9643ea8Slogwang app_cfg.exit_now = 1;
297*2d9fd380Sjfb8856606 RTE_LCORE_FOREACH_WORKER(id_core) {
298a9643ea8Slogwang if (rte_eal_wait_lcore(id_core) < 0)
299a9643ea8Slogwang return -1;
300a9643ea8Slogwang }
301a9643ea8Slogwang
302a9643ea8Slogwang return 0;
303a9643ea8Slogwang }
304