aboutsummaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/linux-generic/Makefile.am4
-rw-r--r--platform/linux-generic/include/odp_internal.h1
-rw-r--r--platform/linux-generic/include/odp_packet_internal.h61
-rw-r--r--platform/linux-generic/include/odp_packet_io_internal.h25
-rw-r--r--platform/linux-generic/include/odp_pool_internal.h13
-rw-r--r--platform/linux-generic/m4/configure.m41
-rw-r--r--platform/linux-generic/m4/odp_pcap.m415
-rw-r--r--platform/linux-generic/odp_classification.c4
-rw-r--r--platform/linux-generic/odp_init.c5
-rw-r--r--platform/linux-generic/odp_packet.c222
-rw-r--r--platform/linux-generic/odp_packet_flags.c24
-rw-r--r--platform/linux-generic/odp_packet_io.c20
-rw-r--r--platform/linux-generic/odp_pool.c28
-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
-rw-r--r--platform/linux-generic/test/Makefile.am5
-rw-r--r--platform/linux-generic/test/pktio/Makefile.am4
-rw-r--r--platform/linux-generic/test/pktio/pktio_env8
-rwxr-xr-xplatform/linux-generic/test/pktio/pktio_run_pcap33
23 files changed, 701 insertions, 187 deletions
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am
index 8da6c6bf5..9269a73c0 100644
--- a/platform/linux-generic/Makefile.am
+++ b/platform/linux-generic/Makefile.am
@@ -189,3 +189,7 @@ EXTRA_DIST = \
arch/linux/odp_cpu_cycles.c \
arch/mips64/odp_cpu_cycles.c \
arch/x86/odp_cpu_cycles.c
+
+if HAVE_PCAP
+__LIB__libodp_la_SOURCES += pktio/pcap.c
+endif
diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h
index 8a1a21976..14ba15900 100644
--- a/platform/linux-generic/include/odp_internal.h
+++ b/platform/linux-generic/include/odp_internal.h
@@ -54,6 +54,7 @@ int odp_shm_term_global(void);
int odp_shm_init_local(void);
int odp_pool_init_global(void);
+int odp_pool_init_local(void);
int odp_pool_term_global(void);
int odp_pool_term_local(void);
diff --git a/platform/linux-generic/include/odp_packet_internal.h b/platform/linux-generic/include/odp_packet_internal.h
index ba2cd7e1a..6f1521ca3 100644
--- a/platform/linux-generic/include/odp_packet_internal.h
+++ b/platform/linux-generic/include/odp_packet_internal.h
@@ -36,7 +36,8 @@ typedef union {
uint32_t all;
struct {
- uint32_t unparsed:1; /**< Set to inticate parse needed */
+ uint32_t parsed_l2:1; /**< L2 parsed */
+ uint32_t parsed_all:1;/**< Parsing complete */
uint32_t l2:1; /**< known L2 protocol present */
uint32_t l3:1; /**< known L3 protocol present */
@@ -155,43 +156,6 @@ static inline odp_packet_hdr_t *odp_packet_hdr(odp_packet_t pkt)
return (odp_packet_hdr_t *)odp_buf_to_hdr((odp_buffer_t)pkt);
}
-/**
- * Initialize packet buffer
- */
-static inline void packet_init(pool_entry_t *pool,
- odp_packet_hdr_t *pkt_hdr,
- size_t size)
-{
- /*
- * Reset parser metadata. Note that we clear via memset to make
- * this routine indepenent of any additional adds to packet metadata.
- */
- const size_t start_offset = ODP_FIELD_SIZEOF(odp_packet_hdr_t, buf_hdr);
- uint8_t *start;
- size_t len;
-
- start = (uint8_t *)pkt_hdr + start_offset;
- len = sizeof(odp_packet_hdr_t) - start_offset;
- memset(start, 0, len);
-
- /* Set metadata items that initialize to non-zero values */
- pkt_hdr->l2_offset = ODP_PACKET_OFFSET_INVALID;
- pkt_hdr->l3_offset = ODP_PACKET_OFFSET_INVALID;
- pkt_hdr->l4_offset = ODP_PACKET_OFFSET_INVALID;
- pkt_hdr->payload_offset = ODP_PACKET_OFFSET_INVALID;
-
- /*
- * Packet headroom is set from the pool's headroom
- * Packet tailroom is rounded up to fill the last
- * segment occupied by the allocated length.
- */
- pkt_hdr->frame_len = size;
- pkt_hdr->headroom = pool->s.headroom;
- pkt_hdr->tailroom =
- (pool->s.seg_size * pkt_hdr->buf_hdr.segcount) -
- (pool->s.headroom + size);
-}
-
static inline void copy_packet_parser_metadata(odp_packet_hdr_t *src_hdr,
odp_packet_hdr_t *dst_hdr)
{
@@ -253,12 +217,14 @@ static inline void packet_set_len(odp_packet_t pkt, uint32_t len)
odp_packet_hdr(pkt)->frame_len = len;
}
-#define ODP_PACKET_UNPARSED ~0
+static inline int packet_parse_l2_not_done(odp_packet_hdr_t *pkt_hdr)
+{
+ return !pkt_hdr->input_flags.parsed_l2;
+}
-static inline void _odp_packet_reset_parse(odp_packet_t pkt)
+static inline int packet_parse_not_complete(odp_packet_hdr_t *pkt_hdr)
{
- odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
- pkt_hdr->input_flags.all = ODP_PACKET_UNPARSED;
+ return !pkt_hdr->input_flags.parsed_all;
}
/* Forward declarations */
@@ -268,9 +234,16 @@ int _odp_packet_copy_to_packet(odp_packet_t srcpkt, uint32_t srcoffset,
void _odp_packet_copy_md_to_packet(odp_packet_t srcpkt, odp_packet_t dstpkt);
-odp_packet_t _odp_packet_alloc(odp_pool_t pool_hdl);
+odp_packet_t packet_alloc(odp_pool_t pool_hdl, uint32_t len, int parse);
+
+/* Fill in parser metadata for L2 */
+void packet_parse_l2(odp_packet_hdr_t *pkt_hdr);
+
+/* Perform full packet parse */
+int packet_parse_full(odp_packet_hdr_t *pkt_hdr);
-int _odp_packet_parse(odp_packet_hdr_t *pkt_hdr);
+/* Reset parser metadata for a new parse */
+void packet_parse_reset(odp_packet_t pkt);
/* Convert a packet handle to a buffer handle */
odp_buffer_t _odp_packet_to_buffer(odp_packet_t pkt);
diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h
index 353b40d94..4745bd5c0 100644
--- a/platform/linux-generic/include/odp_packet_io_internal.h
+++ b/platform/linux-generic/include/odp_packet_io_internal.h
@@ -30,6 +30,8 @@ extern "C" {
#include <odp/hints.h>
#include <net/if.h>
+#define PKTIO_NAME_LEN 256
+
/* Forward declaration */
struct pktio_if_ops;
@@ -38,6 +40,21 @@ typedef struct {
odp_bool_t promisc; /**< promiscuous mode state */
} pkt_loop_t;
+#ifdef HAVE_PCAP
+typedef struct {
+ char *fname_rx; /**< name of pcap file for rx */
+ char *fname_tx; /**< name of pcap file for tx */
+ void *rx; /**< rx pcap handle */
+ void *tx; /**< tx pcap handle */
+ void *tx_dump; /**< tx pcap dumper handle */
+ odp_pool_t pool; /**< rx pool */
+ unsigned char *buf; /**< per-pktio temp buffer */
+ int loops; /**< number of times to loop rx pcap */
+ int loop_cnt; /**< number of loops completed */
+ odp_bool_t promisc; /**< promiscuous mode state */
+} pkt_pcap_t;
+#endif
+
struct pktio_entry {
const struct pktio_if_ops *ops; /**< Implementation specific methods */
odp_ticketlock_t lock; /**< entry ticketlock */
@@ -52,13 +69,16 @@ struct pktio_entry {
pkt_sock_mmap_t pkt_sock_mmap; /**< using socket mmap
* API for IO */
pkt_netmap_t pkt_nm; /**< using netmap API for IO */
+#ifdef HAVE_PCAP
+ pkt_pcap_t pkt_pcap; /**< Using pcap for IO */
+#endif
};
enum {
STATE_START = 0,
STATE_STOP
} state;
classifier_t cls; /**< classifier linked with this pktio*/
- char name[IF_NAMESIZE]; /**< name of pktio provided to
+ char name[PKTIO_NAME_LEN]; /**< name of pktio provided to
pktio_open() */
odp_pktio_param_t param;
};
@@ -128,6 +148,9 @@ extern const pktio_if_ops_t netmap_pktio_ops;
extern const pktio_if_ops_t sock_mmsg_pktio_ops;
extern const pktio_if_ops_t sock_mmap_pktio_ops;
extern const pktio_if_ops_t loopback_pktio_ops;
+#ifdef HAVE_PCAP
+extern const pktio_if_ops_t pcap_pktio_ops;
+#endif
extern const pktio_if_ops_t * const pktio_if_ops[];
#ifdef __cplusplus
diff --git a/platform/linux-generic/include/odp_pool_internal.h b/platform/linux-generic/include/odp_pool_internal.h
index 136db2c21..94bf1faee 100644
--- a/platform/linux-generic/include/odp_pool_internal.h
+++ b/platform/linux-generic/include/odp_pool_internal.h
@@ -53,9 +53,14 @@ typedef struct _odp_buffer_pool_init_t {
/* Local cache for buffer alloc/free acceleration */
typedef struct local_cache_t {
- odp_buffer_hdr_t *buf_freelist; /* The local cache */
- uint64_t bufallocs; /* Local buffer alloc count */
- uint64_t buffrees; /* Local buffer free count */
+ union {
+ struct {
+ odp_buffer_hdr_t *buf_freelist; /* The local cache */
+ uint64_t bufallocs; /* Local buffer alloc count */
+ uint64_t buffrees; /* Local buffer free count */
+ };
+ uint8_t pad[ODP_CACHE_LINE_SIZE_ROUNDUP(sizeof(uint64_t))];
+ };
} local_cache_t;
/* Use ticketlock instead of spinlock */
@@ -133,6 +138,8 @@ struct pool_entry_s {
uint32_t low_wm;
uint32_t headroom;
uint32_t tailroom;
+
+ local_cache_t local_cache[_ODP_INTERNAL_MAX_THREADS] ODP_ALIGNED_CACHE;
};
typedef union pool_entry_u {
diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4
index f2d42f109..df6dc640b 100644
--- a/platform/linux-generic/m4/configure.m4
+++ b/platform/linux-generic/m4/configure.m4
@@ -19,6 +19,7 @@ AC_LINK_IFELSE(
m4_include([platform/linux-generic/m4/odp_pthread.m4])
m4_include([platform/linux-generic/m4/odp_openssl.m4])
m4_include([platform/linux-generic/m4/odp_netmap.m4])
+m4_include([platform/linux-generic/m4/odp_pcap.m4])
AC_CONFIG_FILES([platform/linux-generic/Makefile
platform/linux-generic/test/Makefile
diff --git a/platform/linux-generic/m4/odp_pcap.m4 b/platform/linux-generic/m4/odp_pcap.m4
new file mode 100644
index 000000000..734b79005
--- /dev/null
+++ b/platform/linux-generic/m4/odp_pcap.m4
@@ -0,0 +1,15 @@
+#########################################################################
+# Check for libpcap availability
+#########################################################################
+have_pcap=no
+AC_CHECK_HEADER(pcap/pcap.h,
+ [AC_CHECK_HEADER(pcap/bpf.h,
+ [AC_CHECK_LIB(pcap, pcap_open_offline, have_pcap=yes, [])],
+ [])],
+[])
+
+AM_CONDITIONAL([HAVE_PCAP], [test $have_pcap = yes])
+if test $have_pcap == yes; then
+ AM_CFLAGS="$AM_CFLAGS -DHAVE_PCAP"
+ LIBS="$LIBS -lpcap"
+fi
diff --git a/platform/linux-generic/odp_classification.c b/platform/linux-generic/odp_classification.c
index d5ca13fd4..1b6d5931a 100644
--- a/platform/linux-generic/odp_classification.c
+++ b/platform/linux-generic/odp_classification.c
@@ -860,8 +860,8 @@ cos_t *pktio_select_cos(pktio_entry_t *entry, uint8_t *pkt_addr,
cls = &entry->s.cls;
/* Check for lazy parse needed */
- if (pkt_hdr->input_flags.unparsed)
- _odp_packet_parse(pkt_hdr);
+ if (packet_parse_not_complete(pkt_hdr))
+ packet_parse_full(pkt_hdr);
/* Return error cos for error packet */
if (pkt_hdr->error_flags.all)
diff --git a/platform/linux-generic/odp_init.c b/platform/linux-generic/odp_init.c
index 48d9b2036..5e19d86c6 100644
--- a/platform/linux-generic/odp_init.c
+++ b/platform/linux-generic/odp_init.c
@@ -138,6 +138,11 @@ int odp_init_local(odp_thread_type_t thr_type)
return -1;
}
+ if (odp_pool_init_local()) {
+ ODP_ERR("ODP pool local init failed.\n");
+ return -1;
+ }
+
if (odp_schedule_init_local()) {
ODP_ERR("ODP schedule local init failed.\n");
return -1;
diff --git a/platform/linux-generic/odp_packet.c b/platform/linux-generic/odp_packet.c
index 209a6e6a0..1b496247f 100644
--- a/platform/linux-generic/odp_packet.c
+++ b/platform/linux-generic/odp_packet.c
@@ -25,8 +25,73 @@
*
*/
-odp_packet_t odp_packet_alloc(odp_pool_t pool_hdl, uint32_t len)
+static inline void packet_parse_disable(odp_packet_hdr_t *pkt_hdr)
+{
+ pkt_hdr->input_flags.parsed_l2 = 1;
+ pkt_hdr->input_flags.parsed_all = 1;
+}
+
+void packet_parse_reset(odp_packet_t pkt)
+{
+ odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
+
+ /* Reset parser metadata before new parse */
+ pkt_hdr->error_flags.all = 0;
+ pkt_hdr->input_flags.all = 0;
+ pkt_hdr->output_flags.all = 0;
+ pkt_hdr->l2_offset = 0;
+ pkt_hdr->l3_offset = ODP_PACKET_OFFSET_INVALID;
+ pkt_hdr->l4_offset = ODP_PACKET_OFFSET_INVALID;
+ pkt_hdr->payload_offset = ODP_PACKET_OFFSET_INVALID;
+ pkt_hdr->vlan_s_tag = 0;
+ pkt_hdr->vlan_c_tag = 0;
+ pkt_hdr->l3_protocol = 0;
+ pkt_hdr->l4_protocol = 0;
+}
+
+/**
+ * Initialize packet
+ */
+static void packet_init(pool_entry_t *pool, odp_packet_hdr_t *pkt_hdr,
+ size_t size, int parse)
{
+ /*
+ * Reset parser metadata. Note that we clear via memset to make
+ * this routine indepenent of any additional adds to packet metadata.
+ */
+ const size_t start_offset = ODP_FIELD_SIZEOF(odp_packet_hdr_t, buf_hdr);
+ uint8_t *start;
+ size_t len;
+
+ start = (uint8_t *)pkt_hdr + start_offset;
+ len = sizeof(odp_packet_hdr_t) - start_offset;
+ memset(start, 0, len);
+
+ /* Set metadata items that initialize to non-zero values */
+ pkt_hdr->l3_offset = ODP_PACKET_OFFSET_INVALID;
+ pkt_hdr->l4_offset = ODP_PACKET_OFFSET_INVALID;
+ pkt_hdr->payload_offset = ODP_PACKET_OFFSET_INVALID;
+
+ /* Disable lazy parsing on user allocated packets */
+ if (!parse)
+ packet_parse_disable(pkt_hdr);
+
+ /*
+ * Packet headroom is set from the pool's headroom
+ * Packet tailroom is rounded up to fill the last
+ * segment occupied by the allocated length.
+ */
+ pkt_hdr->frame_len = size;
+ pkt_hdr->headroom = pool->s.headroom;
+ pkt_hdr->tailroom =
+ (pool->s.seg_size * pkt_hdr->buf_hdr.segcount) -
+ (pool->s.headroom + size);
+}
+
+odp_packet_t packet_alloc(odp_pool_t pool_hdl, uint32_t len, int parse)
+{
+ odp_packet_t pkt;
+ odp_packet_hdr_t *pkt_hdr;
pool_entry_t *pool = odp_pool_to_entry(pool_hdl);
if (pool->s.params.type != ODP_POOL_PACKET)
@@ -34,17 +99,32 @@ odp_packet_t odp_packet_alloc(odp_pool_t pool_hdl, uint32_t len)
/* Handle special case for zero-length packets */
if (len == 0) {
- odp_packet_t pkt =
- (odp_packet_t)buffer_alloc(pool_hdl,
- pool->s.params.buf.size);
- if (pkt != ODP_PACKET_INVALID)
- pull_tail(odp_packet_hdr(pkt),
- pool->s.params.buf.size);
-
- return pkt;
+ len = pool->s.params.buf.size;
+
+ pkt = (odp_packet_t)buffer_alloc(pool_hdl, len);
+
+ if (pkt == ODP_PACKET_INVALID)
+ return ODP_PACKET_INVALID;
+
+ pull_tail(odp_packet_hdr(pkt), len);
+
+ } else {
+ pkt = (odp_packet_t)buffer_alloc(pool_hdl, len);
+
+ if (pkt == ODP_PACKET_INVALID)
+ return ODP_PACKET_INVALID;
}
- return (odp_packet_t)buffer_alloc(pool_hdl, len);
+ pkt_hdr = odp_packet_hdr(pkt);
+
+ packet_init(pool, pkt_hdr, len, parse);
+
+ return pkt;
+}
+
+odp_packet_t odp_packet_alloc(odp_pool_t pool_hdl, uint32_t len)
+{
+ return packet_alloc(pool_hdl, len, 0);
}
void odp_packet_free(odp_packet_t pkt)
@@ -61,7 +141,8 @@ int odp_packet_reset(odp_packet_t pkt, uint32_t len)
if (totsize > pkt_hdr->buf_hdr.size)
return -1;
- packet_init(pool, pkt_hdr, len);
+ packet_init(pool, pkt_hdr, len, 0);
+
return 0;
}
@@ -242,16 +323,12 @@ uint32_t odp_packet_user_area_size(odp_packet_t pkt)
void *odp_packet_l2_ptr(odp_packet_t pkt, uint32_t *len)
{
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
- if (pkt_hdr->input_flags.unparsed)
- _odp_packet_parse(pkt_hdr);
return packet_map(pkt_hdr, pkt_hdr->l2_offset, len);
}
uint32_t odp_packet_l2_offset(odp_packet_t pkt)
{
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
- if (pkt_hdr->input_flags.unparsed)
- _odp_packet_parse(pkt_hdr);
return pkt_hdr->l2_offset;
}
@@ -262,8 +339,6 @@ int odp_packet_l2_offset_set(odp_packet_t pkt, uint32_t offset)
if (offset >= pkt_hdr->frame_len)
return -1;
- if (pkt_hdr->input_flags.unparsed)
- _odp_packet_parse(pkt_hdr);
pkt_hdr->l2_offset = offset;
return 0;
}
@@ -271,16 +346,16 @@ int odp_packet_l2_offset_set(odp_packet_t pkt, uint32_t offset)
void *odp_packet_l3_ptr(odp_packet_t pkt, uint32_t *len)
{
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
- if (pkt_hdr->input_flags.unparsed)
- _odp_packet_parse(pkt_hdr);
+ if (packet_parse_not_complete(pkt_hdr))
+ packet_parse_full(pkt_hdr);
return packet_map(pkt_hdr, pkt_hdr->l3_offset, len);
}
uint32_t odp_packet_l3_offset(odp_packet_t pkt)
{
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
- if (pkt_hdr->input_flags.unparsed)
- _odp_packet_parse(pkt_hdr);
+ if (packet_parse_not_complete(pkt_hdr))
+ packet_parse_full(pkt_hdr);
return pkt_hdr->l3_offset;
}
@@ -291,8 +366,8 @@ int odp_packet_l3_offset_set(odp_packet_t pkt, uint32_t offset)
if (offset >= pkt_hdr->frame_len)
return -1;
- if (pkt_hdr->input_flags.unparsed)
- _odp_packet_parse(pkt_hdr);
+ if (packet_parse_not_complete(pkt_hdr))
+ packet_parse_full(pkt_hdr);
pkt_hdr->l3_offset = offset;
return 0;
}
@@ -300,16 +375,16 @@ int odp_packet_l3_offset_set(odp_packet_t pkt, uint32_t offset)
void *odp_packet_l4_ptr(odp_packet_t pkt, uint32_t *len)
{
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
- if (pkt_hdr->input_flags.unparsed)
- _odp_packet_parse(pkt_hdr);
+ if (packet_parse_not_complete(pkt_hdr))
+ packet_parse_full(pkt_hdr);
return packet_map(pkt_hdr, pkt_hdr->l4_offset, len);
}
uint32_t odp_packet_l4_offset(odp_packet_t pkt)
{
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
- if (pkt_hdr->input_flags.unparsed)
- _odp_packet_parse(pkt_hdr);
+ if (packet_parse_not_complete(pkt_hdr))
+ packet_parse_full(pkt_hdr);
return pkt_hdr->l4_offset;
}
@@ -320,8 +395,8 @@ int odp_packet_l4_offset_set(odp_packet_t pkt, uint32_t offset)
if (offset >= pkt_hdr->frame_len)
return -1;
- if (pkt_hdr->input_flags.unparsed)
- _odp_packet_parse(pkt_hdr);
+ if (packet_parse_not_complete(pkt_hdr))
+ packet_parse_full(pkt_hdr);
pkt_hdr->l4_offset = offset;
return 0;
}
@@ -442,22 +517,7 @@ odp_packet_t odp_packet_add_data(odp_packet_t pkt, uint32_t offset,
odp_packet_free(newpkt);
newpkt = ODP_PACKET_INVALID;
} else {
- odp_packet_hdr_t *new_hdr = odp_packet_hdr(newpkt);
- new_hdr->input = pkt_hdr->input;
- new_hdr->buf_hdr.buf_u64 = pkt_hdr->buf_hdr.buf_u64;
- if (new_hdr->buf_hdr.uarea_addr != NULL &&
- pkt_hdr->buf_hdr.uarea_addr != NULL)
- memcpy(new_hdr->buf_hdr.uarea_addr,
- pkt_hdr->buf_hdr.uarea_addr,
- new_hdr->buf_hdr.uarea_size <=
- pkt_hdr->buf_hdr.uarea_size ?
- new_hdr->buf_hdr.uarea_size :
- pkt_hdr->buf_hdr.uarea_size);
- odp_atomic_store_u32(
- &new_hdr->buf_hdr.ref_count,
- odp_atomic_load_u32(
- &pkt_hdr->buf_hdr.ref_count));
- copy_packet_parser_metadata(pkt_hdr, new_hdr);
+ _odp_packet_copy_md_to_packet(pkt, newpkt);
odp_packet_free(pkt);
}
}
@@ -486,22 +546,7 @@ odp_packet_t odp_packet_rem_data(odp_packet_t pkt, uint32_t offset,
odp_packet_free(newpkt);
newpkt = ODP_PACKET_INVALID;
} else {
- odp_packet_hdr_t *new_hdr = odp_packet_hdr(newpkt);
- new_hdr->input = pkt_hdr->input;
- new_hdr->buf_hdr.buf_u64 = pkt_hdr->buf_hdr.buf_u64;
- if (new_hdr->buf_hdr.uarea_addr != NULL &&
- pkt_hdr->buf_hdr.uarea_addr != NULL)
- memcpy(new_hdr->buf_hdr.uarea_addr,
- pkt_hdr->buf_hdr.uarea_addr,
- new_hdr->buf_hdr.uarea_size <=
- pkt_hdr->buf_hdr.uarea_size ?
- new_hdr->buf_hdr.uarea_size :
- pkt_hdr->buf_hdr.uarea_size);
- odp_atomic_store_u32(
- &new_hdr->buf_hdr.ref_count,
- odp_atomic_load_u32(
- &pkt_hdr->buf_hdr.ref_count));
- copy_packet_parser_metadata(pkt_hdr, new_hdr);
+ _odp_packet_copy_md_to_packet(pkt, newpkt);
odp_packet_free(pkt);
}
}
@@ -699,17 +744,6 @@ int _odp_packet_copy_to_packet(odp_packet_t srcpkt, uint32_t srcoffset,
return 0;
}
-odp_packet_t _odp_packet_alloc(odp_pool_t pool_hdl)
-{
- pool_entry_t *pool = odp_pool_to_entry(pool_hdl);
-
- if (pool->s.params.type != ODP_POOL_PACKET)
- return ODP_PACKET_INVALID;
-
- return (odp_packet_t)buffer_alloc(pool_hdl,
- pool->s.params.buf.size);
-}
-
/**
* Parser helper function for IPv4
*/
@@ -847,30 +881,11 @@ static inline void parse_udp(odp_packet_hdr_t *pkt_hdr,
}
/**
- * Simple packet parser
+ * Initialize L2 related parser flags and metadata
*/
-
-int _odp_packet_parse(odp_packet_hdr_t *pkt_hdr)
+void packet_parse_l2(odp_packet_hdr_t *pkt_hdr)
{
- odph_ethhdr_t *eth;
- odph_vlanhdr_t *vlan;
- uint16_t ethtype;
- uint8_t *parseptr;
- uint32_t offset, seglen;
- uint8_t ip_proto = 0;
-
- /* Reset parser metadata for new parse */
- pkt_hdr->error_flags.all = 0;
- pkt_hdr->input_flags.all = 0;
- pkt_hdr->output_flags.all = 0;
- pkt_hdr->l2_offset = 0;
- pkt_hdr->l3_offset = ODP_PACKET_OFFSET_INVALID;
- pkt_hdr->l4_offset = ODP_PACKET_OFFSET_INVALID;
- pkt_hdr->payload_offset = ODP_PACKET_OFFSET_INVALID;
- pkt_hdr->vlan_s_tag = 0;
- pkt_hdr->vlan_c_tag = 0;
- pkt_hdr->l3_protocol = 0;
- pkt_hdr->l4_protocol = 0;
+ /* Packet alloc or reset have already init other offsets and flags */
/* We only support Ethernet for now */
pkt_hdr->input_flags.eth = 1;
@@ -882,6 +897,24 @@ int _odp_packet_parse(odp_packet_hdr_t *pkt_hdr)
/* Assume valid L2 header, no CRC/FCS check in SW */
pkt_hdr->input_flags.l2 = 1;
+ pkt_hdr->input_flags.parsed_l2 = 1;
+}
+
+/**
+ * Simple packet parser
+ */
+int packet_parse_full(odp_packet_hdr_t *pkt_hdr)
+{
+ odph_ethhdr_t *eth;
+ odph_vlanhdr_t *vlan;
+ uint16_t ethtype;
+ uint8_t *parseptr;
+ uint32_t offset, seglen;
+ uint8_t ip_proto = 0;
+
+ if (packet_parse_l2_not_done(pkt_hdr))
+ packet_parse_l2(pkt_hdr);
+
eth = (odph_ethhdr_t *)packet_map(pkt_hdr, 0, &seglen);
offset = sizeof(odph_ethhdr_t);
parseptr = (uint8_t *)&eth->type;
@@ -993,5 +1026,6 @@ int _odp_packet_parse(odp_packet_hdr_t *pkt_hdr)
pkt_hdr->payload_offset = offset;
parse_exit:
+ pkt_hdr->input_flags.parsed_all = 1;
return pkt_hdr->error_flags.all != 0;
}
diff --git a/platform/linux-generic/odp_packet_flags.c b/platform/linux-generic/odp_packet_flags.c
index ea308f711..dbc313748 100644
--- a/platform/linux-generic/odp_packet_flags.c
+++ b/platform/linux-generic/odp_packet_flags.c
@@ -9,23 +9,23 @@
#define retflag(p, x) do { \
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(p); \
- if (pkt_hdr->input_flags.unparsed) \
- _odp_packet_parse(pkt_hdr); \
+ if (packet_parse_not_complete(pkt_hdr)) \
+ packet_parse_full(pkt_hdr); \
return pkt_hdr->x; \
} while (0)
#define setflag(p, x, v) do { \
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(p); \
- if (pkt_hdr->input_flags.unparsed) \
- _odp_packet_parse(pkt_hdr); \
+ if (packet_parse_not_complete(pkt_hdr)) \
+ packet_parse_full(pkt_hdr); \
pkt_hdr->x = v & 1; \
} while (0)
int odp_packet_has_error(odp_packet_t pkt)
{
odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
- if (pkt_hdr->input_flags.unparsed)
- _odp_packet_parse(pkt_hdr);
+ if (packet_parse_not_complete(pkt_hdr))
+ packet_parse_full(pkt_hdr);
return odp_packet_hdr(pkt)->error_flags.all != 0;
}
@@ -33,7 +33,9 @@ int odp_packet_has_error(odp_packet_t pkt)
int odp_packet_has_l2(odp_packet_t pkt)
{
- retflag(pkt, input_flags.l2);
+ odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
+
+ return pkt_hdr->input_flags.l2;
}
int odp_packet_has_l3(odp_packet_t pkt)
@@ -48,12 +50,16 @@ int odp_packet_has_l4(odp_packet_t pkt)
int odp_packet_has_eth(odp_packet_t pkt)
{
- retflag(pkt, input_flags.eth);
+ odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
+
+ return pkt_hdr->input_flags.eth;
}
int odp_packet_has_jumbo(odp_packet_t pkt)
{
- retflag(pkt, input_flags.jumbo);
+ odp_packet_hdr_t *pkt_hdr = odp_packet_hdr(pkt);
+
+ return pkt_hdr->input_flags.jumbo;
}
int odp_packet_has_vlan(odp_packet_t pkt)
diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c
index b3ca4c818..1246bff71 100644
--- a/platform/linux-generic/odp_packet_io.c
+++ b/platform/linux-generic/odp_packet_io.c
@@ -91,6 +91,12 @@ int odp_pktio_term_global(void)
int id;
int pktio_if;
+ for (id = 1; id <= ODP_CONFIG_PKTIO_ENTRIES; ++id) {
+ pktio_entry = &pktio_tbl->entries[id - 1];
+ odp_pktio_close(pktio_entry->s.handle);
+ odp_queue_destroy(pktio_entry->s.outq_default);
+ }
+
for (pktio_if = 0; pktio_if_ops[pktio_if]; ++pktio_if) {
if (pktio_if_ops[pktio_if]->term)
if (pktio_if_ops[pktio_if]->term())
@@ -98,11 +104,6 @@ int odp_pktio_term_global(void)
pktio_if);
}
- for (id = 1; id <= ODP_CONFIG_PKTIO_ENTRIES; ++id) {
- pktio_entry = &pktio_tbl->entries[id - 1];
- odp_queue_destroy(pktio_entry->s.outq_default);
- }
-
ret = odp_shm_free(odp_shm_lookup("odp_pktio_entries"));
if (ret < 0)
ODP_ERR("shm free failed for odp_pktio_entries");
@@ -203,10 +204,10 @@ static odp_pktio_t setup_pktio_entry(const char *dev, odp_pool_t pool,
int ret = -1;
int pktio_if;
- if (strlen(dev) >= IF_NAMESIZE) {
+ if (strlen(dev) >= PKTIO_NAME_LEN - 1) {
/* ioctl names limitation */
ODP_ERR("pktio name %s is too big, limit is %d bytes\n",
- dev, IF_NAMESIZE);
+ dev, PKTIO_NAME_LEN - 1);
return ODP_PKTIO_INVALID;
}
@@ -238,7 +239,8 @@ static odp_pktio_t setup_pktio_entry(const char *dev, odp_pool_t pool,
id = ODP_PKTIO_INVALID;
ODP_ERR("Unable to init any I/O type.\n");
} else {
- snprintf(pktio_entry->s.name, IF_NAMESIZE, "%s", dev);
+ snprintf(pktio_entry->s.name,
+ sizeof(pktio_entry->s.name), "%s", dev);
pktio_entry->s.state = STATE_STOP;
unlock_entry_classifier(pktio_entry);
}
@@ -358,7 +360,7 @@ odp_pktio_t odp_pktio_lookup(const char *dev)
lock_entry(entry);
if (!is_free(entry) &&
- strncmp(entry->s.name, dev, IF_NAMESIZE) == 0)
+ strncmp(entry->s.name, dev, sizeof(entry->s.name)) == 0)
id = _odp_cast_scalar(odp_pktio_t, i);
unlock_entry(entry);
diff --git a/platform/linux-generic/odp_pool.c b/platform/linux-generic/odp_pool.c
index 30d4b2b65..76a4aa585 100644
--- a/platform/linux-generic/odp_pool.c
+++ b/platform/linux-generic/odp_pool.c
@@ -57,8 +57,8 @@ static const char SHM_DEFAULT_NAME[] = "odp_buffer_pools";
/* Pool entry pointers (for inlining) */
void *pool_entry_ptr[ODP_CONFIG_POOLS];
-/* Local cache for buffer alloc/free acceleration */
-static __thread local_cache_t local_cache[ODP_CONFIG_POOLS];
+/* Cache thread id locally for local cache performance */
+static __thread int local_id;
int odp_pool_init_global(void)
{
@@ -107,6 +107,12 @@ int odp_pool_init_global(void)
return 0;
}
+int odp_pool_init_local(void)
+{
+ local_id = odp_thread_id();
+ return 0;
+}
+
int odp_pool_term_global(void)
{
int i;
@@ -442,6 +448,7 @@ int odp_pool_destroy(odp_pool_t pool_hdl)
{
uint32_t pool_id = pool_handle_to_index(pool_hdl);
pool_entry_t *pool = get_pool_entry(pool_id);
+ int i;
if (pool == NULL)
return -1;
@@ -455,8 +462,9 @@ int odp_pool_destroy(odp_pool_t pool_hdl)
return -1;
}
- /* Make sure local cache is empty */
- flush_cache(&local_cache[pool_id], &pool->s);
+ /* Make sure local caches are empty */
+ for (i = 0; i < _ODP_INTERNAL_MAX_THREADS; i++)
+ flush_cache(&pool->s.local_cache[i], &pool->s);
/* Call fails if pool has allocated buffers */
if (odp_atomic_load_u32(&pool->s.bufcount) < pool->s.buf_num) {
@@ -485,8 +493,9 @@ odp_buffer_t buffer_alloc(odp_pool_t pool_hdl, size_t size)
return ODP_BUFFER_INVALID;
/* Try to satisfy request from the local cache */
- buf = (odp_anybuf_t *)(void *)get_local_buf(&local_cache[pool_id],
- &pool->s, totsize);
+ buf = (odp_anybuf_t *)
+ (void *)get_local_buf(&pool->s.local_cache[local_id],
+ &pool->s, totsize);
/* If cache is empty, satisfy request from the pool */
if (odp_unlikely(buf == NULL)) {
@@ -517,9 +526,6 @@ odp_buffer_t buffer_alloc(odp_pool_t pool_hdl, size_t size)
/* By default, buffers are not associated with an ordered queue */
buf->buf.origin_qe = NULL;
- if (buf->buf.type == ODP_EVENT_PACKET)
- packet_init(pool, &buf->pkt, size);
-
return odp_hdr_to_buf(&buf->buf);
}
@@ -537,7 +543,7 @@ void odp_buffer_free(odp_buffer_t buf)
if (odp_unlikely(pool->s.low_wm_assert))
ret_buf(&pool->s, buf_hdr);
else
- ret_local_buf(&local_cache[pool->s.pool_id], buf_hdr);
+ ret_local_buf(&pool->s.local_cache[local_id], buf_hdr);
}
void _odp_flush_caches(void)
@@ -546,7 +552,7 @@ void _odp_flush_caches(void)
for (i = 0; i < ODP_CONFIG_POOLS; i++) {
pool_entry_t *pool = get_pool_entry(i);
- flush_cache(&local_cache[i], &pool->s);
+ flush_cache(&pool->s.local_cache[local_id], &pool->s);
}
}
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++;
diff --git a/platform/linux-generic/test/Makefile.am b/platform/linux-generic/test/Makefile.am
index 327d5bf2f..a657de9fc 100644
--- a/platform/linux-generic/test/Makefile.am
+++ b/platform/linux-generic/test/Makefile.am
@@ -27,6 +27,11 @@ TESTS = pktio/pktio_run \
${top_builddir}/test/validation/system/system_main$(EXEEXT)
SUBDIRS = $(ODP_MODULES)
+
+if HAVE_PCAP
+TESTS += pktio/pktio_run_pcap
+endif
+
endif
#performance tests refer to pktio_env
diff --git a/platform/linux-generic/test/pktio/Makefile.am b/platform/linux-generic/test/pktio/Makefile.am
index 93281dd1b..6fe20139c 100644
--- a/platform/linux-generic/test/pktio/Makefile.am
+++ b/platform/linux-generic/test/pktio/Makefile.am
@@ -1,2 +1,6 @@
dist_bin_SCRIPTS = pktio_env \
pktio_run
+
+if HAVE_PCAP
+dist_bin_SCRIPTS += pktio_run_pcap
+endif
diff --git a/platform/linux-generic/test/pktio/pktio_env b/platform/linux-generic/test/pktio/pktio_env
index 5e547e47b..345b5bd56 100644
--- a/platform/linux-generic/test/pktio/pktio_env
+++ b/platform/linux-generic/test/pktio/pktio_env
@@ -18,10 +18,10 @@
# Network set up
# IF0 <---> IF1
# IF2 <---> IF3
-IF0=pktio-p0-p1
-IF1=pktio-p1-p0
-IF2=pktio-p2-p3
-IF3=pktio-p3-p2
+IF0=pktiop0p1
+IF1=pktiop1p0
+IF2=pktiop2p3
+IF3=pktiop3p2
if [ "$0" = "$BASH_SOURCE" ]; then
echo "Error: Platform specific env file has to be sourced."
diff --git a/platform/linux-generic/test/pktio/pktio_run_pcap b/platform/linux-generic/test/pktio/pktio_run_pcap
new file mode 100755
index 000000000..c130417c5
--- /dev/null
+++ b/platform/linux-generic/test/pktio/pktio_run_pcap
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# Copyright (c) 2015, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# directories where pktio_main binary can be found:
+# -in the validation dir when running make check (intree or out of tree)
+# -in the script directory, when running after 'make install', or
+# -in the validation when running standalone intree.
+# -in the current directory.
+# running stand alone out of tree requires setting PATH
+PATH=${TEST_DIR}/pktio:$PATH
+PATH=$(dirname $0):$PATH
+PATH=$(dirname $0)/../../../../test/validation/pktio:$PATH
+PATH=.:$PATH
+
+pktio_main_path=$(which pktio_main${EXEEXT})
+if [ -x "$pktio_main_path" ] ; then
+ echo "running with $pktio_main_path"
+else
+ echo "cannot find pktio_main${EXEEXT}: please set you PATH for it."
+fi
+
+PCAP_FNAME=vald.pcap
+export ODP_PKTIO_IF0="pcap:out=${PCAP_FNAME}"
+export ODP_PKTIO_IF1="pcap:in=${PCAP_FNAME}"
+pktio_main${EXEEXT}
+ret=$?
+rm -f ${PCAP_FNAME}
+exit $ret