LCOV - code coverage report
Current view: top level - drivers/net/pcap - pcap_ethdev.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 611 815 75.0 %
Date: 2026-06-01 18:36:17 Functions: 47 54 87.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 273 461 59.2 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2010-2016 Intel Corporation.
       3                 :            :  * Copyright(c) 2014 6WIND S.A.
       4                 :            :  * All rights reserved.
       5                 :            :  */
       6                 :            : 
       7                 :            : #include <stdio.h>
       8                 :            : #include <stdlib.h>
       9                 :            : #include <string.h>
      10                 :            : #include <stdbool.h>
      11                 :            : #include <time.h>
      12                 :            : #include <inttypes.h>
      13                 :            : #include <errno.h>
      14                 :            : #include <sys/time.h>
      15                 :            : #include <sys/types.h>
      16                 :            : #include <unistd.h>
      17                 :            : 
      18                 :            : #include <pcap.h>
      19                 :            : 
      20                 :            : #include <rte_alarm.h>
      21                 :            : #include <rte_cycles.h>
      22                 :            : #include <rte_ring.h>
      23                 :            : #include <rte_ethdev.h>
      24                 :            : #include <ethdev_driver.h>
      25                 :            : #include <ethdev_vdev.h>
      26                 :            : #include <rte_kvargs.h>
      27                 :            : #include <rte_malloc.h>
      28                 :            : #include <rte_memcpy.h>
      29                 :            : #include <rte_mbuf.h>
      30                 :            : #include <rte_mbuf_dyn.h>
      31                 :            : #include <bus_vdev_driver.h>
      32                 :            : #include <rte_os_shim.h>
      33                 :            : #include <rte_time.h>
      34                 :            : 
      35                 :            : #include "pcap_osdep.h"
      36                 :            : 
      37                 :            : #define ETH_PCAP_RX_PCAP_ARG  "rx_pcap"
      38                 :            : #define ETH_PCAP_TX_PCAP_ARG  "tx_pcap"
      39                 :            : #define ETH_PCAP_RX_IFACE_ARG "rx_iface"
      40                 :            : #define ETH_PCAP_RX_IFACE_IN_ARG "rx_iface_in"
      41                 :            : #define ETH_PCAP_TX_IFACE_ARG "tx_iface"
      42                 :            : #define ETH_PCAP_IFACE_ARG    "iface"
      43                 :            : #define ETH_PCAP_PHY_MAC_ARG  "phy_mac"
      44                 :            : #define ETH_PCAP_INFINITE_RX_ARG  "infinite_rx"
      45                 :            : #define ETH_PCAP_EOF_ARG          "eof"
      46                 :            : #define ETH_PCAP_SNAPSHOT_LEN_ARG "snaplen"
      47                 :            : 
      48                 :            : #define ETH_PCAP_SNAPSHOT_LEN_DEFAULT 65535
      49                 :            : 
      50                 :            : /* This is defined in libpcap but not exposed in headers */
      51                 :            : #define ETH_PCAP_MAXIMUM_SNAPLEN      262144
      52                 :            : 
      53                 :            : #define ETH_PCAP_LSC_POLL_INTERVAL_US (1000 * 1000) /* 1 second */
      54                 :            : 
      55                 :            : #define ETH_PCAP_ARG_MAXLEN     64
      56                 :            : 
      57                 :            : #define RTE_PMD_PCAP_MAX_QUEUES 16
      58                 :            : 
      59                 :            : static struct timespec start_time;
      60                 :            : static uint64_t start_cycles;
      61                 :            : static uint64_t hz;
      62                 :            : 
      63                 :            : static uint64_t timestamp_rx_dynflag;
      64                 :            : static int timestamp_dynfield_offset = -1;
      65                 :            : 
      66                 :            : struct queue_stat {
      67                 :            :         volatile unsigned long pkts;
      68                 :            :         volatile unsigned long bytes;
      69                 :            :         volatile unsigned long err_pkts;
      70                 :            :         volatile unsigned long rx_nombuf;
      71                 :            : };
      72                 :            : 
      73                 :            : struct queue_missed_stat {
      74                 :            :         /* last value retrieved from pcap */
      75                 :            :         unsigned int pcap;
      76                 :            :         /* stores values lost by pcap stop or rollover */
      77                 :            :         unsigned long mnemonic;
      78                 :            :         /* value on last reset */
      79                 :            :         unsigned long reset;
      80                 :            : };
      81                 :            : 
      82                 :            : struct pcap_rx_queue {
      83                 :            :         uint16_t port_id;
      84                 :            :         uint16_t queue_id;
      85                 :            :         bool vlan_strip;
      86                 :            :         bool rx_scatter;
      87                 :            :         bool timestamp_offloading;
      88                 :            :         struct rte_mempool *mb_pool;
      89                 :            :         struct queue_stat rx_stat;
      90                 :            :         struct queue_missed_stat missed_stat;
      91                 :            :         char name[PATH_MAX];
      92                 :            :         char type[ETH_PCAP_ARG_MAXLEN];
      93                 :            : 
      94                 :            :         /* Contains pre-generated packets to be looped through */
      95                 :            :         struct rte_ring *pkts;
      96                 :            : };
      97                 :            : 
      98                 :            : struct pcap_tx_queue {
      99                 :            :         uint16_t port_id;
     100                 :            :         uint16_t queue_id;
     101                 :            :         struct queue_stat tx_stat;
     102                 :            :         char name[PATH_MAX];
     103                 :            :         char type[ETH_PCAP_ARG_MAXLEN];
     104                 :            : 
     105                 :            :         /* Temp buffer used for non-linear packets */
     106                 :            :         uint8_t *bounce_buf;
     107                 :            : };
     108                 :            : 
     109                 :            : struct pmd_internals {
     110                 :            :         struct pcap_rx_queue rx_queue[RTE_PMD_PCAP_MAX_QUEUES];
     111                 :            :         struct pcap_tx_queue tx_queue[RTE_PMD_PCAP_MAX_QUEUES];
     112                 :            :         char devargs[ETH_PCAP_ARG_MAXLEN];
     113                 :            :         struct rte_ether_addr eth_addr;
     114                 :            :         int if_index;
     115                 :            :         uint32_t snapshot_len;
     116                 :            :         bool single_iface;
     117                 :            :         bool phy_mac;
     118                 :            :         bool infinite_rx;
     119                 :            :         bool eof;
     120                 :            :         RTE_ATOMIC(bool) eof_signaled;
     121                 :            :         bool vlan_strip;
     122                 :            :         bool rx_scatter;
     123                 :            :         bool timestamp_offloading;
     124                 :            :         bool lsc_active;
     125                 :            : };
     126                 :            : 
     127                 :            : struct pmd_process_private {
     128                 :            :         pcap_t *rx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
     129                 :            :         pcap_t *tx_pcap[RTE_PMD_PCAP_MAX_QUEUES];
     130                 :            :         pcap_dumper_t *tx_dumper[RTE_PMD_PCAP_MAX_QUEUES];
     131                 :            : };
     132                 :            : 
     133                 :            : struct pmd_devargs {
     134                 :            :         uint16_t num_of_queue;
     135                 :            :         bool phy_mac;
     136                 :            :         struct devargs_queue {
     137                 :            :                 pcap_dumper_t *dumper;
     138                 :            :                 /* pcap and name/type fields... */
     139                 :            :                 pcap_t *pcap;
     140                 :            :                 const char *name;
     141                 :            :                 const char *type;
     142                 :            :         } queue[RTE_PMD_PCAP_MAX_QUEUES];
     143                 :            :         uint32_t snapshot_len;
     144                 :            : };
     145                 :            : 
     146                 :            : struct pmd_devargs_all {
     147                 :            :         struct pmd_devargs rx_queues;
     148                 :            :         struct pmd_devargs tx_queues;
     149                 :            :         uint32_t snapshot_len;
     150                 :            :         bool single_iface;
     151                 :            :         bool is_tx_pcap;
     152                 :            :         bool is_tx_iface;
     153                 :            :         bool is_rx_pcap;
     154                 :            :         bool is_rx_iface;
     155                 :            :         bool infinite_rx;
     156                 :            :         bool eof;
     157                 :            : };
     158                 :            : 
     159                 :            : static const char *valid_arguments[] = {
     160                 :            :         ETH_PCAP_RX_PCAP_ARG,
     161                 :            :         ETH_PCAP_TX_PCAP_ARG,
     162                 :            :         ETH_PCAP_RX_IFACE_ARG,
     163                 :            :         ETH_PCAP_RX_IFACE_IN_ARG,
     164                 :            :         ETH_PCAP_TX_IFACE_ARG,
     165                 :            :         ETH_PCAP_IFACE_ARG,
     166                 :            :         ETH_PCAP_PHY_MAC_ARG,
     167                 :            :         ETH_PCAP_INFINITE_RX_ARG,
     168                 :            :         ETH_PCAP_EOF_ARG,
     169                 :            :         ETH_PCAP_SNAPSHOT_LEN_ARG,
     170                 :            :         NULL
     171                 :            : };
     172                 :            : 
     173         [ -  + ]:        286 : RTE_LOG_REGISTER_DEFAULT(eth_pcap_logtype, NOTICE);
     174                 :            : 
     175                 :            : /* Forward declarations */
     176                 :            : static int eth_link_update(struct rte_eth_dev *dev, int wait_to_complete);
     177                 :            : 
     178                 :            : static struct queue_missed_stat*
     179                 :         44 : queue_missed_stat_update(struct rte_eth_dev *dev, unsigned int qid)
     180                 :            : {
     181                 :         44 :         struct pmd_internals *internals = dev->data->dev_private;
     182                 :         44 :         struct queue_missed_stat *missed_stat =
     183                 :            :                         &internals->rx_queue[qid].missed_stat;
     184                 :         44 :         const struct pmd_process_private *pp = dev->process_private;
     185                 :         44 :         pcap_t *pcap = pp->rx_pcap[qid];
     186                 :            :         struct pcap_stat stat;
     187                 :            : 
     188   [ +  +  +  + ]:         44 :         if (!pcap || (pcap_stats(pcap, &stat) != 0))
     189                 :         36 :                 return missed_stat;
     190                 :            : 
     191                 :            :         /* rollover check - best effort fixup assuming single rollover */
     192         [ -  + ]:          8 :         if (stat.ps_drop < missed_stat->pcap)
     193                 :          0 :                 missed_stat->mnemonic += UINT_MAX;
     194                 :          8 :         missed_stat->pcap = stat.ps_drop;
     195                 :            : 
     196                 :          8 :         return missed_stat;
     197                 :            : }
     198                 :            : 
     199                 :            : static void
     200                 :            : queue_missed_stat_on_stop_update(struct rte_eth_dev *dev, unsigned int qid)
     201                 :            : {
     202                 :            :         struct queue_missed_stat *missed_stat =
     203                 :         31 :                         queue_missed_stat_update(dev, qid);
     204                 :            : 
     205                 :         31 :         missed_stat->mnemonic += missed_stat->pcap;
     206                 :         31 :         missed_stat->pcap = 0;
     207                 :            : }
     208                 :            : 
     209                 :            : static void
     210                 :            : queue_missed_stat_reset(struct rte_eth_dev *dev, unsigned int qid)
     211                 :            : {
     212                 :            :         struct queue_missed_stat *missed_stat =
     213                 :          5 :                         queue_missed_stat_update(dev, qid);
     214                 :            : 
     215                 :          5 :         missed_stat->reset = missed_stat->pcap;
     216                 :          5 :         missed_stat->mnemonic = 0;
     217                 :            : }
     218                 :            : 
     219                 :            : static unsigned long
     220                 :            : queue_missed_stat_get(struct rte_eth_dev *dev, unsigned int qid)
     221                 :            : {
     222                 :            :         const struct queue_missed_stat *missed_stat =
     223                 :          8 :                         queue_missed_stat_update(dev, qid);
     224                 :            : 
     225                 :          8 :         return missed_stat->pcap + missed_stat->mnemonic - missed_stat->reset;
     226                 :            : }
     227                 :            : 
     228                 :            : static int
     229                 :         32 : eth_pcap_rx_jumbo(struct rte_mempool *mb_pool, struct rte_mbuf *mbuf,
     230                 :            :                 const u_char *data, uint16_t data_len)
     231                 :            : {
     232                 :            :         /* Copy the first segment. */
     233                 :            :         uint16_t len = rte_pktmbuf_tailroom(mbuf);
     234                 :            :         struct rte_mbuf *m = mbuf;
     235                 :            : 
     236                 :         32 :         rte_memcpy(rte_pktmbuf_append(mbuf, len), data, len);
     237                 :         32 :         data_len -= len;
     238                 :         32 :         data += len;
     239                 :            : 
     240         [ +  + ]:        160 :         while (data_len > 0) {
     241                 :            :                 /* Allocate next mbuf and point to that. */
     242                 :        128 :                 m->next = rte_pktmbuf_alloc(mb_pool);
     243                 :            : 
     244         [ +  - ]:        128 :                 if (unlikely(!m->next))
     245                 :            :                         return -1;
     246                 :            : 
     247                 :            :                 m = m->next;
     248                 :            : 
     249                 :            :                 /* Headroom is not needed in chained mbufs. */
     250                 :            :                 rte_pktmbuf_prepend(m, rte_pktmbuf_headroom(m));
     251                 :        128 :                 m->pkt_len = 0;
     252                 :        128 :                 m->data_len = 0;
     253                 :            : 
     254                 :            :                 /* Copy next segment. */
     255                 :        128 :                 len = RTE_MIN(rte_pktmbuf_tailroom(m), data_len);
     256                 :        128 :                 rte_memcpy(rte_pktmbuf_append(m, len), data, len);
     257                 :            : 
     258                 :        128 :                 mbuf->nb_segs++;
     259                 :        128 :                 data_len -= len;
     260                 :        128 :                 data += len;
     261                 :            :         }
     262                 :            : 
     263                 :         32 :         return mbuf->nb_segs;
     264                 :            : }
     265                 :            : 
     266                 :            : static uint16_t
     267                 :          8 : eth_pcap_rx_infinite(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     268                 :            : {
     269                 :            :         int i;
     270                 :            :         struct pcap_rx_queue *pcap_q = queue;
     271                 :            :         uint32_t rx_bytes = 0;
     272                 :            : 
     273         [ +  - ]:          8 :         if (unlikely(nb_pkts == 0))
     274                 :            :                 return 0;
     275                 :            : 
     276         [ +  - ]:          8 :         if (rte_pktmbuf_alloc_bulk(pcap_q->mb_pool, bufs, nb_pkts) != 0)
     277                 :            :                 return 0;
     278                 :            : 
     279         [ +  + ]:        264 :         for (i = 0; i < nb_pkts; i++) {
     280                 :            :                 struct rte_mbuf *pcap_buf;
     281   [ -  +  -  -  :        256 :                 int err = rte_ring_dequeue(pcap_q->pkts, (void **)&pcap_buf);
                      - ]
     282                 :            :                 if (err)
     283                 :          0 :                         return i;
     284                 :            : 
     285                 :        256 :                 rte_memcpy(rte_pktmbuf_mtod(bufs[i], void *),
     286                 :        256 :                                 rte_pktmbuf_mtod(pcap_buf, void *),
     287         [ +  - ]:        256 :                                 pcap_buf->data_len);
     288                 :        256 :                 bufs[i]->data_len = pcap_buf->data_len;
     289                 :        256 :                 bufs[i]->pkt_len = pcap_buf->pkt_len;
     290                 :        256 :                 bufs[i]->port = pcap_q->port_id;
     291                 :            : 
     292         [ -  + ]:        256 :                 if (pcap_q->vlan_strip)
     293                 :          0 :                         rte_vlan_strip(bufs[i]);
     294                 :            : 
     295         [ +  - ]:        256 :                 if (pcap_q->timestamp_offloading) {
     296                 :            :                         struct timespec ts;
     297                 :            : 
     298                 :        256 :                         timespec_get(&ts, TIME_UTC);
     299                 :        256 :                         *RTE_MBUF_DYNFIELD(bufs[i], timestamp_dynfield_offset,
     300                 :        256 :                                            rte_mbuf_timestamp_t *) = rte_timespec_to_ns(&ts);
     301                 :        256 :                         bufs[i]->ol_flags |= timestamp_rx_dynflag;
     302                 :            :                 }
     303                 :            : 
     304                 :        256 :                 rx_bytes += bufs[i]->data_len;
     305                 :            : 
     306                 :            :                 /* Enqueue packet back on ring to allow infinite rx. */
     307   [ -  +  -  -  :        512 :                 rte_ring_enqueue(pcap_q->pkts, pcap_buf);
                      - ]
     308                 :            :         }
     309                 :            : 
     310                 :          8 :         pcap_q->rx_stat.pkts += i;
     311                 :          8 :         pcap_q->rx_stat.bytes += rx_bytes;
     312                 :            : 
     313                 :          8 :         return i;
     314                 :            : }
     315                 :            : 
     316                 :            : /*
     317                 :            :  * Deferred EOF alarm callback.
     318                 :            :  *
     319                 :            :  * Scheduled from the RX burst path when end-of-file is reached,
     320                 :            :  * so that rte_eth_dev_callback_process() runs outside the datapath.
     321                 :            :  * This avoids holding any locks that the application callback
     322                 :            :  * might also need, preventing potential deadlocks.
     323                 :            :  */
     324                 :            : static void
     325                 :          2 : eth_pcap_eof_alarm(void *arg)
     326                 :            : {
     327                 :            :         struct rte_eth_dev *dev = arg;
     328                 :            : 
     329                 :          2 :         rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
     330                 :          2 : }
     331                 :            : 
     332                 :            : static uint16_t
     333                 :        207 : eth_pcap_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     334                 :            : {
     335                 :            :         struct pcap_rx_queue *pcap_q = queue;
     336                 :        207 :         struct rte_eth_dev *dev = &rte_eth_devices[pcap_q->port_id];
     337                 :        207 :         struct pmd_internals *internals = dev->data->dev_private;
     338                 :            :         unsigned int i;
     339                 :            :         struct pcap_pkthdr *header;
     340                 :            :         struct pmd_process_private *pp;
     341                 :            :         const u_char *packet;
     342                 :            :         struct rte_mbuf *mbuf;
     343                 :            :         uint16_t num_rx = 0;
     344                 :            :         uint32_t rx_bytes = 0;
     345                 :            :         pcap_t *pcap;
     346                 :            : 
     347                 :        207 :         pp = rte_eth_devices[pcap_q->port_id].process_private;
     348                 :        207 :         pcap = pp->rx_pcap[pcap_q->queue_id];
     349                 :            : 
     350         [ +  - ]:        207 :         if (unlikely(pcap == NULL || nb_pkts == 0))
     351                 :            :                 return 0;
     352                 :            : 
     353                 :            :         /* Reads the given number of packets from the pcap file one by one
     354                 :            :          * and copies the packet data into a newly allocated mbuf to return.
     355                 :            :          */
     356         [ +  + ]:       1263 :         for (i = 0; i < nb_pkts; i++) {
     357                 :            :                 /* Get the next PCAP packet */
     358                 :       1111 :                 int ret = pcap_next_ex(pcap, &header, &packet);
     359         [ +  + ]:       1111 :                 if (ret != 1) {
     360         [ -  + ]:         55 :                         if (ret == PCAP_ERROR)
     361                 :          0 :                                 pcap_q->rx_stat.err_pkts++;
     362                 :            : 
     363                 :            :                         /*
     364                 :            :                          * EOF: if eof mode is enabled, set link down and
     365                 :            :                          * defer notification via alarm to avoid calling
     366                 :            :                          * rte_eth_dev_callback_process() from the datapath.
     367                 :            :                          */
     368         [ +  + ]:         55 :                         else if (ret == PCAP_ERROR_BREAK) {
     369                 :         48 :                                 bool expected = false;
     370                 :            : 
     371         [ +  + ]:         48 :                                 if (internals->eof &&
     372         [ +  - ]:          2 :                                     rte_atomic_compare_exchange_strong_explicit(
     373                 :            :                                             &internals->eof_signaled, &expected, true,
     374                 :            :                                             rte_memory_order_relaxed, rte_memory_order_relaxed)) {
     375                 :          2 :                                         eth_link_update(dev, 0);
     376                 :          2 :                                         rte_eal_alarm_set(1, eth_pcap_eof_alarm, dev);
     377                 :            :                                 }
     378                 :            :                         }
     379                 :            : 
     380                 :            :                         break;
     381                 :            :                 }
     382                 :            : 
     383                 :       1056 :                 mbuf = rte_pktmbuf_alloc(pcap_q->mb_pool);
     384         [ -  + ]:       1056 :                 if (unlikely(mbuf == NULL)) {
     385                 :          0 :                         pcap_q->rx_stat.rx_nombuf++;
     386                 :          0 :                         break;
     387                 :            :                 }
     388                 :            : 
     389         [ +  + ]:       1056 :                 uint32_t len = header->caplen;
     390         [ +  + ]:       1056 :                 if (len <= rte_pktmbuf_tailroom(mbuf)) {
     391                 :            :                         /* pcap packet will fit in the mbuf, can copy it */
     392         [ +  + ]:       1008 :                         rte_memcpy(rte_pktmbuf_mtod(mbuf, void *), packet, len);
     393                 :       1008 :                         mbuf->data_len = len;
     394         [ +  + ]:         48 :                 } else if (pcap_q->rx_scatter) {
     395                 :            :                         /* Scatter into multi-segment mbufs. */
     396         [ -  + ]:         32 :                         if (unlikely(eth_pcap_rx_jumbo(pcap_q->mb_pool,
     397                 :            :                                                        mbuf, packet, len) == -1)) {
     398                 :          0 :                                 pcap_q->rx_stat.err_pkts++;
     399                 :          0 :                                 rte_pktmbuf_free(mbuf);
     400                 :          0 :                                 break;
     401                 :            :                         }
     402                 :            :                 } else {
     403                 :            :                         /* Packet too large and scatter not enabled, drop it. */
     404                 :         16 :                         pcap_q->rx_stat.err_pkts++;
     405                 :         16 :                         rte_pktmbuf_free(mbuf);
     406                 :         16 :                         continue;
     407                 :            :                 }
     408                 :            : 
     409                 :       1040 :                 mbuf->pkt_len = len;
     410                 :            : 
     411         [ -  + ]:       1040 :                 if (pcap_q->vlan_strip)
     412                 :          0 :                         rte_vlan_strip(mbuf);
     413                 :            : 
     414         [ +  + ]:       1040 :                 if (pcap_q->timestamp_offloading) {
     415                 :            :                         /*
     416                 :            :                          * The use of tv_usec as nanoseconds is not a bug here.
     417                 :            :                          * Interface is always created with nanosecond precision, and
     418                 :            :                          * that is how pcap API bodged in nanoseconds support.
     419                 :            :                          */
     420                 :        496 :                         uint64_t ns = (uint64_t)header->ts.tv_sec * NSEC_PER_SEC
     421                 :        496 :                                 +  header->ts.tv_usec;
     422                 :            : 
     423                 :        496 :                         *RTE_MBUF_DYNFIELD(mbuf, timestamp_dynfield_offset,
     424                 :        496 :                                            rte_mbuf_timestamp_t *) = ns;
     425                 :            : 
     426                 :        496 :                         mbuf->ol_flags |= timestamp_rx_dynflag;
     427                 :            :                 }
     428                 :            : 
     429                 :       1040 :                 mbuf->port = pcap_q->port_id;
     430                 :       1040 :                 bufs[num_rx] = mbuf;
     431                 :       1040 :                 num_rx++;
     432                 :       1040 :                 rx_bytes += len;
     433                 :            :         }
     434                 :        207 :         pcap_q->rx_stat.pkts += num_rx;
     435                 :        207 :         pcap_q->rx_stat.bytes += rx_bytes;
     436                 :            : 
     437                 :        207 :         return num_rx;
     438                 :            : }
     439                 :            : 
     440                 :            : static uint16_t
     441                 :          0 : eth_null_rx(void *queue __rte_unused,
     442                 :            :                 struct rte_mbuf **bufs __rte_unused,
     443                 :            :                 uint16_t nb_pkts __rte_unused)
     444                 :            : {
     445                 :          0 :         return 0;
     446                 :            : }
     447                 :            : 
     448                 :            : /*
     449                 :            :  * Calculate current timestamp in nanoseconds by computing
     450                 :            :  * offset from starting time value.
     451                 :            :  *
     452                 :            :  * Note: it is not a bug that this code is putting nanosecond
     453                 :            :  * value into microsecond timeval field. The pcap API is old
     454                 :            :  * and nanoseconds were bodged on as an after thought.
     455                 :            :  * As long as the pcap stream is set to nanosecond precision
     456                 :            :  * it expects nanoseconds here.
     457                 :            :  */
     458                 :            : static inline void
     459                 :         13 : calculate_timestamp(struct timeval *ts)
     460                 :            : {
     461                 :            :         uint64_t cycles;
     462                 :            :         struct timespec cur_time;
     463                 :            : 
     464                 :         13 :         cycles = rte_get_timer_cycles() - start_cycles;
     465                 :         13 :         cur_time.tv_sec = cycles / hz;
     466                 :         13 :         cur_time.tv_nsec = (cycles % hz) * NSEC_PER_SEC / hz;
     467                 :            : 
     468                 :         13 :         ts->tv_sec = start_time.tv_sec + cur_time.tv_sec;
     469                 :         13 :         ts->tv_usec = start_time.tv_nsec + cur_time.tv_nsec;
     470         [ +  + ]:         13 :         if (ts->tv_usec >= NSEC_PER_SEC) {
     471                 :          5 :                 ts->tv_usec -= NSEC_PER_SEC;
     472                 :          5 :                 ts->tv_sec += 1;
     473                 :            :         }
     474                 :         13 : }
     475                 :            : 
     476                 :            : /*
     477                 :            :  * Insert VLAN tag into packet.
     478                 :            :  *
     479                 :            :  * rte_vlan_insert() modifies the mbuf in place, prepending
     480                 :            :  * RTE_VLAN_HLEN bytes. If mbuf cannot safely be modified in place
     481                 :            :  * a private copy is made first.
     482                 :            :  *
     483                 :            :  * The caller's mbuf pointer is updated on success; on failure the
     484                 :            :  * original mbuf is freed and -1 is returned.
     485                 :            :  */
     486                 :            : static int
     487                 :          0 : pcap_tx_vlan_insert(struct rte_mbuf **m)
     488                 :            : {
     489         [ #  # ]:          0 :         struct rte_mbuf *mbuf = *m;
     490                 :            : 
     491   [ #  #  #  # ]:          0 :         if (rte_mbuf_refcnt_read(mbuf) > 1 ||
     492         [ #  # ]:          0 :             rte_pktmbuf_headroom(mbuf) < RTE_VLAN_HLEN) {
     493                 :            :                 struct rte_mbuf *copy;
     494                 :            : 
     495                 :          0 :                 copy = rte_pktmbuf_copy(mbuf, mbuf->pool, 0, UINT32_MAX);
     496         [ #  # ]:          0 :                 if (unlikely(copy == NULL)) {
     497                 :          0 :                         rte_pktmbuf_free(mbuf);
     498                 :          0 :                         return -1;
     499                 :            :                 }
     500                 :          0 :                 copy->ol_flags |= RTE_MBUF_F_TX_VLAN;
     501                 :          0 :                 copy->vlan_tci = mbuf->vlan_tci;
     502                 :          0 :                 rte_pktmbuf_free(mbuf);
     503                 :          0 :                 *m = copy;
     504                 :          0 :                 mbuf = copy;
     505                 :            :         }
     506                 :            : 
     507         [ #  # ]:          0 :         if (unlikely(rte_vlan_insert(&mbuf) != 0)) {
     508                 :          0 :                 rte_pktmbuf_free(mbuf);
     509                 :          0 :                 return -1;
     510                 :            :         }
     511                 :          0 :         *m = mbuf;
     512                 :          0 :         return 0;
     513                 :            : }
     514                 :            : 
     515                 :            : /*
     516                 :            :  * Callback to handle writing packets to a pcap file.
     517                 :            :  */
     518                 :            : static uint16_t
     519                 :         13 : eth_pcap_tx_dumper(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     520                 :            : {
     521                 :            :         struct pcap_tx_queue *dumper_q = queue;
     522                 :         13 :         struct rte_eth_dev *dev = &rte_eth_devices[dumper_q->port_id];
     523                 :         13 :         struct pmd_internals *internals = dev->data->dev_private;
     524                 :         13 :         struct pmd_process_private *pp = dev->process_private;
     525                 :         13 :         pcap_dumper_t *dumper = pp->tx_dumper[dumper_q->queue_id];
     526                 :         13 :         unsigned char *temp_data = dumper_q->bounce_buf;
     527                 :         13 :         uint32_t snaplen = internals->snapshot_len;
     528                 :            :         uint16_t num_tx = 0;
     529                 :            :         uint32_t tx_bytes = 0;
     530                 :            :         struct pcap_pkthdr header;
     531                 :            :         unsigned int i;
     532                 :            : 
     533         [ +  - ]:         13 :         if (unlikely(dumper == NULL))
     534                 :            :                 return 0;
     535                 :            : 
     536                 :            :         /* all packets in burst have same timestamp */
     537                 :         13 :         calculate_timestamp(&header.ts);
     538                 :            : 
     539                 :            :         /* writes the nb_pkts packets to the previously opened pcap file dumper */
     540         [ +  + ]:        418 :         for (i = 0; i < nb_pkts; i++) {
     541                 :        405 :                 struct rte_mbuf *mbuf = bufs[i];
     542                 :            :                 uint32_t len, caplen;
     543                 :            :                 const uint8_t *data;
     544                 :            : 
     545                 :            :                 /* Do VLAN tag insertion */
     546         [ -  + ]:        405 :                 if (unlikely(mbuf->ol_flags & RTE_MBUF_F_TX_VLAN)) {
     547         [ #  # ]:          0 :                         if (pcap_tx_vlan_insert(&mbuf) != 0) {
     548                 :          0 :                                 dumper_q->tx_stat.err_pkts++;
     549                 :          0 :                                 continue;
     550                 :            :                         }
     551                 :          0 :                         bufs[i] = mbuf;
     552                 :            :                 }
     553                 :            : 
     554                 :        405 :                 len = rte_pktmbuf_pkt_len(mbuf);
     555                 :        405 :                 caplen = RTE_MIN(len, snaplen);
     556                 :            : 
     557                 :        405 :                 header.len = len;
     558         [ +  + ]:        405 :                 header.caplen = caplen;
     559                 :            : 
     560                 :            :                 data = rte_pktmbuf_read(mbuf, 0, caplen, temp_data);
     561                 :            : 
     562                 :            :                 /* This could only happen if mbuf is bogus pkt_len > data_len */
     563                 :            :                 RTE_ASSERT(data != NULL);
     564                 :        405 :                 pcap_dump((u_char *)dumper, &header, data);
     565                 :            : 
     566                 :        405 :                 num_tx++;
     567                 :        405 :                 tx_bytes += caplen;
     568                 :            : 
     569                 :        405 :                 rte_pktmbuf_free(mbuf);
     570                 :            :         }
     571                 :            : 
     572                 :            :         /*
     573                 :            :          * Since there's no place to hook a callback when the forwarding
     574                 :            :          * process stops and to make sure the pcap file is actually written,
     575                 :            :          * we flush the pcap dumper within each burst.
     576                 :            :          */
     577                 :         13 :         pcap_dump_flush(dumper);
     578                 :         13 :         dumper_q->tx_stat.pkts += num_tx;
     579                 :         13 :         dumper_q->tx_stat.bytes += tx_bytes;
     580                 :            : 
     581                 :         13 :         return i;
     582                 :            : }
     583                 :            : 
     584                 :            : /*
     585                 :            :  * Callback to handle dropping packets in the infinite rx case.
     586                 :            :  */
     587                 :            : static uint16_t
     588                 :          1 : eth_tx_drop(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     589                 :            : {
     590                 :            :         unsigned int i;
     591                 :            :         uint32_t tx_bytes = 0;
     592                 :            :         struct pcap_tx_queue *tx_queue = queue;
     593                 :            : 
     594         [ +  + ]:         65 :         for (i = 0; i < nb_pkts; i++) {
     595                 :         64 :                 tx_bytes += bufs[i]->pkt_len;
     596                 :         64 :                 rte_pktmbuf_free(bufs[i]);
     597                 :            :         }
     598                 :            : 
     599                 :          1 :         tx_queue->tx_stat.pkts += nb_pkts;
     600                 :          1 :         tx_queue->tx_stat.bytes += tx_bytes;
     601                 :            : 
     602                 :          1 :         return nb_pkts;
     603                 :            : }
     604                 :            : 
     605                 :            : /*
     606                 :            :  * Send a burst of packets to a pcap device.
     607                 :            :  *
     608                 :            :  * On Linux, pcap_sendpacket() calls send() on a blocking PF_PACKET
     609                 :            :  * socket with default kernel buffer sizes and no TX ring (PACKET_TX_RING).
     610                 :            :  * The send() call only blocks when the kernel socket send buffer is full,
     611                 :            :  * providing limited backpressure.
     612                 :            :  *
     613                 :            :  * On error, pcap_sendpacket() returns non-zero and the loop breaks,
     614                 :            :  * leaving remaining packets unsent.
     615                 :            :  *
     616                 :            :  * Bottom line: backpressure is not an error.
     617                 :            :  */
     618                 :            : static uint16_t
     619                 :          3 : eth_pcap_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     620                 :            : {
     621                 :            :         struct pcap_tx_queue *tx_queue = queue;
     622                 :          3 :         struct rte_eth_dev *dev = &rte_eth_devices[tx_queue->port_id];
     623                 :          3 :         struct pmd_process_private *pp = dev->process_private;
     624                 :          3 :         struct pmd_internals *internals = dev->data->dev_private;
     625                 :          3 :         uint32_t snaplen = internals->snapshot_len;
     626                 :          3 :         pcap_t *pcap = pp->tx_pcap[tx_queue->queue_id];
     627                 :          3 :         unsigned char *temp_data = tx_queue->bounce_buf;
     628                 :            :         uint16_t num_tx = 0;
     629                 :            :         uint32_t tx_bytes = 0;
     630                 :            :         unsigned int i;
     631                 :            : 
     632         [ +  - ]:          3 :         if (unlikely(pcap == NULL))
     633                 :            :                 return 0;
     634                 :            : 
     635         [ +  + ]:         99 :         for (i = 0; i < nb_pkts; i++) {
     636                 :         96 :                 struct rte_mbuf *mbuf = bufs[i];
     637                 :            :                 uint32_t len;
     638                 :            :                 const uint8_t *data;
     639                 :            : 
     640                 :            :                 /* Do VLAN tag insertion */
     641         [ -  + ]:         96 :                 if (unlikely(mbuf->ol_flags & RTE_MBUF_F_TX_VLAN)) {
     642         [ #  # ]:          0 :                         if (pcap_tx_vlan_insert(&mbuf) != 0) {
     643                 :          0 :                                 tx_queue->tx_stat.err_pkts++;
     644                 :          0 :                                 continue;
     645                 :            :                         }
     646                 :          0 :                         bufs[i] = mbuf;
     647                 :            :                 }
     648                 :            : 
     649         [ -  + ]:         96 :                 len = rte_pktmbuf_pkt_len(mbuf);
     650                 :            : 
     651                 :            :                 /*
     652                 :            :                  * multi-segment transmit that has to go through bounce buffer.
     653                 :            :                  * Make sure it fits; don't want to truncate the packet.
     654                 :            :                  */
     655   [ -  +  -  - ]:         96 :                 if (unlikely(!rte_pktmbuf_is_contiguous(mbuf) && len > snaplen)) {
     656                 :            :                         PMD_TX_LOG(ERR, "Multi segment len (%u) > snaplen (%u)",
     657                 :            :                                    len, snaplen);
     658                 :          0 :                         rte_pktmbuf_free(mbuf);
     659                 :          0 :                         tx_queue->tx_stat.err_pkts++;
     660                 :          0 :                         continue;
     661                 :            :                 }
     662                 :            : 
     663                 :            :                 data = rte_pktmbuf_read(mbuf, 0, len, temp_data);
     664                 :            :                 RTE_ASSERT(data != NULL);
     665                 :            : 
     666         [ -  + ]:         96 :                 if (unlikely(pcap_sendpacket(pcap, data, len) != 0)) {
     667                 :            :                         /* Assume failure is backpressure */
     668                 :          0 :                         PMD_LOG(ERR, "pcap_sendpacket() failed: %s", pcap_geterr(pcap));
     669                 :          0 :                         break;
     670                 :            :                 }
     671                 :         96 :                 num_tx++;
     672                 :         96 :                 tx_bytes += len;
     673                 :         96 :                 rte_pktmbuf_free(mbuf);
     674                 :            :         }
     675                 :            : 
     676                 :          3 :         tx_queue->tx_stat.pkts += num_tx;
     677                 :          3 :         tx_queue->tx_stat.bytes += tx_bytes;
     678                 :            : 
     679                 :          3 :         return i;
     680                 :            : }
     681                 :            : 
     682                 :            : /*
     683                 :            :  * pcap_open_live wrapper function
     684                 :            :  */
     685                 :            : static inline int
     686                 :          7 : open_iface_live(const char *iface, pcap_t **pcap, uint32_t snaplen)
     687                 :            : {
     688                 :            :         char errbuf[PCAP_ERRBUF_SIZE];
     689                 :            :         pcap_t *pc;
     690                 :            :         int status;
     691                 :            : 
     692                 :          7 :         pc = pcap_create(iface, errbuf);
     693         [ -  + ]:          7 :         if (pc == NULL) {
     694                 :          0 :                 PMD_LOG(ERR, "Couldn't create %s: %s", iface, errbuf);
     695                 :          0 :                 goto error;
     696                 :            :         }
     697                 :            : 
     698                 :          7 :         status = pcap_set_tstamp_precision(pc, PCAP_TSTAMP_PRECISION_NANO);
     699         [ -  + ]:          7 :         if (status != 0) {
     700                 :          0 :                 PMD_LOG(ERR, "%s: Could not set to ns precision: %s",
     701                 :            :                         iface, pcap_statustostr(status));
     702                 :          0 :                 goto error;
     703                 :            :         }
     704                 :            : 
     705                 :          7 :         status = pcap_set_immediate_mode(pc, 1);
     706         [ -  + ]:          7 :         if (status != 0)
     707                 :          0 :                 PMD_LOG(WARNING, "%s: Could not set to immediate mode: %s",
     708                 :            :                         iface, pcap_statustostr(status));
     709                 :            : 
     710                 :          7 :         status = pcap_set_promisc(pc, 1);
     711         [ -  + ]:          7 :         if (status != 0)
     712                 :          0 :                 PMD_LOG(WARNING, "%s: Could not set to promiscuous: %s",
     713                 :            :                         iface, pcap_statustostr(status));
     714                 :            : 
     715                 :          7 :         status = pcap_set_snaplen(pc, snaplen);
     716         [ -  + ]:          7 :         if (status != 0)
     717                 :          0 :                 PMD_LOG(WARNING, "%s: Could not set snapshot length: %s",
     718                 :            :                         iface, pcap_statustostr(status));
     719                 :            : 
     720                 :          7 :         status = pcap_activate(pc);
     721         [ -  + ]:          7 :         if (status < 0) {
     722                 :          0 :                 char *cp = pcap_geterr(pc);
     723                 :            : 
     724         [ #  # ]:          0 :                 if (status == PCAP_ERROR)
     725                 :          0 :                         PMD_LOG(ERR, "%s: could not activate: %s", iface, cp);
     726                 :            :                 else
     727                 :          0 :                         PMD_LOG(ERR, "%s: %s (%s)", iface, pcap_statustostr(status), cp);
     728                 :          0 :                 goto error;
     729         [ -  + ]:          7 :         } else if (status > 0) {
     730                 :            :                 /* Warning condition - log but continue */
     731                 :          0 :                 PMD_LOG(WARNING, "%s: %s", iface, pcap_statustostr(status));
     732                 :            :         }
     733                 :            : 
     734                 :            :         /*
     735                 :            :          * Verify interface supports Ethernet link type.
     736                 :            :          * Loopback on FreeBSD/macOS uses DLT_NULL which expects a 4-byte
     737                 :            :          * address family header instead of Ethernet, causing kernel warnings.
     738                 :            :          */
     739         [ -  + ]:          7 :         if (pcap_datalink(pc) != DLT_EN10MB) {
     740                 :          0 :                 PMD_LOG(ERR, "%s: not Ethernet (link type %d)",
     741                 :            :                         iface, pcap_datalink(pc));
     742                 :          0 :                 goto error;
     743                 :            :         }
     744                 :            : 
     745         [ -  + ]:          7 :         if (pcap_setnonblock(pc, 1, errbuf)) {
     746                 :          0 :                 PMD_LOG(ERR, "Couldn't set non-blocking on %s: %s", iface, errbuf);
     747                 :          0 :                 goto error;
     748                 :            :         }
     749                 :            : 
     750                 :          7 :         *pcap = pc;
     751                 :          7 :         return 0;
     752                 :            : 
     753                 :          0 : error:
     754         [ #  # ]:          0 :         if (pc != NULL)
     755                 :          0 :                 pcap_close(pc);
     756                 :            :         return -1;
     757                 :            : }
     758                 :            : 
     759                 :            : static int
     760                 :          7 : open_single_iface(const char *iface, pcap_t **pcap, uint32_t snaplen)
     761                 :            : {
     762         [ -  + ]:          7 :         if (open_iface_live(iface, pcap, snaplen) < 0) {
     763                 :          0 :                 PMD_LOG(ERR, "Couldn't open interface %s", iface);
     764                 :          0 :                 return -1;
     765                 :            :         }
     766                 :            : 
     767                 :            :         return 0;
     768                 :            : }
     769                 :            : 
     770                 :            : static int
     771                 :         14 : open_single_tx_pcap(const char *pcap_filename, pcap_dumper_t **dumper,
     772                 :            :                     uint32_t snaplen)
     773                 :            : {
     774                 :            :         pcap_t *tx_pcap;
     775                 :            : 
     776                 :            :         /*
     777                 :            :          * We need to create a dummy empty pcap_t to use it
     778                 :            :          * with pcap_dump_open(). We create big enough an Ethernet
     779                 :            :          * pcap holder.
     780                 :            :          */
     781                 :         14 :         tx_pcap = pcap_open_dead_with_tstamp_precision(DLT_EN10MB,
     782                 :            :                         snaplen, PCAP_TSTAMP_PRECISION_NANO);
     783         [ -  + ]:         14 :         if (tx_pcap == NULL) {
     784                 :          0 :                 PMD_LOG(ERR, "Couldn't create dead pcap");
     785                 :          0 :                 return -1;
     786                 :            :         }
     787                 :            : 
     788                 :            :         /* The dumper is created using the previous pcap_t reference */
     789                 :         14 :         *dumper = pcap_dump_open(tx_pcap, pcap_filename);
     790         [ -  + ]:         14 :         if (*dumper == NULL) {
     791                 :          0 :                 PMD_LOG(ERR, "Couldn't open %s for writing: %s",
     792                 :            :                         pcap_filename, pcap_geterr(tx_pcap));
     793                 :          0 :                 pcap_close(tx_pcap);
     794                 :          0 :                 return -1;
     795                 :            :         }
     796                 :            : 
     797                 :         14 :         pcap_close(tx_pcap);
     798                 :         14 :         return 0;
     799                 :            : }
     800                 :            : 
     801                 :            : static int
     802                 :         25 : open_single_rx_pcap(const char *pcap_filename, pcap_t **pcap)
     803                 :            : {
     804                 :            :         char errbuf[PCAP_ERRBUF_SIZE];
     805                 :            : 
     806                 :         25 :         *pcap = pcap_open_offline_with_tstamp_precision(pcap_filename,
     807                 :            :                                                         PCAP_TSTAMP_PRECISION_NANO, errbuf);
     808         [ -  + ]:         25 :         if (*pcap == NULL) {
     809                 :          0 :                 PMD_LOG(ERR, "Couldn't open %s: %s", pcap_filename,
     810                 :            :                         errbuf);
     811                 :          0 :                 return -1;
     812                 :            :         }
     813                 :            : 
     814                 :            :         return 0;
     815                 :            : }
     816                 :            : 
     817                 :            : static uint64_t
     818                 :          2 : count_packets_in_pcap(pcap_t **pcap, struct pcap_rx_queue *pcap_q)
     819                 :            : {
     820                 :            :         const u_char *packet;
     821                 :            :         struct pcap_pkthdr header;
     822                 :            :         uint64_t pcap_pkt_count = 0;
     823                 :            : 
     824         [ +  + ]:        130 :         while ((packet = pcap_next(*pcap, &header)))
     825                 :        128 :                 pcap_pkt_count++;
     826                 :            : 
     827                 :            :         /* The pcap is reopened so it can be used as normal later. */
     828                 :          2 :         pcap_close(*pcap);
     829                 :          2 :         *pcap = NULL;
     830                 :          2 :         open_single_rx_pcap(pcap_q->name, pcap);
     831                 :            : 
     832                 :          2 :         return pcap_pkt_count;
     833                 :            : }
     834                 :            : 
     835                 :            : /*
     836                 :            :  * Periodic alarm to poll link state.
     837                 :            :  * Enabled when link state interrupt is enabled in single_iface mode.
     838                 :            :  */
     839                 :            : static void
     840                 :          0 : eth_pcap_lsc_alarm(void *arg)
     841                 :            : {
     842                 :            :         struct rte_eth_dev *dev = arg;
     843                 :          0 :         struct pmd_internals *internals = dev->data->dev_private;
     844                 :            :         struct rte_eth_link old_link, new_link;
     845                 :            : 
     846                 :          0 :         rte_eth_linkstatus_get(dev, &old_link);
     847                 :          0 :         eth_link_update(dev, 0);
     848                 :          0 :         rte_eth_linkstatus_get(dev, &new_link);
     849                 :            : 
     850         [ #  # ]:          0 :         if (old_link.link_status != new_link.link_status)
     851                 :          0 :                 rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC, NULL);
     852                 :            : 
     853         [ #  # ]:          0 :         if (internals->lsc_active)
     854                 :          0 :                 rte_eal_alarm_set(ETH_PCAP_LSC_POLL_INTERVAL_US, eth_pcap_lsc_alarm, dev);
     855                 :          0 : }
     856                 :            : 
     857                 :            : static int
     858                 :          1 : set_iface_direction(const char *iface, pcap_t *pcap,
     859                 :            :                 pcap_direction_t direction)
     860                 :            : {
     861         [ -  + ]:          1 :         const char *direction_str = (direction == PCAP_D_IN) ? "IN" : "OUT";
     862         [ -  + ]:          1 :         if (pcap_setdirection(pcap, direction) < 0) {
     863                 :          0 :                 PMD_LOG(ERR, "Setting %s pcap direction %s failed - %s",
     864                 :            :                                 iface, direction_str, pcap_geterr(pcap));
     865                 :          0 :                 return -1;
     866                 :            :         }
     867                 :          1 :         PMD_LOG(INFO, "Setting %s pcap direction %s",
     868                 :            :                         iface, direction_str);
     869                 :          1 :         return 0;
     870                 :            : }
     871                 :            : 
     872                 :            : static int
     873                 :         26 : eth_dev_start(struct rte_eth_dev *dev)
     874                 :            : {
     875                 :            :         unsigned int i;
     876                 :         26 :         struct pmd_internals *internals = dev->data->dev_private;
     877                 :         26 :         struct pmd_process_private *pp = dev->process_private;
     878                 :            :         struct pcap_tx_queue *tx;
     879                 :            :         struct pcap_rx_queue *rx;
     880                 :         26 :         uint32_t snaplen = internals->snapshot_len;
     881                 :            : 
     882                 :            :         /* Special iface case. Single pcap is open and shared between tx/rx. */
     883         [ +  + ]:         26 :         if (internals->single_iface) {
     884                 :            :                 tx = &internals->tx_queue[0];
     885                 :            :                 rx = &internals->rx_queue[0];
     886                 :            : 
     887   [ -  +  -  - ]:          3 :                 if (!pp->tx_pcap[0] && strcmp(tx->type, ETH_PCAP_IFACE_ARG) == 0) {
     888         [ #  # ]:          0 :                         if (open_single_iface(tx->name, &pp->tx_pcap[0], snaplen) < 0)
     889                 :            :                                 return -1;
     890                 :          0 :                         pp->rx_pcap[0] = pp->tx_pcap[0];
     891                 :            :                 }
     892                 :            : 
     893                 :          3 :                 goto status_up;
     894                 :            :         }
     895                 :            : 
     896                 :            :         /* If not open already, open tx pcaps/dumpers */
     897         [ +  + ]:         48 :         for (i = 0; i < dev->data->nb_tx_queues; i++) {
     898                 :            :                 tx = &internals->tx_queue[i];
     899                 :            : 
     900   [ +  +  -  + ]:         25 :                 if (!pp->tx_dumper[i] && strcmp(tx->type, ETH_PCAP_TX_PCAP_ARG) == 0) {
     901         [ #  # ]:          0 :                         if (open_single_tx_pcap(tx->name, &pp->tx_dumper[i], snaplen) < 0)
     902                 :            :                                 return -1;
     903   [ +  +  -  + ]:         25 :                 } else if (!pp->tx_pcap[i] && strcmp(tx->type, ETH_PCAP_TX_IFACE_ARG) == 0) {
     904         [ #  # ]:          0 :                         if (open_single_iface(tx->name, &pp->tx_pcap[i], snaplen) < 0)
     905                 :            :                                 return -1;
     906                 :            :                 }
     907                 :            :         }
     908                 :            : 
     909                 :            :         /* If not open already, open rx pcaps */
     910         [ +  + ]:         48 :         for (i = 0; i < dev->data->nb_rx_queues; i++) {
     911                 :            :                 rx = &internals->rx_queue[i];
     912                 :            : 
     913         [ +  + ]:         25 :                 if (pp->rx_pcap[i] != NULL)
     914                 :         19 :                         continue;
     915                 :            : 
     916         [ +  + ]:          6 :                 if (strcmp(rx->type, ETH_PCAP_RX_PCAP_ARG) == 0) {
     917         [ +  - ]:          1 :                         if (open_single_rx_pcap(rx->name, &pp->rx_pcap[i]) < 0)
     918                 :            :                                 return -1;
     919         [ +  - ]:          5 :                 } else if (strcmp(rx->type, ETH_PCAP_RX_IFACE_ARG) == 0 ||
     920         [ -  + ]:          5 :                            strcmp(rx->type, ETH_PCAP_RX_IFACE_IN_ARG) == 0) {
     921         [ #  # ]:          0 :                         if (open_single_iface(rx->name, &pp->rx_pcap[i], snaplen) < 0)
     922                 :            :                                 return -1;
     923                 :            :                         /* Set direction for rx_iface_in */
     924         [ #  # ]:          0 :                         if (strcmp(rx->type, ETH_PCAP_RX_IFACE_IN_ARG) == 0)
     925                 :          0 :                                 set_iface_direction(rx->name, pp->rx_pcap[i],
     926                 :            :                                                     PCAP_D_IN);
     927                 :            :                 }
     928                 :            :         }
     929                 :            : 
     930                 :         23 : status_up:
     931         [ +  + ]:         54 :         for (i = 0; i < dev->data->nb_rx_queues; i++)
     932                 :         28 :                 dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
     933                 :            : 
     934         [ +  + ]:         54 :         for (i = 0; i < dev->data->nb_tx_queues; i++)
     935                 :         28 :                 dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
     936                 :            : 
     937                 :         26 :         rte_atomic_store_explicit(&internals->eof_signaled, false, rte_memory_order_relaxed);
     938                 :         26 :         dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
     939                 :            : 
     940                 :            :         /* Start LSC polling for iface mode if application requested it */
     941   [ +  +  -  + ]:         26 :         if (internals->single_iface && dev->data->dev_conf.intr_conf.lsc) {
     942                 :          0 :                 internals->lsc_active = true;
     943                 :          0 :                 rte_eal_alarm_set(ETH_PCAP_LSC_POLL_INTERVAL_US,
     944                 :            :                                   eth_pcap_lsc_alarm, dev);
     945                 :            :         }
     946                 :            : 
     947                 :            :         return 0;
     948                 :            : }
     949                 :            : 
     950                 :            : /*
     951                 :            :  * This function gets called when the current port gets stopped.
     952                 :            :  * Is the only place for us to close all the tx streams dumpers.
     953                 :            :  * If not called the dumpers will be flushed within each tx burst.
     954                 :            :  */
     955                 :            : static int
     956                 :         54 : eth_dev_stop(struct rte_eth_dev *dev)
     957                 :            : {
     958                 :            :         unsigned int i;
     959                 :         54 :         struct pmd_internals *internals = dev->data->dev_private;
     960                 :         54 :         struct pmd_process_private *pp = dev->process_private;
     961                 :            :         bool expected;
     962                 :            : 
     963                 :            :         /* Special iface case. Single pcap is open and shared between tx/rx. */
     964         [ +  + ]:         54 :         if (internals->single_iface) {
     965                 :            :                 /* Cancel LSC polling before closing pcap handles */
     966         [ -  + ]:          6 :                 if (internals->lsc_active) {
     967                 :          0 :                         internals->lsc_active = false;
     968                 :          0 :                         rte_eal_alarm_cancel(eth_pcap_lsc_alarm, dev);
     969                 :            :                 }
     970                 :            : 
     971                 :            :                 queue_missed_stat_on_stop_update(dev, 0);
     972         [ +  + ]:          6 :                 if (pp->tx_pcap[0] != NULL) {
     973                 :          3 :                         pcap_close(pp->tx_pcap[0]);
     974                 :          3 :                         pp->tx_pcap[0] = NULL;
     975                 :          3 :                         pp->rx_pcap[0] = NULL;
     976                 :            :                 }
     977                 :          6 :                 goto status_down;
     978                 :            :         }
     979                 :            : 
     980         [ +  + ]:        101 :         for (i = 0; i < dev->data->nb_tx_queues; i++) {
     981         [ +  + ]:         53 :                 if (pp->tx_dumper[i] != NULL) {
     982                 :         14 :                         pcap_dump_close(pp->tx_dumper[i]);
     983                 :         14 :                         pp->tx_dumper[i] = NULL;
     984                 :            :                 }
     985                 :            : 
     986         [ +  + ]:         53 :                 if (pp->tx_pcap[i] != NULL) {
     987                 :          2 :                         pcap_close(pp->tx_pcap[i]);
     988                 :          2 :                         pp->tx_pcap[i] = NULL;
     989                 :            :                 }
     990                 :            :         }
     991                 :            : 
     992         [ +  + ]:        102 :         for (i = 0; i < dev->data->nb_rx_queues; i++) {
     993         [ +  + ]:         54 :                 if (pp->rx_pcap[i] != NULL) {
     994                 :            :                         queue_missed_stat_on_stop_update(dev, i);
     995                 :         25 :                         pcap_close(pp->rx_pcap[i]);
     996                 :         25 :                         pp->rx_pcap[i] = NULL;
     997                 :            :                 }
     998                 :            :         }
     999                 :            : 
    1000                 :         48 : status_down:
    1001                 :            :         /* Cancel any pending EOF alarm */
    1002                 :         54 :         expected = true;
    1003         [ +  + ]:         54 :         if (rte_atomic_compare_exchange_strong_explicit(
    1004                 :            :                     &internals->eof_signaled, &expected, false,
    1005                 :            :                     rte_memory_order_relaxed, rte_memory_order_relaxed))
    1006                 :          2 :                 rte_eal_alarm_cancel(eth_pcap_eof_alarm, dev);
    1007                 :            : 
    1008         [ +  + ]:        114 :         for (i = 0; i < dev->data->nb_rx_queues; i++)
    1009                 :         60 :                 dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
    1010                 :            : 
    1011         [ +  + ]:        113 :         for (i = 0; i < dev->data->nb_tx_queues; i++)
    1012                 :         59 :                 dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
    1013                 :            : 
    1014                 :         54 :         dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
    1015                 :            : 
    1016                 :         54 :         return 0;
    1017                 :            : }
    1018                 :            : 
    1019                 :            : static int
    1020                 :         25 : eth_dev_configure(struct rte_eth_dev *dev)
    1021                 :            : {
    1022                 :         25 :         struct pmd_internals *internals = dev->data->dev_private;
    1023                 :            :         struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
    1024                 :            :         const struct rte_eth_rxmode *rxmode = &dev_conf->rxmode;
    1025                 :            : 
    1026                 :         25 :         internals->vlan_strip = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_VLAN_STRIP);
    1027                 :         25 :         internals->rx_scatter = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_SCATTER);
    1028                 :         25 :         internals->timestamp_offloading = !!(rxmode->offloads & RTE_ETH_RX_OFFLOAD_TIMESTAMP);
    1029                 :            : 
    1030   [ +  +  +  + ]:         25 :         if (internals->timestamp_offloading && timestamp_rx_dynflag == 0) {
    1031                 :          1 :                 int ret = rte_mbuf_dyn_rx_timestamp_register(&timestamp_dynfield_offset,
    1032                 :            :                                                              &timestamp_rx_dynflag);
    1033         [ -  + ]:          1 :                 if (ret != 0) {
    1034                 :          0 :                         PMD_LOG(ERR, "Failed to register Rx timestamp field/flag");
    1035                 :          0 :                         return ret;
    1036                 :            :                 }
    1037                 :            :         }
    1038                 :            : 
    1039                 :            :         return 0;
    1040                 :            : }
    1041                 :            : 
    1042                 :            : static int
    1043                 :        110 : eth_dev_info(struct rte_eth_dev *dev,
    1044                 :            :                 struct rte_eth_dev_info *dev_info)
    1045                 :            : {
    1046                 :        110 :         struct pmd_internals *internals = dev->data->dev_private;
    1047                 :            : 
    1048                 :        110 :         dev_info->if_index = internals->if_index;
    1049                 :        110 :         dev_info->max_mac_addrs = 1;
    1050                 :        110 :         dev_info->max_rx_pktlen = internals->snapshot_len;
    1051                 :        110 :         dev_info->max_rx_queues = dev->data->nb_rx_queues;
    1052                 :        110 :         dev_info->max_tx_queues = dev->data->nb_tx_queues;
    1053                 :        110 :         dev_info->min_rx_bufsize = RTE_ETHER_MIN_LEN;
    1054                 :        110 :         dev_info->max_mtu = internals->snapshot_len - RTE_ETHER_HDR_LEN;
    1055                 :        110 :         dev_info->tx_offload_capa = RTE_ETH_TX_OFFLOAD_MULTI_SEGS |
    1056                 :            :                 RTE_ETH_TX_OFFLOAD_VLAN_INSERT;
    1057                 :        110 :         dev_info->rx_offload_capa = RTE_ETH_RX_OFFLOAD_VLAN_STRIP |
    1058                 :            :                 RTE_ETH_RX_OFFLOAD_TIMESTAMP;
    1059                 :            : 
    1060         [ +  + ]:        110 :         if (!internals->infinite_rx)
    1061                 :        102 :                 dev_info->rx_offload_capa |= RTE_ETH_RX_OFFLOAD_SCATTER;
    1062                 :            : 
    1063                 :        110 :         return 0;
    1064                 :            : }
    1065                 :            : 
    1066                 :            : static int
    1067                 :          8 : eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats,
    1068                 :            :               struct eth_queue_stats *qstats)
    1069                 :            : {
    1070                 :            :         unsigned int i;
    1071                 :            :         unsigned long rx_packets_total = 0, rx_bytes_total = 0;
    1072                 :            :         unsigned long rx_missed_total = 0;
    1073                 :            :         unsigned long rx_nombuf_total = 0, rx_err_total = 0;
    1074                 :            :         unsigned long tx_packets_total = 0, tx_bytes_total = 0;
    1075                 :            :         unsigned long tx_packets_err_total = 0;
    1076                 :          8 :         const struct pmd_internals *internal = dev->data->dev_private;
    1077                 :            : 
    1078         [ +  - ]:         16 :         for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
    1079         [ +  + ]:         16 :                         i < dev->data->nb_rx_queues; i++) {
    1080         [ -  + ]:          8 :                 if (qstats != NULL) {
    1081                 :          0 :                         qstats->q_ipackets[i] = internal->rx_queue[i].rx_stat.pkts;
    1082                 :          0 :                         qstats->q_ibytes[i] = internal->rx_queue[i].rx_stat.bytes;
    1083                 :            :                 }
    1084                 :          8 :                 rx_nombuf_total += internal->rx_queue[i].rx_stat.rx_nombuf;
    1085                 :          8 :                 rx_err_total += internal->rx_queue[i].rx_stat.err_pkts;
    1086                 :          8 :                 rx_packets_total += internal->rx_queue[i].rx_stat.pkts;
    1087                 :          8 :                 rx_bytes_total += internal->rx_queue[i].rx_stat.bytes;
    1088                 :          8 :                 rx_missed_total += queue_missed_stat_get(dev, i);
    1089                 :            :         }
    1090                 :            : 
    1091         [ +  - ]:         16 :         for (i = 0; i < RTE_ETHDEV_QUEUE_STAT_CNTRS &&
    1092         [ +  + ]:         16 :                         i < dev->data->nb_tx_queues; i++) {
    1093         [ -  + ]:          8 :                 if (qstats != NULL) {
    1094                 :          0 :                         qstats->q_opackets[i] = internal->tx_queue[i].tx_stat.pkts;
    1095                 :          0 :                         qstats->q_obytes[i] = internal->tx_queue[i].tx_stat.bytes;
    1096                 :            :                 }
    1097                 :          8 :                 tx_packets_total += internal->tx_queue[i].tx_stat.pkts;
    1098                 :          8 :                 tx_bytes_total += internal->tx_queue[i].tx_stat.bytes;
    1099                 :          8 :                 tx_packets_err_total += internal->tx_queue[i].tx_stat.err_pkts;
    1100                 :            :         }
    1101                 :            : 
    1102                 :          8 :         stats->ipackets = rx_packets_total;
    1103                 :          8 :         stats->ibytes = rx_bytes_total;
    1104                 :          8 :         stats->imissed = rx_missed_total;
    1105                 :          8 :         stats->ierrors = rx_err_total;
    1106                 :          8 :         stats->rx_nombuf = rx_nombuf_total;
    1107                 :          8 :         stats->opackets = tx_packets_total;
    1108                 :          8 :         stats->obytes = tx_bytes_total;
    1109                 :          8 :         stats->oerrors = tx_packets_err_total;
    1110                 :            : 
    1111                 :          8 :         return 0;
    1112                 :            : }
    1113                 :            : 
    1114                 :            : static int
    1115                 :          5 : eth_stats_reset(struct rte_eth_dev *dev)
    1116                 :            : {
    1117                 :            :         unsigned int i;
    1118                 :          5 :         struct pmd_internals *internal = dev->data->dev_private;
    1119                 :            : 
    1120         [ +  + ]:         10 :         for (i = 0; i < dev->data->nb_rx_queues; i++) {
    1121                 :          5 :                 internal->rx_queue[i].rx_stat.pkts = 0;
    1122                 :          5 :                 internal->rx_queue[i].rx_stat.bytes = 0;
    1123                 :          5 :                 internal->rx_queue[i].rx_stat.err_pkts = 0;
    1124                 :          5 :                 internal->rx_queue[i].rx_stat.rx_nombuf = 0;
    1125                 :            :                 queue_missed_stat_reset(dev, i);
    1126                 :            :         }
    1127                 :            : 
    1128         [ +  + ]:         10 :         for (i = 0; i < dev->data->nb_tx_queues; i++) {
    1129                 :          5 :                 internal->tx_queue[i].tx_stat.pkts = 0;
    1130                 :          5 :                 internal->tx_queue[i].tx_stat.bytes = 0;
    1131                 :          5 :                 internal->tx_queue[i].tx_stat.err_pkts = 0;
    1132                 :            :         }
    1133                 :            : 
    1134                 :          5 :         return 0;
    1135                 :            : }
    1136                 :            : 
    1137                 :            : static inline void
    1138                 :          2 : infinite_rx_ring_free(struct rte_ring *pkts)
    1139                 :            : {
    1140                 :            :         struct rte_mbuf *bufs;
    1141                 :            : 
    1142                 :          2 :         while (!rte_ring_dequeue(pkts, (void **)&bufs))
    1143                 :        128 :                 rte_pktmbuf_free(bufs);
    1144                 :            : 
    1145                 :          2 :         rte_ring_free(pkts);
    1146                 :          2 : }
    1147                 :            : 
    1148                 :            : static int
    1149                 :         28 : eth_dev_close(struct rte_eth_dev *dev)
    1150                 :            : {
    1151                 :            :         unsigned int i;
    1152                 :         28 :         struct pmd_internals *internals = dev->data->dev_private;
    1153                 :            : 
    1154                 :         28 :         PMD_LOG(INFO, "Closing pcap ethdev on NUMA socket %d",
    1155                 :            :                         rte_socket_id());
    1156                 :            : 
    1157                 :         28 :         eth_dev_stop(dev);
    1158                 :            : 
    1159                 :         28 :         rte_free(dev->process_private);
    1160                 :            : 
    1161         [ +  - ]:         28 :         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
    1162                 :            :                 return 0;
    1163                 :            : 
    1164                 :            :         /* Device wide flag, but cleanup must be performed per queue. */
    1165         [ +  + ]:         28 :         if (internals->infinite_rx) {
    1166         [ +  + ]:          4 :                 for (i = 0; i < dev->data->nb_rx_queues; i++) {
    1167                 :            :                         struct pcap_rx_queue *pcap_q = &internals->rx_queue[i];
    1168                 :            : 
    1169                 :            :                         /*
    1170                 :            :                          * 'pcap_q->pkts' can be NULL if 'eth_dev_close()'
    1171                 :            :                          * called before 'eth_rx_queue_setup()' has been called
    1172                 :            :                          */
    1173         [ -  + ]:          2 :                         if (pcap_q->pkts == NULL)
    1174                 :          0 :                                 continue;
    1175                 :            : 
    1176                 :          2 :                         infinite_rx_ring_free(pcap_q->pkts);
    1177                 :            :                 }
    1178                 :            :         }
    1179                 :            : 
    1180         [ +  - ]:         28 :         if (!internals->phy_mac)
    1181                 :            :                 /* not dynamically allocated, must not be freed */
    1182                 :         28 :                 dev->data->mac_addrs = NULL;
    1183                 :            : 
    1184                 :            :         return 0;
    1185                 :            : }
    1186                 :            : 
    1187                 :            : static int
    1188                 :         31 : eth_link_update(struct rte_eth_dev *dev, int wait_to_complete __rte_unused)
    1189                 :            : {
    1190                 :         31 :         struct pmd_internals *internals = dev->data->dev_private;
    1191                 :         31 :         struct rte_eth_link link = {
    1192                 :            :                 .link_speed = RTE_ETH_SPEED_NUM_10G,
    1193                 :            :                 .link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
    1194                 :            :                 .link_autoneg = RTE_ETH_LINK_FIXED,
    1195                 :            :         };
    1196                 :            : 
    1197                 :            :         /*
    1198                 :            :          * For pass-through mode (single_iface), query whether the
    1199                 :            :          * underlying interface is up. Otherwise use default values.
    1200                 :            :          */
    1201         [ +  + ]:         31 :         if (internals->single_iface) {
    1202                 :          5 :                 link.link_status = (osdep_iface_link_status(internals->rx_queue[0].name) > 0) ?
    1203                 :          5 :                         RTE_ETH_LINK_UP : RTE_ETH_LINK_DOWN;
    1204         [ +  + ]:         26 :         } else if (rte_atomic_load_explicit(&internals->eof_signaled, rte_memory_order_relaxed)) {
    1205                 :            :                 link.link_status = RTE_ETH_LINK_DOWN;
    1206                 :            :         } else {
    1207                 :         24 :                 link.link_status = dev->data->dev_started ? RTE_ETH_LINK_UP : RTE_ETH_LINK_DOWN;
    1208                 :            :         }
    1209                 :            : 
    1210                 :         31 :         return rte_eth_linkstatus_set(dev, &link);
    1211                 :            : }
    1212                 :            : 
    1213                 :            : static int
    1214                 :         27 : eth_rx_queue_setup(struct rte_eth_dev *dev,
    1215                 :            :                 uint16_t rx_queue_id,
    1216                 :            :                 uint16_t nb_rx_desc __rte_unused,
    1217                 :            :                 unsigned int socket_id __rte_unused,
    1218                 :            :                 const struct rte_eth_rxconf *rx_conf __rte_unused,
    1219                 :            :                 struct rte_mempool *mb_pool)
    1220                 :            : {
    1221                 :         27 :         struct pmd_internals *internals = dev->data->dev_private;
    1222         [ +  - ]:         27 :         struct pcap_rx_queue *pcap_q = &internals->rx_queue[rx_queue_id];
    1223                 :            :         uint16_t buf_size;
    1224                 :            :         bool rx_scatter;
    1225                 :            : 
    1226                 :         27 :         buf_size = rte_pktmbuf_data_room_size(mb_pool) - RTE_PKTMBUF_HEADROOM;
    1227                 :         27 :         rx_scatter = !!(dev->data->dev_conf.rxmode.offloads &
    1228                 :            :                         RTE_ETH_RX_OFFLOAD_SCATTER);
    1229                 :            : 
    1230                 :            :         /*
    1231                 :            :          * If Rx scatter is not enabled, verify that the mbuf data room
    1232                 :            :          * can hold the largest received packet in a single segment.
    1233                 :            :          * Use the MTU-derived frame size as the expected maximum, not
    1234                 :            :          * snapshot_len which is a capture truncation limit rather than
    1235                 :            :          * an expected packet size.
    1236                 :            :          */
    1237         [ +  + ]:         27 :         if (!rx_scatter) {
    1238                 :         25 :                 uint32_t max_rx_pktlen = dev->data->mtu + RTE_ETHER_HDR_LEN;
    1239                 :            : 
    1240         [ -  + ]:         25 :                 if (max_rx_pktlen > buf_size) {
    1241                 :          0 :                         PMD_LOG(ERR,
    1242                 :            :                                 "Rx scatter is disabled and RxQ mbuf pool object size is too small "
    1243                 :            :                                 "(buf_size=%u, max_rx_pkt_len=%u)",
    1244                 :            :                                 buf_size, max_rx_pktlen);
    1245                 :          0 :                         return -EINVAL;
    1246                 :            :                 }
    1247                 :            :         }
    1248                 :            : 
    1249                 :         27 :         pcap_q->mb_pool = mb_pool;
    1250                 :         27 :         pcap_q->port_id = dev->data->port_id;
    1251                 :         27 :         pcap_q->queue_id = rx_queue_id;
    1252                 :         27 :         pcap_q->vlan_strip = internals->vlan_strip;
    1253                 :         27 :         pcap_q->rx_scatter = rx_scatter;
    1254                 :         27 :         dev->data->rx_queues[rx_queue_id] = pcap_q;
    1255                 :         27 :         pcap_q->timestamp_offloading = internals->timestamp_offloading;
    1256                 :            : 
    1257         [ +  + ]:         27 :         if (internals->infinite_rx) {
    1258                 :            :                 struct pmd_process_private *pp;
    1259                 :            :                 char ring_name[RTE_RING_NAMESIZE];
    1260                 :            :                 static uint32_t ring_number;
    1261                 :            :                 uint64_t pcap_pkt_count = 0;
    1262                 :            :                 struct rte_mbuf *bufs[1];
    1263                 :            :                 pcap_t **pcap;
    1264                 :            :                 bool save_vlan_strip;
    1265                 :            : 
    1266         [ -  + ]:          2 :                 if (rx_scatter) {
    1267                 :          0 :                         PMD_LOG(ERR,
    1268                 :            :                                 "Rx scatter is not supported with infinite_rx mode");
    1269                 :          0 :                         return -EINVAL;
    1270                 :            :                 }
    1271                 :            : 
    1272                 :          2 :                 pp = rte_eth_devices[pcap_q->port_id].process_private;
    1273                 :          2 :                 pcap = &pp->rx_pcap[pcap_q->queue_id];
    1274                 :            : 
    1275         [ +  - ]:          2 :                 if (unlikely(*pcap == NULL))
    1276                 :            :                         return -ENOENT;
    1277                 :            : 
    1278                 :          2 :                 pcap_pkt_count = count_packets_in_pcap(pcap, pcap_q);
    1279                 :            : 
    1280                 :          2 :                 snprintf(ring_name, sizeof(ring_name), "PCAP_RING%" PRIu32,
    1281                 :            :                                 ring_number);
    1282                 :            : 
    1283                 :          2 :                 pcap_q->pkts = rte_ring_create(ring_name,
    1284                 :            :                                 rte_align64pow2(pcap_pkt_count + 1), 0,
    1285                 :            :                                 RING_F_SP_ENQ | RING_F_SC_DEQ);
    1286                 :          2 :                 ring_number++;
    1287         [ +  - ]:          2 :                 if (!pcap_q->pkts)
    1288                 :            :                         return -ENOENT;
    1289                 :            : 
    1290                 :            :                 /*
    1291                 :            :                  * Temporarily disable offloads while filling the ring
    1292                 :            :                  * with raw packets. VLAN strip and timestamp will be
    1293                 :            :                  * applied later in eth_pcap_rx_infinite() on each copy.
    1294                 :            :                  */
    1295                 :          2 :                 save_vlan_strip = pcap_q->vlan_strip;
    1296                 :          2 :                 pcap_q->vlan_strip = false;
    1297                 :            : 
    1298                 :            :                 /* Fill ring with packets from PCAP file one by one. */
    1299         [ +  + ]:        132 :                 while (eth_pcap_rx(pcap_q, bufs, 1)) {
    1300                 :            :                         /* Check for multiseg mbufs. */
    1301         [ -  + ]:        128 :                         if (bufs[0]->nb_segs != 1) {
    1302                 :          0 :                                 infinite_rx_ring_free(pcap_q->pkts);
    1303                 :          0 :                                 pcap_q->vlan_strip = save_vlan_strip;
    1304                 :          0 :                                 PMD_LOG(ERR,
    1305                 :            :                                         "Multiseg mbufs are not supported in infinite_rx mode.");
    1306                 :          0 :                                 return -EINVAL;
    1307                 :            :                         }
    1308                 :            : 
    1309   [ -  +  -  -  :        128 :                         rte_ring_enqueue_bulk(pcap_q->pkts,
                      - ]
    1310                 :            :                                         (void * const *)bufs, 1, NULL);
    1311                 :            :                 }
    1312                 :            : 
    1313                 :            :                 /* Restore offloads for use during packet delivery */
    1314                 :          2 :                 pcap_q->vlan_strip = save_vlan_strip;
    1315                 :            : 
    1316         [ -  + ]:          2 :                 if (rte_ring_count(pcap_q->pkts) < pcap_pkt_count) {
    1317                 :          0 :                         infinite_rx_ring_free(pcap_q->pkts);
    1318                 :          0 :                         PMD_LOG(ERR,
    1319                 :            :                                 "Not enough mbufs to accommodate packets in pcap file. "
    1320                 :            :                                 "At least %" PRIu64 " mbufs per queue is required.",
    1321                 :            :                                 pcap_pkt_count);
    1322                 :          0 :                         return -EINVAL;
    1323                 :            :                 }
    1324                 :            : 
    1325                 :            :                 /*
    1326                 :            :                  * Reset the stats for this queue since eth_pcap_rx calls above
    1327                 :            :                  * didn't result in the application receiving packets.
    1328                 :            :                  */
    1329                 :          2 :                 pcap_q->rx_stat.pkts = 0;
    1330                 :          2 :                 pcap_q->rx_stat.bytes = 0;
    1331                 :            :         }
    1332                 :            : 
    1333                 :            :         return 0;
    1334                 :            : }
    1335                 :            : 
    1336                 :            : static int
    1337                 :         27 : eth_tx_queue_setup(struct rte_eth_dev *dev,
    1338                 :            :                 uint16_t tx_queue_id,
    1339                 :            :                 uint16_t nb_tx_desc __rte_unused,
    1340                 :            :                 unsigned int socket_id,
    1341                 :            :                 const struct rte_eth_txconf *tx_conf __rte_unused)
    1342                 :            : {
    1343                 :         27 :         struct pmd_internals *internals = dev->data->dev_private;
    1344                 :         27 :         struct pcap_tx_queue *pcap_q = &internals->tx_queue[tx_queue_id];
    1345                 :            : 
    1346                 :         27 :         pcap_q->port_id = dev->data->port_id;
    1347                 :         27 :         pcap_q->queue_id = tx_queue_id;
    1348                 :         27 :         pcap_q->bounce_buf = rte_malloc_socket(NULL, internals->snapshot_len,
    1349                 :            :                                                RTE_CACHE_LINE_SIZE, socket_id);
    1350         [ +  - ]:         27 :         if (pcap_q->bounce_buf == NULL)
    1351                 :            :                 return -ENOMEM;
    1352                 :            : 
    1353                 :         27 :         dev->data->tx_queues[tx_queue_id] = pcap_q;
    1354                 :            : 
    1355                 :         27 :         return 0;
    1356                 :            : }
    1357                 :            : 
    1358                 :            : static void
    1359                 :          0 : eth_tx_queue_release(struct rte_eth_dev *dev, uint16_t tx_queue_id)
    1360                 :            : {
    1361                 :          0 :         struct pmd_internals *internals = dev->data->dev_private;
    1362                 :          0 :         struct pcap_tx_queue *pcap_q = &internals->tx_queue[tx_queue_id];
    1363                 :            : 
    1364                 :          0 :         rte_free(pcap_q->bounce_buf);
    1365                 :          0 :         pcap_q->bounce_buf = NULL;
    1366                 :          0 : }
    1367                 :            : 
    1368                 :            : static int
    1369                 :          1 : eth_rx_queue_start(struct rte_eth_dev *dev, uint16_t rx_queue_id)
    1370                 :            : {
    1371                 :          1 :         dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
    1372                 :            : 
    1373                 :          1 :         return 0;
    1374                 :            : }
    1375                 :            : 
    1376                 :            : static int
    1377                 :          1 : eth_tx_queue_start(struct rte_eth_dev *dev, uint16_t tx_queue_id)
    1378                 :            : {
    1379                 :          1 :         dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STARTED;
    1380                 :            : 
    1381                 :          1 :         return 0;
    1382                 :            : }
    1383                 :            : 
    1384                 :            : static int
    1385                 :          1 : eth_rx_queue_stop(struct rte_eth_dev *dev, uint16_t rx_queue_id)
    1386                 :            : {
    1387                 :          1 :         dev->data->rx_queue_state[rx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
    1388                 :            : 
    1389                 :          1 :         return 0;
    1390                 :            : }
    1391                 :            : 
    1392                 :            : static int
    1393                 :          1 : eth_tx_queue_stop(struct rte_eth_dev *dev, uint16_t tx_queue_id)
    1394                 :            : {
    1395                 :          1 :         dev->data->tx_queue_state[tx_queue_id] = RTE_ETH_QUEUE_STATE_STOPPED;
    1396                 :            : 
    1397                 :          1 :         return 0;
    1398                 :            : }
    1399                 :            : 
    1400                 :            : /* Timestamp values in receive packets from libpcap are in nanoseconds */
    1401                 :            : static int
    1402                 :          0 : eth_dev_read_clock(struct rte_eth_dev *dev __rte_unused, uint64_t *timestamp)
    1403                 :            : {
    1404                 :            :         struct timespec cur_time;
    1405                 :            : 
    1406                 :          0 :         timespec_get(&cur_time, TIME_UTC);
    1407                 :          0 :         *timestamp = rte_timespec_to_ns(&cur_time);
    1408                 :          0 :         return 0;
    1409                 :            : }
    1410                 :            : 
    1411                 :            : static int
    1412                 :          0 : eth_vlan_offload_set(struct rte_eth_dev *dev, int mask)
    1413                 :            : {
    1414                 :          0 :         struct pmd_internals *internals = dev->data->dev_private;
    1415                 :            :         unsigned int i;
    1416                 :            : 
    1417         [ #  # ]:          0 :         if (mask & RTE_ETH_VLAN_STRIP_MASK) {
    1418                 :          0 :                 bool vlan_strip = !!(dev->data->dev_conf.rxmode.offloads &
    1419                 :            :                                      RTE_ETH_RX_OFFLOAD_VLAN_STRIP);
    1420                 :            : 
    1421                 :          0 :                 internals->vlan_strip = vlan_strip;
    1422                 :            : 
    1423                 :            :                 /* Update all RX queues */
    1424         [ #  # ]:          0 :                 for (i = 0; i < dev->data->nb_rx_queues; i++)
    1425                 :          0 :                         internals->rx_queue[i].vlan_strip = vlan_strip;
    1426                 :            :         }
    1427                 :            : 
    1428                 :          0 :         return 0;
    1429                 :            : }
    1430                 :            : 
    1431                 :            : static const struct eth_dev_ops ops = {
    1432                 :            :         .dev_start = eth_dev_start,
    1433                 :            :         .dev_stop = eth_dev_stop,
    1434                 :            :         .dev_close = eth_dev_close,
    1435                 :            :         .dev_configure = eth_dev_configure,
    1436                 :            :         .dev_infos_get = eth_dev_info,
    1437                 :            :         .read_clock = eth_dev_read_clock,
    1438                 :            :         .rx_queue_setup = eth_rx_queue_setup,
    1439                 :            :         .tx_queue_setup = eth_tx_queue_setup,
    1440                 :            :         .tx_queue_release = eth_tx_queue_release,
    1441                 :            :         .rx_queue_start = eth_rx_queue_start,
    1442                 :            :         .tx_queue_start = eth_tx_queue_start,
    1443                 :            :         .rx_queue_stop = eth_rx_queue_stop,
    1444                 :            :         .tx_queue_stop = eth_tx_queue_stop,
    1445                 :            :         .link_update = eth_link_update,
    1446                 :            :         .stats_get = eth_stats_get,
    1447                 :            :         .stats_reset = eth_stats_reset,
    1448                 :            :         .vlan_offload_set = eth_vlan_offload_set,
    1449                 :            : };
    1450                 :            : 
    1451                 :            : static int
    1452                 :            : add_queue(struct pmd_devargs *pmd, const char *name, const char *type,
    1453                 :            :                 pcap_t *pcap, pcap_dumper_t *dumper)
    1454                 :            : {
    1455   [ +  -  +  - ]:         25 :         if (pmd->num_of_queue >= RTE_PMD_PCAP_MAX_QUEUES)
    1456                 :            :                 return -1;
    1457   [ +  -  +  - ]:         26 :         if (pcap)
    1458                 :         26 :                 pmd->queue[pmd->num_of_queue].pcap = pcap;
    1459         [ +  - ]:         14 :         if (dumper)
    1460                 :         14 :                 pmd->queue[pmd->num_of_queue].dumper = dumper;
    1461                 :         65 :         pmd->queue[pmd->num_of_queue].name = name;
    1462                 :         65 :         pmd->queue[pmd->num_of_queue].type = type;
    1463                 :         40 :         pmd->num_of_queue++;
    1464                 :         25 :         return 0;
    1465                 :            : }
    1466                 :            : 
    1467                 :            : /*
    1468                 :            :  * Function handler that opens the pcap file for reading a stores a
    1469                 :            :  * reference of it for use it later on.
    1470                 :            :  */
    1471                 :            : static int
    1472                 :         22 : open_rx_pcap(const char *key, const char *value, void *extra_args)
    1473                 :            : {
    1474                 :            :         const char *pcap_filename = value;
    1475                 :            :         struct pmd_devargs *rx = extra_args;
    1476                 :         22 :         pcap_t *pcap = NULL;
    1477                 :            : 
    1478         [ +  - ]:         22 :         if (open_single_rx_pcap(pcap_filename, &pcap) < 0)
    1479                 :            :                 return -1;
    1480                 :            : 
    1481         [ -  + ]:         22 :         if (add_queue(rx, pcap_filename, key, pcap, NULL) < 0) {
    1482                 :          0 :                 pcap_close(pcap);
    1483                 :          0 :                 return -1;
    1484                 :            :         }
    1485                 :            : 
    1486                 :            :         return 0;
    1487                 :            : }
    1488                 :            : 
    1489                 :            : /*
    1490                 :            :  * Opens a pcap file for writing and stores a reference to it
    1491                 :            :  * for use it later on.
    1492                 :            :  */
    1493                 :            : static int
    1494                 :         14 : open_tx_pcap(const char *key, const char *value, void *extra_args)
    1495                 :            : {
    1496                 :            :         const char *pcap_filename = value;
    1497                 :            :         struct pmd_devargs *dumpers = extra_args;
    1498                 :            :         pcap_dumper_t *dumper;
    1499                 :            : 
    1500         [ +  - ]:         14 :         if (open_single_tx_pcap(pcap_filename, &dumper,
    1501                 :            :                                 dumpers->snapshot_len) < 0)
    1502                 :            :                 return -1;
    1503                 :            : 
    1504         [ -  + ]:         14 :         if (add_queue(dumpers, pcap_filename, key, NULL, dumper) < 0) {
    1505                 :          0 :                 pcap_dump_close(dumper);
    1506                 :          0 :                 return -1;
    1507                 :            :         }
    1508                 :            : 
    1509                 :            :         return 0;
    1510                 :            : }
    1511                 :            : 
    1512                 :            : /*
    1513                 :            :  * Opens an interface for reading and writing
    1514                 :            :  */
    1515                 :            : static inline int
    1516                 :          3 : open_rx_tx_iface(const char *key, const char *value, void *extra_args)
    1517                 :            : {
    1518                 :            :         const char *iface = value;
    1519                 :            :         struct pmd_devargs *tx = extra_args;
    1520                 :          3 :         pcap_t *pcap = NULL;
    1521                 :            : 
    1522         [ +  - ]:          3 :         if (open_single_iface(iface, &pcap, tx->snapshot_len) < 0)
    1523                 :            :                 return -1;
    1524                 :            : 
    1525                 :          3 :         tx->queue[0].pcap = pcap;
    1526                 :          3 :         tx->queue[0].name = iface;
    1527                 :          3 :         tx->queue[0].type = key;
    1528                 :            : 
    1529                 :          3 :         return 0;
    1530                 :            : }
    1531                 :            : 
    1532                 :            : static inline int
    1533                 :          4 : open_iface(const char *key, const char *value, void *extra_args)
    1534                 :            : {
    1535                 :            :         const char *iface = value;
    1536                 :            :         struct pmd_devargs *pmd = extra_args;
    1537                 :          4 :         pcap_t *pcap = NULL;
    1538                 :            : 
    1539         [ +  - ]:          4 :         if (open_single_iface(iface, &pcap, pmd->snapshot_len) < 0)
    1540                 :            :                 return -1;
    1541         [ -  + ]:          4 :         if (add_queue(pmd, iface, key, pcap, NULL) < 0) {
    1542                 :          0 :                 pcap_close(pcap);
    1543                 :          0 :                 return -1;
    1544                 :            :         }
    1545                 :            : 
    1546                 :            :         return 0;
    1547                 :            : }
    1548                 :            : 
    1549                 :            : /*
    1550                 :            :  * Opens a NIC for reading packets from it
    1551                 :            :  */
    1552                 :            : static inline int
    1553                 :          2 : open_rx_iface(const char *key, const char *value, void *extra_args)
    1554                 :            : {
    1555                 :          2 :         int ret = open_iface(key, value, extra_args);
    1556         [ +  - ]:          2 :         if (ret < 0)
    1557                 :            :                 return ret;
    1558         [ +  + ]:          2 :         if (strcmp(key, ETH_PCAP_RX_IFACE_IN_ARG) == 0) {
    1559                 :            :                 struct pmd_devargs *pmd = extra_args;
    1560                 :          1 :                 unsigned int qid = pmd->num_of_queue - 1;
    1561                 :            : 
    1562                 :          1 :                 set_iface_direction(pmd->queue[qid].name,
    1563                 :            :                                 pmd->queue[qid].pcap,
    1564                 :            :                                 PCAP_D_IN);
    1565                 :            :         }
    1566                 :            : 
    1567                 :            :         return 0;
    1568                 :            : }
    1569                 :            : 
    1570                 :            : static inline int
    1571                 :          4 : rx_iface_args_process(const char *key, const char *value, void *extra_args)
    1572                 :            : {
    1573         [ +  + ]:          4 :         if (strcmp(key, ETH_PCAP_RX_IFACE_ARG) == 0 ||
    1574         [ +  + ]:          3 :                         strcmp(key, ETH_PCAP_RX_IFACE_IN_ARG) == 0)
    1575                 :          2 :                 return open_rx_iface(key, value, extra_args);
    1576                 :            : 
    1577                 :            :         return 0;
    1578                 :            : }
    1579                 :            : 
    1580                 :            : /*
    1581                 :            :  * Opens a NIC for writing packets to it
    1582                 :            :  */
    1583                 :            : static int
    1584                 :          2 : open_tx_iface(const char *key, const char *value, void *extra_args)
    1585                 :            : {
    1586                 :          2 :         return open_iface(key, value, extra_args);
    1587                 :            : }
    1588                 :            : 
    1589                 :            : static int
    1590                 :          5 : process_bool_flag(const char *key, const char *value, void *extra_args)
    1591                 :            : {
    1592                 :            :         bool *flag = extra_args;
    1593                 :            : 
    1594   [ +  -  -  + ]:          5 :         if (value == NULL || *value == '\0') {
    1595                 :          0 :                 *flag = true; /* default with no additional argument */
    1596         [ -  + ]:          5 :         } else if (strcmp(value, "0") == 0) {
    1597                 :          0 :                 *flag = false;
    1598         [ +  - ]:          5 :         } else if (strcmp(value, "1") == 0) {
    1599                 :          5 :                 *flag = true;
    1600                 :            :         } else {
    1601                 :          0 :                 PMD_LOG(ERR, "Invalid '%s' value '%s'", key, value);
    1602                 :          0 :                 return -1;
    1603                 :            :         }
    1604                 :            :         return 0;
    1605                 :            : }
    1606                 :            : 
    1607                 :            : static int
    1608                 :          3 : process_snapshot_len(const char *key, const char *value, void *extra_args)
    1609                 :            : {
    1610                 :            :         uint32_t *snaplen = extra_args;
    1611                 :            :         unsigned long val;
    1612                 :            :         char *endptr;
    1613                 :            : 
    1614   [ +  -  -  + ]:          3 :         if (value == NULL || *value == '\0') {
    1615                 :          0 :                 PMD_LOG(ERR, "Argument '%s' requires a value", key);
    1616                 :          0 :                 return -1;
    1617                 :            :         }
    1618                 :            : 
    1619                 :          3 :         errno = 0;
    1620                 :          3 :         val = strtoul(value, &endptr, 10);
    1621   [ +  -  +  - ]:          3 :         if (errno != 0 || *endptr != '\0' ||
    1622         [ -  + ]:          3 :             val < RTE_ETHER_HDR_LEN ||
    1623                 :            :             val > ETH_PCAP_MAXIMUM_SNAPLEN) {
    1624                 :          0 :                 PMD_LOG(ERR, "Invalid '%s' value '%s'", key, value);
    1625                 :          0 :                 return -1;
    1626                 :            :         }
    1627                 :            : 
    1628                 :          3 :         *snaplen = (uint32_t)val;
    1629                 :          3 :         return 0;
    1630                 :            : }
    1631                 :            : 
    1632                 :            : static int
    1633                 :         28 : pmd_init_internals(struct rte_vdev_device *vdev,
    1634                 :            :                 const unsigned int nb_rx_queues,
    1635                 :            :                 const unsigned int nb_tx_queues,
    1636                 :            :                 struct pmd_internals **internals,
    1637                 :            :                 struct rte_eth_dev **eth_dev)
    1638                 :            : {
    1639                 :            :         struct rte_eth_dev_data *data;
    1640                 :            :         struct pmd_process_private *pp;
    1641                 :         28 :         unsigned int numa_node = vdev->device.numa_node;
    1642                 :            : 
    1643                 :         28 :         PMD_LOG(INFO, "Creating pcap-backed ethdev on numa socket %u",
    1644                 :            :                 numa_node);
    1645                 :            : 
    1646                 :         28 :         pp = rte_zmalloc_socket("pcap_private", sizeof(struct pmd_process_private),
    1647                 :            :                 RTE_CACHE_LINE_SIZE, numa_node);
    1648         [ -  + ]:         28 :         if (pp == NULL) {
    1649                 :          0 :                 PMD_LOG(ERR,
    1650                 :            :                         "Failed to allocate memory for process private");
    1651                 :          0 :                 return -1;
    1652                 :            :         }
    1653                 :            : 
    1654                 :            :         /* reserve an ethdev entry */
    1655                 :         28 :         *eth_dev = rte_eth_vdev_allocate(vdev, sizeof(**internals));
    1656         [ -  + ]:         28 :         if (!(*eth_dev)) {
    1657                 :          0 :                 rte_free(pp);
    1658                 :          0 :                 return -1;
    1659                 :            :         }
    1660                 :         28 :         (*eth_dev)->process_private = pp;
    1661                 :            :         /* now put it all together
    1662                 :            :          * - store queue data in internals,
    1663                 :            :          * - store numa_node info in eth_dev
    1664                 :            :          * - point eth_dev_data to internals
    1665                 :            :          * - and point eth_dev structure to new eth_dev_data structure
    1666                 :            :          */
    1667                 :         28 :         *internals = (*eth_dev)->data->dev_private;
    1668                 :            :         /*
    1669                 :            :          * Interface MAC = 02:70:63:61:70:<iface_idx>
    1670                 :            :          * derived from: 'locally administered':'p':'c':'a':'p':'iface_idx'
    1671                 :            :          * where the middle 4 characters are converted to hex.
    1672                 :            :          */
    1673                 :            :         static uint8_t iface_idx;
    1674                 :         28 :         (*internals)->eth_addr = (struct rte_ether_addr) {
    1675                 :         28 :                 .addr_bytes = { 0x02, 0x70, 0x63, 0x61, 0x70, iface_idx++ }
    1676                 :            :         };
    1677                 :         28 :         (*internals)->phy_mac = 0;
    1678                 :            :         data = (*eth_dev)->data;
    1679                 :         28 :         data->nb_rx_queues = (uint16_t)nb_rx_queues;
    1680                 :         28 :         data->nb_tx_queues = (uint16_t)nb_tx_queues;
    1681                 :         28 :         data->dev_link = (struct rte_eth_link) {
    1682                 :            :                 .link_speed = RTE_ETH_SPEED_NUM_NONE,
    1683                 :            :                 .link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
    1684                 :            :                 .link_status = RTE_ETH_LINK_DOWN,
    1685                 :            :                 .link_autoneg = RTE_ETH_LINK_FIXED,
    1686                 :            :         };
    1687                 :         28 :         data->mac_addrs = &(*internals)->eth_addr;
    1688                 :         28 :         data->promiscuous = 1;
    1689                 :         28 :         data->all_multicast = 1;
    1690                 :         28 :         data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
    1691                 :            : 
    1692                 :            :         /*
    1693                 :            :          * NOTE: we'll replace the data element, of originally allocated
    1694                 :            :          * eth_dev so the rings are local per-process
    1695                 :            :          */
    1696         [ +  - ]:         28 :         (*eth_dev)->dev_ops = &ops;
    1697                 :            : 
    1698                 :         28 :         strlcpy((*internals)->devargs, rte_vdev_device_args(vdev),
    1699                 :            :                         ETH_PCAP_ARG_MAXLEN);
    1700                 :            : 
    1701                 :         28 :         return 0;
    1702                 :            : }
    1703                 :            : 
    1704                 :            : static int
    1705                 :          0 : eth_pcap_update_mac(const char *if_name, struct rte_eth_dev *eth_dev,
    1706                 :            :                 const unsigned int numa_node)
    1707                 :            : {
    1708                 :            :         void *mac_addrs;
    1709                 :            :         struct rte_ether_addr mac;
    1710                 :            : 
    1711         [ #  # ]:          0 :         if (osdep_iface_mac_get(if_name, &mac) < 0)
    1712                 :            :                 return -1;
    1713                 :            : 
    1714                 :          0 :         mac_addrs = rte_zmalloc_socket("pcap_mac", RTE_ETHER_ADDR_LEN, 0, numa_node);
    1715         [ #  # ]:          0 :         if (mac_addrs == NULL)
    1716                 :            :                 return -1;
    1717                 :            : 
    1718                 :          0 :         PMD_LOG(INFO, "Setting phy MAC for %s", if_name);
    1719                 :            :         memcpy(mac_addrs, mac.addr_bytes, RTE_ETHER_ADDR_LEN);
    1720                 :          0 :         eth_dev->data->mac_addrs = mac_addrs;
    1721                 :          0 :         return 0;
    1722                 :            : }
    1723                 :            : 
    1724                 :            : static int
    1725                 :         28 : eth_from_pcaps_common(struct rte_vdev_device *vdev,
    1726                 :            :                 struct pmd_devargs_all *devargs_all,
    1727                 :            :                 struct pmd_internals **internals, struct rte_eth_dev **eth_dev)
    1728                 :            : {
    1729                 :            :         struct pmd_process_private *pp;
    1730                 :            :         struct pmd_devargs *rx_queues = &devargs_all->rx_queues;
    1731                 :            :         struct pmd_devargs *tx_queues = &devargs_all->tx_queues;
    1732                 :         28 :         const unsigned int nb_rx_queues = rx_queues->num_of_queue;
    1733                 :         28 :         const unsigned int nb_tx_queues = tx_queues->num_of_queue;
    1734                 :            :         unsigned int i;
    1735                 :            : 
    1736         [ +  - ]:         28 :         if (pmd_init_internals(vdev, nb_rx_queues, nb_tx_queues, internals,
    1737                 :            :                         eth_dev) < 0)
    1738                 :            :                 return -1;
    1739                 :            : 
    1740                 :         28 :         pp = (*eth_dev)->process_private;
    1741         [ +  + ]:         64 :         for (i = 0; i < nb_rx_queues; i++) {
    1742                 :         36 :                 struct pcap_rx_queue *rx = &(*internals)->rx_queue[i];
    1743                 :            :                 struct devargs_queue *queue = &rx_queues->queue[i];
    1744                 :            : 
    1745                 :         36 :                 pp->rx_pcap[i] = queue->pcap;
    1746                 :         36 :                 strlcpy(rx->name, queue->name, sizeof(rx->name));
    1747                 :         36 :                 strlcpy(rx->type, queue->type, sizeof(rx->type));
    1748                 :            :         }
    1749                 :            : 
    1750         [ +  + ]:         63 :         for (i = 0; i < nb_tx_queues; i++) {
    1751                 :         35 :                 struct pcap_tx_queue *tx = &(*internals)->tx_queue[i];
    1752                 :            :                 struct devargs_queue *queue = &tx_queues->queue[i];
    1753                 :            : 
    1754                 :         35 :                 pp->tx_dumper[i] = queue->dumper;
    1755                 :         35 :                 pp->tx_pcap[i] = queue->pcap;
    1756                 :         35 :                 strlcpy(tx->name, queue->name, sizeof(tx->name));
    1757                 :         35 :                 strlcpy(tx->type, queue->type, sizeof(tx->type));
    1758                 :            :         }
    1759                 :            : 
    1760                 :            :         return 0;
    1761                 :            : }
    1762                 :            : 
    1763                 :            : static int
    1764                 :         28 : eth_from_pcaps(struct rte_vdev_device *vdev,
    1765                 :            :                 struct pmd_devargs_all *devargs_all)
    1766                 :            : {
    1767                 :         28 :         struct pmd_internals *internals = NULL;
    1768                 :         28 :         struct rte_eth_dev *eth_dev = NULL;
    1769                 :            :         struct pmd_devargs *rx_queues = &devargs_all->rx_queues;
    1770                 :         28 :         int single_iface = devargs_all->single_iface;
    1771                 :         28 :         unsigned int infinite_rx = devargs_all->infinite_rx;
    1772                 :            :         int ret;
    1773                 :            : 
    1774                 :         28 :         ret = eth_from_pcaps_common(vdev, devargs_all, &internals, &eth_dev);
    1775                 :            : 
    1776         [ +  - ]:         28 :         if (ret < 0)
    1777                 :            :                 return ret;
    1778                 :            : 
    1779                 :            :         /* store weather we are using a single interface for rx/tx or not */
    1780                 :         28 :         internals->single_iface = single_iface;
    1781                 :            : 
    1782         [ +  + ]:         28 :         if (single_iface) {
    1783                 :          3 :                 internals->if_index =
    1784                 :          3 :                         osdep_iface_index_get(rx_queues->queue[0].name);
    1785                 :            : 
    1786                 :            :                 /* Enable LSC interrupt support for iface mode */
    1787                 :          3 :                 eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
    1788                 :            : 
    1789                 :            :                 /* phy_mac arg is applied only if "iface" devarg is provided */
    1790         [ -  + ]:          3 :                 if (rx_queues->phy_mac) {
    1791         [ #  # ]:          0 :                         if (eth_pcap_update_mac(rx_queues->queue[0].name,
    1792                 :          0 :                                         eth_dev, vdev->device.numa_node) == 0)
    1793                 :          0 :                                 internals->phy_mac = 1;
    1794                 :            :                 }
    1795                 :            :         }
    1796                 :            : 
    1797                 :         28 :         internals->infinite_rx = infinite_rx;
    1798                 :         28 :         internals->eof = devargs_all->eof;
    1799                 :         28 :         internals->snapshot_len = devargs_all->snapshot_len;
    1800                 :            : 
    1801                 :            :         /* Enable LSC for eof mode (already set above for single_iface) */
    1802         [ +  + ]:         28 :         if (internals->eof)
    1803                 :          1 :                 eth_dev->data->dev_flags |= RTE_ETH_DEV_INTR_LSC;
    1804                 :            : 
    1805                 :            :         /* Assign rx ops. */
    1806         [ +  + ]:         28 :         if (infinite_rx)
    1807                 :          2 :                 eth_dev->rx_pkt_burst = eth_pcap_rx_infinite;
    1808   [ +  +  +  +  :         26 :         else if (devargs_all->is_rx_pcap || devargs_all->is_rx_iface ||
                   +  + ]
    1809                 :            :                         single_iface)
    1810                 :         20 :                 eth_dev->rx_pkt_burst = eth_pcap_rx;
    1811                 :            :         else
    1812                 :          6 :                 eth_dev->rx_pkt_burst = eth_null_rx;
    1813                 :            : 
    1814                 :            :         /* Assign tx ops. */
    1815         [ +  + ]:         28 :         if (devargs_all->is_tx_pcap)
    1816                 :         10 :                 eth_dev->tx_pkt_burst = eth_pcap_tx_dumper;
    1817   [ +  +  +  + ]:         18 :         else if (devargs_all->is_tx_iface || single_iface)
    1818                 :          5 :                 eth_dev->tx_pkt_burst = eth_pcap_tx;
    1819                 :            :         else
    1820                 :         13 :                 eth_dev->tx_pkt_burst = eth_tx_drop;
    1821                 :            : 
    1822                 :         28 :         rte_eth_dev_probing_finish(eth_dev);
    1823                 :         28 :         return 0;
    1824                 :            : }
    1825                 :            : 
    1826                 :            : static void
    1827                 :          1 : eth_release_pcaps(struct pmd_devargs *pcaps,
    1828                 :            :                 struct pmd_devargs *dumpers,
    1829                 :            :                 int single_iface)
    1830                 :            : {
    1831                 :            :         unsigned int i;
    1832                 :            : 
    1833         [ -  + ]:          1 :         if (single_iface) {
    1834         [ #  # ]:          0 :                 if (pcaps->queue[0].pcap)
    1835                 :          0 :                         pcap_close(pcaps->queue[0].pcap);
    1836                 :          0 :                 return;
    1837                 :            :         }
    1838                 :            : 
    1839         [ -  + ]:          1 :         for (i = 0; i < dumpers->num_of_queue; i++) {
    1840         [ #  # ]:          0 :                 if (dumpers->queue[i].dumper)
    1841                 :          0 :                         pcap_dump_close(dumpers->queue[i].dumper);
    1842                 :            : 
    1843         [ #  # ]:          0 :                 if (dumpers->queue[i].pcap)
    1844                 :          0 :                         pcap_close(dumpers->queue[i].pcap);
    1845                 :            :         }
    1846                 :            : 
    1847         [ -  + ]:          1 :         for (i = 0; i < pcaps->num_of_queue; i++) {
    1848         [ #  # ]:          0 :                 if (pcaps->queue[i].pcap)
    1849                 :          0 :                         pcap_close(pcaps->queue[i].pcap);
    1850                 :            :         }
    1851                 :            : }
    1852                 :            : 
    1853                 :            : static int
    1854                 :         29 : pmd_pcap_probe(struct rte_vdev_device *dev)
    1855                 :            : {
    1856                 :            :         const char *name;
    1857                 :            :         struct rte_kvargs *kvlist;
    1858                 :         29 :         struct pmd_devargs pcaps = {0};
    1859                 :         29 :         struct pmd_devargs dumpers = {0};
    1860                 :            :         struct rte_eth_dev *eth_dev =  NULL;
    1861                 :            :         struct pmd_internals *internal;
    1862                 :            :         int ret = 0;
    1863                 :            : 
    1864         [ +  - ]:         29 :         struct pmd_devargs_all devargs_all = {
    1865                 :            :                 .snapshot_len = ETH_PCAP_SNAPSHOT_LEN_DEFAULT,
    1866                 :            :                 .single_iface = 0,
    1867                 :            :                 .is_tx_pcap = 0,
    1868                 :            :                 .is_tx_iface = 0,
    1869                 :            :                 .infinite_rx = 0,
    1870                 :            :         };
    1871                 :            : 
    1872                 :            :         name = rte_vdev_device_name(dev);
    1873                 :         29 :         PMD_LOG(INFO, "Initializing pmd_pcap for %s", name);
    1874                 :            : 
    1875                 :            :         /* Record info for timestamps on first probe */
    1876         [ +  + ]:         29 :         if (hz == 0) {
    1877                 :          1 :                 hz = rte_get_timer_hz();
    1878         [ -  + ]:          1 :                 if (hz == 0) {
    1879                 :          0 :                         PMD_LOG(ERR, "Reported hz is zero!");
    1880                 :          0 :                         return -1;
    1881                 :            :                 }
    1882                 :          1 :                 timespec_get(&start_time, TIME_UTC);
    1883                 :          1 :                 start_cycles = rte_get_timer_cycles();
    1884                 :            :         }
    1885                 :            : 
    1886         [ -  + ]:         29 :         if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
    1887                 :          0 :                 eth_dev = rte_eth_dev_attach_secondary(name);
    1888         [ #  # ]:          0 :                 if (!eth_dev) {
    1889                 :          0 :                         PMD_LOG(ERR, "Failed to probe %s", name);
    1890                 :          0 :                         return -1;
    1891                 :            :                 }
    1892                 :            : 
    1893                 :          0 :                 internal = eth_dev->data->dev_private;
    1894                 :            : 
    1895                 :          0 :                 kvlist = rte_kvargs_parse(internal->devargs, valid_arguments);
    1896         [ #  # ]:          0 :                 if (kvlist == NULL)
    1897                 :            :                         return -1;
    1898                 :            :         } else {
    1899                 :         29 :                 kvlist = rte_kvargs_parse(rte_vdev_device_args(dev),
    1900                 :            :                                 valid_arguments);
    1901         [ +  - ]:         29 :                 if (kvlist == NULL)
    1902                 :            :                         return -1;
    1903                 :            :         }
    1904                 :            : 
    1905                 :            :         /*
    1906                 :            :          * Process optional snapshot length argument first, so the value
    1907                 :            :          * is available when opening pcap handles for files and interfaces.
    1908                 :            :          */
    1909         [ +  + ]:         29 :         if (rte_kvargs_count(kvlist, ETH_PCAP_SNAPSHOT_LEN_ARG) == 1) {
    1910                 :          3 :                 ret = rte_kvargs_process(kvlist, ETH_PCAP_SNAPSHOT_LEN_ARG,
    1911                 :            :                                          &process_snapshot_len,
    1912                 :            :                                          &devargs_all.snapshot_len);
    1913         [ -  + ]:          3 :                 if (ret < 0)
    1914                 :          0 :                         goto free_kvlist;
    1915                 :            :         }
    1916                 :            : 
    1917                 :            :         /*
    1918                 :            :          * Propagate snapshot length to per-queue devargs so that
    1919                 :            :          * the open callbacks can access it.
    1920                 :            :          */
    1921                 :         29 :         devargs_all.rx_queues.snapshot_len = devargs_all.snapshot_len;
    1922                 :         29 :         devargs_all.tx_queues.snapshot_len = devargs_all.snapshot_len;
    1923                 :            : 
    1924                 :            :         /*
    1925                 :            :          * If iface argument is passed we open the NICs and use them for
    1926                 :            :          * reading / writing
    1927                 :            :          */
    1928         [ +  + ]:         29 :         if (rte_kvargs_count(kvlist, ETH_PCAP_IFACE_ARG) == 1) {
    1929                 :            : 
    1930                 :          3 :                 ret = rte_kvargs_process(kvlist, ETH_PCAP_IFACE_ARG,
    1931                 :            :                                 &open_rx_tx_iface, &pcaps);
    1932         [ -  + ]:          3 :                 if (ret < 0)
    1933                 :          0 :                         goto free_kvlist;
    1934                 :            : 
    1935                 :          3 :                 dumpers.queue[0] = pcaps.queue[0];
    1936                 :            : 
    1937                 :          3 :                 ret = rte_kvargs_process(kvlist, ETH_PCAP_PHY_MAC_ARG,
    1938                 :            :                                          &process_bool_flag, &pcaps.phy_mac);
    1939         [ -  + ]:          3 :                 if (ret < 0)
    1940                 :          0 :                         goto free_kvlist;
    1941                 :            : 
    1942                 :          3 :                 dumpers.phy_mac = pcaps.phy_mac;
    1943                 :            : 
    1944                 :          3 :                 devargs_all.single_iface = 1;
    1945                 :          3 :                 pcaps.num_of_queue = 1;
    1946                 :          3 :                 dumpers.num_of_queue = 1;
    1947                 :            : 
    1948                 :          3 :                 goto create_eth;
    1949                 :            :         }
    1950                 :            : 
    1951                 :            :         /*
    1952                 :            :          * We check whether we want to open a RX stream from a real NIC, a
    1953                 :            :          * pcap file or open a dummy RX stream
    1954                 :            :          */
    1955                 :         26 :         devargs_all.is_rx_pcap =
    1956                 :         26 :                 rte_kvargs_count(kvlist, ETH_PCAP_RX_PCAP_ARG) ? 1 : 0;
    1957                 :         26 :         devargs_all.is_rx_iface =
    1958                 :         26 :                 (rte_kvargs_count(kvlist, ETH_PCAP_RX_IFACE_ARG) +
    1959                 :         26 :                  rte_kvargs_count(kvlist, ETH_PCAP_RX_IFACE_IN_ARG)) ? 1 : 0;
    1960                 :         26 :         pcaps.num_of_queue = 0;
    1961                 :            : 
    1962                 :         26 :         devargs_all.is_tx_pcap =
    1963                 :         26 :                 rte_kvargs_count(kvlist, ETH_PCAP_TX_PCAP_ARG) ? 1 : 0;
    1964                 :         26 :         devargs_all.is_tx_iface =
    1965                 :         26 :                 rte_kvargs_count(kvlist, ETH_PCAP_TX_IFACE_ARG) ? 1 : 0;
    1966                 :         26 :         dumpers.num_of_queue = 0;
    1967                 :            : 
    1968         [ +  + ]:         26 :         if (devargs_all.is_rx_pcap) {
    1969                 :            :                 /*
    1970                 :            :                  * We check whether we want to infinitely rx the pcap file.
    1971                 :            :                  */
    1972                 :         18 :                 unsigned int infinite_rx_arg_cnt = rte_kvargs_count(kvlist,
    1973                 :            :                                 ETH_PCAP_INFINITE_RX_ARG);
    1974                 :            : 
    1975         [ +  + ]:         18 :                 if (infinite_rx_arg_cnt == 1) {
    1976                 :          3 :                         ret = rte_kvargs_process(kvlist,
    1977                 :            :                                         ETH_PCAP_INFINITE_RX_ARG,
    1978                 :            :                                          &process_bool_flag,
    1979                 :            :                                          &devargs_all.infinite_rx);
    1980         [ -  + ]:          3 :                         if (ret < 0)
    1981                 :          0 :                                 goto free_kvlist;
    1982         [ -  + ]:          3 :                         PMD_LOG(INFO, "infinite_rx has been %s for %s",
    1983                 :            :                                         devargs_all.infinite_rx ? "enabled" : "disabled",
    1984                 :            :                                         name);
    1985                 :            : 
    1986         [ -  + ]:         15 :                 } else if (infinite_rx_arg_cnt > 1) {
    1987                 :          0 :                         PMD_LOG(WARNING, "infinite_rx has not been enabled since the "
    1988                 :            :                                         "argument has been provided more than once "
    1989                 :            :                                         "for %s", name);
    1990                 :            :                 }
    1991                 :            : 
    1992                 :            :                 /*
    1993                 :            :                  * Check whether to signal EOF via link status change.
    1994                 :            :                  */
    1995         [ +  + ]:         18 :                 if (rte_kvargs_count(kvlist, ETH_PCAP_EOF_ARG) == 1) {
    1996                 :          2 :                         ret = rte_kvargs_process(kvlist, ETH_PCAP_EOF_ARG,
    1997                 :            :                                                  &process_bool_flag,
    1998                 :            :                                                  &devargs_all.eof);
    1999         [ -  + ]:          2 :                         if (ret < 0)
    2000                 :          0 :                                 goto free_kvlist;
    2001                 :            :                 }
    2002                 :            : 
    2003   [ +  +  +  + ]:         18 :                 if (devargs_all.infinite_rx && devargs_all.eof) {
    2004                 :          1 :                         PMD_LOG(ERR, "Cannot use both infinite_rx and eof for %s",
    2005                 :            :                                 name);
    2006                 :            :                         ret = -EINVAL;
    2007                 :          1 :                         goto free_kvlist;
    2008                 :            :                 }
    2009                 :            : 
    2010                 :         17 :                 ret = rte_kvargs_process(kvlist, ETH_PCAP_RX_PCAP_ARG,
    2011                 :            :                                 &open_rx_pcap, &pcaps);
    2012         [ +  + ]:          8 :         } else if (devargs_all.is_rx_iface) {
    2013                 :          2 :                 ret = rte_kvargs_process(kvlist, NULL,
    2014                 :            :                                 &rx_iface_args_process, &pcaps);
    2015         [ +  - ]:          6 :         } else if (devargs_all.is_tx_iface || devargs_all.is_tx_pcap) {
    2016                 :            :                 unsigned int i;
    2017                 :            : 
    2018                 :            :                 /* Count number of tx queue args passed before dummy rx queue
    2019                 :            :                  * creation so a dummy rx queue can be created for each tx queue
    2020                 :            :                  */
    2021                 :          6 :                 unsigned int num_tx_queues =
    2022                 :          6 :                         (rte_kvargs_count(kvlist, ETH_PCAP_TX_PCAP_ARG) +
    2023                 :          6 :                         rte_kvargs_count(kvlist, ETH_PCAP_TX_IFACE_ARG));
    2024                 :            : 
    2025                 :          6 :                 PMD_LOG(INFO, "Creating null rx queue since no rx queues were provided.");
    2026                 :            : 
    2027                 :            :                 /* Creating a dummy rx queue for each tx queue passed */
    2028         [ +  + ]:         15 :                 for (i = 0; i < num_tx_queues; i++)
    2029                 :            :                         ret = add_queue(&pcaps, "dummy_rx", "rx_null", NULL,
    2030                 :            :                                         NULL);
    2031                 :            :         } else {
    2032                 :          0 :                 PMD_LOG(ERR, "Error - No rx or tx queues provided");
    2033                 :            :                 ret = -ENOENT;
    2034                 :            :         }
    2035         [ -  + ]:         25 :         if (ret < 0)
    2036                 :          0 :                 goto free_kvlist;
    2037                 :            : 
    2038                 :            :         /*
    2039                 :            :          * We check whether we want to open a TX stream to a real NIC,
    2040                 :            :          * a pcap file, or drop packets on tx
    2041                 :            :          */
    2042         [ +  + ]:         25 :         if (devargs_all.is_tx_pcap) {
    2043                 :         10 :                 ret = rte_kvargs_process(kvlist, ETH_PCAP_TX_PCAP_ARG,
    2044                 :            :                                 &open_tx_pcap, &dumpers);
    2045         [ +  + ]:         15 :         } else if (devargs_all.is_tx_iface) {
    2046                 :          2 :                 ret = rte_kvargs_process(kvlist, ETH_PCAP_TX_IFACE_ARG,
    2047                 :            :                                 &open_tx_iface, &dumpers);
    2048                 :            :         } else {
    2049                 :            :                 unsigned int i;
    2050                 :            : 
    2051                 :         13 :                 PMD_LOG(INFO, "Dropping packets on tx since no tx queues were provided.");
    2052                 :            : 
    2053                 :            :                 /* Add 1 dummy queue per rxq which counts and drops packets. */
    2054         [ +  + ]:         29 :                 for (i = 0; i < pcaps.num_of_queue; i++)
    2055                 :            :                         ret = add_queue(&dumpers, "dummy_tx", "tx_drop", NULL,
    2056                 :            :                                         NULL);
    2057                 :            :         }
    2058                 :            : 
    2059         [ -  + ]:         25 :         if (ret < 0)
    2060                 :          0 :                 goto free_kvlist;
    2061                 :            : 
    2062                 :         25 : create_eth:
    2063         [ -  + ]:         28 :         if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
    2064                 :            :                 struct pmd_process_private *pp;
    2065                 :            :                 unsigned int i;
    2066                 :            : 
    2067                 :            :                 internal = eth_dev->data->dev_private;
    2068                 :          0 :                 pp = rte_zmalloc("pcap_private", sizeof(struct pmd_process_private),
    2069                 :            :                          RTE_CACHE_LINE_SIZE);
    2070         [ #  # ]:          0 :                 if (pp == NULL) {
    2071                 :          0 :                         PMD_LOG(ERR,
    2072                 :            :                                 "Failed to allocate memory for process private");
    2073                 :            :                         ret = -1;
    2074                 :          0 :                         goto free_kvlist;
    2075                 :            :                 }
    2076                 :            : 
    2077                 :          0 :                 eth_dev->dev_ops = &ops;
    2078                 :          0 :                 eth_dev->device = &dev->device;
    2079                 :            : 
    2080                 :            :                 /* setup process private */
    2081         [ #  # ]:          0 :                 for (i = 0; i < pcaps.num_of_queue; i++)
    2082                 :          0 :                         pp->rx_pcap[i] = pcaps.queue[i].pcap;
    2083                 :            : 
    2084         [ #  # ]:          0 :                 for (i = 0; i < dumpers.num_of_queue; i++) {
    2085                 :          0 :                         pp->tx_dumper[i] = dumpers.queue[i].dumper;
    2086                 :          0 :                         pp->tx_pcap[i] = dumpers.queue[i].pcap;
    2087                 :            :                 }
    2088                 :            : 
    2089                 :          0 :                 eth_dev->process_private = pp;
    2090                 :          0 :                 eth_dev->rx_pkt_burst = eth_pcap_rx;
    2091         [ #  # ]:          0 :                 if (devargs_all.is_tx_pcap)
    2092                 :          0 :                         eth_dev->tx_pkt_burst = eth_pcap_tx_dumper;
    2093                 :            :                 else
    2094                 :          0 :                         eth_dev->tx_pkt_burst = eth_pcap_tx;
    2095                 :            : 
    2096                 :          0 :                 rte_eth_dev_probing_finish(eth_dev);
    2097                 :          0 :                 goto free_kvlist;
    2098                 :            :         }
    2099                 :            : 
    2100                 :         28 :         devargs_all.rx_queues = pcaps;
    2101                 :         28 :         devargs_all.tx_queues = dumpers;
    2102                 :            : 
    2103                 :         28 :         ret = eth_from_pcaps(dev, &devargs_all);
    2104                 :            : 
    2105                 :         29 : free_kvlist:
    2106                 :         29 :         rte_kvargs_free(kvlist);
    2107                 :            : 
    2108         [ +  + ]:         29 :         if (ret < 0)
    2109                 :          1 :                 eth_release_pcaps(&pcaps, &dumpers, devargs_all.single_iface);
    2110                 :            : 
    2111                 :            :         return ret;
    2112                 :            : }
    2113                 :            : 
    2114                 :            : static int
    2115                 :         28 : pmd_pcap_remove(struct rte_vdev_device *dev)
    2116                 :            : {
    2117                 :            :         struct rte_eth_dev *eth_dev = NULL;
    2118                 :            : 
    2119         [ +  - ]:         28 :         if (!dev)
    2120                 :            :                 return -1;
    2121                 :            : 
    2122                 :         28 :         eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
    2123         [ +  - ]:         28 :         if (eth_dev == NULL)
    2124                 :            :                 return 0; /* port already released */
    2125                 :            : 
    2126                 :         28 :         eth_dev_close(eth_dev);
    2127                 :         28 :         rte_eth_dev_release_port(eth_dev);
    2128                 :            : 
    2129                 :         28 :         return 0;
    2130                 :            : }
    2131                 :            : 
    2132                 :            : static struct rte_vdev_driver pmd_pcap_drv = {
    2133                 :            :         .probe = pmd_pcap_probe,
    2134                 :            :         .remove = pmd_pcap_remove,
    2135                 :            : };
    2136                 :            : 
    2137                 :        286 : RTE_PMD_REGISTER_VDEV(net_pcap, pmd_pcap_drv);
    2138                 :            : RTE_PMD_REGISTER_ALIAS(net_pcap, eth_pcap);
    2139                 :            : RTE_PMD_REGISTER_PARAM_STRING(net_pcap,
    2140                 :            :         ETH_PCAP_RX_PCAP_ARG "=<string> "
    2141                 :            :         ETH_PCAP_TX_PCAP_ARG "=<string> "
    2142                 :            :         ETH_PCAP_RX_IFACE_ARG "=<ifc> "
    2143                 :            :         ETH_PCAP_RX_IFACE_IN_ARG "=<ifc> "
    2144                 :            :         ETH_PCAP_TX_IFACE_ARG "=<ifc> "
    2145                 :            :         ETH_PCAP_IFACE_ARG "=<ifc> "
    2146                 :            :         ETH_PCAP_PHY_MAC_ARG "=<0|1> "
    2147                 :            :         ETH_PCAP_INFINITE_RX_ARG "=<0|1> "
    2148                 :            :         ETH_PCAP_EOF_ARG "=<0|1> "
    2149                 :            :         ETH_PCAP_SNAPSHOT_LEN_ARG "=<int>");

Generated by: LCOV version 1.14