port: support packet mirroring
[dpdk.git] / lib / port / rte_swx_port_ethdev.c
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->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
256         m->pkt_len = 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_pkt_fast_clone_tx(void *port, struct rte_swx_pkt *pkt)
269 {
270         struct writer *p = port;
271         struct rte_mbuf *m = pkt->handle;
272
273         TRACE("[Ethdev TX port %u queue %u] Pkt %d (%u bytes at offset %u) (fast clone)\n",
274               (uint32_t)p->params.port_id,
275               (uint32_t)p->params.queue_id,
276               p->n_pkts - 1,
277               pkt->length,
278               pkt->offset);
279         if (TRACE_LEVEL)
280                 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
281
282         m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
283         m->pkt_len = pkt->length;
284         m->data_off = (uint16_t)pkt->offset;
285         rte_pktmbuf_refcnt_update(m, 1);
286
287         p->stats.n_pkts++;
288         p->stats.n_bytes += pkt->length;
289         p->stats.n_pkts_clone++;
290
291         p->pkts[p->n_pkts++] = m;
292         if (p->n_pkts == (int)p->params.burst_size)
293                 __writer_flush(p);
294 }
295
296 static void
297 writer_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length)
298 {
299         struct writer *p = port;
300         struct rte_mbuf *m = pkt->handle, *m_clone;
301
302         TRACE("[Ethdev TX port %u queue %u] Pkt %d (%u bytes at offset %u) (clone)\n",
303               (uint32_t)p->params.port_id,
304               (uint32_t)p->params.queue_id,
305               p->n_pkts - 1,
306               pkt->length,
307               pkt->offset);
308         if (TRACE_LEVEL)
309                 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
310
311         m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
312         m->pkt_len = pkt->length;
313         m->data_off = (uint16_t)pkt->offset;
314
315         m_clone = rte_pktmbuf_copy(m, m->pool, 0, truncation_length);
316         if (!m_clone) {
317                 p->stats.n_pkts_clone_err++;
318                 return;
319         }
320
321         p->stats.n_pkts++;
322         p->stats.n_bytes += pkt->length;
323         p->stats.n_pkts_clone++;
324
325         p->pkts[p->n_pkts++] = m_clone;
326         if (p->n_pkts == (int)p->params.burst_size)
327                 __writer_flush(p);
328 }
329
330 static void
331 writer_flush(void *port)
332 {
333         struct writer *p = port;
334
335         if (p->n_pkts)
336                 __writer_flush(p);
337 }
338
339 static void
340 writer_free(void *port)
341 {
342         struct writer *p = port;
343
344         if (!p)
345                 return;
346
347         writer_flush(p);
348         free(p->pkts);
349         free(port);
350 }
351
352 static void
353 writer_stats_read(void *port, struct rte_swx_port_out_stats *stats)
354 {
355         struct writer *p = port;
356
357         memcpy(stats, &p->stats, sizeof(p->stats));
358 }
359
360 /*
361  * Summary of port operations
362  */
363 struct rte_swx_port_in_ops rte_swx_port_ethdev_reader_ops = {
364         .create = reader_create,
365         .free = reader_free,
366         .pkt_rx = reader_pkt_rx,
367         .stats_read = reader_stats_read,
368 };
369
370 struct rte_swx_port_out_ops rte_swx_port_ethdev_writer_ops = {
371         .create = writer_create,
372         .free = writer_free,
373         .pkt_tx = writer_pkt_tx,
374         .pkt_fast_clone_tx = writer_pkt_fast_clone_tx,
375         .pkt_clone_tx = writer_pkt_clone_tx,
376         .flush = writer_flush,
377         .stats_read = writer_stats_read,
378 };