This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project "".
The branch, master has been updated via 49c671e80fd2c88b6f36337ebd1cd4748eb8bae1 (commit) from 11207ff1e211658bfb44c635423ae818a0654239 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- commit 49c671e80fd2c88b6f36337ebd1cd4748eb8bae1 Author: Ilias Apalodimas ilias.apalodimas@linaro.org Date: Fri Feb 16 12:12:26 2018 +0200
odp: pktio: add pcapng capture capabilities
Introduce new fast pcap capture interface to odp. How to test: sudo mkdir /var/run/odp/ start the ODP application sudo dd if=/var/run/odp/"pid"-ethX-flow-"queue" of=~/t.pcap
Signed-off-by: Ilias Apalodimas ilias.apalodimas@linaro.org Reviewed-by: Bill Fischofer bill.fischofer@linaro.org Signed-off-by: Maxim Uvarov maxim.uvarov@linaro.org
diff --git a/.travis.yml b/.travis.yml index cb05b839..886e40f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -58,6 +58,7 @@ env: - CONF="--disable-static-applications" - CONF="--disable-host-optimization" - CONF="--disable-host-optimization --disable-abi-compat" + - CONF="--enable-pcapng-support" - DPDK_SHARED="y" CONF="--disable-static-applications"
compiler: diff --git a/configure.ac b/configure.ac index 11a89b58..f13525de 100644 --- a/configure.ac +++ b/configure.ac @@ -418,4 +418,5 @@ AC_MSG_RESULT([ test_helper: ${test_helper} test_example: ${test_example} user_guides: ${user_guides} + pcapng: ${have_pcapng} ]) diff --git a/doc/users-guide/Makefile.am b/doc/users-guide/Makefile.am index 7be32ddc..6b2e818d 100644 --- a/doc/users-guide/Makefile.am +++ b/doc/users-guide/Makefile.am @@ -7,7 +7,8 @@ SRC = users-guide.adoc \ users-guide-packet.adoc \ users-guide-pktio.adoc \ users-guide-timer.adoc \ - users-guide-tm.adoc + users-guide-tm.adoc \ + users-guide-utilities-examples.adoc TARGET = users-guide.html IMAGES = $(IMAGES_DIR)/overview.svg \ $(IMAGES_DIR)/atomic_queue.svg \ diff --git a/doc/users-guide/users-guide-utilities-examples.adoc b/doc/users-guide/users-guide-utilities-examples.adoc new file mode 100644 index 00000000..e51bbef8 --- /dev/null +++ b/doc/users-guide/users-guide-utilities-examples.adoc @@ -0,0 +1,19 @@ +== Utilities and examples + +=== PcapNg capture +If compiled using `--enable-pcapng-support` ODP will offer packet capturing +functionality in PcapNg format. If the /var/run/odp directory exists prior to +launching the application ODP will create a fifo for each NIC queue. +Queue naming will be of the following format: *<odp global pid>-<NIC +name>-flow-<queue number>*. Linux dd application can be used for capturing a +sample of the live stream from the fifo. Killing ether the application or dd +will stop the capturing process. + +. `./configure --enable-pcapng-support` +. `sudo mkdir /var/run/odp` +. `sudo ./example/generator/odp_generator -I enp2s0 -mu --dstmac +A0:F6:FD:AE:62:6C --dstip 192.168.49.20 --srcmac 2c:56:dc:9a:8f:06 --srcip +192.168.49.4 -i0 -w1` +. `sudo dd if=/var/run/odp/26737-enp2s0-flow-0 of=~/test.pcap` +. `ctrl^c` +. `wireshark ~/test.pcap` diff --git a/doc/users-guide/users-guide.adoc b/doc/users-guide/users-guide.adoc index 7914459e..8ed581f5 100644 --- a/doc/users-guide/users-guide.adoc +++ b/doc/users-guide/users-guide.adoc @@ -1204,4 +1204,6 @@ include::users-guide-tm.adoc[]
include::users-guide-cls.adoc[]
+include::users-guide-utilities-examples.adoc[] + include::../glossary.adoc[] diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index a73dc61d..f9e99afd 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -115,6 +115,7 @@ noinst_HEADERS = \ include/odp_packet_null.h \ include/odp_packet_socket.h \ include/odp_packet_tap.h \ + include/odp_pcapng.h \ include/odp_pkt_queue_internal.h \ include/odp_pool_internal.h \ include/odp_posix_extensions.h \ @@ -190,6 +191,7 @@ __LIB__libodp_linux_la_SOURCES = \ odp_spinlock.c \ odp_spinlock_recursive.c \ odp_system_info.c \ + odp_pcapng.c \ odp_thread.c \ odp_thrmask.c \ odp_time.c \ diff --git a/platform/linux-generic/include/odp_internal.h b/platform/linux-generic/include/odp_internal.h index 153c787e..f39b6152 100644 --- a/platform/linux-generic/include/odp_internal.h +++ b/platform/linux-generic/include/odp_internal.h @@ -24,6 +24,7 @@ extern "C" { #include <stdio.h> #include <sys/types.h> #include <libconfig.h> +#include <pthread.h>
#define MAX_CPU_NUMBER 128 #define UID_MAXLEN 30 @@ -58,7 +59,10 @@ struct odp_global_data_s { int num_cpus_installed; config_t libconfig_default; config_t libconfig_runtime; - + int inotify_pcapng_fd; + int inotify_watch_fd; + pthread_t inotify_thread; + int inotify_pcapng_is_running; };
enum init_stage { diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h index e4852cc9..4be4b151 100644 --- a/platform/linux-generic/include/odp_packet_io_internal.h +++ b/platform/linux-generic/include/odp_packet_io_internal.h @@ -182,6 +182,15 @@ struct pktio_entry { odp_queue_t queue; odp_pktout_queue_t pktout; } out_queue[PKTIO_MAX_QUEUES]; + + /**< inotify instance for pcapng fifos */ + struct { + enum { + PCAPNG_WR_STOP = 0, + PCAPNG_WR_PKT, + } state[PKTIO_MAX_QUEUES]; + int fd[PKTIO_MAX_QUEUES]; + } pcapng; };
typedef union { diff --git a/platform/linux-generic/include/odp_pcapng.h b/platform/linux-generic/include/odp_pcapng.h new file mode 100644 index 00000000..8e0e624e --- /dev/null +++ b/platform/linux-generic/include/odp_pcapng.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <sys/types.h> + +#include <odp_packet_io_internal.h> + +#define PCAPNG_BLOCK_TYPE_EPB 0x00000006UL +#define PCAPNG_BLOCK_TYPE_SHB 0x0A0D0D0AUL +#define PCAPNG_BLOCK_TYPE_IDB 0x00000001UL +#define PCAPNG_ENDIAN_MAGIC 0x1A2B3C4DUL +#define PCAPNG_DATA_ALIGN 4 +#define PCAPNG_LINKTYPE_ETHERNET 0x1 + +/* inotify */ +#define INOTIFY_BUF_LEN (16 * (sizeof(struct inotify_event))) +#define PCAPNG_WATCH_DIR "/var/run/odp/" + +/* pcapng: enhanced packet block file encoding */ +typedef struct ODP_PACKED pcapng_section_hdr_block_s { + uint32_t block_type; + uint32_t block_total_length; + uint32_t magic; + uint16_t version_major; + uint16_t version_minor; + int64_t section_len; + uint32_t block_total_length2; +} pcapng_section_hdr_block_t; + +typedef struct pcapng_interface_description_block { + uint32_t block_type; + uint32_t block_total_length; + uint16_t linktype; + uint16_t reserved; + uint32_t snaplen; + uint32_t block_total_length2; +} pcapng_interface_description_block_t; + +typedef struct pcapng_enhanced_packet_block_s { + uint32_t block_type; + uint32_t block_total_length; + uint32_t interface_idx; + uint32_t timestamp_high; + uint32_t timestamp_low; + uint32_t captured_len; + uint32_t packet_len; +} pcapng_enhanced_packet_block_t; + +int pcapng_prepare(pktio_entry_t *entry); +void pcapng_destroy(pktio_entry_t *entry); +int write_pcapng_hdr(pktio_entry_t *entry, int qidx); +int write_pcapng_pkts(pktio_entry_t *entry, int qidx, + const odp_packet_t packets[], int num); diff --git a/platform/linux-generic/m4/configure.m4 b/platform/linux-generic/m4/configure.m4 index 7cf0a9b6..951704ed 100644 --- a/platform/linux-generic/m4/configure.m4 +++ b/platform/linux-generic/m4/configure.m4 @@ -8,6 +8,7 @@ ODP_TIMER ODP_OPENSSL ODP_LIBCONFIG([linux-generic]) m4_include([platform/linux-generic/m4/odp_pcap.m4]) +m4_include([platform/linux-generic/m4/odp_pcapng.m4]) m4_include([platform/linux-generic/m4/odp_netmap.m4]) m4_include([platform/linux-generic/m4/odp_dpdk.m4]) ODP_SCHEDULER diff --git a/platform/linux-generic/m4/odp_pcapng.m4 b/platform/linux-generic/m4/odp_pcapng.m4 new file mode 100644 index 00000000..44274c26 --- /dev/null +++ b/platform/linux-generic/m4/odp_pcapng.m4 @@ -0,0 +1,18 @@ +########################################################################## +# Enable PCAPNG support +########################################################################## +have_pcapng=no +pcapng_support=0 + +AC_ARG_ENABLE([pcapng-support], + [AS_HELP_STRING([--enable-pcapng-support], + [enable experimental tcpdump for pktios])], + have_pcapng=$enableval + [if test x$enableval = xyes; then + pcapng_support=1 + fi]) + +AC_DEFINE_UNQUOTED([_ODP_PCAPNG], [$pcapng_support], + [Define to 1 to enable pcapng support]) + +AM_CONDITIONAL([have_pcapng], [test x$have_pcapng = xyes]) diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c index bf7aef14..7b211c45 100644 --- a/platform/linux-generic/odp_packet_io.c +++ b/platform/linux-generic/odp_packet_io.c @@ -25,6 +25,7 @@ #include <odp_debug_internal.h> #include <odp_packet_io_ipc_internal.h> #include <odp/api/time.h> +#include <odp_pcapng.h>
#include <string.h> #include <inttypes.h> @@ -512,6 +513,11 @@ int odp_pktio_start(odp_pktio_t hdl) ODP_DBG("interface: %s, input queues: %u, output queues: %u\n", entry->s.name, entry->s.num_in_queue, entry->s.num_out_queue);
+ if (_ODP_PCAPNG) { + if (pcapng_prepare(entry)) + ODP_ERR("pcap init failed, won't capture\n"); + } + return res; }
@@ -536,6 +542,9 @@ static int _pktio_stop(pktio_entry_t *entry) else entry->s.state = PKTIO_STATE_STOPPED;
+ if (_ODP_PCAPNG) + pcapng_destroy(entry); + return res; }
@@ -1746,10 +1755,18 @@ int odp_pktout_queue(odp_pktio_t pktio, odp_pktout_queue_t queues[], int num) return num_queues; }
+static inline void _odp_dump_pcapng_pkts(pktio_entry_t *entry, int qidx, + const odp_packet_t packets[], int num) +{ + if (odp_unlikely(entry->s.pcapng.state[qidx] == PCAPNG_WR_PKT)) + write_pcapng_pkts(entry, qidx, packets, num); +} + int odp_pktin_recv(odp_pktin_queue_t queue, odp_packet_t packets[], int num) { pktio_entry_t *entry; odp_pktio_t pktio = queue.pktio; + int ret;
entry = get_pktio_entry(pktio); if (entry == NULL) { @@ -1757,7 +1774,11 @@ int odp_pktin_recv(odp_pktin_queue_t queue, odp_packet_t packets[], int num) return -1; }
- return entry->s.ops->recv(entry, queue.index, packets, num); + ret = entry->s.ops->recv(entry, queue.index, packets, num); + if (_ODP_PCAPNG) + _odp_dump_pcapng_pkts(entry, queue.index, packets, ret); + + return ret; }
int odp_pktin_recv_tmo(odp_pktin_queue_t queue, odp_packet_t packets[], int num, @@ -1779,12 +1800,19 @@ int odp_pktin_recv_tmo(odp_pktin_queue_t queue, odp_packet_t packets[], int num, return -1; }
- if (entry->s.ops->recv_tmo && wait != ODP_PKTIN_NO_WAIT) - return entry->s.ops->recv_tmo(entry, queue.index, packets, num, + if (entry->s.ops->recv_tmo && wait != ODP_PKTIN_NO_WAIT) { + ret = entry->s.ops->recv_tmo(entry, queue.index, packets, num, wait); + if (_ODP_PCAPNG) + _odp_dump_pcapng_pkts(entry, queue.index, packets, ret); + + return ret; + }
while (1) { ret = entry->s.ops->recv(entry, queue.index, packets, num); + if (_ODP_PCAPNG) + _odp_dump_pcapng_pkts(entry, queue.index, packets, ret);
if (ret != 0 || wait == 0) return ret; @@ -1827,6 +1855,7 @@ int odp_pktin_recv_mq_tmo(const odp_pktin_queue_t queues[], unsigned num_q, int started = 0; uint64_t sleep_round = 0; int trial_successful = 0; + unsigned int lfrom = 0;
for (i = 0; i < num_q; i++) { ret = odp_pktin_recv(queues[i], packets, num); @@ -1841,11 +1870,23 @@ int odp_pktin_recv_mq_tmo(const odp_pktin_queue_t queues[], unsigned num_q, if (wait == 0) return 0;
- ret = sock_recv_mq_tmo_try_int_driven(queues, num_q, from, + ret = sock_recv_mq_tmo_try_int_driven(queues, num_q, &lfrom, packets, num, wait, &trial_successful); - if (trial_successful) + if (ret > 0 && from) + *from = lfrom; + if (trial_successful) { + if (_ODP_PCAPNG) { + pktio_entry_t *entry; + + entry = get_pktio_entry(queues[lfrom].pktio); + if (entry) + _odp_dump_pcapng_pkts(entry, lfrom, packets, + ret); + } + return ret; + }
ts.tv_sec = 0; ts.tv_nsec = 1000 * SLEEP_USEC; @@ -1911,6 +1952,9 @@ int odp_pktout_send(odp_pktout_queue_t queue, const odp_packet_t packets[], return -1; }
+ if (_ODP_PCAPNG) + _odp_dump_pcapng_pkts(entry, queue.index, packets, num); + return entry->s.ops->send(entry, queue.index, packets, num); }
diff --git a/platform/linux-generic/odp_pcapng.c b/platform/linux-generic/odp_pcapng.c new file mode 100644 index 00000000..b8d29e5a --- /dev/null +++ b/platform/linux-generic/odp_pcapng.c @@ -0,0 +1,434 @@ +/* Copyright (c) 2018, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "config.h" + +#if defined(_ODP_PCAPNG) && _ODP_PCAPNG == 1 + +#include <odp_macros_internal.h> +#include <odp_packet_io_internal.h> +#include <odp/api/plat/packet_inlines.h> +#include <odp_posix_extensions.h> +#include <odp_pcapng.h> + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <pthread.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/uio.h> +#include <sys/inotify.h> +#include <sys/select.h> + +static void pcapng_drain_fifo(int fd) +{ + char buffer[4096]; + ssize_t len; + + do { + len = read(fd, buffer, sizeof(buffer)); + } while (len > 0); +} + +static void inotify_event_handle(pktio_entry_t *entry, int qidx, + struct inotify_event *event) +{ + int mtu = MAX(odp_pktin_maxlen(entry->s.handle), + odp_pktout_maxlen(entry->s.handle)); + + if (event->mask & IN_OPEN) { + int ret; + + if (PIPE_BUF < mtu + sizeof(pcapng_enhanced_packet_block_t) + + sizeof(uint32_t)) { + ODP_ERR("PIPE_BUF:%d too small. Disabling pcap\n", + PIPE_BUF); + entry->s.pcapng.state[qidx] = PCAPNG_WR_STOP; + + return; + } + + ret = write_pcapng_hdr(entry, qidx); + if (ret) { + entry->s.pcapng.state[qidx] = PCAPNG_WR_STOP; + } else { + entry->s.pcapng.state[qidx] = PCAPNG_WR_PKT; + ODP_DBG("Open %s for pcap tracing\n", event->name); + } + } else if (event->mask & IN_CLOSE) { + int fd = entry->s.pcapng.fd[qidx]; + + pcapng_drain_fifo(fd); + entry->s.pcapng.state[qidx] = PCAPNG_WR_STOP; + ODP_DBG("Close %s for pcap tracing\n", event->name); + } else { + ODP_ERR("Unknown inotify event 0x%08x\n", event->mask); + } +} + +static void get_pcapng_fifo_name(char *pcapng_entry, size_t len, + char *pktio_name, int qidx) +{ + snprintf(pcapng_entry, len, "%d-%s-flow-%d", + odp_global_data.main_pid, pktio_name, qidx); + pcapng_entry[len - 1] = 0; +} + +static int get_qidx_from_fifo(pktio_entry_t *entry, char *name) +{ + unsigned int max_queue = + MAX(entry->s.num_in_queue, entry->s.num_out_queue); + unsigned int i; + + for (i = 0; i < max_queue; i++) { + char pcapng_entry[256]; + + get_pcapng_fifo_name(pcapng_entry, sizeof(pcapng_entry), + entry->s.name, i); + /* + * verify we still talk to a fifo before returning a valid + * queue number + */ + if (strcmp(name, pcapng_entry) == 0) { + struct stat fstat; + char pcapng_path[256]; + + snprintf(pcapng_path, sizeof(pcapng_path), "%s/%s", + PCAPNG_WATCH_DIR, name); + stat(pcapng_path, &fstat); + + return S_ISFIFO(fstat.st_mode) ? (int)i : -1; + } + } + + return -1; +} + +static void *inotify_update(void *arg) +{ + pktio_entry_t *entry = (pktio_entry_t *)arg; + struct timeval time; + ssize_t rdlen; + int offset; + char buffer[INOTIFY_BUF_LEN]; + fd_set rfds; + + while (1) { + offset = 0; + FD_ZERO(&rfds); + FD_SET(odp_global_data.inotify_pcapng_fd, &rfds); + time.tv_sec = 2; + time.tv_usec = 0; + select(odp_global_data.inotify_pcapng_fd + 1, &rfds, NULL, + NULL, &time); + if (FD_ISSET(odp_global_data.inotify_pcapng_fd, &rfds)) { + rdlen = read(odp_global_data.inotify_pcapng_fd, + buffer, INOTIFY_BUF_LEN); + while (offset < rdlen) { + int qidx; + struct inotify_event *event = + (struct inotify_event *)(void *) + &buffer[offset]; + + qidx = get_qidx_from_fifo(entry, event->name); + if (qidx == -1) { + offset += sizeof(struct inotify_event) + + event->len; + continue; + } + + inotify_event_handle(entry, qidx, event); + offset += sizeof(struct inotify_event) + + event->len; + } + } + } + + return NULL; +} + +static int get_fifo_max_size(void) +{ + FILE *file; + char buf[128]; + int ret = -1; + + file = fopen("/proc/sys/fs/pipe-max-size", "r"); + if (file == NULL) + return ret; + + if (fgets(buf, sizeof(buf), file)) + ret = atoi(buf); + + fclose(file); + + return ret; +} + +int pcapng_prepare(pktio_entry_t *entry) +{ + int ret = -1, fd; + pthread_attr_t attr; + unsigned int i; + unsigned int max_queue = + MAX(entry->s.num_in_queue, entry->s.num_out_queue); + int fifo_sz; + + fifo_sz = get_fifo_max_size(); + if (fifo_sz < 0) + ODP_DBG("failed to read max fifo size\n"); + + for (i = 0; i < max_queue; i++) { + char pcapng_name[128]; + char pcapng_path[256]; + + entry->s.pcapng.fd[i] = -1; + entry->s.pcapng.state[i] = PCAPNG_WR_STOP; + + get_pcapng_fifo_name(pcapng_name, sizeof(pcapng_name), + entry->s.name, i); + snprintf(pcapng_path, sizeof(pcapng_path), "%s/%s", + PCAPNG_WATCH_DIR, pcapng_name); + if (mkfifo(pcapng_path, O_RDWR)) { + ODP_ERR("pcap not available for %s %s\n", + pcapng_path, strerror(errno)); + continue; + } + + fd = open(pcapng_path, O_RDWR | O_NONBLOCK); + if (fd == -1) { + ODP_ERR("Fail to open fifo\n"); + entry->s.pcapng.state[i] = PCAPNG_WR_STOP; + if (remove(pcapng_path) == -1) + ODP_ERR("Can't remove fifo %s\n", pcapng_path); + continue; + } + + if (fifo_sz > 0) { + if (fcntl(fd, F_SETPIPE_SZ, fifo_sz) != fifo_sz) + ODP_DBG("Failed to set max fifo size\n"); + else + ODP_DBG("set pcap fifo size %i\n", fifo_sz); + } + + entry->s.pcapng.fd[i] = fd; + } + + /* already running from a previous pktio */ + if (odp_global_data.inotify_pcapng_is_running == 1) + return 0; + + odp_global_data.inotify_pcapng_fd = -1; + odp_global_data.inotify_watch_fd = -1; + + odp_global_data.inotify_pcapng_fd = inotify_init(); + if (odp_global_data.inotify_pcapng_fd == -1) { + ODP_ERR("can't init inotify. pcap disabled\n"); + goto out_destroy; + } + + odp_global_data.inotify_watch_fd = + inotify_add_watch(odp_global_data.inotify_pcapng_fd, + PCAPNG_WATCH_DIR, IN_CLOSE | IN_OPEN); + + if (odp_global_data.inotify_watch_fd == -1) { + ODP_ERR("can't register inotify for %s. pcap disabled\n", + strerror(errno)); + goto out_destroy; + } + + /* create a thread to poll inotify triggers */ + pthread_attr_init(&attr); + ret = pthread_create(&odp_global_data.inotify_thread, &attr, + inotify_update, entry); + if (ret) + ODP_ERR("can't start inotify thread. pcap disabled\n"); + else + odp_global_data.inotify_pcapng_is_running = 1; + + return ret; + +out_destroy: + pcapng_destroy(entry); + + return ret; +} + +void pcapng_destroy(pktio_entry_t *entry) +{ + int ret; + unsigned int i; + unsigned int max_queue = + MAX(entry->s.num_in_queue, entry->s.num_out_queue); + + if (odp_global_data.inotify_pcapng_is_running == 1) { + ret = pthread_cancel(odp_global_data.inotify_thread); + if (ret) + ODP_ERR("can't cancel inotify thread %s\n", + strerror(errno)); + } + + /* fd's will be -1 in case of any failure */ + ret = inotify_rm_watch(odp_global_data.inotify_pcapng_fd, + odp_global_data.inotify_watch_fd); + if (ret) + ODP_ERR("can't deregister inotify %s\n", strerror(errno)); + + if (odp_global_data.inotify_pcapng_fd != -1) + close(odp_global_data.inotify_pcapng_fd); + + if (odp_global_data.inotify_watch_fd != -1) + close(odp_global_data.inotify_watch_fd); + + for (i = 0; i < max_queue; i++) { + char pcapng_name[128]; + char pcapng_path[256]; + + entry->s.pcapng.state[i] = PCAPNG_WR_STOP; + close(entry->s.pcapng.fd[i]); + + get_pcapng_fifo_name(pcapng_name, sizeof(pcapng_name), + entry->s.name, i); + snprintf(pcapng_path, sizeof(pcapng_path), "%s/%s", + PCAPNG_WATCH_DIR, pcapng_name); + + if (remove(pcapng_path)) + ODP_ERR("can't delete fifo %s\n", pcapng_path); + } +} + +int write_pcapng_hdr(pktio_entry_t *entry, int qidx) +{ + size_t len; + pcapng_section_hdr_block_t shb; + pcapng_interface_description_block_t idb; + int fd = entry->s.pcapng.fd[qidx]; + + memset(&shb, 0, sizeof(shb)); + memset(&idb, 0, sizeof(idb)); + + shb.block_type = PCAPNG_BLOCK_TYPE_SHB; + shb.block_total_length = sizeof(shb); + shb.block_total_length2 = sizeof(shb); + shb.magic = PCAPNG_ENDIAN_MAGIC; + shb.version_major = 0x1; + shb.version_minor = 0x0; + shb.section_len = -1; + + len = write(fd, &shb, sizeof(shb)); + /* fail to write shb/idb means the pcapng is unreadable */ + if (len != sizeof(shb)) { + ODP_ERR("Failed to write pcapng section hdr\n"); + return -1; + } + fsync(fd); + + idb.block_type = PCAPNG_BLOCK_TYPE_IDB; + idb.block_total_length = sizeof(idb); + idb.block_total_length2 = sizeof(idb); + idb.linktype = PCAPNG_LINKTYPE_ETHERNET; + idb.snaplen = 0x0; /* unlimited */ + len = write(fd, &idb, sizeof(idb)); + if (len != sizeof(idb)) { + ODP_ERR("Failed to write pcapng interface description\n"); + return -1; + } + fsync(fd); + + return 0; +} + +/* + * make sure that each fifo write is less than PIPE_BUF + * this will make sure writes are atomic (on non blocking mode). + * writev() transfers all the data and returns the number of bytes requested or + * -EAGAIN + */ +static ssize_t write_fifo(int fd, struct iovec *iov, int iovcnt) +{ + ssize_t len = 0; + + len = writev(fd, iov, iovcnt); + /* + * we don't care if a writev fails, we asynchronously read the fifo + * so the next block of packets might be successful. This error only + * means that some packets failed to append on the pcap file + */ + if (len > 0) + fsync(fd); + + return len; +} + +int write_pcapng_pkts(pktio_entry_t *entry, int qidx, + const odp_packet_t packets[], int num) +{ + int i = 0; + struct iovec packet_iov[3 * num]; + pcapng_enhanced_packet_block_t epb[num]; + int iovcnt = 0; + ssize_t block_len = 0; + int fd = entry->s.pcapng.fd[qidx]; + ssize_t len = 0, wlen; + + for (i = 0; i < num; i++) { + odp_packet_hdr_t *pkt_hdr = packet_hdr(packets[i]); + uint32_t seg_len; + char *buf = (char *)odp_packet_offset(packets[i], 0, &seg_len, + NULL); + + if (block_len + sizeof(epb[i]) + + ROUNDUP_ALIGN(seg_len, PCAPNG_DATA_ALIGN) + + sizeof(uint32_t) > PIPE_BUF) { + wlen = write_fifo(fd, packet_iov, iovcnt); + if (wlen > 0) { + len += wlen; + block_len = 0; + iovcnt = 0; + } + } + epb[i].block_type = PCAPNG_BLOCK_TYPE_EPB; + epb[i].block_total_length = sizeof(epb[i]) + + ROUNDUP_ALIGN(seg_len, PCAPNG_DATA_ALIGN) + + PCAPNG_DATA_ALIGN; + epb[i].interface_idx = 0; + epb[i].timestamp_high = + (uint32_t)(pkt_hdr->timestamp.u64 >> 32); + epb[i].timestamp_low = (uint32_t)(pkt_hdr->timestamp.u64); + epb[i].captured_len = seg_len; + epb[i].packet_len = seg_len; + + /* epb */ + packet_iov[iovcnt].iov_base = &epb[i]; + packet_iov[iovcnt].iov_len = sizeof(epb[i]); + block_len += packet_iov[iovcnt].iov_len; + iovcnt++; + + /* data */ + packet_iov[iovcnt].iov_base = buf; + packet_iov[iovcnt].iov_len = + ROUNDUP_ALIGN(seg_len, PCAPNG_DATA_ALIGN); + block_len += packet_iov[iovcnt].iov_len; + iovcnt++; + + /* trailing */ + packet_iov[iovcnt].iov_base = &epb[i].block_total_length; + packet_iov[iovcnt].iov_len = sizeof(uint32_t); + block_len += packet_iov[iovcnt].iov_len; + iovcnt++; + } + + if (iovcnt) { + wlen = write_fifo(fd, packet_iov, iovcnt); + if (wlen > 0) + len += wlen; + } + + return len; +} + +#endif /* _ODP_PCAPNG */
-----------------------------------------------------------------------
Summary of changes: .travis.yml | 1 + configure.ac | 1 + doc/users-guide/Makefile.am | 3 +- .../users-guide-utilities-examples.adoc | 19 + doc/users-guide/users-guide.adoc | 2 + platform/linux-generic/Makefile.am | 2 + platform/linux-generic/include/odp_internal.h | 6 +- .../linux-generic/include/odp_packet_io_internal.h | 9 + platform/linux-generic/include/odp_pcapng.h | 56 +++ platform/linux-generic/m4/configure.m4 | 1 + platform/linux-generic/m4/odp_pcapng.m4 | 18 + platform/linux-generic/odp_packet_io.c | 54 ++- platform/linux-generic/odp_pcapng.c | 434 +++++++++++++++++++++ 13 files changed, 599 insertions(+), 7 deletions(-) create mode 100644 doc/users-guide/users-guide-utilities-examples.adoc create mode 100644 platform/linux-generic/include/odp_pcapng.h create mode 100644 platform/linux-generic/m4/odp_pcapng.m4 create mode 100644 platform/linux-generic/odp_pcapng.c
hooks/post-receive