port: configure loop count for source port
[dpdk.git] / lib / port / rte_swx_port_source_sink.c
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 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 *
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
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
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
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 *
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
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->pkt_len = pkt->length;
299         m->data_len = (uint16_t)pkt->length;
300         m->data_off = (uint16_t)pkt->offset;
301
302         p->stats.n_pkts++;
303         p->stats.n_bytes += 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
323 sink_stats_read(void *port, struct rte_swx_port_out_stats *stats)
324 {
325         struct sink *p = port;
326
327         if (!p || !stats)
328                 return;
329
330         memcpy(stats, &p->stats, sizeof(p->stats));
331 }
332
333 /*
334  * Summary of port operations
335  */
336 struct rte_swx_port_out_ops rte_swx_port_sink_ops = {
337         .create = sink_create,
338         .free = sink_free,
339         .pkt_tx = sink_pkt_tx,
340         .flush = NULL,
341         .stats_read = sink_stats_read,
342 };