Branch data Line data Source code
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
51 : 0 : source_free(void *port)
52 : : {
53 : : struct source *p = port;
54 : : uint32_t i;
55 : :
56 [ # # ]: 0 : if (!p)
57 : : return;
58 : :
59 [ # # ]: 0 : for (i = 0; i < p->n_pkts; i++)
60 : 0 : rte_pktmbuf_free(p->pkts[i]);
61 : :
62 : 0 : free(p->pkts);
63 : :
64 : 0 : free(p);
65 : : }
66 : :
67 : : static void *
68 : 0 : 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 [ # # ]: 0 : CHECK(params);
78 [ # # ]: 0 : CHECK(params->pool);
79 [ # # # # ]: 0 : CHECK(params->file_name && params->file_name[0]);
80 : 0 : n_pkts_max = params->n_pkts_max ?
81 [ # # ]: 0 : params->n_pkts_max :
82 : : RTE_SWX_PORT_SOURCE_PKTS_MAX;
83 : :
84 : : /* Resource allocation. */
85 : 0 : f = pcap_open_offline(params->file_name, pcap_errbuf);
86 [ # # ]: 0 : if (!f)
87 : 0 : goto error;
88 : :
89 : 0 : p = calloc(1, sizeof(struct source));
90 [ # # ]: 0 : if (!p)
91 : 0 : goto error;
92 : :
93 : 0 : p->pkts = calloc(n_pkts_max, sizeof(struct rte_mbuf *));
94 [ # # ]: 0 : if (!p->pkts)
95 : 0 : goto error;
96 : :
97 : : /* Initialization. */
98 : 0 : p->params.pool = params->pool;
99 : :
100 [ # # ]: 0 : p->params.n_loops = params->n_loops ? params->n_loops : UINT64_MAX;
101 : :
102 : : /* PCAP file. */
103 [ # # ]: 0 : 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 : 0 : pcap_pktdata = pcap_next(f, &pcap_pkthdr);
111 [ # # ]: 0 : if (!pcap_pktdata)
112 : : break;
113 : :
114 : : /* Allocate new buffer from pool. */
115 : 0 : m = rte_pktmbuf_alloc(params->pool);
116 [ # # ]: 0 : if (!m)
117 : 0 : goto error;
118 : 0 : m_data = rte_pktmbuf_mtod(m, uint8_t *);
119 : :
120 [ # # ]: 0 : rte_memcpy(m_data, pcap_pktdata, pcap_pkthdr.caplen);
121 : 0 : m->data_len = pcap_pkthdr.caplen;
122 : 0 : m->pkt_len = pcap_pkthdr.caplen;
123 : :
124 : 0 : p->pkts[p->n_pkts] = m;
125 : 0 : p->n_pkts++;
126 : : }
127 : :
128 [ # # ]: 0 : if (!p->n_pkts)
129 : 0 : goto error;
130 : :
131 : 0 : pcap_close(f);
132 : 0 : return p;
133 : :
134 : 0 : error:
135 : 0 : source_free(p);
136 [ # # ]: 0 : if (f)
137 : 0 : pcap_close(f);
138 : : return NULL;
139 : : }
140 : :
141 : : static int
142 : 0 : 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 [ # # ]: 0 : if (!p->params.n_loops)
149 : : return 0;
150 : : /* m_src identification. */
151 : 0 : m_src = p->pkts[p->pos];
152 : 0 : m_src_data = rte_pktmbuf_mtod(m_src, uint8_t *);
153 : :
154 : : /* m_dst allocation from pool. */
155 : 0 : m_dst = rte_pktmbuf_alloc(p->params.pool);
156 [ # # ]: 0 : if (!m_dst)
157 : : return 0;
158 : :
159 : : /* m_dst initialization. */
160 : 0 : m_dst->data_len = m_src->data_len;
161 : 0 : m_dst->pkt_len = m_src->pkt_len;
162 : 0 : m_dst->data_off = m_src->data_off;
163 : :
164 : 0 : m_dst_data = rte_pktmbuf_mtod(m_dst, uint8_t *);
165 [ # # ]: 0 : rte_memcpy(m_dst_data, m_src_data, m_src->data_len);
166 : :
167 : : /* pkt initialization. */
168 : 0 : pkt->handle = m_dst;
169 : 0 : pkt->pkt = m_dst->buf_addr;
170 : 0 : pkt->offset = m_dst->data_off;
171 : 0 : 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 : 0 : p->stats.n_pkts++;
181 : 0 : p->stats.n_bytes += pkt->length;
182 : :
183 : : /* m_src next. */
184 : 0 : p->pos++;
185 [ # # ]: 0 : if (p->pos == p->n_pkts) {
186 : 0 : p->pos = 0;
187 : 0 : p->params.n_loops--;
188 : : }
189 : :
190 : : return 1;
191 : : }
192 : :
193 : : static void
194 : 0 : source_stats_read(void *port, struct rte_swx_port_in_stats *stats)
195 : : {
196 : : struct source *p = port;
197 : :
198 [ # # ]: 0 : if (!p || !stats)
199 : : return;
200 : :
201 : 0 : 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
235 : 0 : sink_free(void *port)
236 : : {
237 : : struct sink *p = port;
238 : :
239 [ # # ]: 0 : if (!p)
240 : : return;
241 : :
242 : : #ifdef RTE_PORT_PCAP
243 [ # # ]: 0 : if (p->f_dump)
244 : 0 : pcap_dump_close(p->f_dump);
245 [ # # ]: 0 : if (p->f_pcap)
246 : 0 : pcap_close(p->f_pcap);
247 : : #endif
248 : :
249 : 0 : free(p);
250 : : }
251 : :
252 : : static void *
253 : 0 : sink_create(void *args __rte_unused)
254 : : {
255 : : struct sink *p;
256 : :
257 : : /* Memory allocation. */
258 : 0 : p = calloc(1, sizeof(struct sink));
259 [ # # ]: 0 : if (!p)
260 : 0 : goto error;
261 : :
262 : : #ifdef RTE_PORT_PCAP
263 [ # # ]: 0 : if (args) {
264 : : struct rte_swx_port_sink_params *params = args;
265 : :
266 [ # # # # ]: 0 : if (params->file_name && params->file_name[0]) {
267 : 0 : p->f_pcap = pcap_open_dead(DLT_EN10MB, 65535);
268 [ # # ]: 0 : if (!p->f_pcap)
269 : 0 : goto error;
270 : :
271 : 0 : p->f_dump = pcap_dump_open(p->f_pcap,
272 : : params->file_name);
273 [ # # ]: 0 : if (!p->f_dump)
274 : 0 : goto error;
275 : : }
276 : : }
277 : : #endif
278 : :
279 : : return p;
280 : :
281 : 0 : error:
282 : 0 : sink_free(p);
283 : 0 : return NULL;
284 : : }
285 : :
286 : : static void
287 : 0 : sink_pkt_tx(void *port, struct rte_swx_pkt *pkt)
288 : : {
289 : : struct sink *p = port;
290 : 0 : 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 : 0 : m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
299 : 0 : m->pkt_len = pkt->length;
300 : 0 : m->data_off = (uint16_t)pkt->offset;
301 : :
302 : 0 : p->stats.n_pkts_drop++;
303 : 0 : p->stats.n_bytes_drop += pkt->length;
304 : :
305 : : #ifdef RTE_PORT_PCAP
306 [ # # ]: 0 : if (p->f_dump) {
307 : : struct pcap_pkthdr pcap_pkthdr;
308 : 0 : uint8_t *m_data = rte_pktmbuf_mtod(m, uint8_t *);
309 : :
310 : 0 : pcap_pkthdr.len = m->pkt_len;
311 : 0 : pcap_pkthdr.caplen = m->data_len;
312 : 0 : gettimeofday(&pcap_pkthdr.ts, NULL);
313 : :
314 : 0 : pcap_dump((uint8_t *)p->f_dump, &pcap_pkthdr, m_data);
315 : 0 : pcap_dump_flush(p->f_dump);
316 : : }
317 : : #endif
318 : :
319 : 0 : rte_pktmbuf_free(m);
320 : 0 : }
321 : :
322 : : static void
323 : 0 : __sink_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length __rte_unused)
324 : : {
325 : : struct sink *p = port;
326 : 0 : 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 : 0 : m->data_len = (uint16_t)(pkt->length + m->data_len - m->pkt_len);
335 : 0 : m->pkt_len = pkt->length;
336 : 0 : m->data_off = (uint16_t)pkt->offset;
337 : :
338 : 0 : p->stats.n_pkts_drop++;
339 : 0 : p->stats.n_bytes_drop += pkt->length;
340 : 0 : p->stats.n_pkts_clone++;
341 : :
342 : : #ifdef RTE_PORT_PCAP
343 [ # # ]: 0 : if (p->f_dump) {
344 : : struct pcap_pkthdr pcap_pkthdr;
345 : 0 : uint8_t *m_data = rte_pktmbuf_mtod(m, uint8_t *);
346 : :
347 : 0 : pcap_pkthdr.len = m->pkt_len;
348 : 0 : pcap_pkthdr.caplen = RTE_MIN(m->data_len, truncation_length);
349 : 0 : gettimeofday(&pcap_pkthdr.ts, NULL);
350 : :
351 : 0 : pcap_dump((uint8_t *)p->f_dump, &pcap_pkthdr, m_data);
352 : 0 : pcap_dump_flush(p->f_dump);
353 : : }
354 : : #endif
355 : 0 : }
356 : :
357 : : static void
358 : 0 : sink_pkt_fast_clone_tx(void *port, struct rte_swx_pkt *pkt)
359 : : {
360 : 0 : __sink_pkt_clone_tx(port, pkt, UINT32_MAX);
361 : 0 : }
362 : :
363 : : static void
364 : 0 : sink_pkt_clone_tx(void *port, struct rte_swx_pkt *pkt, uint32_t truncation_length)
365 : : {
366 : 0 : __sink_pkt_clone_tx(port, pkt, truncation_length);
367 : 0 : }
368 : :
369 : : static void
370 : 0 : sink_stats_read(void *port, struct rte_swx_port_out_stats *stats)
371 : : {
372 : : struct sink *p = port;
373 : :
374 [ # # ]: 0 : if (!p || !stats)
375 : : return;
376 : :
377 : 0 : 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 : : };
|