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
source_free(void * port)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 *
source_create(void * args)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
source_pkt_rx(void * port,struct rte_swx_pkt * pkt)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
source_stats_read(void * port,struct rte_swx_port_in_stats * stats)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
sink_free(void * port)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 *
sink_create(void * args __rte_unused)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
sink_pkt_tx(void * port,struct rte_swx_pkt * pkt)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
sink_stats_read(void * port,struct rte_swx_port_out_stats * stats)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