xref: /dpdk/lib/port/rte_swx_port_ethdev.c (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2020 Intel Corporation
3  */
4 #include <string.h>
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <stdint.h>
8 
9 #include <rte_mbuf.h>
10 #include <rte_ethdev.h>
11 #include <rte_hexdump.h>
12 
13 #include "rte_swx_port_ethdev.h"
14 
15 #define CHECK(condition)                                                       \
16 do {                                                                           \
17 	if (!(condition))                                                      \
18 		return NULL;                                                   \
19 } while (0)
20 
21 #ifndef TRACE_LEVEL
22 #define TRACE_LEVEL 0
23 #endif
24 
25 #if TRACE_LEVEL
26 #define TRACE(...) printf(__VA_ARGS__)
27 #else
28 #define TRACE(...)
29 #endif
30 
31 /*
32  * Port ETHDEV Reader
33  */
34 struct reader {
35 	struct {
36 		uint16_t port_id;
37 		uint16_t queue_id;
38 		uint32_t burst_size;
39 	} params;
40 	struct rte_swx_port_in_stats stats;
41 	struct rte_mbuf **pkts;
42 	int n_pkts;
43 	int pos;
44 };
45 
46 static void *
47 reader_create(void *args)
48 {
49 	struct rte_eth_dev_info info;
50 	struct rte_swx_port_ethdev_reader_params *params = args;
51 	struct reader *p;
52 	int status;
53 	uint16_t port_id;
54 
55 	/* Check input parameters. */
56 	CHECK(params);
57 
58 	CHECK(params->dev_name);
59 	status = rte_eth_dev_get_port_by_name(params->dev_name, &port_id);
60 	CHECK(!status);
61 
62 	status = rte_eth_dev_info_get(port_id, &info);
63 	CHECK((status == -ENOTSUP) || (params->queue_id < info.nb_rx_queues));
64 
65 	CHECK(params->burst_size);
66 
67 	/* Memory allocation. */
68 	p = calloc(1, sizeof(struct reader));
69 	CHECK(p);
70 
71 	p->pkts = calloc(params->burst_size, sizeof(struct rte_mbuf *));
72 	if (!p->pkts) {
73 		free(p);
74 		CHECK(0);
75 	}
76 
77 	/* Initialization. */
78 	p->params.port_id = port_id;
79 	p->params.queue_id = params->queue_id;
80 	p->params.burst_size = params->burst_size;
81 
82 	return p;
83 }
84 
85 static int
86 reader_pkt_rx(void *port, struct rte_swx_pkt *pkt)
87 {
88 	struct reader *p = port;
89 	struct rte_mbuf *m;
90 
91 	if (p->pos == p->n_pkts) {
92 		int n_pkts;
93 
94 		n_pkts = rte_eth_rx_burst(p->params.port_id,
95 					  p->params.queue_id,
96 					  p->pkts,
97 					  p->params.burst_size);
98 		if (!n_pkts) {
99 			p->stats.n_empty++;
100 			return 0;
101 		}
102 
103 		TRACE("[Ethdev RX port %u queue %u] %d packets in\n",
104 		      (uint32_t)p->params.port_id,
105 		      (uint32_t)p->params.queue_id,
106 		      n_pkts);
107 
108 		p->n_pkts = n_pkts;
109 		p->pos = 0;
110 	}
111 
112 	m = p->pkts[p->pos++];
113 	pkt->handle = m;
114 	pkt->pkt = m->buf_addr;
115 	pkt->offset = m->data_off;
116 	pkt->length = m->pkt_len;
117 
118 	TRACE("[Ethdev RX port %u queue %u] Pkt %d (%u bytes at offset %u)\n",
119 	      (uint32_t)p->params.port_id,
120 	      (uint32_t)p->params.queue_id,
121 	      p->pos - 1,
122 	      pkt->length,
123 	      pkt->offset);
124 	if (TRACE_LEVEL)
125 		rte_hexdump(stdout,
126 			    NULL,
127 			    &((uint8_t *)m->buf_addr)[m->data_off],
128 			    m->data_len);
129 
130 	p->stats.n_pkts++;
131 	p->stats.n_bytes += pkt->length;
132 
133 	return 1;
134 }
135 
136 static void
137 reader_free(void *port)
138 {
139 	struct reader *p = port;
140 	int i;
141 
142 	if (!p)
143 		return;
144 
145 	for (i = 0; i < p->n_pkts; i++) {
146 		struct rte_mbuf *pkt = p->pkts[i];
147 
148 		rte_pktmbuf_free(pkt);
149 	}
150 
151 	free(p->pkts);
152 	free(p);
153 }
154 
155 static void
156 reader_stats_read(void *port, struct rte_swx_port_in_stats *stats)
157 {
158 	struct reader *p = port;
159 
160 	memcpy(stats, &p->stats, sizeof(p->stats));
161 }
162 
163 /*
164  * Port ETHDEV Writer
165  */
166 struct writer {
167 	struct {
168 		uint16_t port_id;
169 		uint16_t queue_id;
170 		uint32_t burst_size;
171 	} params;
172 	struct rte_swx_port_out_stats stats;
173 
174 	struct rte_mbuf **pkts;
175 	int n_pkts;
176 };
177 
178 static void *
179 writer_create(void *args)
180 {
181 	struct rte_eth_dev_info info;
182 	struct rte_swx_port_ethdev_writer_params *params = args;
183 	struct writer *p;
184 	int status;
185 	uint16_t port_id;
186 
187 	/* Check input parameters. */
188 	CHECK(params);
189 
190 	CHECK(params->dev_name);
191 	status = rte_eth_dev_get_port_by_name(params->dev_name, &port_id);
192 	CHECK(!status);
193 
194 	status = rte_eth_dev_info_get(port_id, &info);
195 	CHECK((status == -ENOTSUP) || (params->queue_id < info.nb_tx_queues));
196 
197 	CHECK(params->burst_size);
198 
199 	/* Memory allocation. */
200 	p = calloc(1, sizeof(struct writer));
201 	CHECK(p);
202 
203 	p->pkts = calloc(params->burst_size, sizeof(struct rte_mbuf *));
204 	if (!p->pkts) {
205 		free(p);
206 		CHECK(0);
207 	}
208 
209 	/* Initialization. */
210 	p->params.port_id = port_id;
211 	p->params.queue_id = params->queue_id;
212 	p->params.burst_size = params->burst_size;
213 
214 	return p;
215 }
216 
217 static void
218 __writer_flush(struct writer *p)
219 {
220 	int n_pkts;
221 
222 	for (n_pkts = 0; ; ) {
223 		n_pkts += rte_eth_tx_burst(p->params.port_id,
224 					   p->params.queue_id,
225 					   p->pkts + n_pkts,
226 					   p->n_pkts - n_pkts);
227 
228 		TRACE("[Ethdev TX port %u queue %u] %d packets out\n",
229 		      (uint32_t)p->params.port_id,
230 		      (uint32_t)p->params.queue_id,
231 		      n_pkts);
232 
233 		if (n_pkts == p->n_pkts)
234 			break;
235 	}
236 
237 	p->n_pkts = 0;
238 }
239 
240 static void
241 writer_pkt_tx(void *port, struct rte_swx_pkt *pkt)
242 {
243 	struct writer *p = port;
244 	struct rte_mbuf *m = pkt->handle;
245 
246 	TRACE("[Ethdev TX port %u queue %u] Pkt %d (%u bytes at offset %u)\n",
247 	      (uint32_t)p->params.port_id,
248 	      (uint32_t)p->params.queue_id,
249 	      p->n_pkts - 1,
250 	      pkt->length,
251 	      pkt->offset);
252 	if (TRACE_LEVEL)
253 		rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
254 
255 	m->pkt_len = pkt->length;
256 	m->data_len = (uint16_t)pkt->length;
257 	m->data_off = (uint16_t)pkt->offset;
258 
259 	p->stats.n_pkts++;
260 	p->stats.n_bytes += pkt->length;
261 
262 	p->pkts[p->n_pkts++] = m;
263 	if (p->n_pkts ==  (int)p->params.burst_size)
264 		__writer_flush(p);
265 }
266 
267 static void
268 writer_flush(void *port)
269 {
270 	struct writer *p = port;
271 
272 	if (p->n_pkts)
273 		__writer_flush(p);
274 }
275 
276 static void
277 writer_free(void *port)
278 {
279 	struct writer *p = port;
280 
281 	if (!p)
282 		return;
283 
284 	writer_flush(p);
285 	free(p->pkts);
286 	free(port);
287 }
288 
289 static void
290 writer_stats_read(void *port, struct rte_swx_port_out_stats *stats)
291 {
292 	struct writer *p = port;
293 
294 	memcpy(stats, &p->stats, sizeof(p->stats));
295 }
296 
297 /*
298  * Summary of port operations
299  */
300 struct rte_swx_port_in_ops rte_swx_port_ethdev_reader_ops = {
301 	.create = reader_create,
302 	.free = reader_free,
303 	.pkt_rx = reader_pkt_rx,
304 	.stats_read = reader_stats_read,
305 };
306 
307 struct rte_swx_port_out_ops rte_swx_port_ethdev_writer_ops = {
308 	.create = writer_create,
309 	.free = writer_free,
310 	.pkt_tx = writer_pkt_tx,
311 	.flush = writer_flush,
312 	.stats_read = writer_stats_read,
313 };
314