18d23ce8fSStephen Hemminger /* SPDX-License-Identifier: BSD-3-Clause 28d23ce8fSStephen Hemminger * Copyright(c) 2019 Microsoft Corporation 38d23ce8fSStephen Hemminger */ 48d23ce8fSStephen Hemminger 58d23ce8fSStephen Hemminger #include <errno.h> 6d2e3c4b8SStephen Hemminger #include <stdbool.h> 78d23ce8fSStephen Hemminger #include <stdio.h> 88d23ce8fSStephen Hemminger #include <stdlib.h> 98d23ce8fSStephen Hemminger #include <string.h> 108d23ce8fSStephen Hemminger #include <time.h> 118d23ce8fSStephen Hemminger #include <unistd.h> 128d23ce8fSStephen Hemminger 13beb43124SStephen Hemminger #ifndef RTE_EXEC_ENV_WINDOWS 14beb43124SStephen Hemminger #include <net/if.h> 15beb43124SStephen Hemminger #include <sys/uio.h> 16beb43124SStephen Hemminger #endif 17beb43124SStephen Hemminger 18a04322f6SDavid Marchand #include <bus_driver.h> 198d23ce8fSStephen Hemminger #include <rte_common.h> 208d23ce8fSStephen Hemminger #include <rte_cycles.h> 211acb7f54SDavid Marchand #include <dev_driver.h> 228d23ce8fSStephen Hemminger #include <rte_errno.h> 238d23ce8fSStephen Hemminger #include <rte_ethdev.h> 248d23ce8fSStephen Hemminger #include <rte_ether.h> 258d23ce8fSStephen Hemminger #include <rte_mbuf.h> 26beb43124SStephen Hemminger #include <rte_os_shim.h> 278d23ce8fSStephen Hemminger #include <rte_pcapng.h> 28c882eb54SQuentin Armitage #include <rte_reciprocal.h> 298d23ce8fSStephen Hemminger #include <rte_time.h> 308d23ce8fSStephen Hemminger 318d23ce8fSStephen Hemminger #include "pcapng_proto.h" 328d23ce8fSStephen Hemminger 338d23ce8fSStephen Hemminger /* conversion from DPDK speed to PCAPNG */ 348d23ce8fSStephen Hemminger #define PCAPNG_MBPS_SPEED 1000000ull 358d23ce8fSStephen Hemminger 36*0cbf2752SStephen Hemminger /* upper bound for section, stats and interface blocks (in uint32_t) */ 37*0cbf2752SStephen Hemminger #define PCAPNG_BLKSIZ (2048 / sizeof(uint32_t)) 38dc2d6d20SStephen Hemminger 398d23ce8fSStephen Hemminger /* Format of the capture file handle */ 408d23ce8fSStephen Hemminger struct rte_pcapng { 418d23ce8fSStephen Hemminger int outfd; /* output file */ 42d1da6d0dSStephen Hemminger unsigned int ports; /* number of interfaces added */ 4316659193SStephen Hemminger uint64_t offset_ns; /* ns since 1/1/1970 when initialized */ 4416659193SStephen Hemminger uint64_t tsc_base; /* TSC when started */ 45d1da6d0dSStephen Hemminger 468d23ce8fSStephen Hemminger /* DPDK port id to interface index in file */ 478d23ce8fSStephen Hemminger uint32_t port_index[RTE_MAX_ETHPORTS]; 488d23ce8fSStephen Hemminger }; 498d23ce8fSStephen Hemminger 50beb43124SStephen Hemminger #ifdef RTE_EXEC_ENV_WINDOWS 51beb43124SStephen Hemminger /* 52beb43124SStephen Hemminger * Windows does not have writev() call. 53beb43124SStephen Hemminger * Emulate this by copying to a new buffer. 54beb43124SStephen Hemminger * The copy is necessary since pcapng needs to be thread-safe 55beb43124SStephen Hemminger * and do atomic write operations. 56beb43124SStephen Hemminger */ 57beb43124SStephen Hemminger 58beb43124SStephen Hemminger #define IOV_MAX 128 59beb43124SStephen Hemminger struct iovec { 60beb43124SStephen Hemminger void *iov_base; 61beb43124SStephen Hemminger size_t iov_len; 62beb43124SStephen Hemminger }; 63beb43124SStephen Hemminger 64beb43124SStephen Hemminger static ssize_t writev(int fd, const struct iovec *iov, int iovcnt) 65beb43124SStephen Hemminger { 66beb43124SStephen Hemminger size_t bytes = 0; 67beb43124SStephen Hemminger uint8_t *ptr; 68beb43124SStephen Hemminger void *tmp_buf; 69beb43124SStephen Hemminger ssize_t ret; 70beb43124SStephen Hemminger int i; 71beb43124SStephen Hemminger 72beb43124SStephen Hemminger for (i = 0; i < iovcnt; i++) 73beb43124SStephen Hemminger bytes += iov[i].iov_len; 74beb43124SStephen Hemminger 75beb43124SStephen Hemminger if (unlikely(bytes == 0)) 76beb43124SStephen Hemminger return 0; 77beb43124SStephen Hemminger 78beb43124SStephen Hemminger tmp_buf = malloc(bytes); 79beb43124SStephen Hemminger if (unlikely(tmp_buf == NULL)) { 80beb43124SStephen Hemminger errno = ENOMEM; 81beb43124SStephen Hemminger return -1; 82beb43124SStephen Hemminger } 83beb43124SStephen Hemminger 84beb43124SStephen Hemminger ptr = tmp_buf; 85beb43124SStephen Hemminger for (i = 0; i < iovcnt; i++) { 86beb43124SStephen Hemminger rte_memcpy(ptr, iov[i].iov_base, iov[i].iov_len); 87beb43124SStephen Hemminger ptr += iov[i].iov_len; 88beb43124SStephen Hemminger } 89beb43124SStephen Hemminger 90beb43124SStephen Hemminger ret = write(fd, tmp_buf, bytes); 91beb43124SStephen Hemminger free(tmp_buf); 92beb43124SStephen Hemminger return ret; 93beb43124SStephen Hemminger } 94beb43124SStephen Hemminger 95beb43124SStephen Hemminger #define IF_NAMESIZE 16 96beb43124SStephen Hemminger /* compatibility wrapper because name is optional */ 97beb43124SStephen Hemminger #define if_indextoname(ifindex, ifname) NULL 98beb43124SStephen Hemminger #endif 99beb43124SStephen Hemminger 10016659193SStephen Hemminger /* Convert from TSC (CPU cycles) to nanoseconds */ 10116659193SStephen Hemminger static uint64_t 10216659193SStephen Hemminger pcapng_timestamp(const rte_pcapng_t *self, uint64_t cycles) 1038d23ce8fSStephen Hemminger { 10416659193SStephen Hemminger uint64_t delta, rem, secs, ns; 10516659193SStephen Hemminger const uint64_t hz = rte_get_tsc_hz(); 1068d23ce8fSStephen Hemminger 10716659193SStephen Hemminger delta = cycles - self->tsc_base; 108c882eb54SQuentin Armitage 10916659193SStephen Hemminger /* Avoid numeric wraparound by computing seconds first */ 11016659193SStephen Hemminger secs = delta / hz; 11116659193SStephen Hemminger rem = delta % hz; 11216659193SStephen Hemminger ns = (rem * NS_PER_S) / hz; 1138d23ce8fSStephen Hemminger 11416659193SStephen Hemminger return secs * NS_PER_S + ns + self->offset_ns; 1158d23ce8fSStephen Hemminger } 1168d23ce8fSStephen Hemminger 1178d23ce8fSStephen Hemminger /* length of option including padding */ 1188d23ce8fSStephen Hemminger static uint16_t pcapng_optlen(uint16_t len) 1198d23ce8fSStephen Hemminger { 1208d23ce8fSStephen Hemminger return RTE_ALIGN(sizeof(struct pcapng_option) + len, 1218d23ce8fSStephen Hemminger sizeof(uint32_t)); 1228d23ce8fSStephen Hemminger } 1238d23ce8fSStephen Hemminger 1248d23ce8fSStephen Hemminger /* build TLV option and return location of next */ 1258d23ce8fSStephen Hemminger static struct pcapng_option * 1268d23ce8fSStephen Hemminger pcapng_add_option(struct pcapng_option *popt, uint16_t code, 1278d23ce8fSStephen Hemminger const void *data, uint16_t len) 1288d23ce8fSStephen Hemminger { 1298d23ce8fSStephen Hemminger popt->code = code; 1308d23ce8fSStephen Hemminger popt->length = len; 13106f69f8fSStephen Hemminger if (len > 0) 1328d23ce8fSStephen Hemminger memcpy(popt->data, data, len); 1338d23ce8fSStephen Hemminger 1348d23ce8fSStephen Hemminger return (struct pcapng_option *)((uint8_t *)popt + pcapng_optlen(len)); 1358d23ce8fSStephen Hemminger } 1368d23ce8fSStephen Hemminger 1378d23ce8fSStephen Hemminger /* 1388d23ce8fSStephen Hemminger * Write required initial section header describing the capture 1398d23ce8fSStephen Hemminger */ 1408d23ce8fSStephen Hemminger static int 1418d23ce8fSStephen Hemminger pcapng_section_block(rte_pcapng_t *self, 1428d23ce8fSStephen Hemminger const char *os, const char *hw, 1438d23ce8fSStephen Hemminger const char *app, const char *comment) 1448d23ce8fSStephen Hemminger { 1458d23ce8fSStephen Hemminger struct pcapng_section_header *hdr; 1468d23ce8fSStephen Hemminger struct pcapng_option *opt; 147*0cbf2752SStephen Hemminger uint32_t buf[PCAPNG_BLKSIZ]; 1488d23ce8fSStephen Hemminger uint32_t len; 1498d23ce8fSStephen Hemminger 1508d23ce8fSStephen Hemminger len = sizeof(*hdr); 1518d23ce8fSStephen Hemminger if (hw) 1528d23ce8fSStephen Hemminger len += pcapng_optlen(strlen(hw)); 1538d23ce8fSStephen Hemminger if (os) 1548d23ce8fSStephen Hemminger len += pcapng_optlen(strlen(os)); 1558d23ce8fSStephen Hemminger if (app) 1568d23ce8fSStephen Hemminger len += pcapng_optlen(strlen(app)); 1578d23ce8fSStephen Hemminger if (comment) 1588d23ce8fSStephen Hemminger len += pcapng_optlen(strlen(comment)); 1598d23ce8fSStephen Hemminger 1608d23ce8fSStephen Hemminger /* reserve space for OPT_END */ 1618d23ce8fSStephen Hemminger len += pcapng_optlen(0); 1628d23ce8fSStephen Hemminger len += sizeof(uint32_t); 1638d23ce8fSStephen Hemminger 164dc2d6d20SStephen Hemminger if (len > sizeof(buf)) 1658d23ce8fSStephen Hemminger return -1; 1668d23ce8fSStephen Hemminger 1678d23ce8fSStephen Hemminger hdr = (struct pcapng_section_header *)buf; 1688d23ce8fSStephen Hemminger *hdr = (struct pcapng_section_header) { 1698d23ce8fSStephen Hemminger .block_type = PCAPNG_SECTION_BLOCK, 1708d23ce8fSStephen Hemminger .block_length = len, 1718d23ce8fSStephen Hemminger .byte_order_magic = PCAPNG_BYTE_ORDER_MAGIC, 1728d23ce8fSStephen Hemminger .major_version = PCAPNG_MAJOR_VERS, 1738d23ce8fSStephen Hemminger .minor_version = PCAPNG_MINOR_VERS, 1748d23ce8fSStephen Hemminger .section_length = UINT64_MAX, 1758d23ce8fSStephen Hemminger }; 1768d23ce8fSStephen Hemminger 1778d23ce8fSStephen Hemminger /* After the section header insert variable length options. */ 1788d23ce8fSStephen Hemminger opt = (struct pcapng_option *)(hdr + 1); 1798d23ce8fSStephen Hemminger if (comment) 1808d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_OPT_COMMENT, 1818d23ce8fSStephen Hemminger comment, strlen(comment)); 1828d23ce8fSStephen Hemminger if (hw) 1838d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_SHB_HARDWARE, 1848d23ce8fSStephen Hemminger hw, strlen(hw)); 1858d23ce8fSStephen Hemminger if (os) 1868d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_SHB_OS, 1878d23ce8fSStephen Hemminger os, strlen(os)); 1888d23ce8fSStephen Hemminger if (app) 1898d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_SHB_USERAPPL, 1908d23ce8fSStephen Hemminger app, strlen(app)); 1918d23ce8fSStephen Hemminger 1928d23ce8fSStephen Hemminger /* The standard requires last option to be OPT_END */ 1938d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0); 1948d23ce8fSStephen Hemminger 1958d23ce8fSStephen Hemminger /* clone block_length after option */ 1968d23ce8fSStephen Hemminger memcpy(opt, &hdr->block_length, sizeof(uint32_t)); 1978d23ce8fSStephen Hemminger 198dc2d6d20SStephen Hemminger return write(self->outfd, buf, len); 1998d23ce8fSStephen Hemminger } 2008d23ce8fSStephen Hemminger 2018d23ce8fSStephen Hemminger /* Write an interface block for a DPDK port */ 202d1da6d0dSStephen Hemminger int 203d1da6d0dSStephen Hemminger rte_pcapng_add_interface(rte_pcapng_t *self, uint16_t port, 204d1da6d0dSStephen Hemminger const char *ifname, const char *ifdescr, 205d1da6d0dSStephen Hemminger const char *filter) 2068d23ce8fSStephen Hemminger { 2078d23ce8fSStephen Hemminger struct pcapng_interface_block *hdr; 2088d23ce8fSStephen Hemminger struct rte_eth_dev_info dev_info; 2098d23ce8fSStephen Hemminger struct rte_ether_addr *ea, macaddr; 2108d23ce8fSStephen Hemminger const struct rte_device *dev; 2118d23ce8fSStephen Hemminger struct rte_eth_link link; 2128d23ce8fSStephen Hemminger struct pcapng_option *opt; 2138d23ce8fSStephen Hemminger const uint8_t tsresol = 9; /* nanosecond resolution */ 2148d23ce8fSStephen Hemminger uint32_t len; 215*0cbf2752SStephen Hemminger uint32_t buf[PCAPNG_BLKSIZ]; 216d1da6d0dSStephen Hemminger char ifname_buf[IF_NAMESIZE]; 2178d23ce8fSStephen Hemminger char ifhw[256]; 2188d23ce8fSStephen Hemminger uint64_t speed = 0; 2198d23ce8fSStephen Hemminger 2208d23ce8fSStephen Hemminger if (rte_eth_dev_info_get(port, &dev_info) < 0) 2218d23ce8fSStephen Hemminger return -1; 2228d23ce8fSStephen Hemminger 2238d23ce8fSStephen Hemminger /* make something like an interface name */ 224d1da6d0dSStephen Hemminger if (ifname == NULL) { 225d1da6d0dSStephen Hemminger /* Use kernel name if available */ 226d1da6d0dSStephen Hemminger ifname = if_indextoname(dev_info.if_index, ifname_buf); 227d1da6d0dSStephen Hemminger if (ifname == NULL) { 228d1da6d0dSStephen Hemminger snprintf(ifname_buf, IF_NAMESIZE, "dpdk:%u", port); 229d1da6d0dSStephen Hemminger ifname = ifname_buf; 230d1da6d0dSStephen Hemminger } 231d1da6d0dSStephen Hemminger } 2328d23ce8fSStephen Hemminger 2338d23ce8fSStephen Hemminger /* make a useful device hardware string */ 2348d23ce8fSStephen Hemminger dev = dev_info.device; 2358d23ce8fSStephen Hemminger if (dev) 2368d23ce8fSStephen Hemminger snprintf(ifhw, sizeof(ifhw), 2378d23ce8fSStephen Hemminger "%s-%s", dev->bus->name, dev->name); 2388d23ce8fSStephen Hemminger 2398d23ce8fSStephen Hemminger /* DPDK reports in units of Mbps */ 240442878dbSStephen Hemminger if (rte_eth_link_get(port, &link) == 0 && 241442878dbSStephen Hemminger link.link_status == RTE_ETH_LINK_UP) 2428d23ce8fSStephen Hemminger speed = link.link_speed * PCAPNG_MBPS_SPEED; 2438d23ce8fSStephen Hemminger 2448d23ce8fSStephen Hemminger if (rte_eth_macaddr_get(port, &macaddr) < 0) 2458d23ce8fSStephen Hemminger ea = NULL; 2468d23ce8fSStephen Hemminger else 2478d23ce8fSStephen Hemminger ea = &macaddr; 2488d23ce8fSStephen Hemminger 2498d23ce8fSStephen Hemminger /* Compute length of interface block options */ 2508d23ce8fSStephen Hemminger len = sizeof(*hdr); 2518d23ce8fSStephen Hemminger 2528d23ce8fSStephen Hemminger len += pcapng_optlen(sizeof(tsresol)); /* timestamp */ 2538d23ce8fSStephen Hemminger len += pcapng_optlen(strlen(ifname)); /* ifname */ 2548d23ce8fSStephen Hemminger 255d1da6d0dSStephen Hemminger if (ifdescr) 256d1da6d0dSStephen Hemminger len += pcapng_optlen(strlen(ifdescr)); 2578d23ce8fSStephen Hemminger if (ea) 2588d23ce8fSStephen Hemminger len += pcapng_optlen(RTE_ETHER_ADDR_LEN); /* macaddr */ 2598d23ce8fSStephen Hemminger if (speed != 0) 2608d23ce8fSStephen Hemminger len += pcapng_optlen(sizeof(uint64_t)); 261d1da6d0dSStephen Hemminger if (filter) 262d1da6d0dSStephen Hemminger len += pcapng_optlen(strlen(filter) + 1); 2638d23ce8fSStephen Hemminger if (dev) 2648d23ce8fSStephen Hemminger len += pcapng_optlen(strlen(ifhw)); 2658d23ce8fSStephen Hemminger 2668d23ce8fSStephen Hemminger len += pcapng_optlen(0); 2678d23ce8fSStephen Hemminger len += sizeof(uint32_t); 2688d23ce8fSStephen Hemminger 269dc2d6d20SStephen Hemminger if (len > sizeof(buf)) 2708d23ce8fSStephen Hemminger return -1; 2718d23ce8fSStephen Hemminger 2728d23ce8fSStephen Hemminger hdr = (struct pcapng_interface_block *)buf; 2738d23ce8fSStephen Hemminger *hdr = (struct pcapng_interface_block) { 2748d23ce8fSStephen Hemminger .block_type = PCAPNG_INTERFACE_BLOCK, 2758d23ce8fSStephen Hemminger .link_type = 1, /* DLT_EN10MB - Ethernet */ 2768d23ce8fSStephen Hemminger .block_length = len, 2778d23ce8fSStephen Hemminger }; 2788d23ce8fSStephen Hemminger 2798d23ce8fSStephen Hemminger opt = (struct pcapng_option *)(hdr + 1); 2808d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_IFB_TSRESOL, 2818d23ce8fSStephen Hemminger &tsresol, sizeof(tsresol)); 2828d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_IFB_NAME, 2838d23ce8fSStephen Hemminger ifname, strlen(ifname)); 284d1da6d0dSStephen Hemminger if (ifdescr) 285d1da6d0dSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_IFB_DESCRIPTION, 286d1da6d0dSStephen Hemminger ifdescr, strlen(ifdescr)); 2878d23ce8fSStephen Hemminger if (ea) 2888d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_IFB_MACADDR, 2898d23ce8fSStephen Hemminger ea, RTE_ETHER_ADDR_LEN); 2908d23ce8fSStephen Hemminger if (speed != 0) 2918d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_IFB_SPEED, 2928d23ce8fSStephen Hemminger &speed, sizeof(uint64_t)); 2938d23ce8fSStephen Hemminger if (dev) 2948d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_IFB_HARDWARE, 2958d23ce8fSStephen Hemminger ifhw, strlen(ifhw)); 296d1da6d0dSStephen Hemminger if (filter) { 297d1da6d0dSStephen Hemminger size_t len; 298d1da6d0dSStephen Hemminger 299d1da6d0dSStephen Hemminger len = strlen(filter) + 1; 300dc2d6d20SStephen Hemminger opt->code = PCAPNG_IFB_FILTER; 301dc2d6d20SStephen Hemminger opt->length = len; 302dc2d6d20SStephen Hemminger /* Encoding is that the first octet indicates string vs BPF */ 303dc2d6d20SStephen Hemminger opt->data[0] = 0; 304dc2d6d20SStephen Hemminger memcpy(opt->data + 1, filter, strlen(filter)); 305d1da6d0dSStephen Hemminger 306dc2d6d20SStephen Hemminger opt = (struct pcapng_option *)((uint8_t *)opt + pcapng_optlen(len)); 307d1da6d0dSStephen Hemminger } 308d1da6d0dSStephen Hemminger 3098d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0); 3108d23ce8fSStephen Hemminger 3118d23ce8fSStephen Hemminger /* clone block_length after optionsa */ 3128d23ce8fSStephen Hemminger memcpy(opt, &hdr->block_length, sizeof(uint32_t)); 3138d23ce8fSStephen Hemminger 314d1da6d0dSStephen Hemminger /* remember the file index */ 315d1da6d0dSStephen Hemminger self->port_index[port] = self->ports++; 316d1da6d0dSStephen Hemminger 3178d23ce8fSStephen Hemminger return write(self->outfd, buf, len); 3188d23ce8fSStephen Hemminger } 3198d23ce8fSStephen Hemminger 3208d23ce8fSStephen Hemminger /* 3218d23ce8fSStephen Hemminger * Write an Interface statistics block at the end of capture. 3228d23ce8fSStephen Hemminger */ 3238d23ce8fSStephen Hemminger ssize_t 3248d23ce8fSStephen Hemminger rte_pcapng_write_stats(rte_pcapng_t *self, uint16_t port_id, 32516659193SStephen Hemminger uint64_t ifrecv, uint64_t ifdrop, 32616659193SStephen Hemminger const char *comment) 3278d23ce8fSStephen Hemminger { 3288d23ce8fSStephen Hemminger struct pcapng_statistics *hdr; 3298d23ce8fSStephen Hemminger struct pcapng_option *opt; 33016659193SStephen Hemminger uint64_t start_time = self->offset_ns; 33116659193SStephen Hemminger uint64_t sample_time; 3328d23ce8fSStephen Hemminger uint32_t optlen, len; 333*0cbf2752SStephen Hemminger uint32_t buf[PCAPNG_BLKSIZ]; 3348d23ce8fSStephen Hemminger 3358d23ce8fSStephen Hemminger RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL); 3368d23ce8fSStephen Hemminger 3378d23ce8fSStephen Hemminger optlen = 0; 3388d23ce8fSStephen Hemminger 3398d23ce8fSStephen Hemminger if (ifrecv != UINT64_MAX) 3408d23ce8fSStephen Hemminger optlen += pcapng_optlen(sizeof(ifrecv)); 3418d23ce8fSStephen Hemminger if (ifdrop != UINT64_MAX) 3428d23ce8fSStephen Hemminger optlen += pcapng_optlen(sizeof(ifdrop)); 34316659193SStephen Hemminger 3448d23ce8fSStephen Hemminger if (start_time != 0) 3458d23ce8fSStephen Hemminger optlen += pcapng_optlen(sizeof(start_time)); 34616659193SStephen Hemminger 3478d23ce8fSStephen Hemminger if (comment) 3488d23ce8fSStephen Hemminger optlen += pcapng_optlen(strlen(comment)); 3498d23ce8fSStephen Hemminger if (optlen != 0) 3508d23ce8fSStephen Hemminger optlen += pcapng_optlen(0); 3518d23ce8fSStephen Hemminger 3528d23ce8fSStephen Hemminger len = sizeof(*hdr) + optlen + sizeof(uint32_t); 353dc2d6d20SStephen Hemminger if (len > sizeof(buf)) 3548d23ce8fSStephen Hemminger return -1; 3558d23ce8fSStephen Hemminger 3568d23ce8fSStephen Hemminger hdr = (struct pcapng_statistics *)buf; 3578d23ce8fSStephen Hemminger opt = (struct pcapng_option *)(hdr + 1); 3588d23ce8fSStephen Hemminger 3598d23ce8fSStephen Hemminger if (comment) 3608d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_OPT_COMMENT, 3618d23ce8fSStephen Hemminger comment, strlen(comment)); 3628d23ce8fSStephen Hemminger if (start_time != 0) 3638d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_ISB_STARTTIME, 3648d23ce8fSStephen Hemminger &start_time, sizeof(start_time)); 3658d23ce8fSStephen Hemminger if (ifrecv != UINT64_MAX) 3668d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_ISB_IFRECV, 3678d23ce8fSStephen Hemminger &ifrecv, sizeof(ifrecv)); 3688d23ce8fSStephen Hemminger if (ifdrop != UINT64_MAX) 3698d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_ISB_IFDROP, 3708d23ce8fSStephen Hemminger &ifdrop, sizeof(ifdrop)); 3718d23ce8fSStephen Hemminger if (optlen != 0) 3728d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0); 3738d23ce8fSStephen Hemminger 3748d23ce8fSStephen Hemminger hdr->block_type = PCAPNG_INTERFACE_STATS_BLOCK; 3758d23ce8fSStephen Hemminger hdr->block_length = len; 3768d23ce8fSStephen Hemminger hdr->interface_id = self->port_index[port_id]; 3778d23ce8fSStephen Hemminger 37816659193SStephen Hemminger sample_time = pcapng_timestamp(self, rte_get_tsc_cycles()); 37916659193SStephen Hemminger hdr->timestamp_hi = sample_time >> 32; 38016659193SStephen Hemminger hdr->timestamp_lo = (uint32_t)sample_time; 3818d23ce8fSStephen Hemminger 3828d23ce8fSStephen Hemminger /* clone block_length after option */ 3838d23ce8fSStephen Hemminger memcpy(opt, &len, sizeof(uint32_t)); 3848d23ce8fSStephen Hemminger 3858d23ce8fSStephen Hemminger return write(self->outfd, buf, len); 3868d23ce8fSStephen Hemminger } 3878d23ce8fSStephen Hemminger 3888d23ce8fSStephen Hemminger uint32_t 3898d23ce8fSStephen Hemminger rte_pcapng_mbuf_size(uint32_t length) 3908d23ce8fSStephen Hemminger { 3918d23ce8fSStephen Hemminger /* The VLAN and EPB header must fit in the mbuf headroom. */ 3928d23ce8fSStephen Hemminger RTE_ASSERT(sizeof(struct pcapng_enhance_packet_block) + 3938d23ce8fSStephen Hemminger sizeof(struct rte_vlan_hdr) <= RTE_PKTMBUF_HEADROOM); 3948d23ce8fSStephen Hemminger 3958d23ce8fSStephen Hemminger /* The flags and queue information are added at the end. */ 3968d23ce8fSStephen Hemminger return sizeof(struct rte_mbuf) 3978d23ce8fSStephen Hemminger + RTE_ALIGN(length, sizeof(uint32_t)) 3988d23ce8fSStephen Hemminger + pcapng_optlen(sizeof(uint32_t)) /* flag option */ 3998d23ce8fSStephen Hemminger + pcapng_optlen(sizeof(uint32_t)) /* queue option */ 4008d23ce8fSStephen Hemminger + sizeof(uint32_t); /* length */ 4018d23ce8fSStephen Hemminger } 4028d23ce8fSStephen Hemminger 4038d23ce8fSStephen Hemminger /* More generalized version rte_vlan_insert() */ 4048d23ce8fSStephen Hemminger static int 4058d23ce8fSStephen Hemminger pcapng_vlan_insert(struct rte_mbuf *m, uint16_t ether_type, uint16_t tci) 4068d23ce8fSStephen Hemminger { 4078d23ce8fSStephen Hemminger struct rte_ether_hdr *nh, *oh; 4088d23ce8fSStephen Hemminger struct rte_vlan_hdr *vh; 4098d23ce8fSStephen Hemminger 4108d23ce8fSStephen Hemminger if (!RTE_MBUF_DIRECT(m) || rte_mbuf_refcnt_read(m) > 1) 4118d23ce8fSStephen Hemminger return -EINVAL; 4128d23ce8fSStephen Hemminger 4138d23ce8fSStephen Hemminger if (rte_pktmbuf_data_len(m) < sizeof(*oh)) 4148d23ce8fSStephen Hemminger return -EINVAL; 4158d23ce8fSStephen Hemminger 4168d23ce8fSStephen Hemminger oh = rte_pktmbuf_mtod(m, struct rte_ether_hdr *); 4178d23ce8fSStephen Hemminger nh = (struct rte_ether_hdr *) 4188d23ce8fSStephen Hemminger rte_pktmbuf_prepend(m, sizeof(struct rte_vlan_hdr)); 4198d23ce8fSStephen Hemminger if (nh == NULL) 4208d23ce8fSStephen Hemminger return -ENOSPC; 4218d23ce8fSStephen Hemminger 4228d23ce8fSStephen Hemminger memmove(nh, oh, 2 * RTE_ETHER_ADDR_LEN); 4238d23ce8fSStephen Hemminger nh->ether_type = rte_cpu_to_be_16(ether_type); 4248d23ce8fSStephen Hemminger 4258d23ce8fSStephen Hemminger vh = (struct rte_vlan_hdr *) (nh + 1); 4268d23ce8fSStephen Hemminger vh->vlan_tci = rte_cpu_to_be_16(tci); 4278d23ce8fSStephen Hemminger 4288d23ce8fSStephen Hemminger return 0; 4298d23ce8fSStephen Hemminger } 4308d23ce8fSStephen Hemminger 4318d23ce8fSStephen Hemminger /* 4328d23ce8fSStephen Hemminger * The mbufs created use the Pcapng standard enhanced packet block. 4338d23ce8fSStephen Hemminger * 4348d23ce8fSStephen Hemminger * 1 2 3 4358d23ce8fSStephen Hemminger * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 4368d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4378d23ce8fSStephen Hemminger * 0 | Block Type = 0x00000006 | 4388d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4398d23ce8fSStephen Hemminger * 4 | Block Total Length | 4408d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4418d23ce8fSStephen Hemminger * 8 | Interface ID | 4428d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4438d23ce8fSStephen Hemminger * 12 | Timestamp (High) | 4448d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4458d23ce8fSStephen Hemminger * 16 | Timestamp (Low) | 4468d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4478d23ce8fSStephen Hemminger * 20 | Captured Packet Length | 4488d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4498d23ce8fSStephen Hemminger * 24 | Original Packet Length | 4508d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4518d23ce8fSStephen Hemminger * 28 / / 4528d23ce8fSStephen Hemminger * / Packet Data / 4538d23ce8fSStephen Hemminger * / variable length, padded to 32 bits / 4548d23ce8fSStephen Hemminger * / / 4558d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4568d23ce8fSStephen Hemminger * | Option Code = 0x0002 | Option Length = 0x004 | 4578d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4588d23ce8fSStephen Hemminger * | Flags (direction) | 4598d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4608d23ce8fSStephen Hemminger * | Option Code = 0x0006 | Option Length = 0x002 | 4618d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4628d23ce8fSStephen Hemminger * | Queue id | 4638d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4648d23ce8fSStephen Hemminger * | Block Total Length | 4658d23ce8fSStephen Hemminger * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 4668d23ce8fSStephen Hemminger */ 4678d23ce8fSStephen Hemminger 4688d23ce8fSStephen Hemminger /* Make a copy of original mbuf with pcapng header and options */ 4698d23ce8fSStephen Hemminger struct rte_mbuf * 4708d23ce8fSStephen Hemminger rte_pcapng_copy(uint16_t port_id, uint32_t queue, 4718d23ce8fSStephen Hemminger const struct rte_mbuf *md, 4728d23ce8fSStephen Hemminger struct rte_mempool *mp, 47316659193SStephen Hemminger uint32_t length, 474c1abd1e9SAmit Prakash Shukla enum rte_pcapng_direction direction, 475c1abd1e9SAmit Prakash Shukla const char *comment) 4768d23ce8fSStephen Hemminger { 4778d23ce8fSStephen Hemminger struct pcapng_enhance_packet_block *epb; 4786db35853SOleksandr Nahnybida uint32_t orig_len, pkt_len, padding, flags; 4798d23ce8fSStephen Hemminger struct pcapng_option *opt; 48016659193SStephen Hemminger uint64_t timestamp; 481d2e3c4b8SStephen Hemminger uint16_t optlen; 4828d23ce8fSStephen Hemminger struct rte_mbuf *mc; 483d2e3c4b8SStephen Hemminger bool rss_hash; 4848d23ce8fSStephen Hemminger 4858d23ce8fSStephen Hemminger #ifdef RTE_LIBRTE_ETHDEV_DEBUG 4868d23ce8fSStephen Hemminger RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, NULL); 4878d23ce8fSStephen Hemminger #endif 4888d23ce8fSStephen Hemminger orig_len = rte_pktmbuf_pkt_len(md); 4898d23ce8fSStephen Hemminger 4908d23ce8fSStephen Hemminger /* Take snapshot of the data */ 4918d23ce8fSStephen Hemminger mc = rte_pktmbuf_copy(md, mp, 0, length); 4928d23ce8fSStephen Hemminger if (unlikely(mc == NULL)) 4938d23ce8fSStephen Hemminger return NULL; 4948d23ce8fSStephen Hemminger 4958d23ce8fSStephen Hemminger /* Expand any offloaded VLAN information */ 4968d23ce8fSStephen Hemminger if ((direction == RTE_PCAPNG_DIRECTION_IN && 497daa02b5cSOlivier Matz (md->ol_flags & RTE_MBUF_F_RX_VLAN_STRIPPED)) || 4988d23ce8fSStephen Hemminger (direction == RTE_PCAPNG_DIRECTION_OUT && 499daa02b5cSOlivier Matz (md->ol_flags & RTE_MBUF_F_TX_VLAN))) { 5008d23ce8fSStephen Hemminger if (pcapng_vlan_insert(mc, RTE_ETHER_TYPE_VLAN, 5018d23ce8fSStephen Hemminger md->vlan_tci) != 0) 5028d23ce8fSStephen Hemminger goto fail; 5038d23ce8fSStephen Hemminger } 5048d23ce8fSStephen Hemminger 5058d23ce8fSStephen Hemminger if ((direction == RTE_PCAPNG_DIRECTION_IN && 506daa02b5cSOlivier Matz (md->ol_flags & RTE_MBUF_F_RX_QINQ_STRIPPED)) || 5078d23ce8fSStephen Hemminger (direction == RTE_PCAPNG_DIRECTION_OUT && 508daa02b5cSOlivier Matz (md->ol_flags & RTE_MBUF_F_TX_QINQ))) { 5098d23ce8fSStephen Hemminger if (pcapng_vlan_insert(mc, RTE_ETHER_TYPE_QINQ, 5108d23ce8fSStephen Hemminger md->vlan_tci_outer) != 0) 5118d23ce8fSStephen Hemminger goto fail; 5128d23ce8fSStephen Hemminger } 5138d23ce8fSStephen Hemminger 514d2e3c4b8SStephen Hemminger /* record HASH on incoming packets */ 515d2e3c4b8SStephen Hemminger rss_hash = (direction == RTE_PCAPNG_DIRECTION_IN && 516d2e3c4b8SStephen Hemminger (md->ol_flags & RTE_MBUF_F_RX_RSS_HASH)); 517d2e3c4b8SStephen Hemminger 5188d23ce8fSStephen Hemminger /* pad the packet to 32 bit boundary */ 5196db35853SOleksandr Nahnybida pkt_len = rte_pktmbuf_pkt_len(mc); 5206db35853SOleksandr Nahnybida padding = RTE_ALIGN(pkt_len, sizeof(uint32_t)) - pkt_len; 5218d23ce8fSStephen Hemminger if (padding > 0) { 5228d23ce8fSStephen Hemminger void *tail = rte_pktmbuf_append(mc, padding); 5238d23ce8fSStephen Hemminger 5248d23ce8fSStephen Hemminger if (tail == NULL) 5258d23ce8fSStephen Hemminger goto fail; 5268d23ce8fSStephen Hemminger memset(tail, 0, padding); 5278d23ce8fSStephen Hemminger } 5288d23ce8fSStephen Hemminger 529d2e3c4b8SStephen Hemminger optlen = pcapng_optlen(sizeof(flags)); 530d2e3c4b8SStephen Hemminger optlen += pcapng_optlen(sizeof(queue)); 531d2e3c4b8SStephen Hemminger if (rss_hash) 532d2e3c4b8SStephen Hemminger optlen += pcapng_optlen(sizeof(uint8_t) + sizeof(uint32_t)); 533d2e3c4b8SStephen Hemminger 534c1abd1e9SAmit Prakash Shukla if (comment) 535c1abd1e9SAmit Prakash Shukla optlen += pcapng_optlen(strlen(comment)); 536c1abd1e9SAmit Prakash Shukla 5378d23ce8fSStephen Hemminger /* reserve trailing options and block length */ 5388d23ce8fSStephen Hemminger opt = (struct pcapng_option *) 5398d23ce8fSStephen Hemminger rte_pktmbuf_append(mc, optlen + sizeof(uint32_t)); 5408d23ce8fSStephen Hemminger if (unlikely(opt == NULL)) 5418d23ce8fSStephen Hemminger goto fail; 5428d23ce8fSStephen Hemminger 5438d23ce8fSStephen Hemminger switch (direction) { 5448d23ce8fSStephen Hemminger case RTE_PCAPNG_DIRECTION_IN: 5458d23ce8fSStephen Hemminger flags = PCAPNG_IFB_INBOUND; 5468d23ce8fSStephen Hemminger break; 5478d23ce8fSStephen Hemminger case RTE_PCAPNG_DIRECTION_OUT: 5488d23ce8fSStephen Hemminger flags = PCAPNG_IFB_OUTBOUND; 5498d23ce8fSStephen Hemminger break; 5508d23ce8fSStephen Hemminger default: 5518d23ce8fSStephen Hemminger flags = 0; 5528d23ce8fSStephen Hemminger } 5538d23ce8fSStephen Hemminger 5548d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_EPB_FLAGS, 5558d23ce8fSStephen Hemminger &flags, sizeof(flags)); 5568d23ce8fSStephen Hemminger 5578d23ce8fSStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_EPB_QUEUE, 5588d23ce8fSStephen Hemminger &queue, sizeof(queue)); 5598d23ce8fSStephen Hemminger 560d2e3c4b8SStephen Hemminger if (rss_hash) { 561d2e3c4b8SStephen Hemminger uint8_t hash_opt[5]; 562d2e3c4b8SStephen Hemminger 563d2e3c4b8SStephen Hemminger /* The algorithm could be something else if 564d2e3c4b8SStephen Hemminger * using rte_flow_action_rss; but the current API does not 565d2e3c4b8SStephen Hemminger * have a way for ethdev to report this on a per-packet basis. 566d2e3c4b8SStephen Hemminger */ 567d2e3c4b8SStephen Hemminger hash_opt[0] = PCAPNG_HASH_TOEPLITZ; 568d2e3c4b8SStephen Hemminger 569d2e3c4b8SStephen Hemminger memcpy(&hash_opt[1], &md->hash.rss, sizeof(uint32_t)); 570d2e3c4b8SStephen Hemminger opt = pcapng_add_option(opt, PCAPNG_EPB_HASH, 571d2e3c4b8SStephen Hemminger &hash_opt, sizeof(hash_opt)); 572d2e3c4b8SStephen Hemminger } 573d2e3c4b8SStephen Hemminger 574c1abd1e9SAmit Prakash Shukla if (comment) 575c1abd1e9SAmit Prakash Shukla opt = pcapng_add_option(opt, PCAPNG_OPT_COMMENT, comment, 576c1abd1e9SAmit Prakash Shukla strlen(comment)); 577c1abd1e9SAmit Prakash Shukla 5788d23ce8fSStephen Hemminger /* Note: END_OPT necessary here. Wireshark doesn't do it. */ 5798d23ce8fSStephen Hemminger 5808d23ce8fSStephen Hemminger /* Add PCAPNG packet header */ 5818d23ce8fSStephen Hemminger epb = (struct pcapng_enhance_packet_block *) 5828d23ce8fSStephen Hemminger rte_pktmbuf_prepend(mc, sizeof(*epb)); 5838d23ce8fSStephen Hemminger if (unlikely(epb == NULL)) 5848d23ce8fSStephen Hemminger goto fail; 5858d23ce8fSStephen Hemminger 5868d23ce8fSStephen Hemminger epb->block_type = PCAPNG_ENHANCED_PACKET_BLOCK; 5876db35853SOleksandr Nahnybida epb->block_length = rte_pktmbuf_pkt_len(mc); 5888d23ce8fSStephen Hemminger 5898d23ce8fSStephen Hemminger /* Interface index is filled in later during write */ 5908d23ce8fSStephen Hemminger mc->port = port_id; 5918d23ce8fSStephen Hemminger 59216659193SStephen Hemminger /* Put timestamp in cycles here - adjust in packet write */ 59316659193SStephen Hemminger timestamp = rte_get_tsc_cycles(); 59416659193SStephen Hemminger epb->timestamp_hi = timestamp >> 32; 59516659193SStephen Hemminger epb->timestamp_lo = (uint32_t)timestamp; 5966db35853SOleksandr Nahnybida epb->capture_length = pkt_len; 5978d23ce8fSStephen Hemminger epb->original_length = orig_len; 5988d23ce8fSStephen Hemminger 5998d23ce8fSStephen Hemminger /* set trailer of block length */ 6008d23ce8fSStephen Hemminger *(uint32_t *)opt = epb->block_length; 6018d23ce8fSStephen Hemminger 6028d23ce8fSStephen Hemminger return mc; 6038d23ce8fSStephen Hemminger 6048d23ce8fSStephen Hemminger fail: 6058d23ce8fSStephen Hemminger rte_pktmbuf_free(mc); 6068d23ce8fSStephen Hemminger return NULL; 6078d23ce8fSStephen Hemminger } 6088d23ce8fSStephen Hemminger 6098d23ce8fSStephen Hemminger /* Write pre-formatted packets to file. */ 6108d23ce8fSStephen Hemminger ssize_t 6118d23ce8fSStephen Hemminger rte_pcapng_write_packets(rte_pcapng_t *self, 6128d23ce8fSStephen Hemminger struct rte_mbuf *pkts[], uint16_t nb_pkts) 6138d23ce8fSStephen Hemminger { 6140744f1c9SMário Kuka struct iovec iov[IOV_MAX]; 6150744f1c9SMário Kuka unsigned int i, cnt = 0; 6160744f1c9SMário Kuka ssize_t ret, total = 0; 6178d23ce8fSStephen Hemminger 6180744f1c9SMário Kuka for (i = 0; i < nb_pkts; i++) { 6198d23ce8fSStephen Hemminger struct rte_mbuf *m = pkts[i]; 6208d23ce8fSStephen Hemminger struct pcapng_enhance_packet_block *epb; 62116659193SStephen Hemminger uint64_t cycles, timestamp; 6228d23ce8fSStephen Hemminger 6238d23ce8fSStephen Hemminger /* sanity check that is really a pcapng mbuf */ 6248d23ce8fSStephen Hemminger epb = rte_pktmbuf_mtod(m, struct pcapng_enhance_packet_block *); 6258d23ce8fSStephen Hemminger if (unlikely(epb->block_type != PCAPNG_ENHANCED_PACKET_BLOCK || 6266db35853SOleksandr Nahnybida epb->block_length != rte_pktmbuf_pkt_len(m))) { 6278d23ce8fSStephen Hemminger rte_errno = EINVAL; 6288d23ce8fSStephen Hemminger return -1; 6298d23ce8fSStephen Hemminger } 6308d23ce8fSStephen Hemminger 631d1da6d0dSStephen Hemminger /* check that this interface was added. */ 632d1da6d0dSStephen Hemminger epb->interface_id = self->port_index[m->port]; 633d1da6d0dSStephen Hemminger if (unlikely(epb->interface_id > RTE_MAX_ETHPORTS)) { 634d1da6d0dSStephen Hemminger rte_errno = EINVAL; 635d1da6d0dSStephen Hemminger return -1; 636d1da6d0dSStephen Hemminger } 637d1da6d0dSStephen Hemminger 63816659193SStephen Hemminger /* adjust timestamp recorded in packet */ 63916659193SStephen Hemminger cycles = (uint64_t)epb->timestamp_hi << 32; 64016659193SStephen Hemminger cycles += epb->timestamp_lo; 64116659193SStephen Hemminger timestamp = pcapng_timestamp(self, cycles); 64216659193SStephen Hemminger epb->timestamp_hi = timestamp >> 32; 64316659193SStephen Hemminger epb->timestamp_lo = (uint32_t)timestamp; 64416659193SStephen Hemminger 6458d23ce8fSStephen Hemminger /* 6460744f1c9SMário Kuka * Handle case of highly fragmented and large burst size 6470744f1c9SMário Kuka * Note: this assumes that max segments per mbuf < IOV_MAX 6480744f1c9SMário Kuka */ 6490744f1c9SMário Kuka if (unlikely(cnt + m->nb_segs >= IOV_MAX)) { 6500744f1c9SMário Kuka ret = writev(self->outfd, iov, cnt); 6510744f1c9SMário Kuka if (unlikely(ret < 0)) { 6520744f1c9SMário Kuka rte_errno = errno; 6530744f1c9SMário Kuka return -1; 6540744f1c9SMário Kuka } 6550744f1c9SMário Kuka total += ret; 6560744f1c9SMário Kuka cnt = 0; 6570744f1c9SMário Kuka } 6580744f1c9SMário Kuka 6590744f1c9SMário Kuka /* 6608d23ce8fSStephen Hemminger * The DPDK port is recorded during pcapng_copy. 6618d23ce8fSStephen Hemminger * Map that to PCAPNG interface in file. 6628d23ce8fSStephen Hemminger */ 6638d23ce8fSStephen Hemminger do { 6648d23ce8fSStephen Hemminger iov[cnt].iov_base = rte_pktmbuf_mtod(m, void *); 6658d23ce8fSStephen Hemminger iov[cnt].iov_len = rte_pktmbuf_data_len(m); 6668d23ce8fSStephen Hemminger ++cnt; 6678d23ce8fSStephen Hemminger } while ((m = m->next)); 6688d23ce8fSStephen Hemminger } 6698d23ce8fSStephen Hemminger 6700744f1c9SMário Kuka ret = writev(self->outfd, iov, cnt); 6710744f1c9SMário Kuka if (unlikely(ret < 0)) { 6728d23ce8fSStephen Hemminger rte_errno = errno; 6730744f1c9SMário Kuka return -1; 6740744f1c9SMário Kuka } 6750744f1c9SMário Kuka return total + ret; 6768d23ce8fSStephen Hemminger } 6778d23ce8fSStephen Hemminger 6788d23ce8fSStephen Hemminger /* Create new pcapng writer handle */ 6798d23ce8fSStephen Hemminger rte_pcapng_t * 6808d23ce8fSStephen Hemminger rte_pcapng_fdopen(int fd, 6818d23ce8fSStephen Hemminger const char *osname, const char *hardware, 6828d23ce8fSStephen Hemminger const char *appname, const char *comment) 6838d23ce8fSStephen Hemminger { 684d1da6d0dSStephen Hemminger unsigned int i; 6858d23ce8fSStephen Hemminger rte_pcapng_t *self; 68616659193SStephen Hemminger struct timespec ts; 68716659193SStephen Hemminger uint64_t cycles; 6888d23ce8fSStephen Hemminger 6898d23ce8fSStephen Hemminger self = malloc(sizeof(*self)); 6908d23ce8fSStephen Hemminger if (!self) { 6918d23ce8fSStephen Hemminger rte_errno = ENOMEM; 6928d23ce8fSStephen Hemminger return NULL; 6938d23ce8fSStephen Hemminger } 6948d23ce8fSStephen Hemminger 6958d23ce8fSStephen Hemminger self->outfd = fd; 696d1da6d0dSStephen Hemminger self->ports = 0; 69716659193SStephen Hemminger 69816659193SStephen Hemminger /* record start time in ns since 1/1/1970 */ 69916659193SStephen Hemminger cycles = rte_get_tsc_cycles(); 70016659193SStephen Hemminger clock_gettime(CLOCK_REALTIME, &ts); 70116659193SStephen Hemminger self->tsc_base = (cycles + rte_get_tsc_cycles()) / 2; 70216659193SStephen Hemminger self->offset_ns = rte_timespec_to_ns(&ts); 70316659193SStephen Hemminger 704d1da6d0dSStephen Hemminger for (i = 0; i < RTE_MAX_ETHPORTS; i++) 705d1da6d0dSStephen Hemminger self->port_index[i] = UINT32_MAX; 7068d23ce8fSStephen Hemminger 7078d23ce8fSStephen Hemminger if (pcapng_section_block(self, osname, hardware, appname, comment) < 0) 7088d23ce8fSStephen Hemminger goto fail; 7098d23ce8fSStephen Hemminger 7108d23ce8fSStephen Hemminger return self; 7118d23ce8fSStephen Hemminger fail: 7128d23ce8fSStephen Hemminger free(self); 7138d23ce8fSStephen Hemminger return NULL; 7148d23ce8fSStephen Hemminger } 7158d23ce8fSStephen Hemminger 7168d23ce8fSStephen Hemminger void 7178d23ce8fSStephen Hemminger rte_pcapng_close(rte_pcapng_t *self) 7188d23ce8fSStephen Hemminger { 7198d23ce8fSStephen Hemminger close(self->outfd); 7208d23ce8fSStephen Hemminger free(self); 7218d23ce8fSStephen Hemminger } 722