aboutsummaryrefslogtreecommitdiff
path: root/platform/linux-generic/pktio
diff options
context:
space:
mode:
Diffstat (limited to 'platform/linux-generic/pktio')
-rw-r--r--platform/linux-generic/pktio/io_ops.c3
-rw-r--r--platform/linux-generic/pktio/loop.c5
-rw-r--r--platform/linux-generic/pktio/netmap.c7
-rw-r--r--platform/linux-generic/pktio/pcap.c381
-rw-r--r--platform/linux-generic/pktio/socket.c9
-rw-r--r--platform/linux-generic/pktio/socket_mmap.c10
6 files changed, 405 insertions, 10 deletions
diff --git a/platform/linux-generic/pktio/io_ops.c b/platform/linux-generic/pktio/io_ops.c
index bd4cc4839..3b344e6ad 100644
--- a/platform/linux-generic/pktio/io_ops.c
+++ b/platform/linux-generic/pktio/io_ops.c
@@ -15,6 +15,9 @@ const pktio_if_ops_t * const pktio_if_ops[] = {
#ifdef ODP_NETMAP
&netmap_pktio_ops,
#endif
+#ifdef HAVE_PCAP
+ &pcap_pktio_ops,
+#endif
&sock_mmap_pktio_ops,
&sock_mmsg_pktio_ops,
NULL
diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c
index 22f04758f..0d8dadd0f 100644
--- a/platform/linux-generic/pktio/loop.c
+++ b/platform/linux-generic/pktio/loop.c
@@ -55,13 +55,16 @@ static int loopback_recv(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
int nbr, i;
odp_buffer_hdr_t *hdr_tbl[QUEUE_MULTI_MAX];
queue_entry_t *qentry;
+ odp_packet_hdr_t *pkt_hdr;
qentry = queue_to_qentry(pktio_entry->s.pkt_loop.loopq);
nbr = queue_deq_multi(qentry, hdr_tbl, len);
for (i = 0; i < nbr; ++i) {
pkts[i] = _odp_packet_from_buffer(odp_hdr_to_buf(hdr_tbl[i]));
- _odp_packet_reset_parse(pkts[i]);
+ pkt_hdr = odp_packet_hdr(pkts[i]);
+ packet_parse_reset(pkts[i]);
+ packet_parse_l2(pkt_hdr);
}
return nbr;
diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c
index ab4667e9c..ecda9c58a 100644
--- a/platform/linux-generic/pktio/netmap.c
+++ b/platform/linux-generic/pktio/netmap.c
@@ -168,6 +168,7 @@ static void netmap_recv_cb(u_char *arg, const struct nm_pkthdr *hdr,
struct dispatch_args *args = (struct dispatch_args *)arg;
pkt_netmap_t *pkt_nm = &args->pktio_entry->s.pkt_nm;
odp_packet_t pkt;
+ odp_packet_hdr_t *pkt_hdr;
size_t frame_len = (size_t)hdr->len;
if (odp_unlikely(frame_len > pkt_nm->max_frame_len)) {
@@ -181,10 +182,12 @@ static void netmap_recv_cb(u_char *arg, const struct nm_pkthdr *hdr,
return;
}
- pkt = odp_packet_alloc(pkt_nm->pool, frame_len);
+ pkt = packet_alloc(pkt_nm->pool, frame_len, 1);
if (pkt == ODP_PACKET_INVALID)
return;
+ pkt_hdr = odp_packet_hdr(pkt);
+
/* For now copy the data in the mbuf,
worry about zero-copy later */
if (odp_packet_copydata_in(pkt, 0, frame_len, buf) != 0) {
@@ -192,7 +195,7 @@ static void netmap_recv_cb(u_char *arg, const struct nm_pkthdr *hdr,
return;
}
- _odp_packet_reset_parse(pkt);
+ packet_parse_l2(pkt_hdr);
args->pkt_table[args->nb_rx++] = pkt;
}
diff --git a/platform/linux-generic/pktio/pcap.c b/platform/linux-generic/pktio/pcap.c
new file mode 100644
index 000000000..0817bf595
--- /dev/null
+++ b/platform/linux-generic/pktio/pcap.c
@@ -0,0 +1,381 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/**
+ * @file
+ *
+ * PCAP pktio type
+ *
+ * This file provides a pktio interface that allows for reading from
+ * and writing to pcap capture files. It is intended to be used as
+ * simple way of injecting test packets into an application for the
+ * purpose of functional testing.
+ *
+ * To use this interface the name passed to odp_pktio_open() must begin
+ * with "pcap:" and be in the format;
+ *
+ * pcap:in=test.pcap:out=test_out.pcap:loops=10
+ *
+ * in the name of the input pcap file. If no input file is given
+ * attempts to receive from the pktio will just return no
+ * packets. If an input file is specified it must exist and be
+ * a readable pcap file with a link type of DLT_EN10MB.
+ * out the name of the output pcap file. If no output file is
+ * given any packets transmitted over the interface will just
+ * be freed. If an output file is specified and the file
+ * doesn't exist it will be created, if it does exist it will
+ * be overwritten.
+ * loops the number of times to iterate through the input file, set
+ * to 0 to loop indefinitely. The default value is 1.
+ *
+ * The total length of the string is limited by PKTIO_NAME_LEN.
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <odp.h>
+#include <odp_packet_internal.h>
+#include <odp_packet_io_internal.h>
+
+#include <odp/helper/eth.h>
+
+#include <errno.h>
+#include <pcap/pcap.h>
+#include <pcap/bpf.h>
+
+#define PKTIO_PCAP_MTU (64 * 1024)
+static const char pcap_mac[] = {0x02, 0xe9, 0x34, 0x80, 0x73, 0x04};
+
+static int _pcapif_parse_devname(pkt_pcap_t *pcap, const char *devname)
+{
+ char *tok;
+ char in[PKTIO_NAME_LEN];
+
+ if (strncmp(devname, "pcap:", 5) != 0)
+ return -1;
+
+ snprintf(in, sizeof(in), "%s", devname);
+
+ for (tok = strtok(in + 5, ":"); tok; tok = strtok(NULL, ":")) {
+ if (strncmp(tok, "in=", 3) == 0 && !pcap->fname_rx) {
+ tok += 3;
+ pcap->fname_rx = strdup(tok);
+ } else if (strncmp(tok, "out=", 4) == 0 && !pcap->fname_tx) {
+ tok += 4;
+ pcap->fname_tx = strdup(tok);
+ } else if (strncmp(tok, "loops=", 6) == 0) {
+ pcap->loops = atoi(tok + 6);
+ if (pcap->loops < 0) {
+ ODP_ERR("invalid loop count\n");
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int _pcapif_init_rx(pkt_pcap_t *pcap)
+{
+ char errbuf[PCAP_ERRBUF_SIZE];
+ int linktype;
+
+ pcap->rx = pcap_open_offline(pcap->fname_rx, errbuf);
+ if (!pcap->rx) {
+ ODP_ERR("failed to open pcap file %s (%s)\n",
+ pcap->fname_rx, errbuf);
+ return -1;
+ }
+
+ linktype = pcap_datalink(pcap->rx);
+ if (linktype != DLT_EN10MB) {
+ ODP_ERR("unsupported datalink type: %d\n", linktype);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int _pcapif_init_tx(pkt_pcap_t *pcap)
+{
+ pcap_t *tx = pcap->rx;
+
+ if (!tx) {
+ /* if there is no rx pcap_t already open for rx, a dummy
+ * one needs to be opened for writing the dump */
+ tx = pcap_open_dead(DLT_EN10MB, PKTIO_PCAP_MTU);
+ if (!tx) {
+ ODP_ERR("failed to open TX dump\n");
+ return -1;
+ }
+
+ pcap->tx = tx;
+ }
+
+ pcap->buf = malloc(PKTIO_PCAP_MTU);
+ if (!pcap->buf) {
+ ODP_ERR("failed to malloc temp buffer\n");
+ return -1;
+ }
+
+ pcap->tx_dump = pcap_dump_open(tx, pcap->fname_tx);
+ if (!pcap->tx_dump) {
+ ODP_ERR("failed to open dump file %s (%s)\n",
+ pcap->fname_tx, pcap_geterr(tx));
+ return -1;
+ }
+
+ return pcap_dump_flush(pcap->tx_dump);
+}
+
+static int pcapif_init(odp_pktio_t id ODP_UNUSED, pktio_entry_t *pktio_entry,
+ const char *devname, odp_pool_t pool)
+{
+ pkt_pcap_t *pcap = &pktio_entry->s.pkt_pcap;
+ int ret;
+
+ memset(pcap, 0, sizeof(pkt_pcap_t));
+ pcap->loop_cnt = 1;
+ pcap->loops = 1;
+ pcap->pool = pool;
+ pcap->promisc = 1;
+
+ ret = _pcapif_parse_devname(pcap, devname);
+
+ if (ret == 0 && pcap->fname_rx)
+ ret = _pcapif_init_rx(pcap);
+
+ if (ret == 0 && pcap->fname_tx)
+ ret = _pcapif_init_tx(pcap);
+
+ if (ret == 0 && (!pcap->rx && !pcap->tx_dump))
+ ret = -1;
+
+ return ret;
+}
+
+static int pcapif_close(pktio_entry_t *pktio_entry)
+{
+ pkt_pcap_t *pcap = &pktio_entry->s.pkt_pcap;
+
+ if (pcap->tx_dump)
+ pcap_dump_close(pcap->tx_dump);
+
+ if (pcap->tx)
+ pcap_close(pcap->tx);
+
+ if (pcap->rx)
+ pcap_close(pcap->rx);
+
+ free(pcap->buf);
+ free(pcap->fname_rx);
+ free(pcap->fname_tx);
+
+ return 0;
+}
+
+static int _pcapif_reopen(pkt_pcap_t *pcap)
+{
+ char errbuf[PCAP_ERRBUF_SIZE];
+
+ if (pcap->loops != 0 && ++pcap->loop_cnt >= pcap->loops)
+ return 1;
+
+ if (pcap->rx)
+ pcap_close(pcap->rx);
+
+ pcap->rx = pcap_open_offline(pcap->fname_rx, errbuf);
+ if (!pcap->rx) {
+ ODP_ERR("failed to reopen pcap file %s (%s)\n",
+ pcap->fname_rx, errbuf);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int pcapif_recv_pkt(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
+ unsigned len)
+{
+ unsigned i;
+ struct pcap_pkthdr *hdr;
+ const u_char *data;
+ odp_packet_t pkt;
+ odp_packet_hdr_t *pkt_hdr;
+ uint32_t pkt_len;
+ pkt_pcap_t *pcap = &pktio_entry->s.pkt_pcap;
+
+ ODP_ASSERT(pktio_entry->s.state == STATE_START);
+
+ if (!pcap->rx)
+ return 0;
+
+ pkt = ODP_PACKET_INVALID;
+ pkt_len = 0;
+
+ for (i = 0; i < len; ) {
+ int ret;
+
+ if (pkt == ODP_PACKET_INVALID) {
+ pkt = packet_alloc(pcap->pool, 0 /*default len*/, 1);
+ if (odp_unlikely(pkt == ODP_PACKET_INVALID))
+ break;
+ pkt_len = odp_packet_len(pkt);
+ }
+
+ ret = pcap_next_ex(pcap->rx, &hdr, &data);
+
+ /* end of file, attempt to reopen if within loop limit */
+ if (ret == -2 && _pcapif_reopen(pcap) == 0)
+ continue;
+
+ if (ret != 1)
+ break;
+
+ pkt_hdr = odp_packet_hdr(pkt);
+
+ if (!odp_packet_pull_tail(pkt, pkt_len - hdr->caplen)) {
+ ODP_ERR("failed to pull tail: pkt_len: %d caplen: %d\n",
+ pkt_len, hdr->caplen);
+ break;
+ }
+
+ if (odp_packet_copydata_in(pkt, 0, hdr->caplen, data) != 0) {
+ ODP_ERR("failed to copy packet data\n");
+ break;
+ }
+
+ packet_parse_l2(pkt_hdr);
+
+ pkts[i] = pkt;
+ pkt = ODP_PACKET_INVALID;
+
+ i++;
+ }
+
+ if (pkt != ODP_PACKET_INVALID)
+ odp_packet_free(pkt);
+
+ return i;
+}
+
+static int _pcapif_dump_pkt(pkt_pcap_t *pcap, odp_packet_t pkt)
+{
+ struct pcap_pkthdr hdr;
+
+ if (!pcap->tx_dump)
+ return 0;
+
+ hdr.caplen = odp_packet_len(pkt);
+ hdr.len = hdr.caplen;
+ (void)gettimeofday(&hdr.ts, NULL);
+
+ if (odp_packet_copydata_out(pkt, 0, hdr.len, pcap->buf) != 0)
+ return -1;
+
+ pcap_dump(pcap->tx_dump, &hdr, pcap->buf);
+ (void)pcap_dump_flush(pcap->tx_dump);
+
+ return 0;
+}
+
+static int pcapif_send_pkt(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
+ unsigned len)
+{
+ pkt_pcap_t *pcap = &pktio_entry->s.pkt_pcap;
+ unsigned i;
+
+ ODP_ASSERT(pktio_entry->s.state == STATE_START);
+
+ for (i = 0; i < len; ++i) {
+ if (odp_packet_len(pkts[i]) > PKTIO_PCAP_MTU) {
+ if (i == 0)
+ return -1;
+ break;
+ }
+
+ if (_pcapif_dump_pkt(pcap, pkts[i]) != 0)
+ break;
+
+ odp_packet_free(pkts[i]);
+ }
+
+ return i;
+}
+
+static int pcapif_mtu_get(pktio_entry_t *pktio_entry ODP_UNUSED)
+{
+ return PKTIO_PCAP_MTU;
+}
+
+static int pcapif_mac_addr_get(pktio_entry_t *pktio_entry ODP_UNUSED,
+ void *mac_addr)
+{
+ memcpy(mac_addr, pcap_mac, ODPH_ETHADDR_LEN);
+
+ return ODPH_ETHADDR_LEN;
+}
+
+static int pcapif_promisc_mode_set(pktio_entry_t *pktio_entry,
+ odp_bool_t enable)
+{
+ char filter_exp[64] = {0};
+ struct bpf_program bpf;
+ pkt_pcap_t *pcap = &pktio_entry->s.pkt_pcap;
+
+ if (!pcap->rx) {
+ pcap->promisc = enable;
+ return 0;
+ }
+
+ if (!enable) {
+ char mac_str[18];
+
+ snprintf(mac_str, sizeof(mac_str),
+ "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+ pcap_mac[0], pcap_mac[1], pcap_mac[2],
+ pcap_mac[3], pcap_mac[4], pcap_mac[5]);
+
+ snprintf(filter_exp, sizeof(filter_exp),
+ "ether dst %s or broadcast or multicast",
+ mac_str);
+ }
+
+ if (pcap_compile(pcap->rx, &bpf, filter_exp,
+ 0, PCAP_NETMASK_UNKNOWN) != 0) {
+ ODP_ERR("failed to compile promisc mode filter: %s\n",
+ pcap_geterr(pcap->rx));
+ return -1;
+ }
+
+ if (pcap_setfilter(pcap->rx, &bpf) != 0) {
+ ODP_ERR("failed to set promisc mode filter: %s\n",
+ pcap_geterr(pcap->rx));
+ return -1;
+ }
+
+ pcap->promisc = enable;
+
+ return 0;
+}
+
+static int pcapif_promisc_mode_get(pktio_entry_t *pktio_entry)
+{
+ return pktio_entry->s.pkt_pcap.promisc;
+}
+
+const pktio_if_ops_t pcap_pktio_ops = {
+ .open = pcapif_init,
+ .close = pcapif_close,
+ .recv = pcapif_recv_pkt,
+ .send = pcapif_send_pkt,
+ .mtu_get = pcapif_mtu_get,
+ .promisc_mode_set = pcapif_promisc_mode_set,
+ .promisc_mode_get = pcapif_promisc_mode_get,
+ .mac_get = pcapif_mac_addr_get
+};
diff --git a/platform/linux-generic/pktio/socket.c b/platform/linux-generic/pktio/socket.c
index a95b9a80e..7e3002740 100644
--- a/platform/linux-generic/pktio/socket.c
+++ b/platform/linux-generic/pktio/socket.c
@@ -322,7 +322,7 @@ static int sock_mmsg_recv(pktio_entry_t *pktio_entry,
memset(msgvec, 0, sizeof(msgvec));
for (i = 0; i < (int)len; i++) {
- pkt_table[i] = _odp_packet_alloc(pkt_sock->pool);
+ pkt_table[i] = packet_alloc(pkt_sock->pool, 0 /*default*/, 1);
if (odp_unlikely(pkt_table[i] == ODP_PACKET_INVALID))
break;
@@ -336,6 +336,7 @@ static int sock_mmsg_recv(pktio_entry_t *pktio_entry,
recv_msgs = recvmmsg(sockfd, msgvec, msgvec_len, MSG_DONTWAIT, NULL);
for (i = 0; i < recv_msgs; i++) {
+ odp_packet_hdr_t *pkt_hdr;
void *base = msgvec[i].msg_hdr.msg_iov->iov_base;
struct ethhdr *eth_hdr = base;
@@ -346,11 +347,13 @@ static int sock_mmsg_recv(pktio_entry_t *pktio_entry,
continue;
}
- /* Parse and set packet header data */
+ pkt_hdr = odp_packet_hdr(pkt_table[i]);
+
odp_packet_pull_tail(pkt_table[i],
odp_packet_len(pkt_table[i]) -
msgvec[i].msg_len);
- _odp_packet_reset_parse(pkt_table[i]);
+
+ packet_parse_l2(pkt_hdr);
pkt_table[nb_rx] = pkt_table[i];
nb_rx++;
diff --git a/platform/linux-generic/pktio/socket_mmap.c b/platform/linux-generic/pktio/socket_mmap.c
index ba773a3e6..35d24c693 100644
--- a/platform/linux-generic/pktio/socket_mmap.c
+++ b/platform/linux-generic/pktio/socket_mmap.c
@@ -118,6 +118,7 @@ static inline unsigned pkt_mmap_v2_rx(int sock, struct ring *ring,
uint8_t *pkt_buf;
int pkt_len;
struct ethhdr *eth_hdr;
+ odp_packet_hdr_t *pkt_hdr;
unsigned i = 0;
(void)sock;
@@ -142,20 +143,21 @@ static inline unsigned pkt_mmap_v2_rx(int sock, struct ring *ring,
continue;
}
- pkt_table[i] = odp_packet_alloc(pool, pkt_len);
+ pkt_table[i] = packet_alloc(pool, pkt_len, 1);
if (odp_unlikely(pkt_table[i] == ODP_PACKET_INVALID))
break;
+ pkt_hdr = odp_packet_hdr(pkt_table[i]);
+
if (odp_packet_copydata_in(pkt_table[i], 0,
pkt_len, pkt_buf) != 0) {
odp_packet_free(pkt_table[i]);
break;
}
- mmap_rx_user_ready(ppd.raw);
+ packet_parse_l2(pkt_hdr);
- /* Parse and set packet header data */
- _odp_packet_reset_parse(pkt_table[i]);
+ mmap_rx_user_ready(ppd.raw);
frame_num = next_frame_num;
i++;