1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2020 Intel Corporation
3 */
4 #include <stdint.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #ifdef RTE_PORT_PCAP
8 #include <pcap.h>
9 #endif
10 #include <sys/time.h>
11
12 #include <rte_common.h>
13 #include <rte_mbuf.h>
14 #include <rte_hexdump.h>
15
16 #include "rte_swx_port_source_sink.h"
17
18 #define CHECK(condition) \
19 do { \
20 if (!(condition)) \
21 return NULL; \
22 } while (0)
23
24 #ifndef TRACE_LEVEL
25 #define TRACE_LEVEL 0
26 #endif
27
28 #if TRACE_LEVEL
29 #define TRACE(...) printf(__VA_ARGS__)
30 #else
31 #define TRACE(...)
32 #endif
33
34 /*
35 * Port SOURCE
36 */
37 #ifdef RTE_PORT_PCAP
38
39 struct source {
40 struct {
41 struct rte_mempool *pool;
42 uint64_t n_loops;
43 } params;
44 struct rte_swx_port_in_stats stats;
45 struct rte_mbuf **pkts;
46 uint32_t n_pkts;
47 uint32_t pos;
48 };
49
50 static void
source_free(void * port)51 source_free(void *port)
52 {
53 struct source *p = port;
54 uint32_t i;
55
56 if (!p)
57 return;
58
59 for (i = 0; i < p->n_pkts; i++)
60 rte_pktmbuf_free(p->pkts[i]);
61
62 free(p->pkts);
63
64 free(p);
65 }
66
67 static void *
source_create(void * args)68 source_create(void *args)
69 {
70 char pcap_errbuf[PCAP_ERRBUF_SIZE];
71 struct rte_swx_port_source_params *params = args;
72 struct source *p = NULL;
73 pcap_t *f = NULL;
74 uint32_t n_pkts_max, i;
75
76 /* Check input arguments. */
77 CHECK(params);
78 CHECK(params->pool);
79 CHECK(params->file_name && params->file_name[0]);
80 n_pkts_max = params->n_pkts_max ?
81 params->n_pkts_max :
82 RTE_SWX_PORT_SOURCE_PKTS_MAX;
83
84 /* Resource allocation. */
85 f = pcap_open_offline(params->file_name, pcap_errbuf);
86 if (!f)
87 goto error;
88
89 p = calloc(1, sizeof(struct source));
90 if (!p)
91 goto error;
92
93 p->pkts = calloc(n_pkts_max, sizeof(struct rte_mbuf *));
94 if (!p->pkts)
95 goto error;
96
97 /* Initialization. */
98 p->params.pool = params->pool;
99
100 p->params.n_loops = params->n_loops ? params->n_loops : UINT64_MAX;
101
102 /* PCAP file. */
103 for (i = 0; i < n_pkts_max; i++) {
104 struct pcap_pkthdr pcap_pkthdr;
105 const uint8_t *pcap_pktdata;
106 struct rte_mbuf *m;
107 uint8_t *m_data;
108
109 /* Read new packet from PCAP file. */
110 pcap_pktdata = pcap_next(f, &pcap_pkthdr);
111 if (!pcap_pktdata)
112 break;
113
114 /* Allocate new buffer from pool. */
115 m = rte_pktmbuf_alloc(params->pool);
116 if (!m)
117 goto error;
118 m_data = rte_pktmbuf_mtod(m, uint8_t *);
119
120 rte_memcpy(m_data, pcap_pktdata, pcap_pkthdr.caplen);
121 m->data_len = pcap_pkthdr.caplen;
122 m->pkt_len = pcap_pkthdr.caplen;
123
124 p->pkts[p->n_pkts] = m;
125 p->n_pkts++;
126 }
127
128 if (!p->n_pkts)
129 goto error;
130
131 pcap_close(f);
132 return p;
133
134 error:
135 source_free(p);
136 if (f)
137 pcap_close(f);
138 return NULL;
139 }
140
141 static int
source_pkt_rx(void * port,struct rte_swx_pkt * pkt)142 source_pkt_rx(void *port, struct rte_swx_pkt *pkt)
143 {
144 struct source *p = port;
145 struct rte_mbuf *m_dst, *m_src;
146 uint8_t *m_dst_data, *m_src_data;
147
148 if (!p->params.n_loops)
149 return 0;
150 /* m_src identification. */
151 m_src = p->pkts[p->pos];
152 m_src_data = rte_pktmbuf_mtod(m_src, uint8_t *);
153
154 /* m_dst allocation from pool. */
155 m_dst = rte_pktmbuf_alloc(p->params.pool);
156 if (!m_dst)
157 return 0;
158
159 /* m_dst initialization. */
160 m_dst->data_len = m_src->data_len;
161 m_dst->pkt_len = m_src->pkt_len;
162 m_dst->data_off = m_src->data_off;
163
164 m_dst_data = rte_pktmbuf_mtod(m_dst, uint8_t *);
165 rte_memcpy(m_dst_data, m_src_data, m_src->data_len);
166
167 /* pkt initialization. */
168 pkt->handle = m_dst;
169 pkt->pkt = m_dst->buf_addr;
170 pkt->offset = m_dst->data_off;
171 pkt->length = m_dst->pkt_len;
172
173 TRACE("[Source port] Pkt RX (%u bytes at offset %u)\n",
174 pkt->length,
175 pkt->offset);
176 if (TRACE_LEVEL)
177 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
178
179 /* port stats update. */
180 p->stats.n_pkts++;
181 p->stats.n_bytes += pkt->length;
182
183 /* m_src next. */
184 p->pos++;
185 if (p->pos == p->n_pkts) {
186 p->pos = 0;
187 p->params.n_loops--;
188 }
189
190 return 1;
191 }
192
193 static void
source_stats_read(void * port,struct rte_swx_port_in_stats * stats)194 source_stats_read(void *port, struct rte_swx_port_in_stats *stats)
195 {
196 struct source *p = port;
197
198 if (!p || !stats)
199 return;
200
201 memcpy(stats, &p->stats, sizeof(p->stats));
202 }
203
204 struct rte_swx_port_in_ops rte_swx_port_source_ops = {
205 .create = source_create,
206 .free = source_free,
207 .pkt_rx = source_pkt_rx,
208 .stats_read = source_stats_read,
209 };
210
211 #else
212
213 struct rte_swx_port_in_ops rte_swx_port_source_ops = {
214 .create = NULL,
215 .free = NULL,
216 .pkt_rx = NULL,
217 .stats_read = NULL,
218 };
219
220 #endif
221
222 /*
223 * Port SINK
224 */
225 struct sink {
226 struct rte_swx_port_out_stats stats;
227
228 #ifdef RTE_PORT_PCAP
229 pcap_t *f_pcap;
230 pcap_dumper_t *f_dump;
231 #endif
232 };
233
234 static void
sink_free(void * port)235 sink_free(void *port)
236 {
237 struct sink *p = port;
238
239 if (!p)
240 return;
241
242 #ifdef RTE_PORT_PCAP
243 if (p->f_dump)
244 pcap_dump_close(p->f_dump);
245 if (p->f_pcap)
246 pcap_close(p->f_pcap);
247 #endif
248
249 free(p);
250 }
251
252 static void *
sink_create(void * args __rte_unused)253 sink_create(void *args __rte_unused)
254 {
255 struct sink *p;
256
257 /* Memory allocation. */
258 p = calloc(1, sizeof(struct sink));
259 if (!p)
260 goto error;
261
262 #ifdef RTE_PORT_PCAP
263 if (args) {
264 struct rte_swx_port_sink_params *params = args;
265
266 if (params->file_name && params->file_name[0]) {
267 p->f_pcap = pcap_open_dead(DLT_EN10MB, 65535);
268 if (!p->f_pcap)
269 goto error;
270
271 p->f_dump = pcap_dump_open(p->f_pcap,
272 params->file_name);
273 if (!p->f_dump)
274 goto error;
275 }
276 }
277 #endif
278
279 return p;
280
281 error:
282 sink_free(p);
283 return NULL;
284 }
285
286 static void
sink_pkt_tx(void * port,struct rte_swx_pkt * pkt)287 sink_pkt_tx(void *port, struct rte_swx_pkt *pkt)
288 {
289 struct sink *p = port;
290 struct rte_mbuf *m = pkt->handle;
291
292 TRACE("[Sink port] Pkt TX (%u bytes at offset %u)\n",
293 pkt->length,
294 pkt->offset);
295 if (TRACE_LEVEL)
296 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
297
298 m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
299 m->pkt_len = pkt->length;
300 m->data_off = (uint16_t)pkt->offset;
301
302 p->stats.n_pkts_drop++;
303 p->stats.n_bytes_drop += pkt->length;
304
305 #ifdef RTE_PORT_PCAP
306 if (p->f_dump) {
307 struct pcap_pkthdr pcap_pkthdr;
308 uint8_t *m_data = rte_pktmbuf_mtod(m, uint8_t *);
309
310 pcap_pkthdr.len = m->pkt_len;
311 pcap_pkthdr.caplen = m->data_len;
312 gettimeofday(&pcap_pkthdr.ts, NULL);
313
314 pcap_dump((uint8_t *)p->f_dump, &pcap_pkthdr, m_data);
315 pcap_dump_flush(p->f_dump);
316 }
317 #endif
318
319 rte_pktmbuf_free(m);
320 }
321
322 static void
__sink_pkt_clone_tx(void * port,struct rte_swx_pkt * pkt,uint32_t truncation_length __rte_unused)323 __sink_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length __rte_unused)
324 {
325 struct sink *p = port;
326 struct rte_mbuf *m = pkt->handle;
327
328 TRACE("[Sink port] Pkt TX (%u bytes at offset %u) (clone)\n",
329 pkt->length,
330 pkt->offset);
331 if (TRACE_LEVEL)
332 rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
333
334 m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
335 m->pkt_len = pkt->length;
336 m->data_off = (uint16_t)pkt->offset;
337
338 p->stats.n_pkts_drop++;
339 p->stats.n_bytes_drop += pkt->length;
340 p->stats.n_pkts_clone++;
341
342 #ifdef RTE_PORT_PCAP
343 if (p->f_dump) {
344 struct pcap_pkthdr pcap_pkthdr;
345 uint8_t *m_data = rte_pktmbuf_mtod(m, uint8_t *);
346
347 pcap_pkthdr.len = m->pkt_len;
348 pcap_pkthdr.caplen = RTE_MIN(m->data_len, truncation_length);
349 gettimeofday(&pcap_pkthdr.ts, NULL);
350
351 pcap_dump((uint8_t *)p->f_dump, &pcap_pkthdr, m_data);
352 pcap_dump_flush(p->f_dump);
353 }
354 #endif
355 }
356
357 static void
sink_pkt_fast_clone_tx(void * port,struct rte_swx_pkt * pkt)358 sink_pkt_fast_clone_tx(void *port, struct rte_swx_pkt *pkt)
359 {
360 __sink_pkt_clone_tx(port, pkt, UINT32_MAX);
361 }
362
363 static void
sink_pkt_clone_tx(void * port,struct rte_swx_pkt * pkt,uint32_t truncation_length)364 sink_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length)
365 {
366 __sink_pkt_clone_tx(port, pkt, truncation_length);
367 }
368
369 static void
sink_stats_read(void * port,struct rte_swx_port_out_stats * stats)370 sink_stats_read(void *port, struct rte_swx_port_out_stats *stats)
371 {
372 struct sink *p = port;
373
374 if (!p || !stats)
375 return;
376
377 memcpy(stats, &p->stats, sizeof(p->stats));
378 }
379
380 /*
381 * Summary of port operations
382 */
383 struct rte_swx_port_out_ops rte_swx_port_sink_ops = {
384 .create = sink_create,
385 .free = sink_free,
386 .pkt_tx = sink_pkt_tx,
387 .pkt_fast_clone_tx = sink_pkt_fast_clone_tx,
388 .pkt_clone_tx = sink_pkt_clone_tx,
389 .flush = NULL,
390 .stats_read = sink_stats_read,
391 };
392