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