xref: /dpdk/lib/port/rte_swx_port_source_sink.c (revision 7c10ca26f0cc7afbdfb91d2570fc242fa01fb0b2)
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