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 *
reader_create(void * args)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
reader_pkt_rx(void * port,struct rte_swx_pkt * pkt)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
reader_free(void * port)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
reader_stats_read(void * port,struct rte_swx_port_in_stats * stats)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 *
writer_create(void * args)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
__writer_flush(struct writer * p)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
writer_pkt_tx(void * port,struct rte_swx_pkt * pkt)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
writer_flush(void * port)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
writer_free(void * port)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
writer_stats_read(void * port,struct rte_swx_port_out_stats * stats)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