1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2021 Intel Corporation
3 */
4 #include <string.h>
5 #include <stdint.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8
9 #include <rte_mbuf.h>
10 #include <rte_hexdump.h>
11
12 #include "rte_swx_port_fd.h"
13
14 #ifndef TRACE_LEVEL
15 #define TRACE_LEVEL 0
16 #endif
17
18 #if TRACE_LEVEL
19 #define TRACE(...) printf(__VA_ARGS__)
20 #else
21 #define TRACE(...)
22 #endif
23
24 /*
25 * FD Reader
26 */
27 struct reader {
28 struct {
29 int fd;
30 uint32_t mtu;
31 uint32_t burst_size;
32 struct rte_mempool *mempool;
33 } params;
34
35 struct rte_swx_port_in_stats stats;
36 struct rte_mbuf **pkts;
37 uint32_t n_pkts;
38 uint32_t pos;
39 };
40
41 static void *
reader_create(void * args)42 reader_create(void *args)
43 {
44 struct rte_swx_port_fd_reader_params *conf = args;
45 struct reader *p;
46
47 /* Check input parameters. */
48 if (!conf || conf->fd < 0 || conf->mtu == 0 || !conf->mempool)
49 return NULL;
50
51 /* Memory allocation. */
52 p = calloc(1, sizeof(struct reader));
53 if (!p)
54 return NULL;
55
56 p->pkts = calloc(conf->burst_size, sizeof(struct rte_mbuf *));
57 if (!p->pkts) {
58 free(p);
59 return NULL;
60 }
61
62 /* Initialization. */
63 p->params.fd = conf->fd;
64 p->params.mtu = conf->mtu;
65 p->params.burst_size = conf->burst_size;
66 p->params.mempool = conf->mempool;
67
68 return p;
69 }
70
71 static void
reader_free(void * port)72 reader_free(void *port)
73 {
74 struct reader *p = port;
75 uint32_t i;
76
77 if (!p)
78 return;
79
80 for (i = 0; i < p->n_pkts; i++)
81 rte_pktmbuf_free(p->pkts[i]);
82
83 free(p->pkts);
84 free(p);
85 }
86
87 static int
reader_pkt_rx(void * port,struct rte_swx_pkt * pkt)88 reader_pkt_rx(void *port, struct rte_swx_pkt *pkt)
89 {
90 struct reader *p = port;
91 struct rte_mbuf *m;
92 void *pkt_data;
93 ssize_t n_bytes;
94 uint32_t i, j;
95
96 if (p->n_pkts == p->pos) {
97 if (rte_pktmbuf_alloc_bulk(p->params.mempool, p->pkts, p->params.burst_size) != 0)
98 return 0;
99
100 for (i = 0; i < p->params.burst_size; i++) {
101 m = p->pkts[i];
102 pkt_data = rte_pktmbuf_mtod(m, void *);
103 n_bytes = read(p->params.fd, pkt_data, (size_t) p->params.mtu);
104
105 if (n_bytes <= 0)
106 break;
107
108 m->data_len = n_bytes;
109 m->pkt_len = n_bytes;
110
111 p->stats.n_pkts++;
112 p->stats.n_bytes += n_bytes;
113 }
114
115 for (j = i; j < p->params.burst_size; j++)
116 rte_pktmbuf_free(p->pkts[j]);
117
118 p->n_pkts = i;
119 p->pos = 0;
120
121 if (!p->n_pkts)
122 return 0;
123 }
124
125 m = p->pkts[p->pos++];
126 pkt->handle = m;
127 pkt->pkt = m->buf_addr;
128 pkt->offset = m->data_off;
129 pkt->length = m->pkt_len;
130
131 TRACE("[FD %u] Pkt %d (%u bytes at offset %u)\n",
132 (uint32_t)p->params.fd,
133 p->pos - 1,
134 pkt->length,
135 pkt->offset);
136
137 if (TRACE_LEVEL)
138 rte_hexdump(stdout, NULL,
139 &((uint8_t *)m->buf_addr)[m->data_off], m->data_len);
140
141 return 1;
142 }
143
144 static void
reader_stats_read(void * port,struct rte_swx_port_in_stats * stats)145 reader_stats_read(void *port, struct rte_swx_port_in_stats *stats)
146 {
147 struct reader *p = port;
148
149 memcpy(stats, &p->stats, sizeof(p->stats));
150 }
151
152 /*
153 * FD Writer
154 */
155 struct writer {
156 struct {
157 int fd;
158 uint32_t mtu;
159 uint32_t burst_size;
160 struct rte_mempool *mempool;
161 } params;
162
163 struct rte_swx_port_out_stats stats;
164 struct rte_mbuf **pkts;
165 uint32_t n_pkts;
166 };
167
168 static void *
writer_create(void * args)169 writer_create(void *args)
170 {
171 struct rte_swx_port_fd_writer_params *conf = args;
172 struct writer *p;
173
174 /* Check input parameters. */
175 if (!conf)
176 return NULL;
177
178 /* Memory allocation. */
179 p = calloc(1, sizeof(struct writer));
180 if (!p)
181 return NULL;
182
183
184 p->pkts = calloc(conf->burst_size, sizeof(struct rte_mbuf *));
185 if (!p->pkts) {
186 free(p);
187 return NULL;
188 }
189
190 /* Initialization. */
191 p->params.fd = conf->fd;
192 p->params.burst_size = conf->burst_size;
193
194 return p;
195 }
196
197 static void
__writer_flush(struct writer * p)198 __writer_flush(struct writer *p)
199 {
200 struct rte_mbuf *pkt;
201 void *pkt_data;
202 size_t n_bytes;
203 ssize_t ret;
204 uint32_t i;
205
206 for (i = 0; i < p->n_pkts; i++) {
207 pkt = p->pkts[i];
208 pkt_data = rte_pktmbuf_mtod(pkt, void*);
209 n_bytes = rte_pktmbuf_data_len(pkt);
210
211 ret = write(p->params.fd, pkt_data, n_bytes);
212 if (ret < 0)
213 break;
214 }
215
216 TRACE("[FD %u] %u packets out\n",
217 (uint32_t)p->params.fd,
218 p->n_pkts);
219
220 for (i = 0; i < p->n_pkts; i++)
221 rte_pktmbuf_free(p->pkts[i]);
222
223 p->n_pkts = 0;
224 }
225
226 static void
writer_pkt_tx(void * port,struct rte_swx_pkt * pkt)227 writer_pkt_tx(void *port, struct rte_swx_pkt *pkt)
228 {
229 struct writer *p = port;
230 struct rte_mbuf *m = pkt->handle;
231
232 TRACE("[FD %u] Pkt %u (%u bytes at offset %u)\n",
233 (uint32_t)p->params.fd,
234 p->n_pkts - 1,
235 pkt->length,
236 pkt->offset);
237
238 if (TRACE_LEVEL)
239 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
240
241 m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
242 m->pkt_len = pkt->length;
243 m->data_off = (uint16_t)pkt->offset;
244
245 p->stats.n_pkts++;
246 p->stats.n_bytes += pkt->length;
247
248 p->pkts[p->n_pkts++] = m;
249 if (p->n_pkts == p->params.burst_size)
250 __writer_flush(p);
251 }
252
253 static void
writer_pkt_fast_clone_tx(void * port,struct rte_swx_pkt * pkt)254 writer_pkt_fast_clone_tx(void *port, struct rte_swx_pkt *pkt)
255 {
256 struct writer *p = port;
257 struct rte_mbuf *m = pkt->handle;
258
259 TRACE("[FD %u] Pkt %u (%u bytes at offset %u) (fast clone)\n",
260 (uint32_t)p->params.fd,
261 p->n_pkts - 1,
262 pkt->length,
263 pkt->offset);
264 if (TRACE_LEVEL)
265 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
266
267 m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
268 m->pkt_len = pkt->length;
269 m->data_off = (uint16_t)pkt->offset;
270 rte_pktmbuf_refcnt_update(m, 1);
271
272 p->stats.n_pkts++;
273 p->stats.n_bytes += pkt->length;
274 p->stats.n_pkts_clone++;
275
276 p->pkts[p->n_pkts++] = m;
277 if (p->n_pkts == p->params.burst_size)
278 __writer_flush(p);
279 }
280
281 static void
writer_pkt_clone_tx(void * port,struct rte_swx_pkt * pkt,uint32_t truncation_length)282 writer_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length)
283 {
284 struct writer *p = port;
285 struct rte_mbuf *m = pkt->handle, *m_clone;
286
287 TRACE("[FD %u] Pkt %u (%u bytes at offset %u) (clone)\n",
288 (uint32_t)p->params.fd,
289 p->n_pkts - 1,
290 pkt->length,
291 pkt->offset);
292 if (TRACE_LEVEL)
293 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
294
295 m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
296 m->pkt_len = pkt->length;
297 m->data_off = (uint16_t)pkt->offset;
298
299 m_clone = rte_pktmbuf_copy(m, m->pool, 0, truncation_length);
300 if (!m_clone) {
301 p->stats.n_pkts_clone_err++;
302 return;
303 }
304
305 p->stats.n_pkts++;
306 p->stats.n_bytes += pkt->length;
307 p->stats.n_pkts_clone++;
308
309 p->pkts[p->n_pkts++] = m_clone;
310 if (p->n_pkts == p->params.burst_size)
311 __writer_flush(p);
312 }
313
314 static void
writer_flush(void * port)315 writer_flush(void *port)
316 {
317 struct writer *p = port;
318
319 if (p->n_pkts)
320 __writer_flush(p);
321 }
322
323 static void
writer_free(void * port)324 writer_free(void *port)
325 {
326 struct writer *p = port;
327
328 if (!p)
329 return;
330
331 writer_flush(p);
332 free(p->pkts);
333 free(p);
334 }
335
336 static void
writer_stats_read(void * port,struct rte_swx_port_out_stats * stats)337 writer_stats_read(void *port, struct rte_swx_port_out_stats *stats)
338 {
339 struct writer *p = port;
340
341 memcpy(stats, &p->stats, sizeof(p->stats));
342 }
343
344 /*
345 * Summary of port operations
346 */
347 struct rte_swx_port_in_ops rte_swx_port_fd_reader_ops = {
348 .create = reader_create,
349 .free = reader_free,
350 .pkt_rx = reader_pkt_rx,
351 .stats_read = reader_stats_read,
352 };
353
354 struct rte_swx_port_out_ops rte_swx_port_fd_writer_ops = {
355 .create = writer_create,
356 .free = writer_free,
357 .pkt_tx = writer_pkt_tx,
358 .pkt_fast_clone_tx = writer_pkt_fast_clone_tx,
359 .pkt_clone_tx = writer_pkt_clone_tx,
360 .flush = writer_flush,
361 .stats_read = writer_stats_read,
362 };
363