xref: /dpdk/lib/port/rte_swx_port_source_sink.c (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
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 	} params;
43 	struct rte_swx_port_in_stats stats;
44 	struct rte_mbuf **pkts;
45 	uint32_t n_pkts;
46 	uint32_t pos;
47 };
48 
49 static void
50 source_free(void *port)
51 {
52 	struct source *p = port;
53 	uint32_t i;
54 
55 	if (!p)
56 		return;
57 
58 	for (i = 0; i < p->n_pkts; i++)
59 		rte_pktmbuf_free(p->pkts[i]);
60 
61 	free(p->pkts);
62 
63 	free(p);
64 }
65 
66 static void *
67 source_create(void *args)
68 {
69 	char pcap_errbuf[PCAP_ERRBUF_SIZE];
70 	struct rte_swx_port_source_params *params = args;
71 	struct source *p = NULL;
72 	pcap_t *f = NULL;
73 	uint32_t n_pkts_max, i;
74 
75 	/* Check input arguments. */
76 	CHECK(params);
77 	CHECK(params->pool);
78 	CHECK(params->file_name && params->file_name[0]);
79 	n_pkts_max = params->n_pkts_max ?
80 		params->n_pkts_max :
81 		RTE_SWX_PORT_SOURCE_PKTS_MAX;
82 
83 	/* Resource allocation. */
84 	f = pcap_open_offline(params->file_name, pcap_errbuf);
85 	if (!f)
86 		goto error;
87 
88 	p = calloc(1, sizeof(struct source));
89 	if (!p)
90 		goto error;
91 
92 	p->pkts = calloc(n_pkts_max, sizeof(struct rte_mbuf *));
93 	if (!p->pkts)
94 		goto error;
95 
96 	/* Initialization. */
97 	p->params.pool = params->pool;
98 
99 	/* PCAP file. */
100 	for (i = 0; i < n_pkts_max; i++) {
101 		struct pcap_pkthdr pcap_pkthdr;
102 		const uint8_t *pcap_pktdata;
103 		struct rte_mbuf *m;
104 		uint8_t *m_data;
105 
106 		/* Read new packet from PCAP file. */
107 		pcap_pktdata = pcap_next(f, &pcap_pkthdr);
108 		if (!pcap_pktdata)
109 			break;
110 
111 		/* Allocate new buffer from pool. */
112 		m = rte_pktmbuf_alloc(params->pool);
113 		if (!m)
114 			goto error;
115 		m_data = rte_pktmbuf_mtod(m, uint8_t *);
116 
117 		rte_memcpy(m_data, pcap_pktdata, pcap_pkthdr.caplen);
118 		m->data_len = pcap_pkthdr.caplen;
119 		m->pkt_len = pcap_pkthdr.caplen;
120 
121 		p->pkts[p->n_pkts] = m;
122 		p->n_pkts++;
123 	}
124 
125 	if (!p->n_pkts)
126 		goto error;
127 
128 	pcap_close(f);
129 	return p;
130 
131 error:
132 	source_free(p);
133 	if (f)
134 		pcap_close(f);
135 	return NULL;
136 }
137 
138 static int
139 source_pkt_rx(void *port, struct rte_swx_pkt *pkt)
140 {
141 	struct source *p = port;
142 	struct rte_mbuf *m_dst, *m_src;
143 	uint8_t *m_dst_data, *m_src_data;
144 
145 	/* m_src identification. */
146 	m_src = p->pkts[p->pos];
147 	m_src_data = rte_pktmbuf_mtod(m_src, uint8_t *);
148 
149 	/* m_dst allocation from pool. */
150 	m_dst = rte_pktmbuf_alloc(p->params.pool);
151 	if (!m_dst)
152 		return 0;
153 
154 	/* m_dst initialization. */
155 	m_dst->data_len = m_src->data_len;
156 	m_dst->pkt_len = m_src->pkt_len;
157 	m_dst->data_off = m_src->data_off;
158 
159 	m_dst_data = rte_pktmbuf_mtod(m_dst, uint8_t *);
160 	rte_memcpy(m_dst_data, m_src_data, m_src->data_len);
161 
162 	/* pkt initialization. */
163 	pkt->handle = m_dst;
164 	pkt->pkt = m_dst->buf_addr;
165 	pkt->offset = m_dst->data_off;
166 	pkt->length = m_dst->pkt_len;
167 
168 	TRACE("[Source port] Pkt RX (%u bytes at offset %u)\n",
169 	      pkt->length,
170 	      pkt->offset);
171 	if (TRACE_LEVEL)
172 		rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
173 
174 	/* port stats update. */
175 	p->stats.n_pkts++;
176 	p->stats.n_bytes += pkt->length;
177 
178 	/* m_src next. */
179 	p->pos++;
180 	if (p->pos == p->n_pkts)
181 		p->pos = 0;
182 
183 	return 1;
184 }
185 
186 static void
187 source_stats_read(void *port, struct rte_swx_port_in_stats *stats)
188 {
189 	struct source *p = port;
190 
191 	if (!p || !stats)
192 		return;
193 
194 	memcpy(stats, &p->stats, sizeof(p->stats));
195 }
196 
197 struct rte_swx_port_in_ops rte_swx_port_source_ops = {
198 	.create = source_create,
199 	.free = source_free,
200 	.pkt_rx = source_pkt_rx,
201 	.stats_read = source_stats_read,
202 };
203 
204 #else
205 
206 struct rte_swx_port_in_ops rte_swx_port_source_ops = {
207 	.create = NULL,
208 	.free = NULL,
209 	.pkt_rx = NULL,
210 	.stats_read = NULL,
211 };
212 
213 #endif
214 
215 /*
216  * Port SINK
217  */
218 struct sink {
219 	struct rte_swx_port_out_stats stats;
220 
221 #ifdef RTE_PORT_PCAP
222 	pcap_t *f_pcap;
223 	pcap_dumper_t *f_dump;
224 #endif
225 };
226 
227 static void
228 sink_free(void *port)
229 {
230 	struct sink *p = port;
231 
232 	if (!p)
233 		return;
234 
235 #ifdef RTE_PORT_PCAP
236 	if (p->f_dump)
237 		pcap_dump_close(p->f_dump);
238 	if (p->f_pcap)
239 		pcap_close(p->f_pcap);
240 #endif
241 
242 	free(p);
243 }
244 
245 static void *
246 sink_create(void *args __rte_unused)
247 {
248 	struct sink *p;
249 
250 	/* Memory allocation. */
251 	p = calloc(1, sizeof(struct sink));
252 	if (!p)
253 		goto error;
254 
255 #ifdef RTE_PORT_PCAP
256 	if (args) {
257 		struct rte_swx_port_sink_params *params = args;
258 
259 		if (params->file_name && params->file_name[0]) {
260 			p->f_pcap = pcap_open_dead(DLT_EN10MB, 65535);
261 			if (!p->f_pcap)
262 				goto error;
263 
264 			p->f_dump = pcap_dump_open(p->f_pcap,
265 						   params->file_name);
266 			if (!p->f_dump)
267 				goto error;
268 		}
269 	}
270 #endif
271 
272 	return p;
273 
274 error:
275 	sink_free(p);
276 	return NULL;
277 }
278 
279 static void
280 sink_pkt_tx(void *port, struct rte_swx_pkt *pkt)
281 {
282 	struct sink *p = port;
283 	struct rte_mbuf *m = pkt->handle;
284 
285 	TRACE("[Sink port] Pkt TX (%u bytes at offset %u)\n",
286 	      pkt->length,
287 	      pkt->offset);
288 	if (TRACE_LEVEL)
289 		rte_hexdump(stdout, NULL, &pkt->pkt[pkt->offset], pkt->length);
290 
291 	m->pkt_len = pkt->length;
292 	m->data_len = (uint16_t)pkt->length;
293 	m->data_off = (uint16_t)pkt->offset;
294 
295 	p->stats.n_pkts++;
296 	p->stats.n_bytes += pkt->length;
297 
298 #ifdef RTE_PORT_PCAP
299 	if (p->f_dump) {
300 		struct pcap_pkthdr pcap_pkthdr;
301 		uint8_t *m_data = rte_pktmbuf_mtod(m, uint8_t *);
302 
303 		pcap_pkthdr.len = m->pkt_len;
304 		pcap_pkthdr.caplen = m->data_len;
305 		gettimeofday(&pcap_pkthdr.ts, NULL);
306 
307 		pcap_dump((uint8_t *)p->f_dump, &pcap_pkthdr, m_data);
308 		pcap_dump_flush(p->f_dump);
309 	}
310 #endif
311 
312 	rte_pktmbuf_free(m);
313 }
314 
315 static void
316 sink_stats_read(void *port, struct rte_swx_port_out_stats *stats)
317 {
318 	struct sink *p = port;
319 
320 	if (!p || !stats)
321 		return;
322 
323 	memcpy(stats, &p->stats, sizeof(p->stats));
324 }
325 
326 /*
327  * Summary of port operations
328  */
329 struct rte_swx_port_out_ops rte_swx_port_sink_ops = {
330 	.create = sink_create,
331 	.free = sink_free,
332 	.pkt_tx = sink_pkt_tx,
333 	.flush = NULL,
334 	.stats_read = sink_stats_read,
335 };
336