1a551c94aSIdo Barnea/*-
2a551c94aSIdo Barnea *   BSD LICENSE
3a551c94aSIdo Barnea *
4a551c94aSIdo Barnea *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
5a551c94aSIdo Barnea *   All rights reserved.
6a551c94aSIdo Barnea *
7a551c94aSIdo Barnea *   Redistribution and use in source and binary forms, with or without
8a551c94aSIdo Barnea *   modification, are permitted provided that the following conditions
9a551c94aSIdo Barnea *   are met:
10a551c94aSIdo Barnea *
11a551c94aSIdo Barnea *     * Redistributions of source code must retain the above copyright
12a551c94aSIdo Barnea *       notice, this list of conditions and the following disclaimer.
13a551c94aSIdo Barnea *     * Redistributions in binary form must reproduce the above copyright
14a551c94aSIdo Barnea *       notice, this list of conditions and the following disclaimer in
15a551c94aSIdo Barnea *       the documentation and/or other materials provided with the
16a551c94aSIdo Barnea *       distribution.
17a551c94aSIdo Barnea *     * Neither the name of Intel Corporation nor the names of its
18a551c94aSIdo Barnea *       contributors may be used to endorse or promote products derived
19a551c94aSIdo Barnea *       from this software without specific prior written permission.
20a551c94aSIdo Barnea *
21a551c94aSIdo Barnea *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22a551c94aSIdo Barnea *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23a551c94aSIdo Barnea *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24a551c94aSIdo Barnea *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25a551c94aSIdo Barnea *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26a551c94aSIdo Barnea *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27a551c94aSIdo Barnea *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28a551c94aSIdo Barnea *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29a551c94aSIdo Barnea *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30a551c94aSIdo Barnea *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31a551c94aSIdo Barnea *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32a551c94aSIdo Barnea */
33a551c94aSIdo Barnea#include <stdint.h>
34a551c94aSIdo Barnea#include <string.h>
35a551c94aSIdo Barnea
36a551c94aSIdo Barnea#include <rte_mbuf.h>
37a551c94aSIdo Barnea#include <rte_mempool.h>
38a551c94aSIdo Barnea#include <rte_malloc.h>
39a551c94aSIdo Barnea#include <rte_memcpy.h>
40a551c94aSIdo Barnea
41a551c94aSIdo Barnea#ifdef RTE_PORT_PCAP
42a551c94aSIdo Barnea#include <rte_ether.h>
43a551c94aSIdo Barnea#include <pcap.h>
44a551c94aSIdo Barnea#endif
45a551c94aSIdo Barnea
46a551c94aSIdo Barnea#include "rte_port_source_sink.h"
47a551c94aSIdo Barnea
48a551c94aSIdo Barnea/*
49a551c94aSIdo Barnea * Port SOURCE
50a551c94aSIdo Barnea */
51a551c94aSIdo Barnea#ifdef RTE_PORT_STATS_COLLECT
52a551c94aSIdo Barnea
53a551c94aSIdo Barnea#define RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(port, val) \
54a551c94aSIdo Barnea	port->stats.n_pkts_in += val
55a551c94aSIdo Barnea#define RTE_PORT_SOURCE_STATS_PKTS_DROP_ADD(port, val) \
56a551c94aSIdo Barnea	port->stats.n_pkts_drop += val
57a551c94aSIdo Barnea
58a551c94aSIdo Barnea#else
59a551c94aSIdo Barnea
60a551c94aSIdo Barnea#define RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(port, val)
61a551c94aSIdo Barnea#define RTE_PORT_SOURCE_STATS_PKTS_DROP_ADD(port, val)
62a551c94aSIdo Barnea
63a551c94aSIdo Barnea#endif
64a551c94aSIdo Barnea
65a551c94aSIdo Barneastruct rte_port_source {
66a551c94aSIdo Barnea	struct rte_port_in_stats stats;
67a551c94aSIdo Barnea
68a551c94aSIdo Barnea	struct rte_mempool *mempool;
69a551c94aSIdo Barnea
70a551c94aSIdo Barnea	/* PCAP buffers and indices */
71a551c94aSIdo Barnea	uint8_t **pkts;
72a551c94aSIdo Barnea	uint8_t *pkt_buff;
73a551c94aSIdo Barnea	uint32_t *pkt_len;
74a551c94aSIdo Barnea	uint32_t n_pkts;
75a551c94aSIdo Barnea	uint32_t pkt_index;
76a551c94aSIdo Barnea};
77a551c94aSIdo Barnea
78a551c94aSIdo Barnea#ifdef RTE_PORT_PCAP
79a551c94aSIdo Barnea
80a551c94aSIdo Barneastatic int
81a551c94aSIdo Barneapcap_source_load(struct rte_port_source *port,
82a551c94aSIdo Barnea		const char *file_name,
83a551c94aSIdo Barnea		uint32_t n_bytes_per_pkt,
84a551c94aSIdo Barnea		int socket_id)
85a551c94aSIdo Barnea{
86a551c94aSIdo Barnea	uint32_t n_pkts = 0;
87a551c94aSIdo Barnea	uint32_t i;
88a551c94aSIdo Barnea	uint32_t *pkt_len_aligns = NULL;
89a551c94aSIdo Barnea	size_t total_buff_len = 0;
90a551c94aSIdo Barnea	pcap_t *pcap_handle;
91a551c94aSIdo Barnea	char pcap_errbuf[PCAP_ERRBUF_SIZE];
92a551c94aSIdo Barnea	uint32_t max_len;
93a551c94aSIdo Barnea	struct pcap_pkthdr pcap_hdr;
94a551c94aSIdo Barnea	const uint8_t *pkt;
95a551c94aSIdo Barnea	uint8_t *buff = NULL;
96a551c94aSIdo Barnea	uint32_t pktmbuf_maxlen = (uint32_t)
97a551c94aSIdo Barnea			(rte_pktmbuf_data_room_size(port->mempool) -
98a551c94aSIdo Barnea			RTE_PKTMBUF_HEADROOM);
99a551c94aSIdo Barnea
100a551c94aSIdo Barnea	if (n_bytes_per_pkt == 0)
101a551c94aSIdo Barnea		max_len = pktmbuf_maxlen;
102a551c94aSIdo Barnea	else
103a551c94aSIdo Barnea		max_len = RTE_MIN(n_bytes_per_pkt, pktmbuf_maxlen);
104a551c94aSIdo Barnea
105a551c94aSIdo Barnea	/* first time open, get packet number */
106a551c94aSIdo Barnea	pcap_handle = pcap_open_offline(file_name, pcap_errbuf);
107a551c94aSIdo Barnea	if (pcap_handle == NULL) {
108a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "Failed to open pcap file "
109a551c94aSIdo Barnea			"'%s' for reading\n", file_name);
110a551c94aSIdo Barnea		goto error_exit;
111a551c94aSIdo Barnea	}
112a551c94aSIdo Barnea
113a551c94aSIdo Barnea	while ((pkt = pcap_next(pcap_handle, &pcap_hdr)) != NULL)
114a551c94aSIdo Barnea		n_pkts++;
115a551c94aSIdo Barnea
116a551c94aSIdo Barnea	pcap_close(pcap_handle);
117a551c94aSIdo Barnea
118a551c94aSIdo Barnea	port->pkt_len = rte_zmalloc_socket("PCAP",
119a551c94aSIdo Barnea		(sizeof(*port->pkt_len) * n_pkts), 0, socket_id);
120a551c94aSIdo Barnea	if (port->pkt_len == NULL) {
121a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "No enough memory\n");
122a551c94aSIdo Barnea		goto error_exit;
123a551c94aSIdo Barnea	}
124a551c94aSIdo Barnea
125a551c94aSIdo Barnea	pkt_len_aligns = rte_malloc("PCAP",
126a551c94aSIdo Barnea		(sizeof(*pkt_len_aligns) * n_pkts), 0);
127a551c94aSIdo Barnea	if (pkt_len_aligns == NULL) {
128a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "No enough memory\n");
129a551c94aSIdo Barnea		goto error_exit;
130a551c94aSIdo Barnea	}
131a551c94aSIdo Barnea
132a551c94aSIdo Barnea	port->pkts = rte_zmalloc_socket("PCAP",
133a551c94aSIdo Barnea		(sizeof(*port->pkts) * n_pkts), 0, socket_id);
134a551c94aSIdo Barnea	if (port->pkts == NULL) {
135a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "No enough memory\n");
136a551c94aSIdo Barnea		goto error_exit;
137a551c94aSIdo Barnea	}
138a551c94aSIdo Barnea
139a551c94aSIdo Barnea	/* open 2nd time, get pkt_len */
140a551c94aSIdo Barnea	pcap_handle = pcap_open_offline(file_name, pcap_errbuf);
141a551c94aSIdo Barnea	if (pcap_handle == NULL) {
142a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "Failed to open pcap file "
143a551c94aSIdo Barnea			"'%s' for reading\n", file_name);
144a551c94aSIdo Barnea		goto error_exit;
145a551c94aSIdo Barnea	}
146a551c94aSIdo Barnea
147a551c94aSIdo Barnea	for (i = 0; i < n_pkts; i++) {
148a551c94aSIdo Barnea		pkt = pcap_next(pcap_handle, &pcap_hdr);
149a551c94aSIdo Barnea		port->pkt_len[i] = RTE_MIN(max_len, pcap_hdr.len);
150a551c94aSIdo Barnea		pkt_len_aligns[i] = RTE_CACHE_LINE_ROUNDUP(
151a551c94aSIdo Barnea			port->pkt_len[i]);
152a551c94aSIdo Barnea		total_buff_len += pkt_len_aligns[i];
153a551c94aSIdo Barnea	}
154a551c94aSIdo Barnea
155a551c94aSIdo Barnea	pcap_close(pcap_handle);
156a551c94aSIdo Barnea
157a551c94aSIdo Barnea	/* allocate a big trunk of data for pcap file load */
158a551c94aSIdo Barnea	buff = rte_zmalloc_socket("PCAP",
159a551c94aSIdo Barnea		total_buff_len, 0, socket_id);
160a551c94aSIdo Barnea	if (buff == NULL) {
161a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "No enough memory\n");
162a551c94aSIdo Barnea		goto error_exit;
163a551c94aSIdo Barnea	}
164a551c94aSIdo Barnea
165a551c94aSIdo Barnea	port->pkt_buff = buff;
166a551c94aSIdo Barnea
167a551c94aSIdo Barnea	/* open file one last time to copy the pkt content */
168a551c94aSIdo Barnea	pcap_handle = pcap_open_offline(file_name, pcap_errbuf);
169a551c94aSIdo Barnea	if (pcap_handle == NULL) {
170a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "Failed to open pcap file "
171a551c94aSIdo Barnea			"'%s' for reading\n", file_name);
172a551c94aSIdo Barnea		goto error_exit;
173a551c94aSIdo Barnea	}
174a551c94aSIdo Barnea
175a551c94aSIdo Barnea	for (i = 0; i < n_pkts; i++) {
176a551c94aSIdo Barnea		pkt = pcap_next(pcap_handle, &pcap_hdr);
177a551c94aSIdo Barnea		rte_memcpy(buff, pkt, port->pkt_len[i]);
178a551c94aSIdo Barnea		port->pkts[i] = buff;
179a551c94aSIdo Barnea		buff += pkt_len_aligns[i];
180a551c94aSIdo Barnea	}
181a551c94aSIdo Barnea
182a551c94aSIdo Barnea	pcap_close(pcap_handle);
183a551c94aSIdo Barnea
184a551c94aSIdo Barnea	port->n_pkts = n_pkts;
185a551c94aSIdo Barnea
186a551c94aSIdo Barnea	rte_free(pkt_len_aligns);
187a551c94aSIdo Barnea
188a551c94aSIdo Barnea	RTE_LOG(INFO, PORT, "Successfully load pcap file "
189a551c94aSIdo Barnea		"'%s' with %u pkts\n",
190a551c94aSIdo Barnea		file_name, port->n_pkts);
191a551c94aSIdo Barnea
192a551c94aSIdo Barnea	return 0;
193a551c94aSIdo Barnea
194a551c94aSIdo Barneaerror_exit:
195a551c94aSIdo Barnea	if (pkt_len_aligns)
196a551c94aSIdo Barnea		rte_free(pkt_len_aligns);
197a551c94aSIdo Barnea	if (port->pkt_len)
198a551c94aSIdo Barnea		rte_free(port->pkt_len);
199a551c94aSIdo Barnea	if (port->pkts)
200a551c94aSIdo Barnea		rte_free(port->pkts);
201a551c94aSIdo Barnea	if (port->pkt_buff)
202a551c94aSIdo Barnea		rte_free(port->pkt_buff);
203a551c94aSIdo Barnea
204a551c94aSIdo Barnea	return -1;
205a551c94aSIdo Barnea}
206a551c94aSIdo Barnea
207a551c94aSIdo Barnea#define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id)	\
208a551c94aSIdo Barnea	pcap_source_load(port, file_name, n_bytes, socket_id)
209a551c94aSIdo Barnea
210a551c94aSIdo Barnea#else /* RTE_PORT_PCAP */
211a551c94aSIdo Barnea
212a551c94aSIdo Barnea#define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id)	\
213a551c94aSIdo Barnea({								\
214a551c94aSIdo Barnea	int _ret = 0;						\
215a551c94aSIdo Barnea								\
216a551c94aSIdo Barnea	if (file_name) {					\
217a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "Source port field "		\
218a551c94aSIdo Barnea			"\"file_name\" is not NULL.\n");	\
219a551c94aSIdo Barnea		_ret = -1;					\
220a551c94aSIdo Barnea	}							\
221a551c94aSIdo Barnea								\
222a551c94aSIdo Barnea	_ret;							\
223a551c94aSIdo Barnea})
224a551c94aSIdo Barnea
225a551c94aSIdo Barnea#endif /* RTE_PORT_PCAP */
226a551c94aSIdo Barnea
227a551c94aSIdo Barneastatic void *
228a551c94aSIdo Barnearte_port_source_create(void *params, int socket_id)
229a551c94aSIdo Barnea{
230a551c94aSIdo Barnea	struct rte_port_source_params *p =
231a551c94aSIdo Barnea			(struct rte_port_source_params *) params;
232a551c94aSIdo Barnea	struct rte_port_source *port;
233a551c94aSIdo Barnea
234a551c94aSIdo Barnea	/* Check input arguments*/
235a551c94aSIdo Barnea	if ((p == NULL) || (p->mempool == NULL)) {
236a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "%s: Invalid params\n", __func__);
237a551c94aSIdo Barnea		return NULL;
238a551c94aSIdo Barnea	}
239a551c94aSIdo Barnea
240a551c94aSIdo Barnea	/* Memory allocation */
241a551c94aSIdo Barnea	port = rte_zmalloc_socket("PORT", sizeof(*port),
242a551c94aSIdo Barnea			RTE_CACHE_LINE_SIZE, socket_id);
243a551c94aSIdo Barnea	if (port == NULL) {
244a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
245a551c94aSIdo Barnea		return NULL;
246a551c94aSIdo Barnea	}
247a551c94aSIdo Barnea
248a551c94aSIdo Barnea	/* Initialization */
249a551c94aSIdo Barnea	port->mempool = (struct rte_mempool *) p->mempool;
250a551c94aSIdo Barnea
251a551c94aSIdo Barnea	if (p->file_name) {
252a551c94aSIdo Barnea		int status = PCAP_SOURCE_LOAD(port, p->file_name,
253a551c94aSIdo Barnea			p->n_bytes_per_pkt, socket_id);
254a551c94aSIdo Barnea
255a551c94aSIdo Barnea		if (status < 0) {
256a551c94aSIdo Barnea			rte_free(port);
257a551c94aSIdo Barnea			port = NULL;
258a551c94aSIdo Barnea		}
259a551c94aSIdo Barnea	}
260a551c94aSIdo Barnea
261a551c94aSIdo Barnea	return port;
262a551c94aSIdo Barnea}
263a551c94aSIdo Barnea
264a551c94aSIdo Barneastatic int
265a551c94aSIdo Barnearte_port_source_free(void *port)
266a551c94aSIdo Barnea{
267a551c94aSIdo Barnea	struct rte_port_source *p =
268a551c94aSIdo Barnea			(struct rte_port_source *)port;
269a551c94aSIdo Barnea
270a551c94aSIdo Barnea	/* Check input parameters */
271a551c94aSIdo Barnea	if (p == NULL)
272a551c94aSIdo Barnea		return 0;
273a551c94aSIdo Barnea
274a551c94aSIdo Barnea	if (p->pkt_len)
275a551c94aSIdo Barnea		rte_free(p->pkt_len);
276a551c94aSIdo Barnea	if (p->pkts)
277a551c94aSIdo Barnea		rte_free(p->pkts);
278a551c94aSIdo Barnea	if (p->pkt_buff)
279a551c94aSIdo Barnea		rte_free(p->pkt_buff);
280a551c94aSIdo Barnea
281a551c94aSIdo Barnea	rte_free(p);
282a551c94aSIdo Barnea
283a551c94aSIdo Barnea	return 0;
284a551c94aSIdo Barnea}
285a551c94aSIdo Barnea
286a551c94aSIdo Barneastatic int
287a551c94aSIdo Barnearte_port_source_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)
288a551c94aSIdo Barnea{
289a551c94aSIdo Barnea	struct rte_port_source *p = (struct rte_port_source *) port;
290a551c94aSIdo Barnea	uint32_t i;
291a551c94aSIdo Barnea
292a551c94aSIdo Barnea	if (rte_mempool_get_bulk(p->mempool, (void **) pkts, n_pkts) != 0)
293a551c94aSIdo Barnea		return 0;
294a551c94aSIdo Barnea
295a551c94aSIdo Barnea	for (i = 0; i < n_pkts; i++) {
296a551c94aSIdo Barnea		rte_mbuf_refcnt_set(pkts[i], 1);
297a551c94aSIdo Barnea		rte_pktmbuf_reset(pkts[i]);
298a551c94aSIdo Barnea	}
299a551c94aSIdo Barnea
300a551c94aSIdo Barnea	if (p->pkt_buff != NULL) {
301a551c94aSIdo Barnea		for (i = 0; i < n_pkts; i++) {
302a551c94aSIdo Barnea			uint8_t *pkt_data = rte_pktmbuf_mtod(pkts[i],
303a551c94aSIdo Barnea				uint8_t *);
304a551c94aSIdo Barnea
305a551c94aSIdo Barnea			rte_memcpy(pkt_data, p->pkts[p->pkt_index],
306a551c94aSIdo Barnea					p->pkt_len[p->pkt_index]);
307a551c94aSIdo Barnea			pkts[i]->data_len = p->pkt_len[p->pkt_index];
308a551c94aSIdo Barnea			pkts[i]->pkt_len = pkts[i]->data_len;
309a551c94aSIdo Barnea
310a551c94aSIdo Barnea			p->pkt_index++;
311a551c94aSIdo Barnea			if (p->pkt_index >= p->n_pkts)
312a551c94aSIdo Barnea				p->pkt_index = 0;
313a551c94aSIdo Barnea		}
314a551c94aSIdo Barnea	}
315a551c94aSIdo Barnea
316a551c94aSIdo Barnea	RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(p, n_pkts);
317a551c94aSIdo Barnea
318a551c94aSIdo Barnea	return n_pkts;
319a551c94aSIdo Barnea}
320a551c94aSIdo Barnea
321a551c94aSIdo Barneastatic int
322a551c94aSIdo Barnearte_port_source_stats_read(void *port,
323a551c94aSIdo Barnea		struct rte_port_in_stats *stats, int clear)
324a551c94aSIdo Barnea{
325a551c94aSIdo Barnea	struct rte_port_source *p =
326a551c94aSIdo Barnea		(struct rte_port_source *) port;
327a551c94aSIdo Barnea
328a551c94aSIdo Barnea	if (stats != NULL)
329a551c94aSIdo Barnea		memcpy(stats, &p->stats, sizeof(p->stats));
330a551c94aSIdo Barnea
331a551c94aSIdo Barnea	if (clear)
332a551c94aSIdo Barnea		memset(&p->stats, 0, sizeof(p->stats));
333a551c94aSIdo Barnea
334a551c94aSIdo Barnea	return 0;
335a551c94aSIdo Barnea}
336a551c94aSIdo Barnea
337a551c94aSIdo Barnea/*
338a551c94aSIdo Barnea * Port SINK
339a551c94aSIdo Barnea */
340a551c94aSIdo Barnea#ifdef RTE_PORT_STATS_COLLECT
341a551c94aSIdo Barnea
342a551c94aSIdo Barnea#define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val) \
343a551c94aSIdo Barnea	(port->stats.n_pkts_in += val)
344a551c94aSIdo Barnea#define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val) \
345a551c94aSIdo Barnea	(port->stats.n_pkts_drop += val)
346a551c94aSIdo Barnea
347a551c94aSIdo Barnea#else
348a551c94aSIdo Barnea
349a551c94aSIdo Barnea#define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val)
350a551c94aSIdo Barnea#define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val)
351a551c94aSIdo Barnea
352a551c94aSIdo Barnea#endif
353a551c94aSIdo Barnea
354a551c94aSIdo Barneastruct rte_port_sink {
355a551c94aSIdo Barnea	struct rte_port_out_stats stats;
356a551c94aSIdo Barnea
357a551c94aSIdo Barnea	/* PCAP dumper handle and pkts number */
358a551c94aSIdo Barnea	void *dumper;
359a551c94aSIdo Barnea	uint32_t max_pkts;
360a551c94aSIdo Barnea	uint32_t pkt_index;
361a551c94aSIdo Barnea	uint32_t dump_finish;
362a551c94aSIdo Barnea};
363a551c94aSIdo Barnea
364a551c94aSIdo Barnea#ifdef RTE_PORT_PCAP
365a551c94aSIdo Barnea
366a551c94aSIdo Barneastatic int
367a551c94aSIdo Barneapcap_sink_open(struct rte_port_sink *port,
368a551c94aSIdo Barnea	const char *file_name,
369a551c94aSIdo Barnea	uint32_t max_n_pkts)
370a551c94aSIdo Barnea{
371a551c94aSIdo Barnea	pcap_t *tx_pcap;
372a551c94aSIdo Barnea	pcap_dumper_t *pcap_dumper;
373a551c94aSIdo Barnea
374a551c94aSIdo Barnea	/** Open a dead pcap handler for opening dumper file */
375a551c94aSIdo Barnea	tx_pcap = pcap_open_dead(DLT_EN10MB, 65535);
376a551c94aSIdo Barnea	if (tx_pcap == NULL) {
377a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "Cannot open pcap dead handler\n");
378a551c94aSIdo Barnea		return -1;
379a551c94aSIdo Barnea	}
380a551c94aSIdo Barnea
381a551c94aSIdo Barnea	/* The dumper is created using the previous pcap_t reference */
382a551c94aSIdo Barnea	pcap_dumper = pcap_dump_open(tx_pcap, file_name);
383a551c94aSIdo Barnea	if (pcap_dumper == NULL) {
384a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "Failed to open pcap file "
385a551c94aSIdo Barnea			"\"%s\" for writing\n", file_name);
386a551c94aSIdo Barnea		return -1;
387a551c94aSIdo Barnea	}
388a551c94aSIdo Barnea
389a551c94aSIdo Barnea	port->dumper = pcap_dumper;
390a551c94aSIdo Barnea	port->max_pkts = max_n_pkts;
391a551c94aSIdo Barnea	port->pkt_index = 0;
392a551c94aSIdo Barnea	port->dump_finish = 0;
393a551c94aSIdo Barnea
394a551c94aSIdo Barnea	RTE_LOG(INFO, PORT, "Ready to dump packets to file \"%s\"\n",
395a551c94aSIdo Barnea		file_name);
396a551c94aSIdo Barnea
397a551c94aSIdo Barnea	return 0;
398a551c94aSIdo Barnea}
399a551c94aSIdo Barnea
400a551c94aSIdo Barneastatic void
401a551c94aSIdo Barneapcap_sink_write_pkt(struct rte_port_sink *port, struct rte_mbuf *mbuf)
402a551c94aSIdo Barnea{
403a551c94aSIdo Barnea	uint8_t *pcap_dumper = (uint8_t *)(port->dumper);
404a551c94aSIdo Barnea	struct pcap_pkthdr pcap_hdr;
405a551c94aSIdo Barnea	uint8_t jumbo_pkt_buf[ETHER_MAX_JUMBO_FRAME_LEN];
406a551c94aSIdo Barnea	uint8_t *pkt;
407a551c94aSIdo Barnea
408a551c94aSIdo Barnea	/* Maximum num packets already reached */
409a551c94aSIdo Barnea	if (port->dump_finish)
410a551c94aSIdo Barnea		return;
411a551c94aSIdo Barnea
412a551c94aSIdo Barnea	pkt = rte_pktmbuf_mtod(mbuf, uint8_t *);
413a551c94aSIdo Barnea
414a551c94aSIdo Barnea	pcap_hdr.len = mbuf->pkt_len;
415a551c94aSIdo Barnea	pcap_hdr.caplen = pcap_hdr.len;
416a551c94aSIdo Barnea	gettimeofday(&(pcap_hdr.ts), NULL);
417a551c94aSIdo Barnea
418a551c94aSIdo Barnea	if (mbuf->nb_segs > 1) {
419a551c94aSIdo Barnea		struct rte_mbuf *jumbo_mbuf;
420a551c94aSIdo Barnea		uint32_t pkt_index = 0;
421a551c94aSIdo Barnea
422a551c94aSIdo Barnea		/* if packet size longer than ETHER_MAX_JUMBO_FRAME_LEN,
423a551c94aSIdo Barnea		 * ignore it.
424a551c94aSIdo Barnea		 */
425a551c94aSIdo Barnea		if (mbuf->pkt_len > ETHER_MAX_JUMBO_FRAME_LEN)
426a551c94aSIdo Barnea			return;
427a551c94aSIdo Barnea
428a551c94aSIdo Barnea		for (jumbo_mbuf = mbuf; jumbo_mbuf != NULL;
429a551c94aSIdo Barnea				jumbo_mbuf = jumbo_mbuf->next) {
430a551c94aSIdo Barnea			rte_memcpy(&jumbo_pkt_buf[pkt_index],
431a551c94aSIdo Barnea				rte_pktmbuf_mtod(jumbo_mbuf, uint8_t *),
432a551c94aSIdo Barnea				jumbo_mbuf->data_len);
433a551c94aSIdo Barnea			pkt_index += jumbo_mbuf->data_len;
434a551c94aSIdo Barnea		}
435a551c94aSIdo Barnea
436a551c94aSIdo Barnea		jumbo_pkt_buf[pkt_index] = '\0';
437a551c94aSIdo Barnea
438a551c94aSIdo Barnea		pkt = jumbo_pkt_buf;
439a551c94aSIdo Barnea	}
440a551c94aSIdo Barnea
441a551c94aSIdo Barnea	pcap_dump(pcap_dumper, &pcap_hdr, pkt);
442a551c94aSIdo Barnea
443a551c94aSIdo Barnea	port->pkt_index++;
444a551c94aSIdo Barnea
445a551c94aSIdo Barnea	if ((port->max_pkts != 0) && (port->pkt_index >= port->max_pkts)) {
446a551c94aSIdo Barnea		port->dump_finish = 1;
447a551c94aSIdo Barnea		RTE_LOG(INFO, PORT, "Dumped %u packets to file\n",
448a551c94aSIdo Barnea				port->pkt_index);
449a551c94aSIdo Barnea	}
450a551c94aSIdo Barnea
451a551c94aSIdo Barnea}
452a551c94aSIdo Barnea
453a551c94aSIdo Barnea#define PCAP_SINK_OPEN(port, file_name, max_n_pkts)		\
454a551c94aSIdo Barnea	pcap_sink_open(port, file_name, max_n_pkts)
455a551c94aSIdo Barnea
456a551c94aSIdo Barnea#define PCAP_SINK_WRITE_PKT(port, mbuf)				\
457a551c94aSIdo Barnea	pcap_sink_write_pkt(port, mbuf)
458a551c94aSIdo Barnea
459a551c94aSIdo Barnea#define PCAP_SINK_FLUSH_PKT(dumper)				\
460a551c94aSIdo Barneado {								\
461a551c94aSIdo Barnea	if (dumper)						\
462a551c94aSIdo Barnea		pcap_dump_flush((pcap_dumper_t *)dumper);	\
463a551c94aSIdo Barnea} while (0)
464a551c94aSIdo Barnea
465a551c94aSIdo Barnea#define PCAP_SINK_CLOSE(dumper)					\
466a551c94aSIdo Barneado {								\
467a551c94aSIdo Barnea	if (dumper)						\
468a551c94aSIdo Barnea		pcap_dump_close((pcap_dumper_t *)dumper);	\
469a551c94aSIdo Barnea} while (0)
470a551c94aSIdo Barnea
471a551c94aSIdo Barnea#else
472a551c94aSIdo Barnea
473a551c94aSIdo Barnea#define PCAP_SINK_OPEN(port, file_name, max_n_pkts)		\
474a551c94aSIdo Barnea({								\
475a551c94aSIdo Barnea	int _ret = 0;						\
476a551c94aSIdo Barnea								\
477a551c94aSIdo Barnea	if (file_name) {					\
478a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "Sink port field "		\
479a551c94aSIdo Barnea			"\"file_name\" is not NULL.\n");	\
480a551c94aSIdo Barnea		_ret = -1;					\
481a551c94aSIdo Barnea	}							\
482a551c94aSIdo Barnea								\
483a551c94aSIdo Barnea	_ret;							\
484a551c94aSIdo Barnea})
485a551c94aSIdo Barnea
486a551c94aSIdo Barnea#define PCAP_SINK_WRITE_PKT(port, mbuf) {}
487a551c94aSIdo Barnea
488a551c94aSIdo Barnea#define PCAP_SINK_FLUSH_PKT(dumper)
489a551c94aSIdo Barnea
490a551c94aSIdo Barnea#define PCAP_SINK_CLOSE(dumper)
491a551c94aSIdo Barnea
492a551c94aSIdo Barnea#endif
493a551c94aSIdo Barnea
494a551c94aSIdo Barneastatic void *
495a551c94aSIdo Barnearte_port_sink_create(void *params, int socket_id)
496a551c94aSIdo Barnea{
497a551c94aSIdo Barnea	struct rte_port_sink *port;
498a551c94aSIdo Barnea	struct rte_port_sink_params *p = params;
499a551c94aSIdo Barnea
500a551c94aSIdo Barnea	/* Memory allocation */
501a551c94aSIdo Barnea	port = rte_zmalloc_socket("PORT", sizeof(*port),
502a551c94aSIdo Barnea			RTE_CACHE_LINE_SIZE, socket_id);
503a551c94aSIdo Barnea	if (port == NULL) {
504a551c94aSIdo Barnea		RTE_LOG(ERR, PORT, "%s: Failed to allocate port\n", __func__);
505a551c94aSIdo Barnea		return NULL;
506a551c94aSIdo Barnea	}
507a551c94aSIdo Barnea
508a551c94aSIdo Barnea	if (!p)
509a551c94aSIdo Barnea		return port;
510a551c94aSIdo Barnea
511a551c94aSIdo Barnea	if (p->file_name) {
512a551c94aSIdo Barnea		int status = PCAP_SINK_OPEN(port, p->file_name,
513a551c94aSIdo Barnea			p->max_n_pkts);
514a551c94aSIdo Barnea
515a551c94aSIdo Barnea		if (status < 0) {
516a551c94aSIdo Barnea			rte_free(port);
517a551c94aSIdo Barnea			port = NULL;
518a551c94aSIdo Barnea		}
519a551c94aSIdo Barnea	}
520a551c94aSIdo Barnea
521a551c94aSIdo Barnea	return port;
522a551c94aSIdo Barnea}
523a551c94aSIdo Barnea
524a551c94aSIdo Barneastatic int
525a551c94aSIdo Barnearte_port_sink_tx(void *port, struct rte_mbuf *pkt)
526a551c94aSIdo Barnea{
527a551c94aSIdo Barnea	struct rte_port_sink *p = (struct rte_port_sink *) port;
528a551c94aSIdo Barnea
529a551c94aSIdo Barnea	RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1);
530a551c94aSIdo Barnea	if (p->dumper != NULL)
531a551c94aSIdo Barnea		PCAP_SINK_WRITE_PKT(p, pkt);
532a551c94aSIdo Barnea	rte_pktmbuf_free(pkt);
533a551c94aSIdo Barnea	RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1);
534a551c94aSIdo Barnea
535a551c94aSIdo Barnea	return 0;
536a551c94aSIdo Barnea}
537a551c94aSIdo Barnea
538a551c94aSIdo Barneastatic int
539a551c94aSIdo Barnearte_port_sink_tx_bulk(void *port, struct rte_mbuf **pkts,
540a551c94aSIdo Barnea	uint64_t pkts_mask)
541a551c94aSIdo Barnea{
542a551c94aSIdo Barnea	struct rte_port_sink *p = (struct rte_port_sink *) port;
543a551c94aSIdo Barnea
544a551c94aSIdo Barnea	if ((pkts_mask & (pkts_mask + 1)) == 0) {
545a551c94aSIdo Barnea		uint64_t n_pkts = __builtin_popcountll(pkts_mask);
546a551c94aSIdo Barnea		uint32_t i;
547a551c94aSIdo Barnea
548a551c94aSIdo Barnea		RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, n_pkts);
549a551c94aSIdo Barnea		RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, n_pkts);
550a551c94aSIdo Barnea
551a551c94aSIdo Barnea		if (p->dumper) {
552a551c94aSIdo Barnea			for (i = 0; i < n_pkts; i++)
553a551c94aSIdo Barnea				PCAP_SINK_WRITE_PKT(p, pkts[i]);
554a551c94aSIdo Barnea		}
555a551c94aSIdo Barnea
556a551c94aSIdo Barnea		for (i = 0; i < n_pkts; i++) {
557a551c94aSIdo Barnea			struct rte_mbuf *pkt = pkts[i];
558a551c94aSIdo Barnea
559a551c94aSIdo Barnea			rte_pktmbuf_free(pkt);
560a551c94aSIdo Barnea		}
561a551c94aSIdo Barnea
562a551c94aSIdo Barnea	} else {
563a551c94aSIdo Barnea		if (p->dumper) {
564a551c94aSIdo Barnea			uint64_t dump_pkts_mask = pkts_mask;
565a551c94aSIdo Barnea			uint32_t pkt_index;
566a551c94aSIdo Barnea
567a551c94aSIdo Barnea			for ( ; dump_pkts_mask; ) {
568a551c94aSIdo Barnea				pkt_index = __builtin_ctzll(
569a551c94aSIdo Barnea					dump_pkts_mask);
570a551c94aSIdo Barnea				PCAP_SINK_WRITE_PKT(p, pkts[pkt_index]);
571a551c94aSIdo Barnea				dump_pkts_mask &= ~(1LLU << pkt_index);
572a551c94aSIdo Barnea			}
573a551c94aSIdo Barnea		}
574a551c94aSIdo Barnea
575a551c94aSIdo Barnea		for ( ; pkts_mask; ) {
576a551c94aSIdo Barnea			uint32_t pkt_index = __builtin_ctzll(pkts_mask);
577a551c94aSIdo Barnea			uint64_t pkt_mask = 1LLU << pkt_index;
578a551c94aSIdo Barnea			struct rte_mbuf *pkt = pkts[pkt_index];
579a551c94aSIdo Barnea
580a551c94aSIdo Barnea			RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1);
581a551c94aSIdo Barnea			RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1);
582a551c94aSIdo Barnea			rte_pktmbuf_free(pkt);
583a551c94aSIdo Barnea			pkts_mask &= ~pkt_mask;
584a551c94aSIdo Barnea		}
585a551c94aSIdo Barnea	}
586a551c94aSIdo Barnea
587a551c94aSIdo Barnea	return 0;
588a551c94aSIdo Barnea}
589a551c94aSIdo Barnea
590a551c94aSIdo Barneastatic int
591a551c94aSIdo Barnearte_port_sink_flush(void *port)
592a551c94aSIdo Barnea{
593a551c94aSIdo Barnea	struct rte_port_sink *p =
594a551c94aSIdo Barnea			(struct rte_port_sink *)port;
595a551c94aSIdo Barnea
596a551c94aSIdo Barnea	if (p == NULL)
597a551c94aSIdo Barnea		return 0;
598a551c94aSIdo Barnea
599a551c94aSIdo Barnea	PCAP_SINK_FLUSH_PKT(p->dumper);
600a551c94aSIdo Barnea
601a551c94aSIdo Barnea	return 0;
602a551c94aSIdo Barnea}
603a551c94aSIdo Barnea
604a551c94aSIdo Barneastatic int
605a551c94aSIdo Barnearte_port_sink_free(void *port)
606a551c94aSIdo Barnea{
607a551c94aSIdo Barnea	struct rte_port_sink *p =
608a551c94aSIdo Barnea			(struct rte_port_sink *)port;
609a551c94aSIdo Barnea
610a551c94aSIdo Barnea	if (p == NULL)
611a551c94aSIdo Barnea		return 0;
612a551c94aSIdo Barnea
613a551c94aSIdo Barnea	PCAP_SINK_CLOSE(p->dumper);
614a551c94aSIdo Barnea
615a551c94aSIdo Barnea	rte_free(p);
616a551c94aSIdo Barnea
617a551c94aSIdo Barnea	return 0;
618a551c94aSIdo Barnea}
619a551c94aSIdo Barnea
620a551c94aSIdo Barneastatic int
621a551c94aSIdo Barnearte_port_sink_stats_read(void *port, struct rte_port_out_stats *stats,
622a551c94aSIdo Barnea		int clear)
623a551c94aSIdo Barnea{
624a551c94aSIdo Barnea	struct rte_port_sink *p =
625a551c94aSIdo Barnea		(struct rte_port_sink *) port;
626a551c94aSIdo Barnea
627a551c94aSIdo Barnea	if (stats != NULL)
628a551c94aSIdo Barnea		memcpy(stats, &p->stats, sizeof(p->stats));
629a551c94aSIdo Barnea
630a551c94aSIdo Barnea	if (clear)
631a551c94aSIdo Barnea		memset(&p->stats, 0, sizeof(p->stats));
632a551c94aSIdo Barnea
633a551c94aSIdo Barnea	return 0;
634a551c94aSIdo Barnea}
635a551c94aSIdo Barnea
636a551c94aSIdo Barnea/*
637a551c94aSIdo Barnea * Summary of port operations
638a551c94aSIdo Barnea */
639a551c94aSIdo Barneastruct rte_port_in_ops rte_port_source_ops = {
640a551c94aSIdo Barnea	.f_create = rte_port_source_create,
641a551c94aSIdo Barnea	.f_free = rte_port_source_free,
642a551c94aSIdo Barnea	.f_rx = rte_port_source_rx,
643a551c94aSIdo Barnea	.f_stats = rte_port_source_stats_read,
644a551c94aSIdo Barnea};
645a551c94aSIdo Barnea
646a551c94aSIdo Barneastruct rte_port_out_ops rte_port_sink_ops = {
647a551c94aSIdo Barnea	.f_create = rte_port_sink_create,
648a551c94aSIdo Barnea	.f_free = rte_port_sink_free,
649a551c94aSIdo Barnea	.f_tx = rte_port_sink_tx,
650a551c94aSIdo Barnea	.f_tx_bulk = rte_port_sink_tx_bulk,
651a551c94aSIdo Barnea	.f_flush = rte_port_sink_flush,
652a551c94aSIdo Barnea	.f_stats = rte_port_sink_stats_read,
653a551c94aSIdo Barnea};
654