LCOV - code coverage report
Current view: top level - lib/pcapng - rte_pcapng.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 234 0.0 %
Date: 2024-04-01 19:00:53 Functions: 0 9 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 163 0.0 %

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

Generated by: LCOV version 1.14