LCOV - code coverage report
Current view: top level - lib/pcapng - rte_pcapng.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 170 235 72.3 %
Date: 2025-05-01 17:49:45 Functions: 8 9 88.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 81 181 44.8 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2019 Microsoft Corporation
       3                 :            :  */
       4                 :            : 
       5                 :            : #include <errno.h>
       6                 :            : #include <stdbool.h>
       7                 :            : #include <stdio.h>
       8                 :            : #include <stdlib.h>
       9                 :            : #include <string.h>
      10                 :            : #include <time.h>
      11                 :            : #include <unistd.h>
      12                 :            : 
      13                 :            : #ifndef RTE_EXEC_ENV_WINDOWS
      14                 :            : #include <net/if.h>
      15                 :            : #include <sys/uio.h>
      16                 :            : #endif
      17                 :            : 
      18                 :            : #include <bus_driver.h>
      19                 :            : #include <eal_export.h>
      20                 :            : #include <rte_common.h>
      21                 :            : #include <rte_cycles.h>
      22                 :            : #include <dev_driver.h>
      23                 :            : #include <rte_errno.h>
      24                 :            : #include <rte_ethdev.h>
      25                 :            : #include <rte_ether.h>
      26                 :            : #include <rte_mbuf.h>
      27                 :            : #include <rte_os_shim.h>
      28                 :            : #include <rte_pcapng.h>
      29                 :            : #include <rte_reciprocal.h>
      30                 :            : #include <rte_time.h>
      31                 :            : 
      32                 :            : #include "pcapng_proto.h"
      33                 :            : 
      34                 :            : /* conversion from DPDK speed to PCAPNG */
      35                 :            : #define PCAPNG_MBPS_SPEED 1000000ull
      36                 :            : 
      37                 :            : /* upper bound for section, stats and interface blocks (in uint32_t) */
      38                 :            : #define PCAPNG_BLKSIZ   (2048 / sizeof(uint32_t))
      39                 :            : 
      40                 :            : /* Format of the capture file handle */
      41                 :            : struct rte_pcapng {
      42                 :            :         int  outfd;             /* output file */
      43                 :            :         unsigned int ports;     /* number of interfaces added */
      44                 :            :         uint64_t offset_ns;     /* ns since 1/1/1970 when initialized */
      45                 :            :         uint64_t tsc_base;      /* TSC when started */
      46                 :            : 
      47                 :            :         /* DPDK port id to interface index in file */
      48                 :            :         uint32_t port_index[RTE_MAX_ETHPORTS];
      49                 :            : };
      50                 :            : 
      51                 :            : #ifdef RTE_EXEC_ENV_WINDOWS
      52                 :            : /*
      53                 :            :  * Windows does not have writev() call.
      54                 :            :  * Emulate this by copying to a new buffer.
      55                 :            :  * The copy is necessary since pcapng needs to be thread-safe
      56                 :            :  * and do atomic write operations.
      57                 :            :  */
      58                 :            : 
      59                 :            : #define IOV_MAX 128
      60                 :            : struct iovec {
      61                 :            :         void   *iov_base;
      62                 :            :         size_t  iov_len;
      63                 :            : };
      64                 :            : 
      65                 :            : static ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
      66                 :            : {
      67                 :            :         size_t bytes = 0;
      68                 :            :         uint8_t *ptr;
      69                 :            :         void *tmp_buf;
      70                 :            :         ssize_t ret;
      71                 :            :         int i;
      72                 :            : 
      73                 :            :         for (i = 0; i < iovcnt; i++)
      74                 :            :                 bytes += iov[i].iov_len;
      75                 :            : 
      76                 :            :         if (unlikely(bytes == 0))
      77                 :            :                 return 0;
      78                 :            : 
      79                 :            :         tmp_buf = malloc(bytes);
      80                 :            :         if (unlikely(tmp_buf == NULL)) {
      81                 :            :                 errno = ENOMEM;
      82                 :            :                 return -1;
      83                 :            :         }
      84                 :            : 
      85                 :            :         ptr = tmp_buf;
      86                 :            :         for (i = 0; i < iovcnt; i++) {
      87                 :            :                 rte_memcpy(ptr, iov[i].iov_base, iov[i].iov_len);
      88                 :            :                 ptr += iov[i].iov_len;
      89                 :            :         }
      90                 :            : 
      91                 :            :         ret = write(fd, tmp_buf, bytes);
      92                 :            :         free(tmp_buf);
      93                 :            :         return ret;
      94                 :            : }
      95                 :            : 
      96                 :            : #define IF_NAMESIZE     16
      97                 :            : /* compatibility wrapper because name is optional */
      98                 :            : #define if_indextoname(ifindex, ifname) NULL
      99                 :            : #endif
     100                 :            : 
     101                 :            : /* Convert from TSC (CPU cycles) to nanoseconds */
     102                 :            : static uint64_t
     103                 :            : pcapng_timestamp(const rte_pcapng_t *self, uint64_t cycles)
     104                 :            : {
     105                 :            :         uint64_t delta, rem, secs, ns;
     106                 :          1 :         const uint64_t hz = rte_get_tsc_hz();
     107                 :            : 
     108                 :       4097 :         delta = cycles - self->tsc_base;
     109                 :            : 
     110                 :            :         /* Avoid numeric wraparound by computing seconds first */
     111                 :       4097 :         secs = delta / hz;
     112                 :       4097 :         rem = delta % hz;
     113                 :       4097 :         ns = (rem * NS_PER_S) / hz;
     114                 :            : 
     115                 :       4097 :         return secs * NS_PER_S + ns + self->offset_ns;
     116                 :            : }
     117                 :            : 
     118                 :            : /* length of option including padding */
     119                 :            : static uint16_t pcapng_optlen(uint16_t len)
     120                 :            : {
     121                 :         26 :         return RTE_ALIGN(sizeof(struct pcapng_option) + len,
     122                 :            :                          sizeof(uint32_t));
     123                 :            : }
     124                 :            : 
     125                 :            : /* build TLV option and return location of next */
     126                 :            : static struct pcapng_option *
     127                 :            : pcapng_add_option(struct pcapng_option *popt, uint16_t code,
     128                 :            :                   const void *data, uint16_t len)
     129                 :            : {
     130                 :       4122 :         popt->code = code;
     131                 :       4122 :         popt->length = len;
     132                 :         12 :         if (len > 0)
     133         [ -  + ]:       4110 :                 memcpy(popt->data, data, len);
     134                 :            : 
     135                 :         20 :         return (struct pcapng_option *)((uint8_t *)popt + pcapng_optlen(len));
     136                 :            : }
     137                 :            : 
     138                 :            : /*
     139                 :            :  * Write required initial section header describing the capture
     140                 :            :  */
     141                 :            : static int
     142                 :          2 : pcapng_section_block(rte_pcapng_t *self,
     143                 :            :                     const char *os, const char *hw,
     144                 :            :                     const char *app, const char *comment)
     145                 :            : {
     146                 :            :         struct pcapng_section_header *hdr;
     147                 :            :         struct pcapng_option *opt;
     148                 :            :         uint32_t buf[PCAPNG_BLKSIZ];
     149                 :            :         uint32_t len;
     150                 :            : 
     151                 :            :         len = sizeof(*hdr);
     152         [ -  + ]:          2 :         if (hw)
     153                 :          0 :                 len += pcapng_optlen(strlen(hw));
     154         [ -  + ]:          2 :         if (os)
     155                 :          0 :                 len += pcapng_optlen(strlen(os));
     156         [ +  - ]:          2 :         if (app)
     157                 :          2 :                 len += pcapng_optlen(strlen(app));
     158         [ -  + ]:          2 :         if (comment)
     159                 :          0 :                 len += pcapng_optlen(strlen(comment));
     160                 :            : 
     161                 :            :         /* reserve space for OPT_END */
     162                 :            :         len += pcapng_optlen(0);
     163                 :          2 :         len += sizeof(uint32_t);
     164                 :            : 
     165         [ +  - ]:          2 :         if (len > sizeof(buf))
     166                 :            :                 return -1;
     167                 :            : 
     168                 :            :         hdr = (struct pcapng_section_header *)buf;
     169                 :          2 :         *hdr = (struct pcapng_section_header) {
     170                 :            :                 .block_type = PCAPNG_SECTION_BLOCK,
     171                 :            :                 .block_length = len,
     172                 :            :                 .byte_order_magic = PCAPNG_BYTE_ORDER_MAGIC,
     173                 :            :                 .major_version = PCAPNG_MAJOR_VERS,
     174                 :            :                 .minor_version = PCAPNG_MINOR_VERS,
     175                 :            :                 .section_length = UINT64_MAX,
     176                 :            :         };
     177                 :            : 
     178                 :            :         /* After the section header insert variable length options. */
     179                 :            :         opt = (struct pcapng_option *)(hdr + 1);
     180         [ -  + ]:          2 :         if (comment)
     181                 :          0 :                 opt = pcapng_add_option(opt, PCAPNG_OPT_COMMENT,
     182         [ #  # ]:          0 :                                         comment, strlen(comment));
     183         [ -  + ]:          2 :         if (hw)
     184                 :          0 :                 opt = pcapng_add_option(opt, PCAPNG_SHB_HARDWARE,
     185         [ #  # ]:          0 :                                         hw, strlen(hw));
     186         [ -  + ]:          2 :         if (os)
     187                 :          0 :                 opt = pcapng_add_option(opt, PCAPNG_SHB_OS,
     188         [ #  # ]:          0 :                                         os, strlen(os));
     189         [ +  - ]:          2 :         if (app)
     190                 :          2 :                 opt = pcapng_add_option(opt, PCAPNG_SHB_USERAPPL,
     191         [ +  - ]:          2 :                                         app, strlen(app));
     192                 :            : 
     193                 :            :         /* The standard requires last option to be OPT_END */
     194                 :            :         opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0);
     195                 :            : 
     196                 :            :         /* clone block_length after option */
     197                 :            :         memcpy(opt, &hdr->block_length, sizeof(uint32_t));
     198                 :            : 
     199                 :          2 :         return write(self->outfd, buf, len);
     200                 :            : }
     201                 :            : 
     202                 :            : /* Write an interface block for a DPDK port */
     203                 :            : RTE_EXPORT_SYMBOL(rte_pcapng_add_interface)
     204                 :            : int
     205                 :          4 : rte_pcapng_add_interface(rte_pcapng_t *self, uint16_t port,
     206                 :            :                          const char *ifname, const char *ifdescr,
     207                 :            :                          const char *filter)
     208                 :            : {
     209                 :            :         struct pcapng_interface_block *hdr;
     210                 :            :         struct rte_eth_dev_info dev_info;
     211                 :            :         struct rte_ether_addr *ea, macaddr;
     212                 :            :         const struct rte_device *dev;
     213                 :            :         struct rte_eth_link link;
     214                 :            :         struct pcapng_option *opt;
     215                 :          4 :         const uint8_t tsresol = 9;      /* nanosecond resolution */
     216                 :            :         uint32_t len;
     217                 :            :         uint32_t buf[PCAPNG_BLKSIZ];
     218                 :            :         char ifname_buf[IF_NAMESIZE];
     219                 :            :         char ifhw[256];
     220                 :          4 :         uint64_t speed = 0;
     221                 :            : 
     222         [ +  - ]:          4 :         if (rte_eth_dev_info_get(port, &dev_info) < 0)
     223                 :            :                 return -1;
     224                 :            : 
     225                 :            :         /* make something like an interface name */
     226         [ +  + ]:          4 :         if (ifname == NULL) {
     227                 :            :                 /* Use kernel name if available */
     228                 :          3 :                 ifname = if_indextoname(dev_info.if_index, ifname_buf);
     229         [ +  - ]:          3 :                 if (ifname == NULL) {
     230                 :            :                         snprintf(ifname_buf, IF_NAMESIZE, "dpdk:%u", port);
     231                 :            :                         ifname = ifname_buf;
     232                 :            :                 }
     233                 :            :         }
     234                 :            : 
     235                 :            :         /* make a useful device hardware string */
     236                 :          4 :         dev = dev_info.device;
     237         [ +  - ]:          4 :         if (dev)
     238                 :            :                 snprintf(ifhw, sizeof(ifhw),
     239                 :          4 :                          "%s-%s", dev->bus->name, dev->name);
     240                 :            : 
     241                 :            :         /* DPDK reports in units of Mbps */
     242         [ +  - ]:          4 :         if (rte_eth_link_get(port, &link) == 0 &&
     243         [ -  + ]:          4 :             link.link_status == RTE_ETH_LINK_UP)
     244                 :          0 :                 speed = link.link_speed * PCAPNG_MBPS_SPEED;
     245                 :            : 
     246         [ +  - ]:          4 :         if (rte_eth_macaddr_get(port, &macaddr) < 0)
     247                 :            :                 ea = NULL;
     248                 :            :         else
     249                 :            :                 ea = &macaddr;
     250                 :            : 
     251                 :            :         /* Compute length of interface block options */
     252                 :            :         len = sizeof(*hdr);
     253                 :            : 
     254                 :            :         len += pcapng_optlen(sizeof(tsresol));  /* timestamp */
     255                 :          4 :         len += pcapng_optlen(strlen(ifname));   /* ifname */
     256                 :            : 
     257         [ +  + ]:          4 :         if (ifdescr)
     258                 :          1 :                 len += pcapng_optlen(strlen(ifdescr));
     259         [ +  - ]:          4 :         if (ea)
     260                 :          4 :                 len += pcapng_optlen(RTE_ETHER_ADDR_LEN); /* macaddr */
     261         [ -  + ]:          4 :         if (speed != 0)
     262                 :          0 :                 len += pcapng_optlen(sizeof(uint64_t));
     263         [ +  + ]:          4 :         if (filter)
     264                 :          1 :                 len += pcapng_optlen(strlen(filter) + 1);
     265         [ +  - ]:          4 :         if (dev)
     266                 :          4 :                 len += pcapng_optlen(strlen(ifhw));
     267                 :            : 
     268                 :            :         len += pcapng_optlen(0);
     269                 :          4 :         len += sizeof(uint32_t);
     270                 :            : 
     271         [ +  - ]:          4 :         if (len > sizeof(buf))
     272                 :            :                 return -1;
     273                 :            : 
     274                 :            :         hdr = (struct pcapng_interface_block *)buf;
     275         [ +  - ]:          4 :         *hdr = (struct pcapng_interface_block) {
     276                 :            :                 .block_type = PCAPNG_INTERFACE_BLOCK,
     277                 :            :                 .link_type = 1,         /* DLT_EN10MB - Ethernet */
     278                 :            :                 .block_length = len,
     279                 :            :         };
     280                 :            : 
     281                 :            :         opt = (struct pcapng_option *)(hdr + 1);
     282                 :            :         opt = pcapng_add_option(opt, PCAPNG_IFB_TSRESOL,
     283                 :            :                                 &tsresol, sizeof(tsresol));
     284                 :          4 :         opt = pcapng_add_option(opt, PCAPNG_IFB_NAME,
     285         [ +  - ]:          4 :                                 ifname, strlen(ifname));
     286         [ +  + ]:          4 :         if (ifdescr)
     287                 :          1 :                 opt = pcapng_add_option(opt, PCAPNG_IFB_DESCRIPTION,
     288         [ +  - ]:          1 :                                         ifdescr, strlen(ifdescr));
     289         [ +  - ]:          4 :         if (ea)
     290                 :            :                 opt = pcapng_add_option(opt, PCAPNG_IFB_MACADDR,
     291                 :            :                                         ea, RTE_ETHER_ADDR_LEN);
     292         [ -  + ]:          4 :         if (speed != 0)
     293                 :            :                 opt = pcapng_add_option(opt, PCAPNG_IFB_SPEED,
     294                 :            :                                          &speed, sizeof(uint64_t));
     295         [ +  - ]:          4 :         if (dev)
     296                 :          4 :                 opt = pcapng_add_option(opt, PCAPNG_IFB_HARDWARE,
     297         [ +  - ]:          4 :                                          ifhw, strlen(ifhw));
     298         [ +  + ]:          4 :         if (filter) {
     299                 :            :                 size_t len;
     300                 :            : 
     301                 :          1 :                 len = strlen(filter) + 1;
     302                 :          1 :                 opt->code = PCAPNG_IFB_FILTER;
     303                 :          1 :                 opt->length = len;
     304                 :            :                 /* Encoding is that the first octet indicates string vs BPF */
     305                 :          1 :                 opt->data[0] = 0;
     306                 :          1 :                 memcpy(opt->data + 1, filter, strlen(filter));
     307                 :            : 
     308                 :          1 :                 opt = (struct pcapng_option *)((uint8_t *)opt + pcapng_optlen(len));
     309                 :            :         }
     310                 :            : 
     311                 :            :         opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0);
     312                 :            : 
     313                 :            :         /* clone block_length after optionsa */
     314                 :            :         memcpy(opt, &hdr->block_length, sizeof(uint32_t));
     315                 :            : 
     316                 :            :         /* remember the file index */
     317                 :          4 :         self->port_index[port] = self->ports++;
     318                 :            : 
     319                 :          4 :         return write(self->outfd, buf, len);
     320                 :            : }
     321                 :            : 
     322                 :            : /*
     323                 :            :  * Write an Interface statistics block at the end of capture.
     324                 :            :  */
     325                 :            : RTE_EXPORT_SYMBOL(rte_pcapng_write_stats)
     326                 :            : ssize_t
     327                 :          1 : rte_pcapng_write_stats(rte_pcapng_t *self, uint16_t port_id,
     328                 :            :                        uint64_t ifrecv, uint64_t ifdrop,
     329                 :            :                        const char *comment)
     330                 :            : {
     331                 :            :         struct pcapng_statistics *hdr;
     332                 :            :         struct pcapng_option *opt;
     333                 :          1 :         uint64_t start_time = self->offset_ns;
     334                 :            :         uint64_t sample_time;
     335                 :            :         uint32_t optlen, len;
     336                 :            :         uint32_t buf[PCAPNG_BLKSIZ];
     337                 :            : 
     338         [ -  + ]:          1 :         RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -EINVAL);
     339                 :            : 
     340                 :            :         optlen = 0;
     341                 :            : 
     342         [ +  - ]:          1 :         if (ifrecv != UINT64_MAX)
     343                 :            :                 optlen += pcapng_optlen(sizeof(ifrecv));
     344         [ +  - ]:          1 :         if (ifdrop != UINT64_MAX)
     345                 :          1 :                 optlen += pcapng_optlen(sizeof(ifdrop));
     346                 :            : 
     347         [ +  - ]:          1 :         if (start_time != 0)
     348                 :          1 :                 optlen += pcapng_optlen(sizeof(start_time));
     349                 :            : 
     350         [ +  - ]:          1 :         if (comment)
     351                 :          1 :                 optlen += pcapng_optlen(strlen(comment));
     352         [ +  - ]:          1 :         if (optlen != 0)
     353                 :          1 :                 optlen += pcapng_optlen(0);
     354                 :            : 
     355                 :          1 :         len = sizeof(*hdr) + optlen + sizeof(uint32_t);
     356         [ +  - ]:          1 :         if (len > sizeof(buf))
     357                 :            :                 return -1;
     358                 :            : 
     359                 :            :         hdr = (struct pcapng_statistics *)buf;
     360                 :            :         opt = (struct pcapng_option *)(hdr + 1);
     361                 :            : 
     362         [ +  - ]:          1 :         if (comment)
     363                 :          1 :                 opt = pcapng_add_option(opt, PCAPNG_OPT_COMMENT,
     364         [ +  - ]:          1 :                                         comment, strlen(comment));
     365         [ +  - ]:          1 :         if (start_time != 0)
     366                 :            :                 opt = pcapng_add_option(opt, PCAPNG_ISB_STARTTIME,
     367                 :            :                                          &start_time, sizeof(start_time));
     368         [ +  - ]:          1 :         if (ifrecv != UINT64_MAX)
     369                 :            :                 opt = pcapng_add_option(opt, PCAPNG_ISB_IFRECV,
     370                 :            :                                 &ifrecv, sizeof(ifrecv));
     371         [ +  - ]:          1 :         if (ifdrop != UINT64_MAX)
     372                 :            :                 opt = pcapng_add_option(opt, PCAPNG_ISB_IFDROP,
     373                 :            :                                 &ifdrop, sizeof(ifdrop));
     374         [ +  - ]:          1 :         if (optlen != 0)
     375                 :            :                 opt = pcapng_add_option(opt, PCAPNG_OPT_END, NULL, 0);
     376                 :            : 
     377                 :          1 :         hdr->block_type = PCAPNG_INTERFACE_STATS_BLOCK;
     378                 :          1 :         hdr->block_length = len;
     379                 :          1 :         hdr->interface_id = self->port_index[port_id];
     380                 :            : 
     381                 :            :         sample_time = pcapng_timestamp(self, rte_get_tsc_cycles());
     382                 :          1 :         hdr->timestamp_hi = sample_time >> 32;
     383                 :          1 :         hdr->timestamp_lo = (uint32_t)sample_time;
     384                 :            : 
     385                 :            :         /* clone block_length after option */
     386                 :            :         memcpy(opt, &len, sizeof(uint32_t));
     387                 :            : 
     388                 :          1 :         return write(self->outfd, buf, len);
     389                 :            : }
     390                 :            : 
     391                 :            : RTE_EXPORT_SYMBOL(rte_pcapng_mbuf_size)
     392                 :            : uint32_t
     393                 :          1 : rte_pcapng_mbuf_size(uint32_t length)
     394                 :            : {
     395                 :            :         /* The VLAN and EPB header must fit in the mbuf headroom. */
     396                 :            :         RTE_ASSERT(sizeof(struct pcapng_enhance_packet_block) +
     397                 :            :                    sizeof(struct rte_vlan_hdr) <= RTE_PKTMBUF_HEADROOM);
     398                 :            : 
     399                 :            :         /* The flags and queue information are added at the end. */
     400                 :            :         return sizeof(struct rte_mbuf)
     401                 :          1 :                 + RTE_ALIGN(length, sizeof(uint32_t))
     402                 :            :                 + pcapng_optlen(sizeof(uint32_t)) /* flag option */
     403                 :            :                 + pcapng_optlen(sizeof(uint32_t)) /* queue option */
     404                 :          1 :                 + sizeof(uint32_t);               /*  length */
     405                 :            : }
     406                 :            : 
     407                 :            : /* More generalized version rte_vlan_insert() */
     408                 :            : static int
     409                 :          0 : pcapng_vlan_insert(struct rte_mbuf *m, uint16_t ether_type, uint16_t tci)
     410                 :            : {
     411                 :            :         struct rte_ether_hdr *nh, *oh;
     412                 :            :         struct rte_vlan_hdr *vh;
     413                 :            : 
     414   [ #  #  #  # ]:          0 :         if (!RTE_MBUF_DIRECT(m) || rte_mbuf_refcnt_read(m) > 1)
     415                 :          0 :                 return -EINVAL;
     416                 :            : 
     417         [ #  # ]:          0 :         if (rte_pktmbuf_data_len(m) < sizeof(*oh))
     418                 :            :                 return -EINVAL;
     419                 :            : 
     420         [ #  # ]:          0 :         oh = rte_pktmbuf_mtod(m, struct rte_ether_hdr *);
     421                 :            :         nh = (struct rte_ether_hdr *)
     422                 :            :                 rte_pktmbuf_prepend(m, sizeof(struct rte_vlan_hdr));
     423         [ #  # ]:          0 :         if (nh == NULL)
     424                 :          0 :                 return -ENOSPC;
     425                 :            : 
     426                 :            :         memmove(nh, oh, 2 * RTE_ETHER_ADDR_LEN);
     427         [ #  # ]:          0 :         nh->ether_type = rte_cpu_to_be_16(ether_type);
     428                 :            : 
     429                 :            :         vh = (struct rte_vlan_hdr *) (nh + 1);
     430         [ #  # ]:          0 :         vh->vlan_tci = rte_cpu_to_be_16(tci);
     431                 :            : 
     432                 :          0 :         return 0;
     433                 :            : }
     434                 :            : 
     435                 :            : /*
     436                 :            :  *   The mbufs created use the Pcapng standard enhanced packet  block.
     437                 :            :  *
     438                 :            :  *                         1                   2                   3
     439                 :            :  *     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
     440                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     441                 :            :  *  0 |                    Block Type = 0x00000006                    |
     442                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     443                 :            :  *  4 |                      Block Total Length                       |
     444                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     445                 :            :  *  8 |                         Interface ID                          |
     446                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     447                 :            :  * 12 |                        Timestamp (High)                       |
     448                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     449                 :            :  * 16 |                        Timestamp (Low)                        |
     450                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     451                 :            :  * 20 |                    Captured Packet Length                     |
     452                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     453                 :            :  * 24 |                    Original Packet Length                     |
     454                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     455                 :            :  * 28 /                                                               /
     456                 :            :  *    /                          Packet Data                          /
     457                 :            :  *    /              variable length, padded to 32 bits               /
     458                 :            :  *    /                                                               /
     459                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     460                 :            :  *    |      Option Code = 0x0002     |     Option Length = 0x004     |
     461                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     462                 :            :  *    |              Flags (direction)                                |
     463                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     464                 :            :  *    |      Option Code = 0x0006     |     Option Length = 0x002     |
     465                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     466                 :            :  *    |              Queue id                                         |
     467                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     468                 :            :  *    |                      Block Total Length                       |
     469                 :            :  *    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     470                 :            :  */
     471                 :            : 
     472                 :            : /* Make a copy of original mbuf with pcapng header and options */
     473                 :            : RTE_EXPORT_SYMBOL(rte_pcapng_copy)
     474                 :            : struct rte_mbuf *
     475                 :       4096 : rte_pcapng_copy(uint16_t port_id, uint32_t queue,
     476                 :            :                 const struct rte_mbuf *md,
     477                 :            :                 struct rte_mempool *mp,
     478                 :            :                 uint32_t length,
     479                 :            :                 enum rte_pcapng_direction direction,
     480                 :            :                 const char *comment)
     481                 :            : {
     482                 :            :         struct pcapng_enhance_packet_block *epb;
     483                 :            :         uint32_t orig_len, pkt_len, padding, flags;
     484                 :            :         struct pcapng_option *opt;
     485                 :            :         uint64_t timestamp;
     486                 :            :         uint16_t optlen;
     487                 :            :         struct rte_mbuf *mc;
     488                 :            :         bool rss_hash;
     489                 :            : 
     490                 :            : #ifdef RTE_LIBRTE_ETHDEV_DEBUG
     491                 :            :         RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, NULL);
     492                 :            : #endif
     493                 :       4096 :         orig_len = rte_pktmbuf_pkt_len(md);
     494                 :            : 
     495                 :            :         /* Take snapshot of the data */
     496                 :       4096 :         mc = rte_pktmbuf_copy(md, mp, 0, length);
     497         [ +  - ]:       4096 :         if (unlikely(mc == NULL))
     498                 :            :                 return NULL;
     499                 :            : 
     500                 :            :         /* Expand any offloaded VLAN information */
     501         [ +  - ]:       4096 :         if ((direction == RTE_PCAPNG_DIRECTION_IN &&
     502   [ +  -  -  + ]:       4096 :              (md->ol_flags & RTE_MBUF_F_RX_VLAN_STRIPPED)) ||
     503                 :          0 :             (direction == RTE_PCAPNG_DIRECTION_OUT &&
     504         [ #  # ]:          0 :              (md->ol_flags & RTE_MBUF_F_TX_VLAN))) {
     505         [ #  # ]:          0 :                 if (pcapng_vlan_insert(mc, RTE_ETHER_TYPE_VLAN,
     506                 :          0 :                                        md->vlan_tci) != 0)
     507                 :          0 :                         goto fail;
     508                 :            :         }
     509                 :            : 
     510         [ +  - ]:       4096 :         if ((direction == RTE_PCAPNG_DIRECTION_IN &&
     511   [ +  -  -  + ]:       4096 :              (md->ol_flags & RTE_MBUF_F_RX_QINQ_STRIPPED)) ||
     512                 :          0 :             (direction == RTE_PCAPNG_DIRECTION_OUT &&
     513         [ #  # ]:          0 :              (md->ol_flags & RTE_MBUF_F_TX_QINQ))) {
     514         [ #  # ]:          0 :                 if (pcapng_vlan_insert(mc, RTE_ETHER_TYPE_QINQ,
     515                 :          0 :                                        md->vlan_tci_outer) != 0)
     516                 :          0 :                         goto fail;
     517                 :            :         }
     518                 :            : 
     519                 :            :         /* record HASH on incoming packets */
     520         [ +  - ]:       4096 :         rss_hash = (direction == RTE_PCAPNG_DIRECTION_IN &&
     521         [ +  - ]:       4096 :                     (md->ol_flags & RTE_MBUF_F_RX_RSS_HASH));
     522                 :            : 
     523                 :            :         /* pad the packet to 32 bit boundary */
     524                 :       4096 :         pkt_len = rte_pktmbuf_pkt_len(mc);
     525                 :       4096 :         padding = RTE_ALIGN(pkt_len, sizeof(uint32_t)) - pkt_len;
     526         [ -  + ]:       4096 :         if (padding > 0) {
     527                 :          0 :                 void *tail = rte_pktmbuf_append(mc, padding);
     528                 :            : 
     529         [ #  # ]:          0 :                 if (tail == NULL)
     530                 :          0 :                         goto fail;
     531                 :          0 :                 memset(tail, 0, padding);
     532                 :            :         }
     533                 :            : 
     534                 :            :         optlen = pcapng_optlen(sizeof(flags));
     535                 :            :         optlen += pcapng_optlen(sizeof(queue));
     536         [ -  + ]:       4096 :         if (rss_hash)
     537                 :            :                 optlen += pcapng_optlen(sizeof(uint8_t) + sizeof(uint32_t));
     538                 :            : 
     539         [ -  + ]:       4096 :         if (comment)
     540                 :          0 :                 optlen += pcapng_optlen(strlen(comment));
     541                 :            : 
     542                 :            :         /* reserve trailing options and block length */
     543                 :            :         opt = (struct pcapng_option *)
     544                 :       4096 :                 rte_pktmbuf_append(mc, optlen + sizeof(uint32_t));
     545         [ -  + ]:       4096 :         if (unlikely(opt == NULL))
     546                 :          0 :                 goto fail;
     547                 :            : 
     548      [ +  -  - ]:       4096 :         switch (direction) {
     549                 :       4096 :         case RTE_PCAPNG_DIRECTION_IN:
     550                 :       4096 :                 flags = PCAPNG_IFB_INBOUND;
     551                 :       4096 :                 break;
     552                 :          0 :         case RTE_PCAPNG_DIRECTION_OUT:
     553                 :          0 :                 flags = PCAPNG_IFB_OUTBOUND;
     554                 :          0 :                 break;
     555                 :          0 :         default:
     556                 :          0 :                 flags = 0;
     557                 :            :         }
     558                 :            : 
     559                 :            :         opt = pcapng_add_option(opt, PCAPNG_EPB_FLAGS,
     560                 :            :                                 &flags, sizeof(flags));
     561                 :            : 
     562                 :            :         opt = pcapng_add_option(opt, PCAPNG_EPB_QUEUE,
     563                 :            :                                 &queue, sizeof(queue));
     564                 :            : 
     565         [ -  + ]:       4096 :         if (rss_hash) {
     566                 :            :                 uint8_t hash_opt[5];
     567                 :            : 
     568                 :            :                 /* The algorithm could be something else if
     569                 :            :                  * using rte_flow_action_rss; but the current API does not
     570                 :            :                  * have a way for ethdev to report  this on a per-packet basis.
     571                 :            :                  */
     572                 :          0 :                 hash_opt[0] = PCAPNG_HASH_TOEPLITZ;
     573                 :            : 
     574                 :            :                 memcpy(&hash_opt[1], &md->hash.rss, sizeof(uint32_t));
     575                 :            :                 opt = pcapng_add_option(opt, PCAPNG_EPB_HASH,
     576                 :            :                                         &hash_opt, sizeof(hash_opt));
     577                 :            :         }
     578                 :            : 
     579         [ -  + ]:       4096 :         if (comment)
     580                 :          0 :                 opt = pcapng_add_option(opt, PCAPNG_OPT_COMMENT, comment,
     581         [ #  # ]:          0 :                                         strlen(comment));
     582                 :            : 
     583                 :            :         /* Note: END_OPT necessary here. Wireshark doesn't do it. */
     584                 :            : 
     585                 :            :         /* Add PCAPNG packet header */
     586                 :            :         epb = (struct pcapng_enhance_packet_block *)
     587                 :            :                 rte_pktmbuf_prepend(mc, sizeof(*epb));
     588         [ -  + ]:       4096 :         if (unlikely(epb == NULL))
     589                 :          0 :                 goto fail;
     590                 :            : 
     591                 :       4096 :         epb->block_type = PCAPNG_ENHANCED_PACKET_BLOCK;
     592                 :       4096 :         epb->block_length = rte_pktmbuf_pkt_len(mc);
     593                 :            : 
     594                 :            :         /* Interface index is filled in later during write */
     595                 :       4096 :         mc->port = port_id;
     596                 :            : 
     597                 :            :         /* Put timestamp in cycles here - adjust in packet write */
     598                 :            :         timestamp = rte_get_tsc_cycles();
     599                 :       4096 :         epb->timestamp_hi = timestamp >> 32;
     600                 :       4096 :         epb->timestamp_lo = (uint32_t)timestamp;
     601                 :       4096 :         epb->capture_length = pkt_len;
     602                 :       4096 :         epb->original_length = orig_len;
     603                 :            : 
     604                 :            :         /* set trailer of block length */
     605                 :       4096 :         *(uint32_t *)opt = epb->block_length;
     606                 :            : 
     607                 :       4096 :         return mc;
     608                 :            : 
     609                 :          0 : fail:
     610                 :          0 :         rte_pktmbuf_free(mc);
     611                 :          0 :         return NULL;
     612                 :            : }
     613                 :            : 
     614                 :            : /* Write pre-formatted packets to file. */
     615                 :            : RTE_EXPORT_SYMBOL(rte_pcapng_write_packets)
     616                 :            : ssize_t
     617                 :        145 : rte_pcapng_write_packets(rte_pcapng_t *self,
     618                 :            :                          struct rte_mbuf *pkts[], uint16_t nb_pkts)
     619                 :            : {
     620                 :            :         struct iovec iov[IOV_MAX];
     621                 :            :         unsigned int i, cnt = 0;
     622                 :            :         ssize_t ret, total = 0;
     623                 :            : 
     624         [ +  + ]:       4241 :         for (i = 0; i < nb_pkts; i++) {
     625                 :       4096 :                 struct rte_mbuf *m = pkts[i];
     626                 :            :                 struct pcapng_enhance_packet_block *epb;
     627                 :            :                 uint64_t cycles, timestamp;
     628                 :            : 
     629                 :            :                 /* sanity check that is really a pcapng mbuf */
     630                 :       4096 :                 epb = rte_pktmbuf_mtod(m, struct pcapng_enhance_packet_block *);
     631   [ +  -  -  + ]:       4096 :                 if (unlikely(epb->block_type != PCAPNG_ENHANCED_PACKET_BLOCK ||
     632                 :            :                              epb->block_length != rte_pktmbuf_pkt_len(m))) {
     633                 :          0 :                         rte_errno = EINVAL;
     634                 :          0 :                         return -1;
     635                 :            :                 }
     636                 :            : 
     637                 :            :                 /* check that this interface was added. */
     638                 :       4096 :                 epb->interface_id = self->port_index[m->port];
     639         [ -  + ]:       4096 :                 if (unlikely(epb->interface_id > RTE_MAX_ETHPORTS)) {
     640                 :          0 :                         rte_errno = EINVAL;
     641                 :          0 :                         return -1;
     642                 :            :                 }
     643                 :            : 
     644                 :            :                 /* adjust timestamp recorded in packet */
     645                 :       4096 :                 cycles = (uint64_t)epb->timestamp_hi << 32;
     646                 :       4096 :                 cycles += epb->timestamp_lo;
     647                 :            :                 timestamp = pcapng_timestamp(self, cycles);
     648                 :       4096 :                 epb->timestamp_hi = timestamp >> 32;
     649                 :       4096 :                 epb->timestamp_lo = (uint32_t)timestamp;
     650                 :            : 
     651                 :            :                 /*
     652                 :            :                  * Handle case of highly fragmented and large burst size
     653                 :            :                  * Note: this assumes that max segments per mbuf < IOV_MAX
     654                 :            :                  */
     655         [ -  + ]:       4096 :                 if (unlikely(cnt + m->nb_segs >= IOV_MAX)) {
     656                 :          0 :                         ret = writev(self->outfd, iov, cnt);
     657         [ #  # ]:          0 :                         if (unlikely(ret < 0)) {
     658                 :          0 :                                 rte_errno = errno;
     659                 :          0 :                                 return -1;
     660                 :            :                         }
     661                 :          0 :                         total += ret;
     662                 :            :                         cnt = 0;
     663                 :            :                 }
     664                 :            : 
     665                 :            :                 /*
     666                 :            :                  * The DPDK port is recorded during pcapng_copy.
     667                 :            :                  * Map that to PCAPNG interface in file.
     668                 :            :                  */
     669                 :            :                 do {
     670                 :       8192 :                         iov[cnt].iov_base = rte_pktmbuf_mtod(m, void *);
     671                 :       8192 :                         iov[cnt].iov_len = rte_pktmbuf_data_len(m);
     672                 :       8192 :                         ++cnt;
     673         [ +  + ]:       8192 :                 } while ((m = m->next));
     674                 :            :         }
     675                 :            : 
     676                 :        145 :         ret = writev(self->outfd, iov, cnt);
     677         [ -  + ]:        145 :         if (unlikely(ret < 0)) {
     678                 :          0 :                 rte_errno = errno;
     679                 :          0 :                 return -1;
     680                 :            :         }
     681                 :        145 :         return total + ret;
     682                 :            : }
     683                 :            : 
     684                 :            : /* Create new pcapng writer handle */
     685                 :            : RTE_EXPORT_SYMBOL(rte_pcapng_fdopen)
     686                 :            : rte_pcapng_t *
     687                 :          2 : rte_pcapng_fdopen(int fd,
     688                 :            :                   const char *osname, const char *hardware,
     689                 :            :                   const char *appname, const char *comment)
     690                 :            : {
     691                 :            :         unsigned int i;
     692                 :            :         rte_pcapng_t *self;
     693                 :            :         struct timespec ts;
     694                 :            :         uint64_t cycles;
     695                 :            : 
     696                 :          2 :         self = malloc(sizeof(*self));
     697         [ -  + ]:          2 :         if (!self) {
     698                 :          0 :                 rte_errno = ENOMEM;
     699                 :          0 :                 return NULL;
     700                 :            :         }
     701                 :            : 
     702                 :          2 :         self->outfd = fd;
     703                 :          2 :         self->ports = 0;
     704                 :            : 
     705                 :            :         /* record start time in ns since 1/1/1970 */
     706                 :            :         cycles = rte_get_tsc_cycles();
     707                 :          2 :         clock_gettime(CLOCK_REALTIME, &ts);
     708                 :          2 :         self->tsc_base = (cycles + rte_get_tsc_cycles()) / 2;
     709                 :          2 :         self->offset_ns = rte_timespec_to_ns(&ts);
     710                 :            : 
     711         [ +  + ]:         66 :         for (i = 0; i < RTE_MAX_ETHPORTS; i++)
     712                 :         64 :                 self->port_index[i] = UINT32_MAX;
     713                 :            : 
     714         [ -  + ]:          2 :         if (pcapng_section_block(self, osname, hardware, appname, comment) < 0)
     715                 :          0 :                 goto fail;
     716                 :            : 
     717                 :            :         return self;
     718                 :            : fail:
     719                 :          0 :         free(self);
     720                 :          0 :         return NULL;
     721                 :            : }
     722                 :            : 
     723                 :            : RTE_EXPORT_SYMBOL(rte_pcapng_close)
     724                 :            : void
     725                 :          2 : rte_pcapng_close(rte_pcapng_t *self)
     726                 :            : {
     727                 :          2 :         close(self->outfd);
     728                 :          2 :         free(self);
     729                 :          2 : }

Generated by: LCOV version 1.14