xref: /dpdk/lib/port/rte_port_source_sink.c (revision 93998f3c5f22747e4f2c5e8714fa5cbe6c9d1574)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2010-2016 Intel Corporation
399a2dd95SBruce Richardson  */
499a2dd95SBruce Richardson #include <stdint.h>
599a2dd95SBruce Richardson #include <string.h>
699a2dd95SBruce Richardson 
799a2dd95SBruce Richardson #include <rte_mbuf.h>
899a2dd95SBruce Richardson #include <rte_malloc.h>
999a2dd95SBruce Richardson #include <rte_memcpy.h>
1099a2dd95SBruce Richardson 
1199a2dd95SBruce Richardson #ifdef RTE_PORT_PCAP
1299a2dd95SBruce Richardson #include <rte_ether.h>
1399a2dd95SBruce Richardson #include <pcap.h>
1499a2dd95SBruce Richardson #endif
1599a2dd95SBruce Richardson 
1699a2dd95SBruce Richardson #include "rte_port_source_sink.h"
1799a2dd95SBruce Richardson 
18ae67895bSDavid Marchand #include "port_log.h"
19ae67895bSDavid Marchand 
2099a2dd95SBruce Richardson /*
2199a2dd95SBruce Richardson  * Port SOURCE
2299a2dd95SBruce Richardson  */
2399a2dd95SBruce Richardson #ifdef RTE_PORT_STATS_COLLECT
2499a2dd95SBruce Richardson 
2599a2dd95SBruce Richardson #define RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(port, val) \
2699a2dd95SBruce Richardson 	port->stats.n_pkts_in += val
2799a2dd95SBruce Richardson #define RTE_PORT_SOURCE_STATS_PKTS_DROP_ADD(port, val) \
2899a2dd95SBruce Richardson 	port->stats.n_pkts_drop += val
2999a2dd95SBruce Richardson 
3099a2dd95SBruce Richardson #else
3199a2dd95SBruce Richardson 
3299a2dd95SBruce Richardson #define RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(port, val)
3399a2dd95SBruce Richardson #define RTE_PORT_SOURCE_STATS_PKTS_DROP_ADD(port, val)
3499a2dd95SBruce Richardson 
3599a2dd95SBruce Richardson #endif
3699a2dd95SBruce Richardson 
3799a2dd95SBruce Richardson struct rte_port_source {
3899a2dd95SBruce Richardson 	struct rte_port_in_stats stats;
3999a2dd95SBruce Richardson 
4099a2dd95SBruce Richardson 	struct rte_mempool *mempool;
4199a2dd95SBruce Richardson 
4299a2dd95SBruce Richardson 	/* PCAP buffers and indices */
4399a2dd95SBruce Richardson 	uint8_t **pkts;
4499a2dd95SBruce Richardson 	uint8_t *pkt_buff;
4599a2dd95SBruce Richardson 	uint32_t *pkt_len;
4699a2dd95SBruce Richardson 	uint32_t n_pkts;
4799a2dd95SBruce Richardson 	uint32_t pkt_index;
4899a2dd95SBruce Richardson };
4999a2dd95SBruce Richardson 
5099a2dd95SBruce Richardson #ifdef RTE_PORT_PCAP
5199a2dd95SBruce Richardson 
5299a2dd95SBruce Richardson static int
pcap_source_load(struct rte_port_source * port,const char * file_name,uint32_t n_bytes_per_pkt,int socket_id)5399a2dd95SBruce Richardson pcap_source_load(struct rte_port_source *port,
5499a2dd95SBruce Richardson 		const char *file_name,
5599a2dd95SBruce Richardson 		uint32_t n_bytes_per_pkt,
5699a2dd95SBruce Richardson 		int socket_id)
5799a2dd95SBruce Richardson {
5899a2dd95SBruce Richardson 	uint32_t n_pkts = 0;
5999a2dd95SBruce Richardson 	uint32_t i;
6099a2dd95SBruce Richardson 	uint32_t *pkt_len_aligns = NULL;
6199a2dd95SBruce Richardson 	size_t total_buff_len = 0;
6299a2dd95SBruce Richardson 	pcap_t *pcap_handle;
6399a2dd95SBruce Richardson 	char pcap_errbuf[PCAP_ERRBUF_SIZE];
6499a2dd95SBruce Richardson 	uint32_t max_len;
6599a2dd95SBruce Richardson 	struct pcap_pkthdr pcap_hdr;
6699a2dd95SBruce Richardson 	const uint8_t *pkt;
6799a2dd95SBruce Richardson 	uint8_t *buff = NULL;
6899a2dd95SBruce Richardson 	uint32_t pktmbuf_maxlen = (uint32_t)
6999a2dd95SBruce Richardson 			(rte_pktmbuf_data_room_size(port->mempool) -
7099a2dd95SBruce Richardson 			RTE_PKTMBUF_HEADROOM);
7199a2dd95SBruce Richardson 
7299a2dd95SBruce Richardson 	if (n_bytes_per_pkt == 0)
7399a2dd95SBruce Richardson 		max_len = pktmbuf_maxlen;
7499a2dd95SBruce Richardson 	else
7599a2dd95SBruce Richardson 		max_len = RTE_MIN(n_bytes_per_pkt, pktmbuf_maxlen);
7699a2dd95SBruce Richardson 
7799a2dd95SBruce Richardson 	/* first time open, get packet number */
7899a2dd95SBruce Richardson 	pcap_handle = pcap_open_offline(file_name, pcap_errbuf);
7999a2dd95SBruce Richardson 	if (pcap_handle == NULL) {
80ae67895bSDavid Marchand 		PORT_LOG(ERR, "Failed to open pcap file "
81ae67895bSDavid Marchand 			"'%s' for reading", file_name);
8299a2dd95SBruce Richardson 		goto error_exit;
8399a2dd95SBruce Richardson 	}
8499a2dd95SBruce Richardson 
8599a2dd95SBruce Richardson 	while ((pkt = pcap_next(pcap_handle, &pcap_hdr)) != NULL)
8699a2dd95SBruce Richardson 		n_pkts++;
8799a2dd95SBruce Richardson 
8899a2dd95SBruce Richardson 	pcap_close(pcap_handle);
8999a2dd95SBruce Richardson 
9099a2dd95SBruce Richardson 	port->pkt_len = rte_zmalloc_socket("PCAP",
9199a2dd95SBruce Richardson 		(sizeof(*port->pkt_len) * n_pkts), 0, socket_id);
9299a2dd95SBruce Richardson 	if (port->pkt_len == NULL) {
93ae67895bSDavid Marchand 		PORT_LOG(ERR, "No enough memory");
9499a2dd95SBruce Richardson 		goto error_exit;
9599a2dd95SBruce Richardson 	}
9699a2dd95SBruce Richardson 
9799a2dd95SBruce Richardson 	pkt_len_aligns = rte_malloc("PCAP",
9899a2dd95SBruce Richardson 		(sizeof(*pkt_len_aligns) * n_pkts), 0);
9999a2dd95SBruce Richardson 	if (pkt_len_aligns == NULL) {
100ae67895bSDavid Marchand 		PORT_LOG(ERR, "No enough memory");
10199a2dd95SBruce Richardson 		goto error_exit;
10299a2dd95SBruce Richardson 	}
10399a2dd95SBruce Richardson 
10499a2dd95SBruce Richardson 	port->pkts = rte_zmalloc_socket("PCAP",
10599a2dd95SBruce Richardson 		(sizeof(*port->pkts) * n_pkts), 0, socket_id);
10699a2dd95SBruce Richardson 	if (port->pkts == NULL) {
107ae67895bSDavid Marchand 		PORT_LOG(ERR, "No enough memory");
10899a2dd95SBruce Richardson 		goto error_exit;
10999a2dd95SBruce Richardson 	}
11099a2dd95SBruce Richardson 
11199a2dd95SBruce Richardson 	/* open 2nd time, get pkt_len */
11299a2dd95SBruce Richardson 	pcap_handle = pcap_open_offline(file_name, pcap_errbuf);
11399a2dd95SBruce Richardson 	if (pcap_handle == NULL) {
114ae67895bSDavid Marchand 		PORT_LOG(ERR, "Failed to open pcap file "
115ae67895bSDavid Marchand 			"'%s' for reading", file_name);
11699a2dd95SBruce Richardson 		goto error_exit;
11799a2dd95SBruce Richardson 	}
11899a2dd95SBruce Richardson 
11999a2dd95SBruce Richardson 	for (i = 0; i < n_pkts; i++) {
12099a2dd95SBruce Richardson 		pcap_next(pcap_handle, &pcap_hdr);
12199a2dd95SBruce Richardson 		port->pkt_len[i] = RTE_MIN(max_len, pcap_hdr.len);
12299a2dd95SBruce Richardson 		pkt_len_aligns[i] = RTE_CACHE_LINE_ROUNDUP(
12399a2dd95SBruce Richardson 			port->pkt_len[i]);
12499a2dd95SBruce Richardson 		total_buff_len += pkt_len_aligns[i];
12599a2dd95SBruce Richardson 	}
12699a2dd95SBruce Richardson 
12799a2dd95SBruce Richardson 	pcap_close(pcap_handle);
12899a2dd95SBruce Richardson 
12999a2dd95SBruce Richardson 	/* allocate a big trunk of data for pcap file load */
13099a2dd95SBruce Richardson 	buff = rte_zmalloc_socket("PCAP",
13199a2dd95SBruce Richardson 		total_buff_len, 0, socket_id);
13299a2dd95SBruce Richardson 	if (buff == NULL) {
133ae67895bSDavid Marchand 		PORT_LOG(ERR, "No enough memory");
13499a2dd95SBruce Richardson 		goto error_exit;
13599a2dd95SBruce Richardson 	}
13699a2dd95SBruce Richardson 
13799a2dd95SBruce Richardson 	port->pkt_buff = buff;
13899a2dd95SBruce Richardson 
13999a2dd95SBruce Richardson 	/* open file one last time to copy the pkt content */
14099a2dd95SBruce Richardson 	pcap_handle = pcap_open_offline(file_name, pcap_errbuf);
14199a2dd95SBruce Richardson 	if (pcap_handle == NULL) {
142ae67895bSDavid Marchand 		PORT_LOG(ERR, "Failed to open pcap file "
143ae67895bSDavid Marchand 			"'%s' for reading", file_name);
14499a2dd95SBruce Richardson 		goto error_exit;
14599a2dd95SBruce Richardson 	}
14699a2dd95SBruce Richardson 
14799a2dd95SBruce Richardson 	for (i = 0; i < n_pkts; i++) {
14899a2dd95SBruce Richardson 		pkt = pcap_next(pcap_handle, &pcap_hdr);
14999a2dd95SBruce Richardson 		rte_memcpy(buff, pkt, port->pkt_len[i]);
15099a2dd95SBruce Richardson 		port->pkts[i] = buff;
15199a2dd95SBruce Richardson 		buff += pkt_len_aligns[i];
15299a2dd95SBruce Richardson 	}
15399a2dd95SBruce Richardson 
15499a2dd95SBruce Richardson 	pcap_close(pcap_handle);
15599a2dd95SBruce Richardson 
15699a2dd95SBruce Richardson 	port->n_pkts = n_pkts;
15799a2dd95SBruce Richardson 
15899a2dd95SBruce Richardson 	rte_free(pkt_len_aligns);
15999a2dd95SBruce Richardson 
160ae67895bSDavid Marchand 	PORT_LOG(INFO, "Successfully load pcap file "
161ae67895bSDavid Marchand 		"'%s' with %u pkts",
16299a2dd95SBruce Richardson 		file_name, port->n_pkts);
16399a2dd95SBruce Richardson 
16499a2dd95SBruce Richardson 	return 0;
16599a2dd95SBruce Richardson 
16699a2dd95SBruce Richardson error_exit:
16799a2dd95SBruce Richardson 	rte_free(pkt_len_aligns);
16899a2dd95SBruce Richardson 	rte_free(port->pkt_len);
16999a2dd95SBruce Richardson 	rte_free(port->pkts);
17099a2dd95SBruce Richardson 	rte_free(port->pkt_buff);
17199a2dd95SBruce Richardson 
17299a2dd95SBruce Richardson 	return -1;
17399a2dd95SBruce Richardson }
17499a2dd95SBruce Richardson 
17599a2dd95SBruce Richardson #define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id)	\
17699a2dd95SBruce Richardson 	pcap_source_load(port, file_name, n_bytes, socket_id)
17799a2dd95SBruce Richardson 
17899a2dd95SBruce Richardson #else /* RTE_PORT_PCAP */
17999a2dd95SBruce Richardson 
18099a2dd95SBruce Richardson #define PCAP_SOURCE_LOAD(port, file_name, n_bytes, socket_id)	\
181*93998f3cSTyler Retzlaff __extension__ ({						\
18299a2dd95SBruce Richardson 	int _ret = 0;						\
18399a2dd95SBruce Richardson 								\
18499a2dd95SBruce Richardson 	if (file_name) {					\
185ae67895bSDavid Marchand 		PORT_LOG(ERR, "Source port field "		\
186ae67895bSDavid Marchand 			"\"file_name\" is not NULL.");	\
18799a2dd95SBruce Richardson 		_ret = -1;					\
18899a2dd95SBruce Richardson 	}							\
18999a2dd95SBruce Richardson 								\
19099a2dd95SBruce Richardson 	_ret;							\
19199a2dd95SBruce Richardson })
19299a2dd95SBruce Richardson 
19399a2dd95SBruce Richardson #endif /* RTE_PORT_PCAP */
19499a2dd95SBruce Richardson 
19599a2dd95SBruce Richardson static void *
rte_port_source_create(void * params,int socket_id)19699a2dd95SBruce Richardson rte_port_source_create(void *params, int socket_id)
19799a2dd95SBruce Richardson {
19899a2dd95SBruce Richardson 	struct rte_port_source_params *p =
19999a2dd95SBruce Richardson 			params;
20099a2dd95SBruce Richardson 	struct rte_port_source *port;
20199a2dd95SBruce Richardson 
20299a2dd95SBruce Richardson 	/* Check input arguments*/
20399a2dd95SBruce Richardson 	if ((p == NULL) || (p->mempool == NULL)) {
204ae67895bSDavid Marchand 		PORT_LOG(ERR, "%s: Invalid params", __func__);
20599a2dd95SBruce Richardson 		return NULL;
20699a2dd95SBruce Richardson 	}
20799a2dd95SBruce Richardson 
20899a2dd95SBruce Richardson 	/* Memory allocation */
20999a2dd95SBruce Richardson 	port = rte_zmalloc_socket("PORT", sizeof(*port),
21099a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE, socket_id);
21199a2dd95SBruce Richardson 	if (port == NULL) {
212ae67895bSDavid Marchand 		PORT_LOG(ERR, "%s: Failed to allocate port", __func__);
21399a2dd95SBruce Richardson 		return NULL;
21499a2dd95SBruce Richardson 	}
21599a2dd95SBruce Richardson 
21699a2dd95SBruce Richardson 	/* Initialization */
21799a2dd95SBruce Richardson 	port->mempool = (struct rte_mempool *) p->mempool;
21899a2dd95SBruce Richardson 
21999a2dd95SBruce Richardson 	if (p->file_name) {
22099a2dd95SBruce Richardson 		int status = PCAP_SOURCE_LOAD(port, p->file_name,
22199a2dd95SBruce Richardson 			p->n_bytes_per_pkt, socket_id);
22299a2dd95SBruce Richardson 
22399a2dd95SBruce Richardson 		if (status < 0) {
22499a2dd95SBruce Richardson 			rte_free(port);
22599a2dd95SBruce Richardson 			port = NULL;
22699a2dd95SBruce Richardson 		}
22799a2dd95SBruce Richardson 	}
22899a2dd95SBruce Richardson 
22999a2dd95SBruce Richardson 	return port;
23099a2dd95SBruce Richardson }
23199a2dd95SBruce Richardson 
23299a2dd95SBruce Richardson static int
rte_port_source_free(void * port)23399a2dd95SBruce Richardson rte_port_source_free(void *port)
23499a2dd95SBruce Richardson {
23599a2dd95SBruce Richardson 	struct rte_port_source *p =
23699a2dd95SBruce Richardson 			port;
23799a2dd95SBruce Richardson 
23899a2dd95SBruce Richardson 	/* Check input parameters */
23999a2dd95SBruce Richardson 	if (p == NULL)
24099a2dd95SBruce Richardson 		return 0;
24199a2dd95SBruce Richardson 
24299a2dd95SBruce Richardson 	rte_free(p->pkt_len);
24399a2dd95SBruce Richardson 	rte_free(p->pkts);
24499a2dd95SBruce Richardson 	rte_free(p->pkt_buff);
24599a2dd95SBruce Richardson 
24699a2dd95SBruce Richardson 	rte_free(p);
24799a2dd95SBruce Richardson 
24899a2dd95SBruce Richardson 	return 0;
24999a2dd95SBruce Richardson }
25099a2dd95SBruce Richardson 
25199a2dd95SBruce Richardson static int
rte_port_source_rx(void * port,struct rte_mbuf ** pkts,uint32_t n_pkts)25299a2dd95SBruce Richardson rte_port_source_rx(void *port, struct rte_mbuf **pkts, uint32_t n_pkts)
25399a2dd95SBruce Richardson {
25499a2dd95SBruce Richardson 	struct rte_port_source *p = port;
25599a2dd95SBruce Richardson 	uint32_t i;
25699a2dd95SBruce Richardson 
25799a2dd95SBruce Richardson 	if (rte_pktmbuf_alloc_bulk(p->mempool, pkts, n_pkts) != 0)
25899a2dd95SBruce Richardson 		return 0;
25999a2dd95SBruce Richardson 
26099a2dd95SBruce Richardson 	if (p->pkt_buff != NULL) {
26199a2dd95SBruce Richardson 		for (i = 0; i < n_pkts; i++) {
26299a2dd95SBruce Richardson 			uint8_t *pkt_data = rte_pktmbuf_mtod(pkts[i],
26399a2dd95SBruce Richardson 				uint8_t *);
26499a2dd95SBruce Richardson 
26599a2dd95SBruce Richardson 			rte_memcpy(pkt_data, p->pkts[p->pkt_index],
26699a2dd95SBruce Richardson 					p->pkt_len[p->pkt_index]);
26799a2dd95SBruce Richardson 			pkts[i]->data_len = p->pkt_len[p->pkt_index];
26899a2dd95SBruce Richardson 			pkts[i]->pkt_len = pkts[i]->data_len;
26999a2dd95SBruce Richardson 
27099a2dd95SBruce Richardson 			p->pkt_index++;
27199a2dd95SBruce Richardson 			if (p->pkt_index >= p->n_pkts)
27299a2dd95SBruce Richardson 				p->pkt_index = 0;
27399a2dd95SBruce Richardson 		}
27499a2dd95SBruce Richardson 	}
27599a2dd95SBruce Richardson 
27699a2dd95SBruce Richardson 	RTE_PORT_SOURCE_STATS_PKTS_IN_ADD(p, n_pkts);
27799a2dd95SBruce Richardson 
27899a2dd95SBruce Richardson 	return n_pkts;
27999a2dd95SBruce Richardson }
28099a2dd95SBruce Richardson 
28199a2dd95SBruce Richardson static int
rte_port_source_stats_read(void * port,struct rte_port_in_stats * stats,int clear)28299a2dd95SBruce Richardson rte_port_source_stats_read(void *port,
28399a2dd95SBruce Richardson 		struct rte_port_in_stats *stats, int clear)
28499a2dd95SBruce Richardson {
28599a2dd95SBruce Richardson 	struct rte_port_source *p =
28699a2dd95SBruce Richardson 		port;
28799a2dd95SBruce Richardson 
28899a2dd95SBruce Richardson 	if (stats != NULL)
28999a2dd95SBruce Richardson 		memcpy(stats, &p->stats, sizeof(p->stats));
29099a2dd95SBruce Richardson 
29199a2dd95SBruce Richardson 	if (clear)
29299a2dd95SBruce Richardson 		memset(&p->stats, 0, sizeof(p->stats));
29399a2dd95SBruce Richardson 
29499a2dd95SBruce Richardson 	return 0;
29599a2dd95SBruce Richardson }
29699a2dd95SBruce Richardson 
29799a2dd95SBruce Richardson /*
29899a2dd95SBruce Richardson  * Port SINK
29999a2dd95SBruce Richardson  */
30099a2dd95SBruce Richardson #ifdef RTE_PORT_STATS_COLLECT
30199a2dd95SBruce Richardson 
30299a2dd95SBruce Richardson #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val) \
30399a2dd95SBruce Richardson 	(port->stats.n_pkts_in += val)
30499a2dd95SBruce Richardson #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val) \
30599a2dd95SBruce Richardson 	(port->stats.n_pkts_drop += val)
30699a2dd95SBruce Richardson 
30799a2dd95SBruce Richardson #else
30899a2dd95SBruce Richardson 
30999a2dd95SBruce Richardson #define RTE_PORT_SINK_STATS_PKTS_IN_ADD(port, val)
31099a2dd95SBruce Richardson #define RTE_PORT_SINK_STATS_PKTS_DROP_ADD(port, val)
31199a2dd95SBruce Richardson 
31299a2dd95SBruce Richardson #endif
31399a2dd95SBruce Richardson 
31499a2dd95SBruce Richardson struct rte_port_sink {
31599a2dd95SBruce Richardson 	struct rte_port_out_stats stats;
31699a2dd95SBruce Richardson 
31799a2dd95SBruce Richardson 	/* PCAP dumper handle and pkts number */
31899a2dd95SBruce Richardson 	void *dumper;
31999a2dd95SBruce Richardson 	uint32_t max_pkts;
32099a2dd95SBruce Richardson 	uint32_t pkt_index;
32199a2dd95SBruce Richardson 	uint32_t dump_finish;
32299a2dd95SBruce Richardson };
32399a2dd95SBruce Richardson 
32499a2dd95SBruce Richardson #ifdef RTE_PORT_PCAP
32599a2dd95SBruce Richardson 
32699a2dd95SBruce Richardson static int
pcap_sink_open(struct rte_port_sink * port,const char * file_name,uint32_t max_n_pkts)32799a2dd95SBruce Richardson pcap_sink_open(struct rte_port_sink *port,
32899a2dd95SBruce Richardson 	const char *file_name,
32999a2dd95SBruce Richardson 	uint32_t max_n_pkts)
33099a2dd95SBruce Richardson {
33199a2dd95SBruce Richardson 	pcap_t *tx_pcap;
33299a2dd95SBruce Richardson 	pcap_dumper_t *pcap_dumper;
33399a2dd95SBruce Richardson 
33499a2dd95SBruce Richardson 	/** Open a dead pcap handler for opening dumper file */
33599a2dd95SBruce Richardson 	tx_pcap = pcap_open_dead(DLT_EN10MB, 65535);
33699a2dd95SBruce Richardson 	if (tx_pcap == NULL) {
337ae67895bSDavid Marchand 		PORT_LOG(ERR, "Cannot open pcap dead handler");
33899a2dd95SBruce Richardson 		return -1;
33999a2dd95SBruce Richardson 	}
34099a2dd95SBruce Richardson 
34199a2dd95SBruce Richardson 	/* The dumper is created using the previous pcap_t reference */
34299a2dd95SBruce Richardson 	pcap_dumper = pcap_dump_open(tx_pcap, file_name);
34399a2dd95SBruce Richardson 	if (pcap_dumper == NULL) {
344ae67895bSDavid Marchand 		PORT_LOG(ERR, "Failed to open pcap file "
345ae67895bSDavid Marchand 			"\"%s\" for writing", file_name);
34699a2dd95SBruce Richardson 		return -1;
34799a2dd95SBruce Richardson 	}
34899a2dd95SBruce Richardson 
34999a2dd95SBruce Richardson 	port->dumper = pcap_dumper;
35099a2dd95SBruce Richardson 	port->max_pkts = max_n_pkts;
35199a2dd95SBruce Richardson 	port->pkt_index = 0;
35299a2dd95SBruce Richardson 	port->dump_finish = 0;
35399a2dd95SBruce Richardson 
354ae67895bSDavid Marchand 	PORT_LOG(INFO, "Ready to dump packets to file \"%s\"",
35599a2dd95SBruce Richardson 		file_name);
35699a2dd95SBruce Richardson 
35799a2dd95SBruce Richardson 	return 0;
35899a2dd95SBruce Richardson }
35999a2dd95SBruce Richardson 
36099a2dd95SBruce Richardson static void
pcap_sink_write_pkt(struct rte_port_sink * port,struct rte_mbuf * mbuf)36199a2dd95SBruce Richardson pcap_sink_write_pkt(struct rte_port_sink *port, struct rte_mbuf *mbuf)
36299a2dd95SBruce Richardson {
36399a2dd95SBruce Richardson 	uint8_t *pcap_dumper = (port->dumper);
36499a2dd95SBruce Richardson 	struct pcap_pkthdr pcap_hdr;
36599a2dd95SBruce Richardson 	uint8_t jumbo_pkt_buf[RTE_ETHER_MAX_JUMBO_FRAME_LEN];
36699a2dd95SBruce Richardson 	uint8_t *pkt;
36799a2dd95SBruce Richardson 
36899a2dd95SBruce Richardson 	/* Maximum num packets already reached */
36999a2dd95SBruce Richardson 	if (port->dump_finish)
37099a2dd95SBruce Richardson 		return;
37199a2dd95SBruce Richardson 
37299a2dd95SBruce Richardson 	pkt = rte_pktmbuf_mtod(mbuf, uint8_t *);
37399a2dd95SBruce Richardson 
37499a2dd95SBruce Richardson 	pcap_hdr.len = mbuf->pkt_len;
37599a2dd95SBruce Richardson 	pcap_hdr.caplen = pcap_hdr.len;
37699a2dd95SBruce Richardson 	gettimeofday(&(pcap_hdr.ts), NULL);
37799a2dd95SBruce Richardson 
37899a2dd95SBruce Richardson 	if (mbuf->nb_segs > 1) {
37999a2dd95SBruce Richardson 		struct rte_mbuf *jumbo_mbuf;
38099a2dd95SBruce Richardson 		uint32_t pkt_index = 0;
38199a2dd95SBruce Richardson 
38299a2dd95SBruce Richardson 		/* if packet size longer than RTE_ETHER_MAX_JUMBO_FRAME_LEN,
38399a2dd95SBruce Richardson 		 * ignore it.
38499a2dd95SBruce Richardson 		 */
38599a2dd95SBruce Richardson 		if (mbuf->pkt_len > RTE_ETHER_MAX_JUMBO_FRAME_LEN)
38699a2dd95SBruce Richardson 			return;
38799a2dd95SBruce Richardson 
38899a2dd95SBruce Richardson 		for (jumbo_mbuf = mbuf; jumbo_mbuf != NULL;
38999a2dd95SBruce Richardson 				jumbo_mbuf = jumbo_mbuf->next) {
39099a2dd95SBruce Richardson 			rte_memcpy(&jumbo_pkt_buf[pkt_index],
39199a2dd95SBruce Richardson 				rte_pktmbuf_mtod(jumbo_mbuf, uint8_t *),
39299a2dd95SBruce Richardson 				jumbo_mbuf->data_len);
39399a2dd95SBruce Richardson 			pkt_index += jumbo_mbuf->data_len;
39499a2dd95SBruce Richardson 		}
39599a2dd95SBruce Richardson 
39699a2dd95SBruce Richardson 		jumbo_pkt_buf[pkt_index] = '\0';
39799a2dd95SBruce Richardson 
39899a2dd95SBruce Richardson 		pkt = jumbo_pkt_buf;
39999a2dd95SBruce Richardson 	}
40099a2dd95SBruce Richardson 
40199a2dd95SBruce Richardson 	pcap_dump(pcap_dumper, &pcap_hdr, pkt);
40299a2dd95SBruce Richardson 
40399a2dd95SBruce Richardson 	port->pkt_index++;
40499a2dd95SBruce Richardson 
40599a2dd95SBruce Richardson 	if ((port->max_pkts != 0) && (port->pkt_index >= port->max_pkts)) {
40699a2dd95SBruce Richardson 		port->dump_finish = 1;
407ae67895bSDavid Marchand 		PORT_LOG(INFO, "Dumped %u packets to file",
40899a2dd95SBruce Richardson 				port->pkt_index);
40999a2dd95SBruce Richardson 	}
41099a2dd95SBruce Richardson 
41199a2dd95SBruce Richardson }
41299a2dd95SBruce Richardson 
41399a2dd95SBruce Richardson #define PCAP_SINK_OPEN(port, file_name, max_n_pkts)		\
41499a2dd95SBruce Richardson 	pcap_sink_open(port, file_name, max_n_pkts)
41599a2dd95SBruce Richardson 
41699a2dd95SBruce Richardson #define PCAP_SINK_WRITE_PKT(port, mbuf)				\
41799a2dd95SBruce Richardson 	pcap_sink_write_pkt(port, mbuf)
41899a2dd95SBruce Richardson 
41999a2dd95SBruce Richardson #define PCAP_SINK_FLUSH_PKT(dumper)				\
42099a2dd95SBruce Richardson do {								\
42199a2dd95SBruce Richardson 	if (dumper)						\
42299a2dd95SBruce Richardson 		pcap_dump_flush((pcap_dumper_t *)dumper);	\
42399a2dd95SBruce Richardson } while (0)
42499a2dd95SBruce Richardson 
42599a2dd95SBruce Richardson #define PCAP_SINK_CLOSE(dumper)					\
42699a2dd95SBruce Richardson do {								\
42799a2dd95SBruce Richardson 	if (dumper)						\
42899a2dd95SBruce Richardson 		pcap_dump_close((pcap_dumper_t *)dumper);	\
42999a2dd95SBruce Richardson } while (0)
43099a2dd95SBruce Richardson 
43199a2dd95SBruce Richardson #else
43299a2dd95SBruce Richardson 
43399a2dd95SBruce Richardson #define PCAP_SINK_OPEN(port, file_name, max_n_pkts)		\
434*93998f3cSTyler Retzlaff __extension__ ({						\
43599a2dd95SBruce Richardson 	int _ret = 0;						\
43699a2dd95SBruce Richardson 								\
43799a2dd95SBruce Richardson 	if (file_name) {					\
438ae67895bSDavid Marchand 		PORT_LOG(ERR, "Sink port field "		\
439ae67895bSDavid Marchand 			"\"file_name\" is not NULL.");	\
44099a2dd95SBruce Richardson 		_ret = -1;					\
44199a2dd95SBruce Richardson 	}							\
44299a2dd95SBruce Richardson 								\
44399a2dd95SBruce Richardson 	_ret;							\
44499a2dd95SBruce Richardson })
44599a2dd95SBruce Richardson 
44699a2dd95SBruce Richardson #define PCAP_SINK_WRITE_PKT(port, mbuf) {}
44799a2dd95SBruce Richardson 
44899a2dd95SBruce Richardson #define PCAP_SINK_FLUSH_PKT(dumper)
44999a2dd95SBruce Richardson 
45099a2dd95SBruce Richardson #define PCAP_SINK_CLOSE(dumper)
45199a2dd95SBruce Richardson 
45299a2dd95SBruce Richardson #endif
45399a2dd95SBruce Richardson 
45499a2dd95SBruce Richardson static void *
rte_port_sink_create(void * params,int socket_id)45599a2dd95SBruce Richardson rte_port_sink_create(void *params, int socket_id)
45699a2dd95SBruce Richardson {
45799a2dd95SBruce Richardson 	struct rte_port_sink *port;
45899a2dd95SBruce Richardson 	struct rte_port_sink_params *p = params;
45999a2dd95SBruce Richardson 
46099a2dd95SBruce Richardson 	/* Memory allocation */
46199a2dd95SBruce Richardson 	port = rte_zmalloc_socket("PORT", sizeof(*port),
46299a2dd95SBruce Richardson 			RTE_CACHE_LINE_SIZE, socket_id);
46399a2dd95SBruce Richardson 	if (port == NULL) {
464ae67895bSDavid Marchand 		PORT_LOG(ERR, "%s: Failed to allocate port", __func__);
46599a2dd95SBruce Richardson 		return NULL;
46699a2dd95SBruce Richardson 	}
46799a2dd95SBruce Richardson 
46899a2dd95SBruce Richardson 	if (!p)
46999a2dd95SBruce Richardson 		return port;
47099a2dd95SBruce Richardson 
47199a2dd95SBruce Richardson 	if (p->file_name) {
47299a2dd95SBruce Richardson 		int status = PCAP_SINK_OPEN(port, p->file_name,
47399a2dd95SBruce Richardson 			p->max_n_pkts);
47499a2dd95SBruce Richardson 
47599a2dd95SBruce Richardson 		if (status < 0) {
47699a2dd95SBruce Richardson 			rte_free(port);
47799a2dd95SBruce Richardson 			port = NULL;
47899a2dd95SBruce Richardson 		}
47999a2dd95SBruce Richardson 	}
48099a2dd95SBruce Richardson 
48199a2dd95SBruce Richardson 	return port;
48299a2dd95SBruce Richardson }
48399a2dd95SBruce Richardson 
48499a2dd95SBruce Richardson static int
rte_port_sink_tx(void * port,struct rte_mbuf * pkt)48599a2dd95SBruce Richardson rte_port_sink_tx(void *port, struct rte_mbuf *pkt)
48699a2dd95SBruce Richardson {
48799a2dd95SBruce Richardson 	struct rte_port_sink *p = port;
48899a2dd95SBruce Richardson 
48999a2dd95SBruce Richardson 	RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1);
49099a2dd95SBruce Richardson 	if (p->dumper != NULL)
49199a2dd95SBruce Richardson 		PCAP_SINK_WRITE_PKT(p, pkt);
49299a2dd95SBruce Richardson 	rte_pktmbuf_free(pkt);
49399a2dd95SBruce Richardson 	RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1);
49499a2dd95SBruce Richardson 
49599a2dd95SBruce Richardson 	return 0;
49699a2dd95SBruce Richardson }
49799a2dd95SBruce Richardson 
49899a2dd95SBruce Richardson static int
rte_port_sink_tx_bulk(void * port,struct rte_mbuf ** pkts,uint64_t pkts_mask)49999a2dd95SBruce Richardson rte_port_sink_tx_bulk(void *port, struct rte_mbuf **pkts,
50099a2dd95SBruce Richardson 	uint64_t pkts_mask)
50199a2dd95SBruce Richardson {
50299a2dd95SBruce Richardson 	struct rte_port_sink *p = port;
50399a2dd95SBruce Richardson 
50499a2dd95SBruce Richardson 	if ((pkts_mask & (pkts_mask + 1)) == 0) {
5053d4e27fdSDavid Marchand 		uint64_t n_pkts = rte_popcount64(pkts_mask);
50699a2dd95SBruce Richardson 		uint32_t i;
50799a2dd95SBruce Richardson 
50899a2dd95SBruce Richardson 		RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, n_pkts);
50999a2dd95SBruce Richardson 		RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, n_pkts);
51099a2dd95SBruce Richardson 
51199a2dd95SBruce Richardson 		if (p->dumper) {
51299a2dd95SBruce Richardson 			for (i = 0; i < n_pkts; i++)
51399a2dd95SBruce Richardson 				PCAP_SINK_WRITE_PKT(p, pkts[i]);
51499a2dd95SBruce Richardson 		}
51599a2dd95SBruce Richardson 
51699a2dd95SBruce Richardson 		for (i = 0; i < n_pkts; i++) {
51799a2dd95SBruce Richardson 			struct rte_mbuf *pkt = pkts[i];
51899a2dd95SBruce Richardson 
51999a2dd95SBruce Richardson 			rte_pktmbuf_free(pkt);
52099a2dd95SBruce Richardson 		}
52199a2dd95SBruce Richardson 
52299a2dd95SBruce Richardson 	} else {
52399a2dd95SBruce Richardson 		if (p->dumper) {
52499a2dd95SBruce Richardson 			uint64_t dump_pkts_mask = pkts_mask;
52599a2dd95SBruce Richardson 			uint32_t pkt_index;
52699a2dd95SBruce Richardson 
52799a2dd95SBruce Richardson 			for ( ; dump_pkts_mask; ) {
5283d4e27fdSDavid Marchand 				pkt_index = rte_ctz64(
52999a2dd95SBruce Richardson 					dump_pkts_mask);
53099a2dd95SBruce Richardson 				PCAP_SINK_WRITE_PKT(p, pkts[pkt_index]);
53199a2dd95SBruce Richardson 				dump_pkts_mask &= ~(1LLU << pkt_index);
53299a2dd95SBruce Richardson 			}
53399a2dd95SBruce Richardson 		}
53499a2dd95SBruce Richardson 
53599a2dd95SBruce Richardson 		for ( ; pkts_mask; ) {
5363d4e27fdSDavid Marchand 			uint32_t pkt_index = rte_ctz64(pkts_mask);
53799a2dd95SBruce Richardson 			uint64_t pkt_mask = 1LLU << pkt_index;
53899a2dd95SBruce Richardson 			struct rte_mbuf *pkt = pkts[pkt_index];
53999a2dd95SBruce Richardson 
54099a2dd95SBruce Richardson 			RTE_PORT_SINK_STATS_PKTS_IN_ADD(p, 1);
54199a2dd95SBruce Richardson 			RTE_PORT_SINK_STATS_PKTS_DROP_ADD(p, 1);
54299a2dd95SBruce Richardson 			rte_pktmbuf_free(pkt);
54399a2dd95SBruce Richardson 			pkts_mask &= ~pkt_mask;
54499a2dd95SBruce Richardson 		}
54599a2dd95SBruce Richardson 	}
54699a2dd95SBruce Richardson 
54799a2dd95SBruce Richardson 	return 0;
54899a2dd95SBruce Richardson }
54999a2dd95SBruce Richardson 
55099a2dd95SBruce Richardson static int
rte_port_sink_flush(void * port)55199a2dd95SBruce Richardson rte_port_sink_flush(void *port)
55299a2dd95SBruce Richardson {
55399a2dd95SBruce Richardson 	struct rte_port_sink *p =
55499a2dd95SBruce Richardson 			port;
55599a2dd95SBruce Richardson 
55699a2dd95SBruce Richardson 	if (p == NULL)
55799a2dd95SBruce Richardson 		return 0;
55899a2dd95SBruce Richardson 
55999a2dd95SBruce Richardson 	PCAP_SINK_FLUSH_PKT(p->dumper);
56099a2dd95SBruce Richardson 
56199a2dd95SBruce Richardson 	return 0;
56299a2dd95SBruce Richardson }
56399a2dd95SBruce Richardson 
56499a2dd95SBruce Richardson static int
rte_port_sink_free(void * port)56599a2dd95SBruce Richardson rte_port_sink_free(void *port)
56699a2dd95SBruce Richardson {
56799a2dd95SBruce Richardson 	struct rte_port_sink *p =
56899a2dd95SBruce Richardson 			port;
56999a2dd95SBruce Richardson 
57099a2dd95SBruce Richardson 	if (p == NULL)
57199a2dd95SBruce Richardson 		return 0;
57299a2dd95SBruce Richardson 
57399a2dd95SBruce Richardson 	PCAP_SINK_CLOSE(p->dumper);
57499a2dd95SBruce Richardson 
57599a2dd95SBruce Richardson 	rte_free(p);
57699a2dd95SBruce Richardson 
57799a2dd95SBruce Richardson 	return 0;
57899a2dd95SBruce Richardson }
57999a2dd95SBruce Richardson 
58099a2dd95SBruce Richardson static int
rte_port_sink_stats_read(void * port,struct rte_port_out_stats * stats,int clear)58199a2dd95SBruce Richardson rte_port_sink_stats_read(void *port, struct rte_port_out_stats *stats,
58299a2dd95SBruce Richardson 		int clear)
58399a2dd95SBruce Richardson {
58499a2dd95SBruce Richardson 	struct rte_port_sink *p =
58599a2dd95SBruce Richardson 		port;
58699a2dd95SBruce Richardson 
58799a2dd95SBruce Richardson 	if (stats != NULL)
58899a2dd95SBruce Richardson 		memcpy(stats, &p->stats, sizeof(p->stats));
58999a2dd95SBruce Richardson 
59099a2dd95SBruce Richardson 	if (clear)
59199a2dd95SBruce Richardson 		memset(&p->stats, 0, sizeof(p->stats));
59299a2dd95SBruce Richardson 
59399a2dd95SBruce Richardson 	return 0;
59499a2dd95SBruce Richardson }
59599a2dd95SBruce Richardson 
59699a2dd95SBruce Richardson /*
59799a2dd95SBruce Richardson  * Summary of port operations
59899a2dd95SBruce Richardson  */
59999a2dd95SBruce Richardson struct rte_port_in_ops rte_port_source_ops = {
60099a2dd95SBruce Richardson 	.f_create = rte_port_source_create,
60199a2dd95SBruce Richardson 	.f_free = rte_port_source_free,
60299a2dd95SBruce Richardson 	.f_rx = rte_port_source_rx,
60399a2dd95SBruce Richardson 	.f_stats = rte_port_source_stats_read,
60499a2dd95SBruce Richardson };
60599a2dd95SBruce Richardson 
60699a2dd95SBruce Richardson struct rte_port_out_ops rte_port_sink_ops = {
60799a2dd95SBruce Richardson 	.f_create = rte_port_sink_create,
60899a2dd95SBruce Richardson 	.f_free = rte_port_sink_free,
60999a2dd95SBruce Richardson 	.f_tx = rte_port_sink_tx,
61099a2dd95SBruce Richardson 	.f_tx_bulk = rte_port_sink_tx_bulk,
61199a2dd95SBruce Richardson 	.f_flush = rte_port_sink_flush,
61299a2dd95SBruce Richardson 	.f_stats = rte_port_sink_stats_read,
61399a2dd95SBruce Richardson };
614