From patchwork Mon Oct 7 16:52:31 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Stephen Hemminger X-Patchwork-Id: 60651 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id B61FE1D37D; Mon, 7 Oct 2019 18:52:58 +0200 (CEST) Received: from mail-pf1-f196.google.com (mail-pf1-f196.google.com [209.85.210.196]) by dpdk.org (Postfix) with ESMTP id 204641D159 for ; Mon, 7 Oct 2019 18:52:50 +0200 (CEST) Received: by mail-pf1-f196.google.com with SMTP id b128so9054134pfa.1 for ; Mon, 07 Oct 2019 09:52:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=networkplumber-org.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=QGhlsAZUTXIfdCmzS6vHhtVgwqGoDe7ZxIOrTe28vBw=; b=bOr8Bufxlyb/nQ86ugFwuofk2ADUFjfyReS0pbHp9qk7MfPR3sfQrqUJAwnAqrX0OB anQUQDOVBsPG0uqsmaiWDT80mtpUU2yVn9E7IPO0Bc6FsCHPpgrn0pJ++iXo045USpcf jgfzWm9+9ZOgwjeGkwq67dpiRGVl1Q0Cbcu/2KKx2BZ6gcRBmAtjqfzNq7TN9WTZ9lYb RSAsfKc4Kz/YNRzTn9UIj1C9Hm4ohSmNx8nzUh6dldeP9djAxOwUmwWzmVrHLz9yjUMS k1Ld7VHXontsnifXWkty1kpqVdAVvKx8q3TFHiioMOOsxW9ugFFEBIXpi0PtQgAGduFq h4Ow== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=QGhlsAZUTXIfdCmzS6vHhtVgwqGoDe7ZxIOrTe28vBw=; b=rszpDMg5q6sjQdoBk0SYhBVahSt8XCLqMemUctABm3JJroz0oIwySMFwZcIUonJQGC dFXOcWDydW6bhBQoev5bBvxYYcd1n4H9wPZB8F3PwIR9/kCZDH9hZojtB5IFv67NXPkM 9JppuPW4rWr9aRr1XLIp+ZFlqgD5BQ24oOM0ijOdLE4Z1lbFprjOBRoEWa19x3/swE6G xARKTSxVIQyLXGfP9Y54DteUFyBTCRJPP40mHPpgpwrPOSLiTQTYFKUCPuN2gS3jwWto Af/reHjjKxgQ5zzZHJ8BR4hu/aaQruB/CpiFOYxwZfc3vCnzQCryl0Q5VYrRj7GpX/lg u6yg== X-Gm-Message-State: APjAAAWrDrdf10CRa6qc/FUfGYQLTdpIJ6ht+MT5hY1qQ/emFP2+9jc2 CEagFtVtg47zGtxCEAO2Jua1zYdvqXor8Q== X-Google-Smtp-Source: APXvYqx6K6/BijNJUlptzNeH4KS07G3GtQbxW0NuBEzr/cS588LElgC89T+mvQZUQsUPkm7pyEBnHQ== X-Received: by 2002:a62:cd41:: with SMTP id o62mr1937432pfg.94.1570467168642; Mon, 07 Oct 2019 09:52:48 -0700 (PDT) Received: from hermes.lan (204-195-22-127.wavecable.com. [204.195.22.127]) by smtp.gmail.com with ESMTPSA id w5sm15920979pfn.96.2019.10.07.09.52.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Oct 2019 09:52:47 -0700 (PDT) From: Stephen Hemminger To: dev@dpdk.org Cc: Stephen Hemminger Date: Mon, 7 Oct 2019 09:52:31 -0700 Message-Id: <20191007165232.14535-8-stephen@networkplumber.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191007165232.14535-1-stephen@networkplumber.org> References: <20191007165232.14535-1-stephen@networkplumber.org> MIME-Version: 1.0 Subject: [dpdk-dev] [RFC 7/8] pcapng: add new library for writing pcapng files X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Simple library for formatting pcapng files used by wireshark and other programs. See PCAP next generation file format specification https://github.com/pcapng/pcapng Signed-off-by: Stephen Hemminger --- config/common_base | 6 + lib/Makefile | 2 + lib/librte_pcapng/Makefile | 22 ++ lib/librte_pcapng/meson.build | 10 + lib/librte_pcapng/pcapng_proto.h | 112 ++++++ lib/librte_pcapng/rte_pcapng.c | 449 +++++++++++++++++++++++ lib/librte_pcapng/rte_pcapng.h | 132 +++++++ lib/librte_pcapng/rte_pcapng_version.map | 12 + lib/meson.build | 2 +- mk/rte.app.mk | 1 + 10 files changed, 747 insertions(+), 1 deletion(-) create mode 100644 lib/librte_pcapng/Makefile create mode 100644 lib/librte_pcapng/meson.build create mode 100644 lib/librte_pcapng/pcapng_proto.h create mode 100644 lib/librte_pcapng/rte_pcapng.c create mode 100644 lib/librte_pcapng/rte_pcapng.h create mode 100644 lib/librte_pcapng/rte_pcapng_version.map diff --git a/config/common_base b/config/common_base index 8ef75c2039a2..0ccfcfae377d 100644 --- a/config/common_base +++ b/config/common_base @@ -998,6 +998,12 @@ CONFIG_RTE_KNI_PREEMPT_DEFAULT=y # CONFIG_RTE_LIBRTE_PDUMP=y +# +# Compile the pcapng library +# +CONFIG_RTE_LIBRTE_PCAPNG=y + +# # # Compile vhost user library # diff --git a/lib/Makefile b/lib/Makefile index 41c463d92139..47786030fade 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -102,6 +102,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_REORDER) += librte_reorder DEPDIRS-librte_reorder := librte_eal librte_mempool librte_mbuf DIRS-$(CONFIG_RTE_LIBRTE_PDUMP) += librte_pdump DEPDIRS-librte_pdump := librte_eal librte_mempool librte_mbuf librte_ethdev +DIRS-$(CONFIG_RTE_LIBRTE_PCAPNG) += librte_pcapng +DEPDIRS-librte_pcapng := librte_eal librte_mbuf librte_ethdev librte_net DIRS-$(CONFIG_RTE_LIBRTE_GSO) += librte_gso DEPDIRS-librte_gso := librte_eal librte_mbuf librte_ethdev librte_net DEPDIRS-librte_gso += librte_mempool diff --git a/lib/librte_pcapng/Makefile b/lib/librte_pcapng/Makefile new file mode 100644 index 000000000000..eaf3e85e3ad2 --- /dev/null +++ b/lib/librte_pcapng/Makefile @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2019 Microsoft Corporation + +include $(RTE_SDK)/mk/rte.vars.mk + +# library name +LIB = librte_pcapng.a + +CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3 +CFLAGS += -DALLOW_EXPERIMENTAL_API + +EXPORT_MAP := rte_pcapng_version.map + +LIBABIVER := 1 + +# all source are stored in SRCS-y +SRCS-$(CONFIG_RTE_LIBRTE_PCAPNG) := rte_pcapng.c + +# install includes +SYMLINK-$(CONFIG_RTE_LIBRTE_MBUF)-include := rte_pcapng.h + +include $(RTE_SDK)/mk/rte.lib.mk diff --git a/lib/librte_pcapng/meson.build b/lib/librte_pcapng/meson.build new file mode 100644 index 000000000000..7904b4759b00 --- /dev/null +++ b/lib/librte_pcapng/meson.build @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2019 Microsoft Corporation + +version = 1 +sources = files('rte_pcapng.c') +headers = files('rte_pcapng.h') + +allow_experimental_apis = true + +deps += ['ethdev'] diff --git a/lib/librte_pcapng/pcapng_proto.h b/lib/librte_pcapng/pcapng_proto.h new file mode 100644 index 000000000000..8f35bc31d979 --- /dev/null +++ b/lib/librte_pcapng/pcapng_proto.h @@ -0,0 +1,112 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Microsoft Corporation + * + * Pcapng protocol data structures + * from Draft RFC + */ + +enum pcapng_block_types { + PCAPNG_INTERFACE_BLOCK = 1, + PCAPNG_PACKET_BLOCK, /* Obsolete */ + PCAPNG_SIMPLE_PACKET_BLOCK, + PCAPNG_NAME_RESOLUTION_BLOCK, + PCAPNG_INTERFACE_STATS_BLOCK, + PCAPNG_ENHANCED_PACKET_BLOCK, + + PCAPNG_SECTION_BLOCK = 0x0A0D0D0A, +}; + +struct pcapng_option { + uint16_t code; + uint16_t length; + uint8_t data[]; +}; + +#define PCAPNG_BYTE_ORDER_MAGIC 0x1A2B3C4D +#define PCAPNG_MAJOR_VERS 1 +#define PCAPNG_MINOR_VERS 0 + +enum pcapng_opt { + PCAPNG_OPT_END = 0, + PCAPNG_OPT_COMMENT = 1, +}; + +struct pcapng_section_header { + uint32_t block_type; + uint32_t block_length; + uint32_t byte_order_magic; + uint16_t major_version; + uint16_t minor_version; + uint64_t section_length; +}; + +enum pcapng_section_opt { + PCAPNG_SHB_HARDWARE = 2, + PCAPNG_SHB_OS = 3, + PCAPNG_SHB_USERAPPL = 4, +}; + +struct pcapng_interface_block { + uint32_t block_type; /* 1 */ + uint32_t block_length; + uint16_t link_type; + uint16_t reserved; + uint32_t snap_len; +}; + +enum pcapng_interface_options { + PCAPNG_IFB_NAME = 2, + PCAPNG_IFB_DESCRIPTION, + PCAPNG_IFB_IPV4ADDR, + PCAPNG_IFB_IPV6ADDR, + PCAPNG_IFB_MACADDR, + PCAPNG_IFB_EUIADDR, + PCAPNG_IFB_SPEED, + PCAPNG_IFB_TSRESOL, + PCAPNG_IFB_TZONE, + PCAPNG_IFB_FILTER, + PCAPNG_IFB_OS, + PCAPNG_IFB_FCSLEN, + PCAPNG_IFB_TSOFFSET, + PCAPNG_IFB_HARDWARE, +}; + +struct pcapng_enhance_packet_block { + uint32_t block_type; /* 6 */ + uint32_t block_length; + uint32_t interface_id; + uint32_t timestamp_hi; + uint32_t timestamp_lo; + uint32_t capture_length; + uint32_t original_length; +}; + +enum pcapng_epb_options { + PCAPNG_EPB_FLAGS = 2, + PCAPNG_EPB_HASH, + PCAPNG_EPB_DROPS +}; + +struct pcapng_simple_packet { + uint32_t block_type; /* 3 */ + uint32_t block_length; + uint32_t packet_length; +}; + +struct pcapng_statistics { + uint32_t block_type; /* 5 */ + uint32_t block_length; + uint32_t interface_id; + uint32_t timestamp_hi; + uint32_t timestamp_lo; +}; + +enum pcapng_isb_options { + PCAPNG_ISB_STARTTIME = 2, + PCAPNG_ISB_ENDTIME, + PCAPNG_ISB_IFRECV, + PCAPNG_ISB_IFDROP, + PCAPNG_ISB_FILTERACCEPT, + PCAPNG_ISB_OSDROP, + PCAPNG_ISB_USRDELIV +}; diff --git a/lib/librte_pcapng/rte_pcapng.c b/lib/librte_pcapng/rte_pcapng.c new file mode 100644 index 000000000000..2beb3c24f882 --- /dev/null +++ b/lib/librte_pcapng/rte_pcapng.c @@ -0,0 +1,449 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2019 Microsoft Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "pcapng_proto.h" + +/* conversion from DPDK speed to PCAPNG */ +#define PCAPNG_MBPS_SPEED 1000000ull + +#define PCAPNG_MAX_COMMENT 256 + +#define NS_PER_US 1000ul +#define US_PER_SEC 1000ul +#define NS_PER_SEC (NS_PER_US * US_PER_SEC) + +/* Private state for the library */ +struct rte_pcapng { + int outfd; /* output file */ + + uint64_t tsc_t0; /* TSC cycles when opened */ + uint32_t tsc_per_us; /* TSC cycles per microsecond */ + uint64_t tsc_offset; /* nanosecond since 1970 */ + + uint32_t next_index; + uint32_t port_index[RTE_MAX_ETHPORTS]; +}; + +/* length of option including padding */ +static size_t pcapng_optlen(uint16_t len) +{ + return RTE_ALIGN(sizeof(struct pcapng_option) + len, + sizeof(uint32_t)); +} + +/* build TLV option and return location of next */ +static struct pcapng_option * +pcapng_add_option(struct pcapng_option *popt, uint16_t code, + const void *data, uint16_t len) +{ + popt->code = code; + popt->length = len; + memcpy(popt->data, data, len); + + return (struct pcapng_option *)((uint8_t *)popt + pcapng_optlen(len)); +} + +/* + * Convert from DPDK timestamp (tsc cycles) + * to what Pcapng uses (nanosecond since 1 Jan 1970 UTC) + */ +static inline uint64_t tsc_to_timestamp(const rte_pcapng_t *self, + uint64_t tsc) +{ + uint64_t ticks = tsc - self->tsc_t0; + + return (ticks * NS_PER_US) / self->tsc_per_us + self->tsc_offset; +} + +/* + * Write required initial section header describing the capture + */ +static int +write_section_block(rte_pcapng_t *self, + const char *os, const char *hw, + const char *app, const char *comment) +{ + struct pcapng_section_header *hdr; + struct pcapng_option *opt; + void *buf; + size_t len; + ssize_t cc; + + len = sizeof(*hdr); + if (hw) + len += pcapng_optlen(strlen(hw)); + if (os) + len += pcapng_optlen(strlen(os)); + if (app) + len += pcapng_optlen(strlen(app)); + if (comment) + len += pcapng_optlen(strlen(comment)); + + len += pcapng_optlen(0); + len += sizeof(uint32_t); + + buf = calloc(1, len); + if (!buf) + return -1; + + hdr = (struct pcapng_section_header *)buf; + *hdr = (struct pcapng_section_header) { + .block_type = PCAPNG_SECTION_BLOCK, + .block_length = len, + .byte_order_magic = PCAPNG_BYTE_ORDER_MAGIC, + .major_version = PCAPNG_MAJOR_VERS, + .minor_version = PCAPNG_MINOR_VERS, + .section_length = UINT64_MAX, + }; + hdr->block_length = len; + + opt = (struct pcapng_option *)(hdr + 1); + if (comment) + opt = pcapng_add_option(opt, PCAPNG_OPT_COMMENT, + comment, strlen(comment)); + if (hw) + opt = pcapng_add_option(opt, PCAPNG_SHB_HARDWARE, + hw, strlen(hw)); + if (os) + opt = pcapng_add_option(opt, PCAPNG_SHB_OS, + os, strlen(os)); + if (app) + opt = pcapng_add_option(opt, PCAPNG_SHB_USERAPPL, + app, strlen(app)); + + opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0); + /* clone block_length after option */ + memcpy(opt, &hdr->block_length, sizeof(uint32_t)); + + cc = write(self->outfd, buf, len); + free(buf); + + return cc; +} + +static int +capture_header(rte_pcapng_t *self, + const char *os, const char *hw, + const char *app, const char *comment) +{ + char osbuf[256]; + + if (app == NULL) { + errno = EINVAL; + return -1; + } + + if (os == NULL) { + struct utsname uts; + + uname(&uts); + snprintf(osbuf, sizeof(osbuf), + "%s %s", uts.sysname, uts.release); + os = osbuf; + } + + if (hw == NULL) + hw = rte_version(); + + if (write_section_block(self, os, hw, app, comment) > 0) + return 0; + else + return -1; +} + +static ssize_t +write_interface_block(rte_pcapng_t *self, const char *if_name, + uint64_t if_speed, const uint8_t *mac_addr, + const char *if_hw, const char *comment) +{ + struct pcapng_interface_block *hdr; + struct pcapng_option *opt; + const uint8_t tsresol = 9; /* nanosecond resolution */ + size_t len = sizeof(*hdr); + ssize_t cc; + void *buf; + + len += pcapng_optlen(sizeof(tsresol)); + if (if_name) + len += pcapng_optlen(strlen(if_name)); + if (mac_addr) + len += pcapng_optlen(6); + if (if_speed) + len += pcapng_optlen(sizeof(uint64_t)); + if (if_hw) + len += pcapng_optlen(strlen(if_hw)); + if (comment) + len += pcapng_optlen(strlen(comment)); + + len += pcapng_optlen(0); + len += sizeof(uint32_t); + buf = calloc(1, len); + if (!buf) + return -ENOMEM; + + hdr = (struct pcapng_interface_block *)buf; + hdr->block_type = PCAPNG_INTERFACE_BLOCK; + hdr->link_type = 1; /* Ethernet */ + hdr->block_length = len; + + opt = (struct pcapng_option *)(hdr + 1); + if (if_name) + opt = pcapng_add_option(opt, PCAPNG_IFB_NAME, + if_name, strlen(if_name)); + if (mac_addr) + opt = pcapng_add_option(opt, PCAPNG_IFB_MACADDR, + mac_addr, RTE_ETHER_ADDR_LEN); + if (if_speed) + opt = pcapng_add_option(opt, PCAPNG_IFB_SPEED, + &if_speed, sizeof(uint64_t)); + opt = pcapng_add_option(opt, PCAPNG_IFB_TSRESOL, + &tsresol, sizeof(tsresol)); + if (if_hw) + opt = pcapng_add_option(opt, PCAPNG_IFB_HARDWARE, + if_hw, strlen(if_hw)); + if (comment) + opt = pcapng_add_option(opt, PCAPNG_OPT_COMMENT, + comment, strlen(comment)); + + opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0); + + memcpy(opt, &hdr->block_length, sizeof(uint32_t)); + cc = write(self->outfd, buf, len); + free(buf); + + return cc; +} + +int +rte_pcapng_add_interface(rte_pcapng_t *self, uint16_t port, + const char *comment, uint32_t flags) +{ + struct rte_eth_dev_info dev_info; + struct rte_ether_addr macaddr; + const struct rte_device *dev; + struct rte_eth_link link; + char ifname[IF_NAMESIZE]; + char ifhw[256]; + uint64_t speed = 0; + int cc; + + if (flags != 0) { + rte_errno = EINVAL; + return -1; + } + + rte_eth_dev_info_get(port, &dev_info); + + /* make something like an interface name */ + if (if_indextoname(dev_info.if_index, ifname) == NULL) + snprintf(ifname, IF_NAMESIZE, "dpdk:%u", port); + + /* make a useful device hardware string */ + dev = dev_info.device; + if (dev) + snprintf(ifhw, sizeof(ifhw), + "%s-%s", dev->bus->name, dev->name); + + /* DPDK reports in units of Mbps */ + rte_eth_link_get(port, &link); + if (link.link_status == ETH_LINK_UP) + speed = link.link_speed * PCAPNG_MBPS_SPEED; + + rte_eth_macaddr_get(port, &macaddr); + + cc = write_interface_block(self, ifname, speed, + macaddr.addr_bytes, + dev ? ifhw : NULL, + comment); + if (cc < 0) { + rte_errno = errno; + return -1; + } + + self->port_index[port] = self->next_index++; + return 0; +} + +/* Create new pcapng writer handle */ +rte_pcapng_t * +rte_pcapng_fdopen(int fd, + const char *osname, const char *hardware, + const char *appname, const char *comment, + uint32_t flags) +{ + rte_pcapng_t *self; + struct timeval tv; + + if (flags != 0) { + rte_errno = EINVAL; + return NULL; + } + + self = rte_zmalloc("pcapng", sizeof(*self), 0); + if (!self) { + rte_errno = ENOMEM; + return NULL; + } + + self->outfd = fd; + + /* compute clock offsets */ + self->tsc_t0 = rte_rdtsc(); + self->tsc_per_us = rte_get_tsc_hz() / US_PER_SEC; + gettimeofday(&tv, NULL); + self->tsc_offset = (tv.tv_sec * US_PER_SEC + tv.tv_usec) * NS_PER_US; + + if (capture_header(self, osname, hardware, + appname, comment) < 0) + goto error; + + return self; + +error: + close(self->outfd); + rte_errno = errno; + rte_free(self); + return NULL; +} + +void +rte_pcapng_close(rte_pcapng_t *self) +{ + close(self->outfd); + rte_free(self); +} + +int +rte_pcapng_dump_packet(rte_pcapng_t *self, uint16_t port, + const struct rte_mbuf *m, + enum rte_pcapng_direction dir, + const char *comment) +{ + struct pcapng_enhance_packet_block hdr; + uint32_t snap_len, padded_len, pad_bytes; + uint64_t ts = tsc_to_timestamp(self, m->timestamp); + static uint64_t zero_pad; + struct pcapng_option *opt; + uint32_t flags = dir; + uint32_t options[512]; + uint16_t i; + struct iovec iov[m->nb_segs + 4]; + size_t len, optlen; + +#ifdef RTE_LIBRTE_ETHDEV_DEBUG + RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL); +#endif + /* only handle single segment mbuf */ + snap_len = rte_pktmbuf_data_len(m); + padded_len = RTE_ALIGN(snap_len, sizeof(uint32_t)); + pad_bytes = padded_len - snap_len; + + len = sizeof(hdr) + padded_len + sizeof(uint32_t); + opt = (struct pcapng_option *)options; + + opt = pcapng_add_option(opt, PCAPNG_EPB_FLAGS, + &flags, sizeof(flags)); + + if (comment) + opt = pcapng_add_option(opt, PCAPNG_OPT_COMMENT, comment, + strnlen(comment, PCAPNG_MAX_COMMENT)); + + optlen = (char *)opt - (char *)options; + len += optlen; + + hdr.block_type = PCAPNG_ENHANCED_PACKET_BLOCK; + hdr.block_length = len; + + hdr.interface_id = self->port_index[port]; + hdr.timestamp_hi = ts >> 32; + hdr.timestamp_lo = (uint32_t)ts; + hdr.capture_length = snap_len; + hdr.original_length = rte_pktmbuf_pkt_len(m); + + iov[0].iov_base = &hdr; + iov[0].iov_len = sizeof(hdr); + + for (i = 1; m; ++i, m = m->next) { + iov[i].iov_base = rte_pktmbuf_mtod(m, void *); + iov[i].iov_len = rte_pktmbuf_data_len(m); + } + + if (pad_bytes > 0) { + iov[i].iov_base = &zero_pad; + iov[i].iov_len = pad_bytes; + ++i; + } + + iov[i].iov_base = options; + iov[i].iov_len = optlen; + ++i; + + iov[i].iov_base = &hdr.block_length; + iov[i].iov_len = sizeof(uint32_t); + ++i; + + if (unlikely(writev(self->outfd, iov, i) < 0)) { + rte_errno = errno; + return -1; + } + + return 0; +} + +int +rte_pcapng_dump_tx(rte_pcapng_t *out, uint16_t port, + struct rte_mbuf *pkts[], uint32_t nb_pkts) +{ + uint32_t i; + int r = 0; + + for (i = 0; i < nb_pkts; i++) { + struct rte_mbuf *m = pkts[i]; + + r = rte_pcapng_dump_packet(out, port, m, + RTE_PCAPNG_DIR_OUTBOUND, NULL); + if (unlikely(r < 0)) + break; + } + + return r; +} + +int +rte_pcapng_dump_rx(rte_pcapng_t *out, + struct rte_mbuf *pkts[], uint32_t nb_pkts) +{ + uint32_t i; + int r = 0; + + for (i = 0; i < nb_pkts; i++) { + struct rte_mbuf *m = pkts[i]; + + r = rte_pcapng_dump_packet(out, m->port, m, + RTE_PCAPNG_DIR_INBOUND, NULL); + if (unlikely(r < 0)) + break; + } + return r; +} diff --git a/lib/librte_pcapng/rte_pcapng.h b/lib/librte_pcapng/rte_pcapng.h new file mode 100644 index 000000000000..23763c6882c8 --- /dev/null +++ b/lib/librte_pcapng/rte_pcapng.h @@ -0,0 +1,132 @@ +/* + * Simple library to write files in Pcap-ng format. + * Copyright(c) 2019 Microsoft Corporation + * All rights reserved. + */ + + +/* Handle used for functions in this library. */ +typedef struct rte_pcapng rte_pcapng_t; + +/** + * Open new packet capture file + * + * @param fd + * file descriptor + * @param osname + * Operating system name. + * If NULL will be filled in based on result of utsname. + * @param hardware + * Hardware information. + * If NULL will be filled in with DPDK version. + * @param appname + * Applicaton name. + * @param comment + * Comment for the file (optional can be NULL) + * @param flags + * Options for capture (reserved must be 0) + * @return + * handle to library, or NULL in case of error (and rte_errno is set). + */ +__rte_experimental +rte_pcapng_t * +rte_pcapng_fdopen(int fd, + const char *osname, const char *hardware, + const char *appname, const char *comment, + uint32_t flags); + + +enum rte_pcapng_direction { + RTE_PCAPNG_DIR_UNKNOWN = 0, + RTE_PCAPNG_DIR_INBOUND = 1, + RTE_PCAPNG_DIR_OUTBOUND = 2, +}; + +/** + * Add interface to capture file + * This must be done after opening and before dumping any packets. + * Call once for each port being followed. + * + * @param out + * The handle to the packet capture file + * @param port + * The Ethernet port being captured. + * @param comment + * Comment for the file (optional can be NULL) + * @param flags + * Options for capture (reserved must be 0) + * @return + * 0 on success, -1 on failure (and rte_errno is set). + */ +__rte_experimental +int +rte_pcapng_add_interface(rte_pcapng_t *self, uint16_t port, + const char *comment, uint32_t flags); + +/** + * Record packet in capture file + * + * @param out + * The handle to the packet capture file + * @param port + * The Ethernet port on which the packet is being sent. + * @param m + * The packet to record + * @param dir + * Direction in/out or unknown + * @param comment + * Comment to add to record + * @return + * 0 on success, -1 on failure + */ +__rte_experimental +int +rte_pcapng_dump_packet(rte_pcapng_t *self, uint16_t port, + const struct rte_mbuf *m, + enum rte_pcapng_direction dir, + const char *comment); +/** + * Dump packets to be transmitted. + * + * @param out + * The handle to the packet capture file + * @param port_id + * The Ethernet port on which the packet is being sent. + * @param pkts + * The packets to be recorded. + * @param nb_pkts + * The number of packets in the burst pointed to by "pkts". + * @return + * 0 on success, -1 on failure (and rte_errno is set). + */ +__rte_experimental +int +rte_pcapng_dump_tx(rte_pcapng_t *out, uint16_t port, + struct rte_mbuf *pkts[], uint32_t nb_pkts); + +/** + * Dump a packets received. + * + * @param out + * The handle to the packet capture file + * @param pkts + * The packets to be recorded. + * @param nb_pkts + * The number of packets in the burst pointed to by "pkts". + * @return + * 0 on success, -1 on failure (and rte_errno is set). + */ +__rte_experimental +int +rte_pcapng_dump_rx(rte_pcapng_t *out, + struct rte_mbuf *pkts[], uint32_t nb_pkts); + +/** + * Close capture file + * + * @param self + * handle to library + */ +__rte_experimental +void +rte_pcapng_close(rte_pcapng_t *self); diff --git a/lib/librte_pcapng/rte_pcapng_version.map b/lib/librte_pcapng/rte_pcapng_version.map new file mode 100644 index 000000000000..eb8ae2b50984 --- /dev/null +++ b/lib/librte_pcapng/rte_pcapng_version.map @@ -0,0 +1,12 @@ +EXPERIMENTAL { + global: + + rte_pcapng_fdopen; + rte_pcapng_add_interface; + rte_pcapng_dump_packet; + rte_pcapng_dump_tx; + rte_pcapng_dump_rx; + rte_pcapng_close; + + local: *; +}; diff --git a/lib/meson.build b/lib/meson.build index e5ff83893489..cb07e38d8b58 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -21,7 +21,7 @@ libraries = [ 'distributor', 'efd', 'eventdev', 'gro', 'gso', 'ip_frag', 'jobstats', 'kni', 'latencystats', 'lpm', 'member', - 'power', 'pdump', 'rawdev', + 'power', 'pdump', 'rawdev', 'pcapng', 'rcu', 'reorder', 'sched', 'security', 'stack', 'vhost', # ipsec lib depends on net, crypto and security 'ipsec', diff --git a/mk/rte.app.mk b/mk/rte.app.mk index ba5c39e01957..b50b74ed6c99 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -42,6 +42,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_PORT) += -lrte_port _LDLIBS-$(CONFIG_RTE_LIBRTE_PORT) += --no-whole-archive _LDLIBS-$(CONFIG_RTE_LIBRTE_PDUMP) += -lrte_pdump +_LDLIBS-$(CONFIG_RTE_LIBRTE_PCAPNG) += -lrte_pcapng _LDLIBS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += -lrte_distributor _LDLIBS-$(CONFIG_RTE_LIBRTE_IP_FRAG) += -lrte_ip_frag _LDLIBS-$(CONFIG_RTE_LIBRTE_METER) += -lrte_meter