LCOV - code coverage report
Current view: top level - drivers/net/af_xdp - rte_eth_af_xdp.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 2 841 0.2 %
Date: 2024-01-22 16:26:08 Functions: 2 50 4.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 1 398 0.3 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2019-2020 Intel Corporation.
       3                 :            :  */
       4                 :            : #include <unistd.h>
       5                 :            : #include <errno.h>
       6                 :            : #include <stdlib.h>
       7                 :            : #include <string.h>
       8                 :            : #include <netinet/in.h>
       9                 :            : #include <net/if.h>
      10                 :            : #include <sys/un.h>
      11                 :            : #include <sys/socket.h>
      12                 :            : #include <sys/ioctl.h>
      13                 :            : #include <linux/if_ether.h>
      14                 :            : #include <linux/if_xdp.h>
      15                 :            : #include <linux/if_link.h>
      16                 :            : #include <linux/ethtool.h>
      17                 :            : #include <linux/sockios.h>
      18                 :            : #include "af_xdp_deps.h"
      19                 :            : 
      20                 :            : #include <rte_ethdev.h>
      21                 :            : #include <ethdev_driver.h>
      22                 :            : #include <ethdev_vdev.h>
      23                 :            : #include <rte_kvargs.h>
      24                 :            : #include <bus_vdev_driver.h>
      25                 :            : #include <rte_string_fns.h>
      26                 :            : #include <rte_branch_prediction.h>
      27                 :            : #include <rte_common.h>
      28                 :            : #include <dev_driver.h>
      29                 :            : #include <rte_eal.h>
      30                 :            : #include <rte_ether.h>
      31                 :            : #include <rte_lcore.h>
      32                 :            : #include <rte_log.h>
      33                 :            : #include <rte_memory.h>
      34                 :            : #include <rte_memzone.h>
      35                 :            : #include <rte_mempool.h>
      36                 :            : #include <rte_mbuf.h>
      37                 :            : #include <rte_malloc.h>
      38                 :            : #include <rte_ring.h>
      39                 :            : #include <rte_spinlock.h>
      40                 :            : #include <rte_power_intrinsics.h>
      41                 :            : 
      42                 :            : #include "compat.h"
      43                 :            : #include "eal_filesystem.h"
      44                 :            : 
      45                 :            : #ifndef SO_PREFER_BUSY_POLL
      46                 :            : #define SO_PREFER_BUSY_POLL 69
      47                 :            : #endif
      48                 :            : #ifndef SO_BUSY_POLL_BUDGET
      49                 :            : #define SO_BUSY_POLL_BUDGET 70
      50                 :            : #endif
      51                 :            : 
      52                 :            : 
      53                 :            : #ifndef SOL_XDP
      54                 :            : #define SOL_XDP 283
      55                 :            : #endif
      56                 :            : 
      57                 :            : #ifndef AF_XDP
      58                 :            : #define AF_XDP 44
      59                 :            : #endif
      60                 :            : 
      61                 :            : #ifndef PF_XDP
      62                 :            : #define PF_XDP AF_XDP
      63                 :            : #endif
      64                 :            : 
      65         [ -  + ]:        235 : RTE_LOG_REGISTER_DEFAULT(af_xdp_logtype, NOTICE);
      66                 :            : 
      67                 :            : #define AF_XDP_LOG(level, fmt, args...)                 \
      68                 :            :         rte_log(RTE_LOG_ ## level, af_xdp_logtype,      \
      69                 :            :                 "%s(): " fmt, __func__, ##args)
      70                 :            : 
      71                 :            : #define ETH_AF_XDP_FRAME_SIZE           2048
      72                 :            : #define ETH_AF_XDP_NUM_BUFFERS          4096
      73                 :            : #define ETH_AF_XDP_DFLT_NUM_DESCS       XSK_RING_CONS__DEFAULT_NUM_DESCS
      74                 :            : #define ETH_AF_XDP_DFLT_START_QUEUE_IDX 0
      75                 :            : #define ETH_AF_XDP_DFLT_QUEUE_COUNT     1
      76                 :            : #define ETH_AF_XDP_DFLT_BUSY_BUDGET     64
      77                 :            : #define ETH_AF_XDP_DFLT_BUSY_TIMEOUT    20
      78                 :            : 
      79                 :            : #define ETH_AF_XDP_RX_BATCH_SIZE        XSK_RING_CONS__DEFAULT_NUM_DESCS
      80                 :            : #define ETH_AF_XDP_TX_BATCH_SIZE        XSK_RING_CONS__DEFAULT_NUM_DESCS
      81                 :            : 
      82                 :            : #define ETH_AF_XDP_ETH_OVERHEAD         (RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN)
      83                 :            : 
      84                 :            : #define ETH_AF_XDP_MP_KEY "afxdp_mp_send_fds"
      85                 :            : 
      86                 :            : #define MAX_LONG_OPT_SZ                 64
      87                 :            : #define UDS_MAX_FD_NUM                  2
      88                 :            : #define UDS_MAX_CMD_LEN                 64
      89                 :            : #define UDS_MAX_CMD_RESP                128
      90                 :            : #define UDS_XSK_MAP_FD_MSG              "/xsk_map_fd"
      91                 :            : #define UDS_SOCK                        "/tmp/afxdp.sock"
      92                 :            : #define UDS_CONNECT_MSG                 "/connect"
      93                 :            : #define UDS_HOST_OK_MSG                 "/host_ok"
      94                 :            : #define UDS_HOST_NAK_MSG                "/host_nak"
      95                 :            : #define UDS_VERSION_MSG                 "/version"
      96                 :            : #define UDS_XSK_MAP_FD_MSG              "/xsk_map_fd"
      97                 :            : #define UDS_XSK_SOCKET_MSG              "/xsk_socket"
      98                 :            : #define UDS_FD_ACK_MSG                  "/fd_ack"
      99                 :            : #define UDS_FD_NAK_MSG                  "/fd_nak"
     100                 :            : #define UDS_FIN_MSG                     "/fin"
     101                 :            : #define UDS_FIN_ACK_MSG                 "/fin_ack"
     102                 :            : 
     103                 :            : static int afxdp_dev_count;
     104                 :            : 
     105                 :            : /* Message header to synchronize fds via IPC */
     106                 :            : struct ipc_hdr {
     107                 :            :         char port_name[RTE_DEV_NAME_MAX_LEN];
     108                 :            :         /* The file descriptors are in the dedicated part
     109                 :            :          * of the Unix message to be translated by the kernel.
     110                 :            :          */
     111                 :            : };
     112                 :            : 
     113                 :            : struct xsk_umem_info {
     114                 :            :         struct xsk_umem *umem;
     115                 :            :         struct rte_ring *buf_ring;
     116                 :            :         const struct rte_memzone *mz;
     117                 :            :         struct rte_mempool *mb_pool;
     118                 :            :         void *buffer;
     119                 :            :         uint8_t refcnt;
     120                 :            :         uint32_t max_xsks;
     121                 :            : };
     122                 :            : 
     123                 :            : struct rx_stats {
     124                 :            :         uint64_t rx_pkts;
     125                 :            :         uint64_t rx_bytes;
     126                 :            :         uint64_t rx_dropped;
     127                 :            : };
     128                 :            : 
     129                 :            : struct pkt_rx_queue {
     130                 :            :         struct xsk_ring_cons rx;
     131                 :            :         struct xsk_umem_info *umem;
     132                 :            :         struct xsk_socket *xsk;
     133                 :            :         struct rte_mempool *mb_pool;
     134                 :            : 
     135                 :            :         struct rx_stats stats;
     136                 :            : 
     137                 :            :         struct xsk_ring_prod fq;
     138                 :            :         struct xsk_ring_cons cq;
     139                 :            : 
     140                 :            :         struct pkt_tx_queue *pair;
     141                 :            :         struct pollfd fds[1];
     142                 :            :         int xsk_queue_idx;
     143                 :            :         int busy_budget;
     144                 :            : };
     145                 :            : 
     146                 :            : struct tx_stats {
     147                 :            :         uint64_t tx_pkts;
     148                 :            :         uint64_t tx_bytes;
     149                 :            :         uint64_t tx_dropped;
     150                 :            : };
     151                 :            : 
     152                 :            : struct pkt_tx_queue {
     153                 :            :         struct xsk_ring_prod tx;
     154                 :            :         struct xsk_umem_info *umem;
     155                 :            : 
     156                 :            :         struct tx_stats stats;
     157                 :            : 
     158                 :            :         struct pkt_rx_queue *pair;
     159                 :            :         int xsk_queue_idx;
     160                 :            : };
     161                 :            : 
     162                 :            : struct pmd_internals {
     163                 :            :         int if_index;
     164                 :            :         char if_name[IFNAMSIZ];
     165                 :            :         int start_queue_idx;
     166                 :            :         int queue_cnt;
     167                 :            :         int max_queue_cnt;
     168                 :            :         int combined_queue_cnt;
     169                 :            :         bool shared_umem;
     170                 :            :         char prog_path[PATH_MAX];
     171                 :            :         bool custom_prog_configured;
     172                 :            :         bool force_copy;
     173                 :            :         bool use_cni;
     174                 :            :         struct bpf_map *map;
     175                 :            : 
     176                 :            :         struct rte_ether_addr eth_addr;
     177                 :            : 
     178                 :            :         struct pkt_rx_queue *rx_queues;
     179                 :            :         struct pkt_tx_queue *tx_queues;
     180                 :            : };
     181                 :            : 
     182                 :            : struct pmd_process_private {
     183                 :            :         int rxq_xsk_fds[RTE_MAX_QUEUES_PER_PORT];
     184                 :            : };
     185                 :            : 
     186                 :            : #define ETH_AF_XDP_IFACE_ARG                    "iface"
     187                 :            : #define ETH_AF_XDP_START_QUEUE_ARG              "start_queue"
     188                 :            : #define ETH_AF_XDP_QUEUE_COUNT_ARG              "queue_count"
     189                 :            : #define ETH_AF_XDP_SHARED_UMEM_ARG              "shared_umem"
     190                 :            : #define ETH_AF_XDP_PROG_ARG                     "xdp_prog"
     191                 :            : #define ETH_AF_XDP_BUDGET_ARG                   "busy_budget"
     192                 :            : #define ETH_AF_XDP_FORCE_COPY_ARG               "force_copy"
     193                 :            : #define ETH_AF_XDP_USE_CNI_ARG                  "use_cni"
     194                 :            : 
     195                 :            : static const char * const valid_arguments[] = {
     196                 :            :         ETH_AF_XDP_IFACE_ARG,
     197                 :            :         ETH_AF_XDP_START_QUEUE_ARG,
     198                 :            :         ETH_AF_XDP_QUEUE_COUNT_ARG,
     199                 :            :         ETH_AF_XDP_SHARED_UMEM_ARG,
     200                 :            :         ETH_AF_XDP_PROG_ARG,
     201                 :            :         ETH_AF_XDP_BUDGET_ARG,
     202                 :            :         ETH_AF_XDP_FORCE_COPY_ARG,
     203                 :            :         ETH_AF_XDP_USE_CNI_ARG,
     204                 :            :         NULL
     205                 :            : };
     206                 :            : 
     207                 :            : static const struct rte_eth_link pmd_link = {
     208                 :            :         .link_speed = RTE_ETH_SPEED_NUM_10G,
     209                 :            :         .link_duplex = RTE_ETH_LINK_FULL_DUPLEX,
     210                 :            :         .link_status = RTE_ETH_LINK_DOWN,
     211                 :            :         .link_autoneg = RTE_ETH_LINK_AUTONEG
     212                 :            : };
     213                 :            : 
     214                 :            : /* List which tracks PMDs to facilitate sharing UMEMs across them. */
     215                 :            : struct internal_list {
     216                 :            :         TAILQ_ENTRY(internal_list) next;
     217                 :            :         struct rte_eth_dev *eth_dev;
     218                 :            : };
     219                 :            : 
     220                 :            : TAILQ_HEAD(internal_list_head, internal_list);
     221                 :            : static struct internal_list_head internal_list =
     222                 :            :         TAILQ_HEAD_INITIALIZER(internal_list);
     223                 :            : 
     224                 :            : static pthread_mutex_t internal_list_lock = PTHREAD_MUTEX_INITIALIZER;
     225                 :            : 
     226                 :            : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
     227                 :            : static inline int
     228                 :          0 : reserve_fill_queue_zc(struct xsk_umem_info *umem, uint16_t reserve_size,
     229                 :            :                       struct rte_mbuf **bufs, struct xsk_ring_prod *fq)
     230                 :            : {
     231                 :            :         uint32_t idx;
     232                 :            :         uint16_t i;
     233                 :            : 
     234   [ #  #  #  # ]:          0 :         if (unlikely(!xsk_ring_prod__reserve(fq, reserve_size, &idx))) {
     235         [ #  # ]:          0 :                 for (i = 0; i < reserve_size; i++)
     236                 :          0 :                         rte_pktmbuf_free(bufs[i]);
     237                 :          0 :                 AF_XDP_LOG(DEBUG, "Failed to reserve enough fq descs.\n");
     238                 :          0 :                 return -1;
     239                 :            :         }
     240                 :            : 
     241         [ #  # ]:          0 :         for (i = 0; i < reserve_size; i++) {
     242                 :            :                 __u64 *fq_addr;
     243                 :            :                 uint64_t addr;
     244                 :            : 
     245                 :          0 :                 fq_addr = xsk_ring_prod__fill_addr(fq, idx++);
     246                 :          0 :                 addr = (uint64_t)bufs[i] - (uint64_t)umem->buffer -
     247                 :          0 :                                 umem->mb_pool->header_size;
     248                 :          0 :                 *fq_addr = addr;
     249                 :            :         }
     250                 :            : 
     251                 :            :         xsk_ring_prod__submit(fq, reserve_size);
     252                 :            : 
     253                 :          0 :         return 0;
     254                 :            : }
     255                 :            : #else
     256                 :            : static inline int
     257                 :            : reserve_fill_queue_cp(struct xsk_umem_info *umem, uint16_t reserve_size,
     258                 :            :                       struct rte_mbuf **bufs __rte_unused,
     259                 :            :                       struct xsk_ring_prod *fq)
     260                 :            : {
     261                 :            :         void *addrs[reserve_size];
     262                 :            :         uint32_t idx;
     263                 :            :         uint16_t i;
     264                 :            : 
     265                 :            :         if (rte_ring_dequeue_bulk(umem->buf_ring, addrs, reserve_size, NULL)
     266                 :            :                     != reserve_size) {
     267                 :            :                 AF_XDP_LOG(DEBUG, "Failed to get enough buffers for fq.\n");
     268                 :            :                 return -1;
     269                 :            :         }
     270                 :            : 
     271                 :            :         if (unlikely(!xsk_ring_prod__reserve(fq, reserve_size, &idx))) {
     272                 :            :                 AF_XDP_LOG(DEBUG, "Failed to reserve enough fq descs.\n");
     273                 :            :                 rte_ring_enqueue_bulk(umem->buf_ring, addrs,
     274                 :            :                                 reserve_size, NULL);
     275                 :            :                 return -1;
     276                 :            :         }
     277                 :            : 
     278                 :            :         for (i = 0; i < reserve_size; i++) {
     279                 :            :                 __u64 *fq_addr;
     280                 :            : 
     281                 :            :                 fq_addr = xsk_ring_prod__fill_addr(fq, idx++);
     282                 :            :                 *fq_addr = (uint64_t)addrs[i];
     283                 :            :         }
     284                 :            : 
     285                 :            :         xsk_ring_prod__submit(fq, reserve_size);
     286                 :            : 
     287                 :            :         return 0;
     288                 :            : }
     289                 :            : #endif
     290                 :            : 
     291                 :            : static inline int
     292                 :            : reserve_fill_queue(struct xsk_umem_info *umem, uint16_t reserve_size,
     293                 :            :                    struct rte_mbuf **bufs, struct xsk_ring_prod *fq)
     294                 :            : {
     295                 :            : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
     296                 :          0 :         return reserve_fill_queue_zc(umem, reserve_size, bufs, fq);
     297                 :            : #else
     298                 :            :         return reserve_fill_queue_cp(umem, reserve_size, bufs, fq);
     299                 :            : #endif
     300                 :            : }
     301                 :            : 
     302                 :            : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
     303                 :            : static uint16_t
     304                 :          0 : af_xdp_rx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     305                 :            : {
     306                 :            :         struct pkt_rx_queue *rxq = queue;
     307                 :            :         struct xsk_ring_cons *rx = &rxq->rx;
     308                 :          0 :         struct xsk_ring_prod *fq = &rxq->fq;
     309                 :          0 :         struct xsk_umem_info *umem = rxq->umem;
     310                 :            :         uint32_t idx_rx = 0;
     311                 :            :         unsigned long rx_bytes = 0;
     312                 :            :         int i;
     313                 :            :         struct rte_mbuf *fq_bufs[ETH_AF_XDP_RX_BATCH_SIZE];
     314                 :            : 
     315         [ #  # ]:          0 :         nb_pkts = xsk_ring_cons__peek(rx, nb_pkts, &idx_rx);
     316                 :            : 
     317         [ #  # ]:          0 :         if (nb_pkts == 0) {
     318                 :            :                 /* we can assume a kernel >= 5.11 is in use if busy polling is
     319                 :            :                  * enabled and thus we can safely use the recvfrom() syscall
     320                 :            :                  * which is only supported for AF_XDP sockets in kernels >=
     321                 :            :                  * 5.11.
     322                 :            :                  */
     323         [ #  # ]:          0 :                 if (rxq->busy_budget) {
     324                 :          0 :                         (void)recvfrom(xsk_socket__fd(rxq->xsk), NULL, 0,
     325                 :            :                                        MSG_DONTWAIT, NULL, NULL);
     326         [ #  # ]:          0 :                 } else if (xsk_ring_prod__needs_wakeup(fq)) {
     327         [ #  # ]:          0 :                         (void)poll(&rxq->fds[0], 1, 1000);
     328                 :            :                 }
     329                 :            : 
     330                 :          0 :                 return 0;
     331                 :            :         }
     332                 :            : 
     333                 :            :         /* allocate bufs for fill queue replenishment after rx */
     334         [ #  # ]:          0 :         if (rte_pktmbuf_alloc_bulk(umem->mb_pool, fq_bufs, nb_pkts)) {
     335                 :          0 :                 AF_XDP_LOG(DEBUG,
     336                 :            :                         "Failed to get enough buffers for fq.\n");
     337                 :            :                 /* rollback cached_cons which is added by
     338                 :            :                  * xsk_ring_cons__peek
     339                 :            :                  */
     340                 :          0 :                 rx->cached_cons -= nb_pkts;
     341                 :          0 :                 return 0;
     342                 :            :         }
     343                 :            : 
     344         [ #  # ]:          0 :         for (i = 0; i < nb_pkts; i++) {
     345                 :            :                 const struct xdp_desc *desc;
     346                 :            :                 uint64_t addr;
     347                 :            :                 uint32_t len;
     348                 :            :                 uint64_t offset;
     349                 :            : 
     350         [ #  # ]:          0 :                 desc = xsk_ring_cons__rx_desc(rx, idx_rx++);
     351                 :          0 :                 addr = desc->addr;
     352         [ #  # ]:          0 :                 len = desc->len;
     353                 :            : 
     354                 :            :                 offset = xsk_umem__extract_offset(addr);
     355                 :            :                 addr = xsk_umem__extract_addr(addr);
     356                 :            : 
     357                 :          0 :                 bufs[i] = (struct rte_mbuf *)
     358                 :          0 :                                 xsk_umem__get_data(umem->buffer, addr +
     359         [ #  # ]:          0 :                                         umem->mb_pool->header_size);
     360         [ #  # ]:          0 :                 bufs[i]->data_off = offset - sizeof(struct rte_mbuf) -
     361                 :          0 :                         rte_pktmbuf_priv_size(umem->mb_pool) -
     362                 :            :                         umem->mb_pool->header_size;
     363                 :            : 
     364                 :          0 :                 rte_pktmbuf_pkt_len(bufs[i]) = len;
     365                 :          0 :                 rte_pktmbuf_data_len(bufs[i]) = len;
     366                 :          0 :                 rx_bytes += len;
     367                 :            :         }
     368                 :            : 
     369                 :            :         xsk_ring_cons__release(rx, nb_pkts);
     370                 :            :         (void)reserve_fill_queue(umem, nb_pkts, fq_bufs, fq);
     371                 :            : 
     372                 :            :         /* statistics */
     373                 :          0 :         rxq->stats.rx_pkts += nb_pkts;
     374                 :          0 :         rxq->stats.rx_bytes += rx_bytes;
     375                 :            : 
     376                 :          0 :         return nb_pkts;
     377                 :            : }
     378                 :            : #else
     379                 :            : static uint16_t
     380                 :            : af_xdp_rx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     381                 :            : {
     382                 :            :         struct pkt_rx_queue *rxq = queue;
     383                 :            :         struct xsk_ring_cons *rx = &rxq->rx;
     384                 :            :         struct xsk_umem_info *umem = rxq->umem;
     385                 :            :         struct xsk_ring_prod *fq = &rxq->fq;
     386                 :            :         uint32_t idx_rx = 0;
     387                 :            :         unsigned long rx_bytes = 0;
     388                 :            :         int i;
     389                 :            :         uint32_t free_thresh = fq->size >> 1;
     390                 :            :         struct rte_mbuf *mbufs[ETH_AF_XDP_RX_BATCH_SIZE];
     391                 :            : 
     392                 :            :         if (xsk_prod_nb_free(fq, free_thresh) >= free_thresh)
     393                 :            :                 (void)reserve_fill_queue(umem, nb_pkts, NULL, fq);
     394                 :            : 
     395                 :            :         nb_pkts = xsk_ring_cons__peek(rx, nb_pkts, &idx_rx);
     396                 :            :         if (nb_pkts == 0) {
     397                 :            : #if defined(XDP_USE_NEED_WAKEUP)
     398                 :            :                 if (xsk_ring_prod__needs_wakeup(fq))
     399                 :            :                         (void)poll(rxq->fds, 1, 1000);
     400                 :            : #endif
     401                 :            :                 return 0;
     402                 :            :         }
     403                 :            : 
     404                 :            :         if (unlikely(rte_pktmbuf_alloc_bulk(rxq->mb_pool, mbufs, nb_pkts))) {
     405                 :            :                 /* rollback cached_cons which is added by
     406                 :            :                  * xsk_ring_cons__peek
     407                 :            :                  */
     408                 :            :                 rx->cached_cons -= nb_pkts;
     409                 :            :                 return 0;
     410                 :            :         }
     411                 :            : 
     412                 :            :         for (i = 0; i < nb_pkts; i++) {
     413                 :            :                 const struct xdp_desc *desc;
     414                 :            :                 uint64_t addr;
     415                 :            :                 uint32_t len;
     416                 :            :                 void *pkt;
     417                 :            : 
     418                 :            :                 desc = xsk_ring_cons__rx_desc(rx, idx_rx++);
     419                 :            :                 addr = desc->addr;
     420                 :            :                 len = desc->len;
     421                 :            :                 pkt = xsk_umem__get_data(rxq->umem->mz->addr, addr);
     422                 :            : 
     423                 :            :                 rte_memcpy(rte_pktmbuf_mtod(mbufs[i], void *), pkt, len);
     424                 :            :                 rte_ring_enqueue(umem->buf_ring, (void *)addr);
     425                 :            :                 rte_pktmbuf_pkt_len(mbufs[i]) = len;
     426                 :            :                 rte_pktmbuf_data_len(mbufs[i]) = len;
     427                 :            :                 rx_bytes += len;
     428                 :            :                 bufs[i] = mbufs[i];
     429                 :            :         }
     430                 :            : 
     431                 :            :         xsk_ring_cons__release(rx, nb_pkts);
     432                 :            : 
     433                 :            :         /* statistics */
     434                 :            :         rxq->stats.rx_pkts += nb_pkts;
     435                 :            :         rxq->stats.rx_bytes += rx_bytes;
     436                 :            : 
     437                 :            :         return nb_pkts;
     438                 :            : }
     439                 :            : #endif
     440                 :            : 
     441                 :            : static uint16_t
     442                 :            : af_xdp_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     443                 :            : {
     444                 :            : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
     445                 :          0 :         return af_xdp_rx_zc(queue, bufs, nb_pkts);
     446                 :            : #else
     447                 :            :         return af_xdp_rx_cp(queue, bufs, nb_pkts);
     448                 :            : #endif
     449                 :            : }
     450                 :            : 
     451                 :            : static uint16_t
     452                 :          0 : eth_af_xdp_rx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     453                 :            : {
     454                 :            :         uint16_t nb_rx;
     455                 :            : 
     456         [ #  # ]:          0 :         if (likely(nb_pkts <= ETH_AF_XDP_RX_BATCH_SIZE))
     457                 :          0 :                 return af_xdp_rx(queue, bufs, nb_pkts);
     458                 :            : 
     459                 :            :         /* Split larger batch into smaller batches of size
     460                 :            :          * ETH_AF_XDP_RX_BATCH_SIZE or less.
     461                 :            :          */
     462                 :            :         nb_rx = 0;
     463         [ #  # ]:          0 :         while (nb_pkts) {
     464                 :            :                 uint16_t ret, n;
     465                 :            : 
     466                 :          0 :                 n = (uint16_t)RTE_MIN(nb_pkts, ETH_AF_XDP_RX_BATCH_SIZE);
     467                 :          0 :                 ret = af_xdp_rx(queue, &bufs[nb_rx], n);
     468                 :          0 :                 nb_rx = (uint16_t)(nb_rx + ret);
     469                 :          0 :                 nb_pkts = (uint16_t)(nb_pkts - ret);
     470         [ #  # ]:          0 :                 if (ret < n)
     471                 :            :                         break;
     472                 :            :         }
     473                 :            : 
     474                 :            :         return nb_rx;
     475                 :            : }
     476                 :            : 
     477                 :            : static void
     478                 :          0 : pull_umem_cq(struct xsk_umem_info *umem, int size, struct xsk_ring_cons *cq)
     479                 :            : {
     480                 :            :         size_t i, n;
     481                 :            :         uint32_t idx_cq = 0;
     482                 :            : 
     483         [ #  # ]:          0 :         n = xsk_ring_cons__peek(cq, size, &idx_cq);
     484                 :            : 
     485         [ #  # ]:          0 :         for (i = 0; i < n; i++) {
     486                 :            :                 uint64_t addr;
     487                 :          0 :                 addr = *xsk_ring_cons__comp_addr(cq, idx_cq++);
     488                 :            : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
     489                 :            :                 addr = xsk_umem__extract_addr(addr);
     490                 :          0 :                 rte_pktmbuf_free((struct rte_mbuf *)
     491                 :          0 :                                         xsk_umem__get_data(umem->buffer,
     492                 :          0 :                                         addr + umem->mb_pool->header_size));
     493                 :            : #else
     494                 :            :                 rte_ring_enqueue(umem->buf_ring, (void *)addr);
     495                 :            : #endif
     496                 :            :         }
     497                 :            : 
     498                 :            :         xsk_ring_cons__release(cq, n);
     499                 :          0 : }
     500                 :            : 
     501                 :            : static void
     502                 :          0 : kick_tx(struct pkt_tx_queue *txq, struct xsk_ring_cons *cq)
     503                 :            : {
     504                 :          0 :         struct xsk_umem_info *umem = txq->umem;
     505                 :            : 
     506                 :          0 :         pull_umem_cq(umem, XSK_RING_CONS__DEFAULT_NUM_DESCS, cq);
     507                 :            : 
     508         [ #  # ]:          0 :         if (tx_syscall_needed(&txq->tx))
     509                 :          0 :                 while (send(xsk_socket__fd(txq->pair->xsk), NULL,
     510         [ #  # ]:          0 :                             0, MSG_DONTWAIT) < 0) {
     511                 :            :                         /* some thing unexpected */
     512   [ #  #  #  # ]:          0 :                         if (errno != EBUSY && errno != EAGAIN && errno != EINTR)
     513                 :            :                                 break;
     514                 :            : 
     515                 :            :                         /* pull from completion queue to leave more space */
     516         [ #  # ]:          0 :                         if (errno == EAGAIN)
     517                 :          0 :                                 pull_umem_cq(umem,
     518                 :            :                                              XSK_RING_CONS__DEFAULT_NUM_DESCS,
     519                 :            :                                              cq);
     520                 :            :                 }
     521                 :          0 : }
     522                 :            : 
     523                 :            : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
     524                 :            : static uint16_t
     525                 :          0 : af_xdp_tx_zc(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     526                 :            : {
     527                 :            :         struct pkt_tx_queue *txq = queue;
     528                 :          0 :         struct xsk_umem_info *umem = txq->umem;
     529                 :            :         struct rte_mbuf *mbuf;
     530                 :            :         unsigned long tx_bytes = 0;
     531                 :            :         int i;
     532                 :            :         uint32_t idx_tx;
     533                 :            :         uint16_t count = 0;
     534                 :            :         struct xdp_desc *desc;
     535                 :            :         uint64_t addr, offset;
     536                 :          0 :         struct xsk_ring_cons *cq = &txq->pair->cq;
     537         [ #  # ]:          0 :         uint32_t free_thresh = cq->size >> 1;
     538                 :            : 
     539         [ #  # ]:          0 :         if (xsk_cons_nb_avail(cq, free_thresh) >= free_thresh)
     540                 :          0 :                 pull_umem_cq(umem, XSK_RING_CONS__DEFAULT_NUM_DESCS, cq);
     541                 :            : 
     542         [ #  # ]:          0 :         for (i = 0; i < nb_pkts; i++) {
     543                 :          0 :                 mbuf = bufs[i];
     544                 :            : 
     545         [ #  # ]:          0 :                 if (mbuf->pool == umem->mb_pool) {
     546                 :            :                         if (!xsk_ring_prod__reserve(&txq->tx, 1, &idx_tx)) {
     547                 :          0 :                                 kick_tx(txq, cq);
     548                 :            :                                 if (!xsk_ring_prod__reserve(&txq->tx, 1,
     549                 :            :                                                             &idx_tx))
     550                 :          0 :                                         goto out;
     551                 :            :                         }
     552                 :            :                         desc = xsk_ring_prod__tx_desc(&txq->tx, idx_tx);
     553                 :          0 :                         desc->len = mbuf->pkt_len;
     554                 :          0 :                         addr = (uint64_t)mbuf - (uint64_t)umem->buffer -
     555                 :          0 :                                         umem->mb_pool->header_size;
     556                 :          0 :                         offset = rte_pktmbuf_mtod(mbuf, uint64_t) -
     557                 :            :                                         (uint64_t)mbuf +
     558                 :            :                                         umem->mb_pool->header_size;
     559                 :          0 :                         offset = offset << XSK_UNALIGNED_BUF_OFFSET_SHIFT;
     560                 :          0 :                         desc->addr = addr | offset;
     561                 :          0 :                         count++;
     562                 :            :                 } else {
     563                 :            :                         struct rte_mbuf *local_mbuf =
     564                 :          0 :                                         rte_pktmbuf_alloc(umem->mb_pool);
     565                 :            :                         void *pkt;
     566                 :            : 
     567         [ #  # ]:          0 :                         if (local_mbuf == NULL)
     568                 :          0 :                                 goto out;
     569                 :            : 
     570                 :            :                         if (!xsk_ring_prod__reserve(&txq->tx, 1, &idx_tx)) {
     571                 :          0 :                                 rte_pktmbuf_free(local_mbuf);
     572                 :          0 :                                 goto out;
     573                 :            :                         }
     574                 :            : 
     575                 :            :                         desc = xsk_ring_prod__tx_desc(&txq->tx, idx_tx);
     576                 :          0 :                         desc->len = mbuf->pkt_len;
     577                 :            : 
     578                 :          0 :                         addr = (uint64_t)local_mbuf - (uint64_t)umem->buffer -
     579                 :          0 :                                         umem->mb_pool->header_size;
     580                 :          0 :                         offset = rte_pktmbuf_mtod(local_mbuf, uint64_t) -
     581                 :            :                                         (uint64_t)local_mbuf +
     582                 :            :                                         umem->mb_pool->header_size;
     583         [ #  # ]:          0 :                         pkt = xsk_umem__get_data(umem->buffer, addr + offset);
     584                 :          0 :                         offset = offset << XSK_UNALIGNED_BUF_OFFSET_SHIFT;
     585                 :          0 :                         desc->addr = addr | offset;
     586         [ #  # ]:          0 :                         rte_memcpy(pkt, rte_pktmbuf_mtod(mbuf, void *),
     587                 :            :                                         desc->len);
     588                 :          0 :                         rte_pktmbuf_free(mbuf);
     589                 :          0 :                         count++;
     590                 :            :                 }
     591                 :            : 
     592                 :          0 :                 tx_bytes += mbuf->pkt_len;
     593                 :            :         }
     594                 :            : 
     595                 :          0 : out:
     596                 :          0 :         xsk_ring_prod__submit(&txq->tx, count);
     597                 :          0 :         kick_tx(txq, cq);
     598                 :            : 
     599                 :          0 :         txq->stats.tx_pkts += count;
     600                 :          0 :         txq->stats.tx_bytes += tx_bytes;
     601                 :          0 :         txq->stats.tx_dropped += nb_pkts - count;
     602                 :            : 
     603                 :          0 :         return count;
     604                 :            : }
     605                 :            : #else
     606                 :            : static uint16_t
     607                 :            : af_xdp_tx_cp(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     608                 :            : {
     609                 :            :         struct pkt_tx_queue *txq = queue;
     610                 :            :         struct xsk_umem_info *umem = txq->umem;
     611                 :            :         struct rte_mbuf *mbuf;
     612                 :            :         void *addrs[ETH_AF_XDP_TX_BATCH_SIZE];
     613                 :            :         unsigned long tx_bytes = 0;
     614                 :            :         int i;
     615                 :            :         uint32_t idx_tx;
     616                 :            :         struct xsk_ring_cons *cq = &txq->pair->cq;
     617                 :            : 
     618                 :            :         pull_umem_cq(umem, nb_pkts, cq);
     619                 :            : 
     620                 :            :         nb_pkts = rte_ring_dequeue_bulk(umem->buf_ring, addrs,
     621                 :            :                                         nb_pkts, NULL);
     622                 :            :         if (nb_pkts == 0)
     623                 :            :                 return 0;
     624                 :            : 
     625                 :            :         if (xsk_ring_prod__reserve(&txq->tx, nb_pkts, &idx_tx) != nb_pkts) {
     626                 :            :                 kick_tx(txq, cq);
     627                 :            :                 rte_ring_enqueue_bulk(umem->buf_ring, addrs, nb_pkts, NULL);
     628                 :            :                 return 0;
     629                 :            :         }
     630                 :            : 
     631                 :            :         for (i = 0; i < nb_pkts; i++) {
     632                 :            :                 struct xdp_desc *desc;
     633                 :            :                 void *pkt;
     634                 :            : 
     635                 :            :                 desc = xsk_ring_prod__tx_desc(&txq->tx, idx_tx + i);
     636                 :            :                 mbuf = bufs[i];
     637                 :            :                 desc->len = mbuf->pkt_len;
     638                 :            : 
     639                 :            :                 desc->addr = (uint64_t)addrs[i];
     640                 :            :                 pkt = xsk_umem__get_data(umem->mz->addr,
     641                 :            :                                          desc->addr);
     642                 :            :                 rte_memcpy(pkt, rte_pktmbuf_mtod(mbuf, void *), desc->len);
     643                 :            :                 tx_bytes += mbuf->pkt_len;
     644                 :            :                 rte_pktmbuf_free(mbuf);
     645                 :            :         }
     646                 :            : 
     647                 :            :         xsk_ring_prod__submit(&txq->tx, nb_pkts);
     648                 :            : 
     649                 :            :         kick_tx(txq, cq);
     650                 :            : 
     651                 :            :         txq->stats.tx_pkts += nb_pkts;
     652                 :            :         txq->stats.tx_bytes += tx_bytes;
     653                 :            : 
     654                 :            :         return nb_pkts;
     655                 :            : }
     656                 :            : 
     657                 :            : static uint16_t
     658                 :            : af_xdp_tx_cp_batch(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     659                 :            : {
     660                 :            :         uint16_t nb_tx;
     661                 :            : 
     662                 :            :         if (likely(nb_pkts <= ETH_AF_XDP_TX_BATCH_SIZE))
     663                 :            :                 return af_xdp_tx_cp(queue, bufs, nb_pkts);
     664                 :            : 
     665                 :            :         nb_tx = 0;
     666                 :            :         while (nb_pkts) {
     667                 :            :                 uint16_t ret, n;
     668                 :            : 
     669                 :            :                 /* Split larger batch into smaller batches of size
     670                 :            :                  * ETH_AF_XDP_TX_BATCH_SIZE or less.
     671                 :            :                  */
     672                 :            :                 n = (uint16_t)RTE_MIN(nb_pkts, ETH_AF_XDP_TX_BATCH_SIZE);
     673                 :            :                 ret = af_xdp_tx_cp(queue, &bufs[nb_tx], n);
     674                 :            :                 nb_tx = (uint16_t)(nb_tx + ret);
     675                 :            :                 nb_pkts = (uint16_t)(nb_pkts - ret);
     676                 :            :                 if (ret < n)
     677                 :            :                         break;
     678                 :            :         }
     679                 :            : 
     680                 :            :         return nb_tx;
     681                 :            : }
     682                 :            : #endif
     683                 :            : 
     684                 :            : static uint16_t
     685                 :          0 : eth_af_xdp_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
     686                 :            : {
     687                 :            : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
     688                 :          0 :         return af_xdp_tx_zc(queue, bufs, nb_pkts);
     689                 :            : #else
     690                 :            :         return af_xdp_tx_cp_batch(queue, bufs, nb_pkts);
     691                 :            : #endif
     692                 :            : }
     693                 :            : 
     694                 :            : static int
     695                 :          0 : eth_dev_start(struct rte_eth_dev *dev)
     696                 :            : {
     697                 :            :         uint16_t i;
     698                 :            : 
     699                 :          0 :         dev->data->dev_link.link_status = RTE_ETH_LINK_UP;
     700         [ #  # ]:          0 :         for (i = 0; i < dev->data->nb_rx_queues; i++) {
     701                 :          0 :                 dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
     702                 :          0 :                 dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STARTED;
     703                 :            :         }
     704                 :            : 
     705                 :          0 :         return 0;
     706                 :            : }
     707                 :            : 
     708                 :            : /* This function gets called when the current port gets stopped. */
     709                 :            : static int
     710                 :          0 : eth_dev_stop(struct rte_eth_dev *dev)
     711                 :            : {
     712                 :            :         uint16_t i;
     713                 :            : 
     714                 :          0 :         dev->data->dev_link.link_status = RTE_ETH_LINK_DOWN;
     715         [ #  # ]:          0 :         for (i = 0; i < dev->data->nb_rx_queues; i++) {
     716                 :          0 :                 dev->data->rx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
     717                 :          0 :                 dev->data->tx_queue_state[i] = RTE_ETH_QUEUE_STATE_STOPPED;
     718                 :            :         }
     719                 :            : 
     720                 :          0 :         return 0;
     721                 :            : }
     722                 :            : 
     723                 :            : /* Find ethdev in list */
     724                 :            : static inline struct internal_list *
     725                 :          0 : find_internal_resource(struct pmd_internals *port_int)
     726                 :            : {
     727                 :            :         int found = 0;
     728                 :            :         struct internal_list *list = NULL;
     729                 :            : 
     730         [ #  # ]:          0 :         if (port_int == NULL)
     731                 :            :                 return NULL;
     732                 :            : 
     733                 :          0 :         pthread_mutex_lock(&internal_list_lock);
     734                 :            : 
     735         [ #  # ]:          0 :         TAILQ_FOREACH(list, &internal_list, next) {
     736                 :          0 :                 struct pmd_internals *list_int =
     737                 :          0 :                                 list->eth_dev->data->dev_private;
     738         [ #  # ]:          0 :                 if (list_int == port_int) {
     739                 :            :                         found = 1;
     740                 :            :                         break;
     741                 :            :                 }
     742                 :            :         }
     743                 :            : 
     744                 :          0 :         pthread_mutex_unlock(&internal_list_lock);
     745                 :            : 
     746         [ #  # ]:          0 :         if (!found)
     747                 :          0 :                 return NULL;
     748                 :            : 
     749                 :            :         return list;
     750                 :            : }
     751                 :            : 
     752                 :            : static int
     753                 :          0 : eth_dev_configure(struct rte_eth_dev *dev)
     754                 :            : {
     755                 :          0 :         struct pmd_internals *internal = dev->data->dev_private;
     756                 :            : 
     757                 :            :         /* rx/tx must be paired */
     758         [ #  # ]:          0 :         if (dev->data->nb_rx_queues != dev->data->nb_tx_queues)
     759                 :            :                 return -EINVAL;
     760                 :            : 
     761         [ #  # ]:          0 :         if (internal->shared_umem) {
     762                 :            :                 struct internal_list *list = NULL;
     763                 :          0 :                 const char *name = dev->device->name;
     764                 :            : 
     765                 :            :                 /* Ensure PMD is not already inserted into the list */
     766                 :          0 :                 list = find_internal_resource(internal);
     767         [ #  # ]:          0 :                 if (list)
     768                 :            :                         return 0;
     769                 :            : 
     770                 :          0 :                 list = rte_zmalloc_socket(name, sizeof(*list), 0,
     771                 :          0 :                                         dev->device->numa_node);
     772         [ #  # ]:          0 :                 if (list == NULL)
     773                 :            :                         return -1;
     774                 :            : 
     775                 :          0 :                 list->eth_dev = dev;
     776                 :          0 :                 pthread_mutex_lock(&internal_list_lock);
     777                 :          0 :                 TAILQ_INSERT_TAIL(&internal_list, list, next);
     778                 :          0 :                 pthread_mutex_unlock(&internal_list_lock);
     779                 :            :         }
     780                 :            : 
     781                 :            :         return 0;
     782                 :            : }
     783                 :            : 
     784                 :            : #define CLB_VAL_IDX 0
     785                 :            : static int
     786                 :          0 : eth_monitor_callback(const uint64_t value,
     787                 :            :                 const uint64_t opaque[RTE_POWER_MONITOR_OPAQUE_SZ])
     788                 :            : {
     789                 :          0 :         const uint64_t v = opaque[CLB_VAL_IDX];
     790                 :            :         const uint64_t m = (uint32_t)~0;
     791                 :            : 
     792                 :            :         /* if the value has changed, abort entering power optimized state */
     793         [ #  # ]:          0 :         return (value & m) == v ? 0 : -1;
     794                 :            : }
     795                 :            : 
     796                 :            : static int
     797                 :          0 : eth_get_monitor_addr(void *rx_queue, struct rte_power_monitor_cond *pmc)
     798                 :            : {
     799                 :            :         struct pkt_rx_queue *rxq = rx_queue;
     800                 :          0 :         unsigned int *prod = rxq->rx.producer;
     801                 :          0 :         const uint32_t cur_val = rxq->rx.cached_prod; /* use cached value */
     802                 :            : 
     803                 :            :         /* watch for changes in producer ring */
     804                 :          0 :         pmc->addr = (void *)prod;
     805                 :            : 
     806                 :            :         /* store current value */
     807                 :          0 :         pmc->opaque[CLB_VAL_IDX] = cur_val;
     808                 :          0 :         pmc->fn = eth_monitor_callback;
     809                 :            : 
     810                 :            :         /* AF_XDP producer ring index is 32-bit */
     811                 :          0 :         pmc->size = sizeof(uint32_t);
     812                 :            : 
     813                 :          0 :         return 0;
     814                 :            : }
     815                 :            : 
     816                 :            : static int
     817                 :          0 : eth_dev_info(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
     818                 :            : {
     819                 :          0 :         struct pmd_internals *internals = dev->data->dev_private;
     820                 :            : 
     821                 :          0 :         dev_info->if_index = internals->if_index;
     822                 :          0 :         dev_info->max_mac_addrs = 1;
     823                 :          0 :         dev_info->max_rx_queues = internals->queue_cnt;
     824                 :          0 :         dev_info->max_tx_queues = internals->queue_cnt;
     825                 :            : 
     826                 :          0 :         dev_info->min_mtu = RTE_ETHER_MIN_MTU;
     827                 :            : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
     828                 :          0 :         dev_info->max_rx_pktlen = getpagesize() -
     829                 :            :                                   sizeof(struct rte_mempool_objhdr) -
     830                 :            :                                   sizeof(struct rte_mbuf) -
     831                 :          0 :                                   RTE_PKTMBUF_HEADROOM - XDP_PACKET_HEADROOM;
     832                 :            : #else
     833                 :            :         dev_info->max_rx_pktlen = ETH_AF_XDP_FRAME_SIZE - XDP_PACKET_HEADROOM;
     834                 :            : #endif
     835                 :          0 :         dev_info->max_mtu = dev_info->max_rx_pktlen - ETH_AF_XDP_ETH_OVERHEAD;
     836                 :            : 
     837                 :          0 :         dev_info->default_rxportconf.burst_size = ETH_AF_XDP_DFLT_BUSY_BUDGET;
     838                 :          0 :         dev_info->default_txportconf.burst_size = ETH_AF_XDP_DFLT_BUSY_BUDGET;
     839                 :          0 :         dev_info->default_rxportconf.nb_queues = 1;
     840                 :          0 :         dev_info->default_txportconf.nb_queues = 1;
     841                 :          0 :         dev_info->default_rxportconf.ring_size = ETH_AF_XDP_DFLT_NUM_DESCS;
     842                 :          0 :         dev_info->default_txportconf.ring_size = ETH_AF_XDP_DFLT_NUM_DESCS;
     843                 :            : 
     844                 :          0 :         return 0;
     845                 :            : }
     846                 :            : 
     847                 :            : static int
     848                 :          0 : eth_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
     849                 :            : {
     850                 :          0 :         struct pmd_internals *internals = dev->data->dev_private;
     851                 :          0 :         struct pmd_process_private *process_private = dev->process_private;
     852                 :            :         struct xdp_statistics xdp_stats;
     853                 :            :         struct pkt_rx_queue *rxq;
     854                 :            :         struct pkt_tx_queue *txq;
     855                 :            :         socklen_t optlen;
     856                 :            :         int i, ret, fd;
     857                 :            : 
     858         [ #  # ]:          0 :         for (i = 0; i < dev->data->nb_rx_queues; i++) {
     859                 :          0 :                 optlen = sizeof(struct xdp_statistics);
     860                 :          0 :                 rxq = &internals->rx_queues[i];
     861                 :          0 :                 txq = rxq->pair;
     862                 :          0 :                 stats->q_ipackets[i] = rxq->stats.rx_pkts;
     863                 :          0 :                 stats->q_ibytes[i] = rxq->stats.rx_bytes;
     864                 :            : 
     865                 :          0 :                 stats->q_opackets[i] = txq->stats.tx_pkts;
     866                 :          0 :                 stats->q_obytes[i] = txq->stats.tx_bytes;
     867                 :            : 
     868                 :          0 :                 stats->ipackets += stats->q_ipackets[i];
     869                 :          0 :                 stats->ibytes += stats->q_ibytes[i];
     870                 :          0 :                 stats->imissed += rxq->stats.rx_dropped;
     871                 :          0 :                 stats->oerrors += txq->stats.tx_dropped;
     872                 :          0 :                 fd = process_private->rxq_xsk_fds[i];
     873                 :          0 :                 ret = fd >= 0 ? getsockopt(fd, SOL_XDP, XDP_STATISTICS,
     874         [ #  # ]:          0 :                                            &xdp_stats, &optlen) : -1;
     875         [ #  # ]:          0 :                 if (ret != 0) {
     876                 :          0 :                         AF_XDP_LOG(ERR, "getsockopt() failed for XDP_STATISTICS.\n");
     877                 :          0 :                         return -1;
     878                 :            :                 }
     879                 :          0 :                 stats->imissed += xdp_stats.rx_dropped;
     880                 :            : 
     881                 :          0 :                 stats->opackets += stats->q_opackets[i];
     882                 :          0 :                 stats->obytes += stats->q_obytes[i];
     883                 :            :         }
     884                 :            : 
     885                 :            :         return 0;
     886                 :            : }
     887                 :            : 
     888                 :            : static int
     889                 :          0 : eth_stats_reset(struct rte_eth_dev *dev)
     890                 :            : {
     891                 :          0 :         struct pmd_internals *internals = dev->data->dev_private;
     892                 :            :         int i;
     893                 :            : 
     894         [ #  # ]:          0 :         for (i = 0; i < internals->queue_cnt; i++) {
     895                 :          0 :                 memset(&internals->rx_queues[i].stats, 0,
     896                 :            :                                         sizeof(struct rx_stats));
     897                 :          0 :                 memset(&internals->tx_queues[i].stats, 0,
     898                 :            :                                         sizeof(struct tx_stats));
     899                 :            :         }
     900                 :            : 
     901                 :          0 :         return 0;
     902                 :            : }
     903                 :            : 
     904                 :            : #ifdef RTE_NET_AF_XDP_LIBBPF_XDP_ATTACH
     905                 :            : 
     906                 :            : static int link_xdp_prog_with_dev(int ifindex, int fd, __u32 flags)
     907                 :            : {
     908                 :            :         return bpf_xdp_attach(ifindex, fd, flags, NULL);
     909                 :            : }
     910                 :            : 
     911                 :            : static int
     912                 :            : remove_xdp_program(struct pmd_internals *internals)
     913                 :            : {
     914                 :            :         uint32_t curr_prog_id = 0;
     915                 :            :         int ret;
     916                 :            : 
     917                 :            :         ret = bpf_xdp_query_id(internals->if_index, XDP_FLAGS_UPDATE_IF_NOEXIST,
     918                 :            :                                &curr_prog_id);
     919                 :            :         if (ret != 0) {
     920                 :            :                 AF_XDP_LOG(ERR, "bpf_xdp_query_id failed\n");
     921                 :            :                 return ret;
     922                 :            :         }
     923                 :            : 
     924                 :            :         ret = bpf_xdp_detach(internals->if_index, XDP_FLAGS_UPDATE_IF_NOEXIST,
     925                 :            :                              NULL);
     926                 :            :         if (ret != 0)
     927                 :            :                 AF_XDP_LOG(ERR, "bpf_xdp_detach failed\n");
     928                 :            :         return ret;
     929                 :            : }
     930                 :            : 
     931                 :            : #else
     932                 :            : 
     933                 :            : static int link_xdp_prog_with_dev(int ifindex, int fd, __u32 flags)
     934                 :            : {
     935                 :          0 :         return bpf_set_link_xdp_fd(ifindex, fd, flags);
     936                 :            : }
     937                 :            : 
     938                 :            : static int
     939                 :          0 : remove_xdp_program(struct pmd_internals *internals)
     940                 :            : {
     941                 :          0 :         uint32_t curr_prog_id = 0;
     942                 :            :         int ret;
     943                 :            : 
     944                 :          0 :         ret = bpf_get_link_xdp_id(internals->if_index, &curr_prog_id,
     945                 :            :                                   XDP_FLAGS_UPDATE_IF_NOEXIST);
     946         [ #  # ]:          0 :         if (ret != 0) {
     947                 :          0 :                 AF_XDP_LOG(ERR, "bpf_get_link_xdp_id failed\n");
     948                 :          0 :                 return ret;
     949                 :            :         }
     950                 :            : 
     951                 :          0 :         ret = bpf_set_link_xdp_fd(internals->if_index, -1,
     952                 :            :                                   XDP_FLAGS_UPDATE_IF_NOEXIST);
     953         [ #  # ]:          0 :         if (ret != 0)
     954                 :          0 :                 AF_XDP_LOG(ERR, "bpf_set_link_xdp_fd failed\n");
     955                 :            :         return ret;
     956                 :            : }
     957                 :            : 
     958                 :            : #endif
     959                 :            : 
     960                 :            : static void
     961                 :            : xdp_umem_destroy(struct xsk_umem_info *umem)
     962                 :            : {
     963                 :            : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
     964                 :          0 :         umem->mb_pool = NULL;
     965                 :            : #else
     966                 :            :         rte_memzone_free(umem->mz);
     967                 :            :         umem->mz = NULL;
     968                 :            : 
     969                 :            :         rte_ring_free(umem->buf_ring);
     970                 :            :         umem->buf_ring = NULL;
     971                 :            : #endif
     972                 :            : 
     973                 :          0 :         rte_free(umem);
     974                 :          0 : }
     975                 :            : 
     976                 :            : static int
     977                 :          0 : eth_dev_close(struct rte_eth_dev *dev)
     978                 :            : {
     979                 :          0 :         struct pmd_internals *internals = dev->data->dev_private;
     980                 :            :         struct pkt_rx_queue *rxq;
     981                 :            :         int i;
     982                 :            : 
     983         [ #  # ]:          0 :         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
     984                 :          0 :                 goto out;
     985                 :            : 
     986                 :          0 :         AF_XDP_LOG(INFO, "Closing AF_XDP ethdev on numa socket %u\n",
     987                 :            :                 rte_socket_id());
     988                 :            : 
     989         [ #  # ]:          0 :         for (i = 0; i < internals->queue_cnt; i++) {
     990                 :          0 :                 rxq = &internals->rx_queues[i];
     991         [ #  # ]:          0 :                 if (rxq->umem == NULL)
     992                 :            :                         break;
     993                 :          0 :                 xsk_socket__delete(rxq->xsk);
     994                 :            : 
     995         [ #  # ]:          0 :                 if (__atomic_fetch_sub(&rxq->umem->refcnt, 1, __ATOMIC_ACQUIRE) - 1
     996                 :            :                                 == 0) {
     997                 :          0 :                         (void)xsk_umem__delete(rxq->umem->umem);
     998                 :          0 :                         xdp_umem_destroy(rxq->umem);
     999                 :            :                 }
    1000                 :            : 
    1001                 :            :                 /* free pkt_tx_queue */
    1002                 :          0 :                 rte_free(rxq->pair);
    1003                 :          0 :                 rte_free(rxq);
    1004                 :            :         }
    1005                 :            : 
    1006                 :            :         /*
    1007                 :            :          * MAC is not allocated dynamically, setting it to NULL would prevent
    1008                 :            :          * from releasing it in rte_eth_dev_release_port.
    1009                 :            :          */
    1010                 :          0 :         dev->data->mac_addrs = NULL;
    1011                 :            : 
    1012         [ #  # ]:          0 :         if (remove_xdp_program(internals) != 0)
    1013                 :          0 :                 AF_XDP_LOG(ERR, "Error while removing XDP program.\n");
    1014                 :            : 
    1015         [ #  # ]:          0 :         if (internals->shared_umem) {
    1016                 :            :                 struct internal_list *list;
    1017                 :            : 
    1018                 :            :                 /* Remove ethdev from list used to track and share UMEMs */
    1019                 :          0 :                 list = find_internal_resource(internals);
    1020         [ #  # ]:          0 :                 if (list) {
    1021                 :          0 :                         pthread_mutex_lock(&internal_list_lock);
    1022         [ #  # ]:          0 :                         TAILQ_REMOVE(&internal_list, list, next);
    1023                 :          0 :                         pthread_mutex_unlock(&internal_list_lock);
    1024                 :          0 :                         rte_free(list);
    1025                 :            :                 }
    1026                 :            :         }
    1027                 :            : 
    1028                 :          0 : out:
    1029                 :          0 :         rte_free(dev->process_private);
    1030                 :            : 
    1031                 :          0 :         return 0;
    1032                 :            : }
    1033                 :            : 
    1034                 :            : static int
    1035                 :          0 : eth_link_update(struct rte_eth_dev *dev __rte_unused,
    1036                 :            :                 int wait_to_complete __rte_unused)
    1037                 :            : {
    1038                 :          0 :         return 0;
    1039                 :            : }
    1040                 :            : 
    1041                 :            : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
    1042                 :            : static inline uintptr_t get_base_addr(struct rte_mempool *mp, uint64_t *align)
    1043                 :            : {
    1044                 :            :         struct rte_mempool_memhdr *memhdr;
    1045                 :            :         uintptr_t memhdr_addr, aligned_addr;
    1046                 :            : 
    1047                 :          0 :         memhdr = STAILQ_FIRST(&mp->mem_list);
    1048                 :          0 :         memhdr_addr = (uintptr_t)memhdr->addr;
    1049                 :          0 :         aligned_addr = memhdr_addr & ~(getpagesize() - 1);
    1050                 :          0 :         *align = memhdr_addr - aligned_addr;
    1051                 :            : 
    1052                 :            :         return aligned_addr;
    1053                 :            : }
    1054                 :            : 
    1055                 :            : /* Check if the netdev,qid context already exists */
    1056                 :            : static inline bool
    1057                 :          0 : ctx_exists(struct pkt_rx_queue *rxq, const char *ifname,
    1058                 :            :                 struct pkt_rx_queue *list_rxq, const char *list_ifname)
    1059                 :            : {
    1060                 :            :         bool exists = false;
    1061                 :            : 
    1062         [ #  # ]:          0 :         if (rxq->xsk_queue_idx == list_rxq->xsk_queue_idx &&
    1063         [ #  # ]:          0 :                         !strncmp(ifname, list_ifname, IFNAMSIZ)) {
    1064                 :          0 :                 AF_XDP_LOG(ERR, "ctx %s,%i already exists, cannot share umem\n",
    1065                 :            :                                         ifname, rxq->xsk_queue_idx);
    1066                 :            :                 exists = true;
    1067                 :            :         }
    1068                 :            : 
    1069                 :          0 :         return exists;
    1070                 :            : }
    1071                 :            : 
    1072                 :            : /* Get a pointer to an existing UMEM which overlays the rxq's mb_pool */
    1073                 :            : static inline int
    1074                 :          0 : get_shared_umem(struct pkt_rx_queue *rxq, const char *ifname,
    1075                 :            :                         struct xsk_umem_info **umem)
    1076                 :            : {
    1077                 :            :         struct internal_list *list;
    1078                 :            :         struct pmd_internals *internals;
    1079                 :            :         int i = 0, ret = 0;
    1080                 :          0 :         struct rte_mempool *mb_pool = rxq->mb_pool;
    1081                 :            : 
    1082         [ #  # ]:          0 :         if (mb_pool == NULL)
    1083                 :            :                 return ret;
    1084                 :            : 
    1085                 :          0 :         pthread_mutex_lock(&internal_list_lock);
    1086                 :            : 
    1087         [ #  # ]:          0 :         TAILQ_FOREACH(list, &internal_list, next) {
    1088                 :          0 :                 internals = list->eth_dev->data->dev_private;
    1089         [ #  # ]:          0 :                 for (i = 0; i < internals->queue_cnt; i++) {
    1090                 :          0 :                         struct pkt_rx_queue *list_rxq =
    1091                 :          0 :                                                 &internals->rx_queues[i];
    1092         [ #  # ]:          0 :                         if (rxq == list_rxq)
    1093                 :          0 :                                 continue;
    1094         [ #  # ]:          0 :                         if (mb_pool == internals->rx_queues[i].mb_pool) {
    1095         [ #  # ]:          0 :                                 if (ctx_exists(rxq, ifname, list_rxq,
    1096                 :          0 :                                                 internals->if_name)) {
    1097                 :            :                                         ret = -1;
    1098                 :          0 :                                         goto out;
    1099                 :            :                                 }
    1100         [ #  # ]:          0 :                                 if (__atomic_load_n(&internals->rx_queues[i].umem->refcnt,
    1101                 :            :                                                     __ATOMIC_ACQUIRE)) {
    1102                 :          0 :                                         *umem = internals->rx_queues[i].umem;
    1103                 :          0 :                                         goto out;
    1104                 :            :                                 }
    1105                 :            :                         }
    1106                 :            :                 }
    1107                 :            :         }
    1108                 :            : 
    1109                 :          0 : out:
    1110                 :          0 :         pthread_mutex_unlock(&internal_list_lock);
    1111                 :            : 
    1112                 :          0 :         return ret;
    1113                 :            : }
    1114                 :            : 
    1115                 :            : static struct
    1116                 :          0 : xsk_umem_info *xdp_umem_configure(struct pmd_internals *internals,
    1117                 :            :                                   struct pkt_rx_queue *rxq)
    1118                 :            : {
    1119                 :          0 :         struct xsk_umem_info *umem = NULL;
    1120                 :            :         int ret;
    1121                 :          0 :         struct xsk_umem_config usr_config = {
    1122                 :            :                 .fill_size = ETH_AF_XDP_DFLT_NUM_DESCS * 2,
    1123                 :            :                 .comp_size = ETH_AF_XDP_DFLT_NUM_DESCS,
    1124                 :            :                 .flags = XDP_UMEM_UNALIGNED_CHUNK_FLAG};
    1125                 :            :         void *base_addr = NULL;
    1126                 :          0 :         struct rte_mempool *mb_pool = rxq->mb_pool;
    1127                 :            :         uint64_t umem_size, align = 0;
    1128                 :            : 
    1129         [ #  # ]:          0 :         if (internals->shared_umem) {
    1130         [ #  # ]:          0 :                 if (get_shared_umem(rxq, internals->if_name, &umem) < 0)
    1131                 :            :                         return NULL;
    1132                 :            : 
    1133         [ #  # ]:          0 :                 if (umem != NULL &&
    1134                 :          0 :                         __atomic_load_n(&umem->refcnt, __ATOMIC_ACQUIRE) <
    1135         [ #  # ]:          0 :                                         umem->max_xsks) {
    1136                 :          0 :                         AF_XDP_LOG(INFO, "%s,qid%i sharing UMEM\n",
    1137                 :            :                                         internals->if_name, rxq->xsk_queue_idx);
    1138                 :          0 :                         __atomic_fetch_add(&umem->refcnt, 1, __ATOMIC_ACQUIRE);
    1139                 :            :                 }
    1140                 :            :         }
    1141                 :            : 
    1142         [ #  # ]:          0 :         if (umem == NULL) {
    1143                 :          0 :                 usr_config.frame_size =
    1144                 :          0 :                         rte_mempool_calc_obj_size(mb_pool->elt_size,
    1145                 :            :                                                   mb_pool->flags, NULL);
    1146         [ #  # ]:          0 :                 usr_config.frame_headroom = mb_pool->header_size +
    1147                 :          0 :                                                 sizeof(struct rte_mbuf) +
    1148                 :          0 :                                                 rte_pktmbuf_priv_size(mb_pool) +
    1149                 :            :                                                 RTE_PKTMBUF_HEADROOM;
    1150                 :            : 
    1151                 :          0 :                 umem = rte_zmalloc_socket("umem", sizeof(*umem), 0,
    1152                 :          0 :                                           rte_socket_id());
    1153         [ #  # ]:          0 :                 if (umem == NULL) {
    1154                 :          0 :                         AF_XDP_LOG(ERR, "Failed to allocate umem info\n");
    1155                 :          0 :                         return NULL;
    1156                 :            :                 }
    1157                 :            : 
    1158                 :          0 :                 umem->mb_pool = mb_pool;
    1159                 :          0 :                 base_addr = (void *)get_base_addr(mb_pool, &align);
    1160                 :          0 :                 umem_size = (uint64_t)mb_pool->populated_size *
    1161                 :          0 :                                 (uint64_t)usr_config.frame_size +
    1162                 :            :                                 align;
    1163                 :            : 
    1164                 :          0 :                 ret = xsk_umem__create(&umem->umem, base_addr, umem_size,
    1165                 :            :                                 &rxq->fq, &rxq->cq, &usr_config);
    1166         [ #  # ]:          0 :                 if (ret) {
    1167                 :          0 :                         AF_XDP_LOG(ERR, "Failed to create umem [%d]: [%s]\n",
    1168                 :            :                                    errno, strerror(errno));
    1169                 :          0 :                         goto err;
    1170                 :            :                 }
    1171                 :          0 :                 umem->buffer = base_addr;
    1172                 :            : 
    1173         [ #  # ]:          0 :                 if (internals->shared_umem) {
    1174                 :          0 :                         umem->max_xsks = mb_pool->populated_size /
    1175                 :            :                                                 ETH_AF_XDP_NUM_BUFFERS;
    1176                 :          0 :                         AF_XDP_LOG(INFO, "Max xsks for UMEM %s: %u\n",
    1177                 :            :                                                 mb_pool->name, umem->max_xsks);
    1178                 :            :                 }
    1179                 :            : 
    1180                 :          0 :                 __atomic_store_n(&umem->refcnt, 1, __ATOMIC_RELEASE);
    1181                 :            :         }
    1182                 :            : 
    1183                 :          0 :         return umem;
    1184                 :            : 
    1185                 :            : err:
    1186                 :            :         xdp_umem_destroy(umem);
    1187                 :          0 :         return NULL;
    1188                 :            : }
    1189                 :            : #else
    1190                 :            : static struct
    1191                 :            : xsk_umem_info *xdp_umem_configure(struct pmd_internals *internals,
    1192                 :            :                                   struct pkt_rx_queue *rxq)
    1193                 :            : {
    1194                 :            :         struct xsk_umem_info *umem;
    1195                 :            :         const struct rte_memzone *mz;
    1196                 :            :         struct xsk_umem_config usr_config = {
    1197                 :            :                 .fill_size = ETH_AF_XDP_DFLT_NUM_DESCS,
    1198                 :            :                 .comp_size = ETH_AF_XDP_DFLT_NUM_DESCS,
    1199                 :            :                 .frame_size = ETH_AF_XDP_FRAME_SIZE,
    1200                 :            :                 .frame_headroom = 0 };
    1201                 :            :         char ring_name[RTE_RING_NAMESIZE];
    1202                 :            :         char mz_name[RTE_MEMZONE_NAMESIZE];
    1203                 :            :         int ret;
    1204                 :            :         uint64_t i;
    1205                 :            : 
    1206                 :            :         umem = rte_zmalloc_socket("umem", sizeof(*umem), 0, rte_socket_id());
    1207                 :            :         if (umem == NULL) {
    1208                 :            :                 AF_XDP_LOG(ERR, "Failed to allocate umem info\n");
    1209                 :            :                 return NULL;
    1210                 :            :         }
    1211                 :            : 
    1212                 :            :         snprintf(ring_name, sizeof(ring_name), "af_xdp_ring_%s_%u",
    1213                 :            :                        internals->if_name, rxq->xsk_queue_idx);
    1214                 :            :         umem->buf_ring = rte_ring_create(ring_name,
    1215                 :            :                                          ETH_AF_XDP_NUM_BUFFERS,
    1216                 :            :                                          rte_socket_id(),
    1217                 :            :                                          0x0);
    1218                 :            :         if (umem->buf_ring == NULL) {
    1219                 :            :                 AF_XDP_LOG(ERR, "Failed to create rte_ring\n");
    1220                 :            :                 goto err;
    1221                 :            :         }
    1222                 :            : 
    1223                 :            :         for (i = 0; i < ETH_AF_XDP_NUM_BUFFERS; i++)
    1224                 :            :                 rte_ring_enqueue(umem->buf_ring,
    1225                 :            :                                  (void *)(i * ETH_AF_XDP_FRAME_SIZE));
    1226                 :            : 
    1227                 :            :         snprintf(mz_name, sizeof(mz_name), "af_xdp_umem_%s_%u",
    1228                 :            :                        internals->if_name, rxq->xsk_queue_idx);
    1229                 :            :         mz = rte_memzone_reserve_aligned(mz_name,
    1230                 :            :                         ETH_AF_XDP_NUM_BUFFERS * ETH_AF_XDP_FRAME_SIZE,
    1231                 :            :                         rte_socket_id(), RTE_MEMZONE_IOVA_CONTIG,
    1232                 :            :                         getpagesize());
    1233                 :            :         if (mz == NULL) {
    1234                 :            :                 AF_XDP_LOG(ERR, "Failed to reserve memzone for af_xdp umem.\n");
    1235                 :            :                 goto err;
    1236                 :            :         }
    1237                 :            : 
    1238                 :            :         ret = xsk_umem__create(&umem->umem, mz->addr,
    1239                 :            :                                ETH_AF_XDP_NUM_BUFFERS * ETH_AF_XDP_FRAME_SIZE,
    1240                 :            :                                &rxq->fq, &rxq->cq,
    1241                 :            :                                &usr_config);
    1242                 :            : 
    1243                 :            :         if (ret) {
    1244                 :            :                 AF_XDP_LOG(ERR, "Failed to create umem\n");
    1245                 :            :                 goto err;
    1246                 :            :         }
    1247                 :            :         umem->mz = mz;
    1248                 :            : 
    1249                 :            :         return umem;
    1250                 :            : 
    1251                 :            : err:
    1252                 :            :         xdp_umem_destroy(umem);
    1253                 :            :         return NULL;
    1254                 :            : }
    1255                 :            : #endif
    1256                 :            : 
    1257                 :            : static int
    1258                 :          0 : load_custom_xdp_prog(const char *prog_path, int if_index, struct bpf_map **map)
    1259                 :            : {
    1260                 :            :         int ret, prog_fd;
    1261                 :            :         struct bpf_object *obj;
    1262                 :            : 
    1263                 :            :         prog_fd = load_program(prog_path, &obj);
    1264         [ #  # ]:          0 :         if (prog_fd < 0) {
    1265                 :          0 :                 AF_XDP_LOG(ERR, "Failed to load program %s\n", prog_path);
    1266                 :          0 :                 return -1;
    1267                 :            :         }
    1268                 :            : 
    1269                 :            :         /*
    1270                 :            :          * The loaded program must provision for a map of xsks, such that some
    1271                 :            :          * traffic can be redirected to userspace.
    1272                 :            :          */
    1273                 :          0 :         *map = bpf_object__find_map_by_name(obj, "xsks_map");
    1274         [ #  # ]:          0 :         if (!*map) {
    1275                 :          0 :                 AF_XDP_LOG(ERR, "Failed to find xsks_map in %s\n", prog_path);
    1276                 :          0 :                 return -1;
    1277                 :            :         }
    1278                 :            : 
    1279                 :            :         /* Link the program with the given network device */
    1280                 :            :         ret = link_xdp_prog_with_dev(if_index, prog_fd,
    1281                 :            :                                         XDP_FLAGS_UPDATE_IF_NOEXIST);
    1282         [ #  # ]:          0 :         if (ret) {
    1283                 :          0 :                 AF_XDP_LOG(ERR, "Failed to set prog fd %d on interface\n",
    1284                 :            :                                 prog_fd);
    1285                 :          0 :                 return -1;
    1286                 :            :         }
    1287                 :            : 
    1288                 :          0 :         AF_XDP_LOG(INFO, "Successfully loaded XDP program %s with fd %d\n",
    1289                 :            :                                 prog_path, prog_fd);
    1290                 :            : 
    1291                 :          0 :         return 0;
    1292                 :            : }
    1293                 :            : 
    1294                 :            : /* Detect support for busy polling through setsockopt(). */
    1295                 :            : static int
    1296                 :          0 : configure_preferred_busy_poll(struct pkt_rx_queue *rxq)
    1297                 :            : {
    1298                 :          0 :         int sock_opt = 1;
    1299                 :          0 :         int fd = xsk_socket__fd(rxq->xsk);
    1300                 :            :         int ret = 0;
    1301                 :            : 
    1302                 :          0 :         ret = setsockopt(fd, SOL_SOCKET, SO_PREFER_BUSY_POLL,
    1303                 :            :                         (void *)&sock_opt, sizeof(sock_opt));
    1304         [ #  # ]:          0 :         if (ret < 0) {
    1305                 :          0 :                 AF_XDP_LOG(DEBUG, "Failed to set SO_PREFER_BUSY_POLL\n");
    1306                 :          0 :                 goto err_prefer;
    1307                 :            :         }
    1308                 :            : 
    1309                 :          0 :         sock_opt = ETH_AF_XDP_DFLT_BUSY_TIMEOUT;
    1310                 :          0 :         ret = setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL, (void *)&sock_opt,
    1311                 :            :                         sizeof(sock_opt));
    1312         [ #  # ]:          0 :         if (ret < 0) {
    1313                 :          0 :                 AF_XDP_LOG(DEBUG, "Failed to set SO_BUSY_POLL\n");
    1314                 :          0 :                 goto err_timeout;
    1315                 :            :         }
    1316                 :            : 
    1317                 :          0 :         sock_opt = rxq->busy_budget;
    1318                 :          0 :         ret = setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL_BUDGET,
    1319                 :            :                         (void *)&sock_opt, sizeof(sock_opt));
    1320         [ #  # ]:          0 :         if (ret < 0) {
    1321                 :          0 :                 AF_XDP_LOG(DEBUG, "Failed to set SO_BUSY_POLL_BUDGET\n");
    1322                 :            :         } else {
    1323                 :          0 :                 AF_XDP_LOG(INFO, "Busy polling budget set to: %u\n",
    1324                 :            :                                         rxq->busy_budget);
    1325                 :          0 :                 return 0;
    1326                 :            :         }
    1327                 :            : 
    1328                 :            :         /* setsockopt failure - attempt to restore xsk to default state and
    1329                 :            :          * proceed without busy polling support.
    1330                 :            :          */
    1331                 :          0 :         sock_opt = 0;
    1332                 :          0 :         ret = setsockopt(fd, SOL_SOCKET, SO_BUSY_POLL, (void *)&sock_opt,
    1333                 :            :                         sizeof(sock_opt));
    1334         [ #  # ]:          0 :         if (ret < 0) {
    1335                 :          0 :                 AF_XDP_LOG(ERR, "Failed to unset SO_BUSY_POLL\n");
    1336                 :          0 :                 return -1;
    1337                 :            :         }
    1338                 :            : 
    1339                 :          0 : err_timeout:
    1340                 :          0 :         sock_opt = 0;
    1341                 :          0 :         ret = setsockopt(fd, SOL_SOCKET, SO_PREFER_BUSY_POLL,
    1342                 :            :                         (void *)&sock_opt, sizeof(sock_opt));
    1343         [ #  # ]:          0 :         if (ret < 0) {
    1344                 :          0 :                 AF_XDP_LOG(ERR, "Failed to unset SO_PREFER_BUSY_POLL\n");
    1345                 :          0 :                 return -1;
    1346                 :            :         }
    1347                 :            : 
    1348                 :          0 : err_prefer:
    1349                 :          0 :         rxq->busy_budget = 0;
    1350                 :          0 :         return 0;
    1351                 :            : }
    1352                 :            : 
    1353                 :            : static int
    1354                 :          0 : init_uds_sock(struct sockaddr_un *server)
    1355                 :            : {
    1356                 :            :         int sock;
    1357                 :            : 
    1358                 :          0 :         sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
    1359         [ #  # ]:          0 :         if (sock < 0) {
    1360                 :          0 :                 AF_XDP_LOG(ERR, "Failed to opening stream socket\n");
    1361                 :          0 :                 return -1;
    1362                 :            :         }
    1363                 :            : 
    1364                 :          0 :         server->sun_family = AF_UNIX;
    1365                 :          0 :         strlcpy(server->sun_path, UDS_SOCK, sizeof(server->sun_path));
    1366                 :            : 
    1367         [ #  # ]:          0 :         if (connect(sock, (struct sockaddr *)server, sizeof(struct sockaddr_un)) < 0) {
    1368                 :          0 :                 close(sock);
    1369                 :          0 :                 AF_XDP_LOG(ERR, "Error connecting stream socket errno = [%d]: [%s]\n",
    1370                 :            :                            errno, strerror(errno));
    1371                 :          0 :                 return -1;
    1372                 :            :         }
    1373                 :            : 
    1374                 :            :         return sock;
    1375                 :            : }
    1376                 :            : 
    1377                 :            : struct msg_internal {
    1378                 :            :         char response[UDS_MAX_CMD_RESP];
    1379                 :            :         int len_param;
    1380                 :            :         int num_fds;
    1381                 :            :         int fds[UDS_MAX_FD_NUM];
    1382                 :            : };
    1383                 :            : 
    1384                 :            : static int
    1385                 :          0 : send_msg(int sock, char *request, int *fd)
    1386                 :            : {
    1387                 :            :         int snd;
    1388                 :            :         struct iovec iov;
    1389                 :            :         struct msghdr msgh;
    1390                 :            :         struct cmsghdr *cmsg;
    1391                 :            :         struct sockaddr_un dst;
    1392                 :            :         char control[CMSG_SPACE(sizeof(*fd))];
    1393                 :            : 
    1394                 :            :         memset(&dst, 0, sizeof(dst));
    1395                 :          0 :         dst.sun_family = AF_UNIX;
    1396                 :            :         strlcpy(dst.sun_path, UDS_SOCK, sizeof(dst.sun_path));
    1397                 :            : 
    1398                 :            :         /* Initialize message header structure */
    1399                 :            :         memset(&msgh, 0, sizeof(msgh));
    1400                 :            :         memset(control, 0, sizeof(control));
    1401                 :          0 :         iov.iov_base = request;
    1402                 :          0 :         iov.iov_len = strlen(request);
    1403                 :            : 
    1404                 :          0 :         msgh.msg_name = &dst;
    1405                 :          0 :         msgh.msg_namelen = sizeof(dst);
    1406                 :          0 :         msgh.msg_iov = &iov;
    1407                 :          0 :         msgh.msg_iovlen = 1;
    1408                 :          0 :         msgh.msg_control = control;
    1409                 :          0 :         msgh.msg_controllen = sizeof(control);
    1410                 :            : 
    1411                 :            :         /* Translate the FD. */
    1412                 :            :         cmsg = CMSG_FIRSTHDR(&msgh);
    1413                 :          0 :         cmsg->cmsg_len = CMSG_LEN(sizeof(*fd));
    1414                 :          0 :         cmsg->cmsg_level = SOL_SOCKET;
    1415                 :          0 :         cmsg->cmsg_type = SCM_RIGHTS;
    1416                 :            :         memcpy(CMSG_DATA(cmsg), fd, sizeof(*fd));
    1417                 :            : 
    1418                 :            :         /* Send the request message. */
    1419                 :            :         do {
    1420                 :          0 :                 snd = sendmsg(sock, &msgh, 0);
    1421   [ #  #  #  # ]:          0 :         } while (snd < 0 && errno == EINTR);
    1422                 :            : 
    1423                 :          0 :         return snd;
    1424                 :            : }
    1425                 :            : 
    1426                 :            : static int
    1427                 :          0 : read_msg(int sock, char *response, struct sockaddr_un *s, int *fd)
    1428                 :            : {
    1429                 :            :         int msglen;
    1430                 :            :         struct msghdr msgh;
    1431                 :            :         struct iovec iov;
    1432                 :            :         char control[CMSG_SPACE(sizeof(*fd))];
    1433                 :            :         struct cmsghdr *cmsg;
    1434                 :            : 
    1435                 :            :         /* Initialize message header structure */
    1436                 :            :         memset(&msgh, 0, sizeof(msgh));
    1437                 :          0 :         iov.iov_base = response;
    1438                 :          0 :         iov.iov_len = UDS_MAX_CMD_RESP;
    1439                 :            : 
    1440                 :          0 :         msgh.msg_name = s;
    1441                 :          0 :         msgh.msg_namelen = sizeof(*s);
    1442                 :          0 :         msgh.msg_iov = &iov;
    1443                 :          0 :         msgh.msg_iovlen = 1;
    1444                 :          0 :         msgh.msg_control = control;
    1445                 :          0 :         msgh.msg_controllen = sizeof(control);
    1446                 :            : 
    1447                 :          0 :         msglen = recvmsg(sock, &msgh, 0);
    1448                 :            : 
    1449                 :            :         /* zero length message means socket was closed */
    1450         [ #  # ]:          0 :         if (msglen == 0)
    1451                 :            :                 return 0;
    1452                 :            : 
    1453         [ #  # ]:          0 :         if (msglen < 0) {
    1454                 :          0 :                 AF_XDP_LOG(ERR, "recvmsg failed, %s\n", strerror(errno));
    1455                 :          0 :                 return -1;
    1456                 :            :         }
    1457                 :            : 
    1458                 :            :         /* read auxiliary FDs if any */
    1459   [ #  #  #  # ]:          0 :         for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
    1460                 :            :                         cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
    1461         [ #  # ]:          0 :                 if (cmsg->cmsg_level == SOL_SOCKET &&
    1462                 :            :                                 cmsg->cmsg_type == SCM_RIGHTS) {
    1463                 :          0 :                         memcpy(fd, CMSG_DATA(cmsg), sizeof(*fd));
    1464                 :            :                         break;
    1465                 :            :                 }
    1466                 :            :         }
    1467                 :            : 
    1468                 :          0 :         response[msglen] = '\0';
    1469                 :          0 :         return msglen;
    1470                 :            : }
    1471                 :            : 
    1472                 :            : static int
    1473                 :          0 : make_request_cni(int sock, struct sockaddr_un *server, char *request,
    1474                 :            :                  int *req_fd, char *response, int *out_fd)
    1475                 :            : {
    1476                 :            :         int rval;
    1477                 :            : 
    1478                 :          0 :         AF_XDP_LOG(DEBUG, "Request: [%s]\n", request);
    1479                 :            : 
    1480                 :            :         /* if no file descriptor to send then directly write to socket.
    1481                 :            :          * else use sendmsg() to send the file descriptor.
    1482                 :            :          */
    1483         [ #  # ]:          0 :         if (req_fd == NULL)
    1484                 :          0 :                 rval = write(sock, request, strlen(request));
    1485                 :            :         else
    1486                 :          0 :                 rval = send_msg(sock, request, req_fd);
    1487                 :            : 
    1488         [ #  # ]:          0 :         if (rval < 0) {
    1489                 :          0 :                 AF_XDP_LOG(ERR, "Write error %s\n", strerror(errno));
    1490                 :          0 :                 return -1;
    1491                 :            :         }
    1492                 :            : 
    1493                 :          0 :         rval = read_msg(sock, response, server, out_fd);
    1494         [ #  # ]:          0 :         if (rval <= 0) {
    1495                 :          0 :                 AF_XDP_LOG(ERR, "Read error %d\n", rval);
    1496                 :          0 :                 return -1;
    1497                 :            :         }
    1498                 :          0 :         AF_XDP_LOG(DEBUG, "Response: [%s]\n", request);
    1499                 :            : 
    1500                 :          0 :         return 0;
    1501                 :            : }
    1502                 :            : 
    1503                 :            : static int
    1504                 :            : check_response(char *response, char *exp_resp, long size)
    1505                 :            : {
    1506                 :          0 :         return strncmp(response, exp_resp, size);
    1507                 :            : }
    1508                 :            : 
    1509                 :            : static int
    1510                 :          0 : get_cni_fd(char *if_name)
    1511                 :            : {
    1512                 :            :         char request[UDS_MAX_CMD_LEN], response[UDS_MAX_CMD_RESP];
    1513                 :            :         char hostname[MAX_LONG_OPT_SZ], exp_resp[UDS_MAX_CMD_RESP];
    1514                 :            :         struct sockaddr_un server;
    1515                 :          0 :         int xsk_map_fd = -1, out_fd = 0;
    1516                 :            :         int sock, err;
    1517                 :            : 
    1518                 :            :         err = gethostname(hostname, MAX_LONG_OPT_SZ - 1);
    1519         [ #  # ]:          0 :         if (err)
    1520                 :            :                 return -1;
    1521                 :            : 
    1522                 :            :         memset(&server, 0, sizeof(server));
    1523                 :          0 :         sock = init_uds_sock(&server);
    1524         [ #  # ]:          0 :         if (sock < 0)
    1525                 :            :                 return -1;
    1526                 :            : 
    1527                 :            :         /* Initiates handshake to CNI send: /connect,hostname */
    1528                 :            :         snprintf(request, sizeof(request), "%s,%s", UDS_CONNECT_MSG, hostname);
    1529                 :            :         memset(response, 0, sizeof(response));
    1530         [ #  # ]:          0 :         if (make_request_cni(sock, &server, request, NULL, response, &out_fd) < 0) {
    1531                 :          0 :                 AF_XDP_LOG(ERR, "Error in processing cmd [%s]\n", request);
    1532                 :          0 :                 goto err_close;
    1533                 :            :         }
    1534                 :            : 
    1535                 :            :         /* Expect /host_ok */
    1536                 :            :         strlcpy(exp_resp, UDS_HOST_OK_MSG, UDS_MAX_CMD_LEN);
    1537         [ #  # ]:          0 :         if (check_response(response, exp_resp, strlen(exp_resp)) < 0) {
    1538                 :          0 :                 AF_XDP_LOG(ERR, "Unexpected response [%s]\n", response);
    1539                 :          0 :                 goto err_close;
    1540                 :            :         }
    1541                 :            :         /* Request for "/version" */
    1542                 :            :         strlcpy(request, UDS_VERSION_MSG, UDS_MAX_CMD_LEN);
    1543                 :            :         memset(response, 0, sizeof(response));
    1544         [ #  # ]:          0 :         if (make_request_cni(sock, &server, request, NULL, response, &out_fd) < 0) {
    1545                 :          0 :                 AF_XDP_LOG(ERR, "Error in processing cmd [%s]\n", request);
    1546                 :          0 :                 goto err_close;
    1547                 :            :         }
    1548                 :            : 
    1549                 :            :         /* Request for file descriptor for netdev name*/
    1550                 :            :         snprintf(request, sizeof(request), "%s,%s", UDS_XSK_MAP_FD_MSG, if_name);
    1551                 :            :         memset(response, 0, sizeof(response));
    1552         [ #  # ]:          0 :         if (make_request_cni(sock, &server, request, NULL, response, &out_fd) < 0) {
    1553                 :          0 :                 AF_XDP_LOG(ERR, "Error in processing cmd [%s]\n", request);
    1554                 :          0 :                 goto err_close;
    1555                 :            :         }
    1556                 :            : 
    1557         [ #  # ]:          0 :         if (out_fd < 0) {
    1558                 :          0 :                 AF_XDP_LOG(ERR, "Error in processing cmd [%s]\n", request);
    1559                 :          0 :                 goto err_close;
    1560                 :            :         }
    1561                 :            : 
    1562                 :            :         xsk_map_fd = out_fd;
    1563                 :            : 
    1564                 :            :         /* Expect fd_ack with file descriptor */
    1565                 :            :         strlcpy(exp_resp, UDS_FD_ACK_MSG, UDS_MAX_CMD_LEN);
    1566         [ #  # ]:          0 :         if (check_response(response, exp_resp, strlen(exp_resp)) < 0) {
    1567                 :          0 :                 AF_XDP_LOG(ERR, "Unexpected response [%s]\n", response);
    1568                 :          0 :                 goto err_close;
    1569                 :            :         }
    1570                 :            : 
    1571                 :            :         /* Initiate close connection */
    1572                 :            :         strlcpy(request, UDS_FIN_MSG, UDS_MAX_CMD_LEN);
    1573                 :            :         memset(response, 0, sizeof(response));
    1574         [ #  # ]:          0 :         if (make_request_cni(sock, &server, request, NULL, response, &out_fd) < 0) {
    1575                 :          0 :                 AF_XDP_LOG(ERR, "Error in processing cmd [%s]\n", request);
    1576                 :          0 :                 goto err_close;
    1577                 :            :         }
    1578                 :            : 
    1579                 :            :         /* Connection close */
    1580                 :            :         strlcpy(exp_resp, UDS_FIN_ACK_MSG, UDS_MAX_CMD_LEN);
    1581         [ #  # ]:          0 :         if (check_response(response, exp_resp, strlen(exp_resp)) < 0) {
    1582                 :          0 :                 AF_XDP_LOG(ERR, "Unexpected response [%s]\n", response);
    1583                 :          0 :                 goto err_close;
    1584                 :            :         }
    1585                 :          0 :         close(sock);
    1586                 :            : 
    1587                 :          0 :         return xsk_map_fd;
    1588                 :            : 
    1589                 :          0 : err_close:
    1590                 :          0 :         close(sock);
    1591                 :          0 :         return -1;
    1592                 :            : }
    1593                 :            : 
    1594                 :            : static int
    1595                 :          0 : xsk_configure(struct pmd_internals *internals, struct pkt_rx_queue *rxq,
    1596                 :            :               int ring_size)
    1597                 :          0 : {
    1598                 :            :         struct xsk_socket_config cfg;
    1599                 :          0 :         struct pkt_tx_queue *txq = rxq->pair;
    1600                 :            :         int ret = 0;
    1601                 :            :         int reserve_size = ETH_AF_XDP_DFLT_NUM_DESCS;
    1602                 :          0 :         struct rte_mbuf *fq_bufs[reserve_size];
    1603                 :            :         bool reserve_before;
    1604                 :            : 
    1605                 :          0 :         rxq->umem = xdp_umem_configure(internals, rxq);
    1606         [ #  # ]:          0 :         if (rxq->umem == NULL)
    1607                 :            :                 return -ENOMEM;
    1608                 :          0 :         txq->umem = rxq->umem;
    1609                 :          0 :         reserve_before = __atomic_load_n(&rxq->umem->refcnt, __ATOMIC_ACQUIRE) <= 1;
    1610                 :            : 
    1611                 :            : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
    1612                 :          0 :         ret = rte_pktmbuf_alloc_bulk(rxq->umem->mb_pool, fq_bufs, reserve_size);
    1613         [ #  # ]:          0 :         if (ret) {
    1614                 :          0 :                 AF_XDP_LOG(DEBUG, "Failed to get enough buffers for fq.\n");
    1615                 :          0 :                 goto out_umem;
    1616                 :            :         }
    1617                 :            : #endif
    1618                 :            : 
    1619                 :            :         /* reserve fill queue of queues not (yet) sharing UMEM */
    1620         [ #  # ]:          0 :         if (reserve_before) {
    1621                 :          0 :                 ret = reserve_fill_queue(rxq->umem, reserve_size, fq_bufs, &rxq->fq);
    1622         [ #  # ]:          0 :                 if (ret) {
    1623                 :          0 :                         AF_XDP_LOG(ERR, "Failed to reserve fill queue.\n");
    1624                 :          0 :                         goto out_umem;
    1625                 :            :                 }
    1626                 :            :         }
    1627                 :            : 
    1628                 :          0 :         cfg.rx_size = ring_size;
    1629                 :          0 :         cfg.tx_size = ring_size;
    1630                 :          0 :         cfg.libbpf_flags = 0;
    1631                 :          0 :         cfg.xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
    1632                 :          0 :         cfg.bind_flags = 0;
    1633                 :            : 
    1634                 :            :         /* Force AF_XDP socket into copy mode when users want it */
    1635         [ #  # ]:          0 :         if (internals->force_copy)
    1636                 :          0 :                 cfg.bind_flags |= XDP_COPY;
    1637                 :            : 
    1638                 :            : #if defined(XDP_USE_NEED_WAKEUP)
    1639                 :          0 :         cfg.bind_flags |= XDP_USE_NEED_WAKEUP;
    1640                 :            : #endif
    1641                 :            : 
    1642                 :            :         /* Disable libbpf from loading XDP program */
    1643         [ #  # ]:          0 :         if (internals->use_cni)
    1644                 :          0 :                 cfg.libbpf_flags |= XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
    1645                 :            : 
    1646         [ #  # ]:          0 :         if (strnlen(internals->prog_path, PATH_MAX)) {
    1647         [ #  # ]:          0 :                 if (!internals->custom_prog_configured) {
    1648                 :          0 :                         ret = load_custom_xdp_prog(internals->prog_path,
    1649                 :            :                                                         internals->if_index,
    1650                 :            :                                                         &internals->map);
    1651         [ #  # ]:          0 :                         if (ret) {
    1652                 :          0 :                                 AF_XDP_LOG(ERR, "Failed to load custom XDP program %s\n",
    1653                 :            :                                                 internals->prog_path);
    1654                 :          0 :                                 goto out_umem;
    1655                 :            :                         }
    1656                 :          0 :                         internals->custom_prog_configured = 1;
    1657                 :            :                 }
    1658                 :          0 :                 cfg.libbpf_flags |= XSK_LIBBPF_FLAGS__INHIBIT_PROG_LOAD;
    1659                 :            :         }
    1660                 :            : 
    1661         [ #  # ]:          0 :         if (internals->shared_umem)
    1662                 :          0 :                 ret = create_shared_socket(&rxq->xsk, internals->if_name,
    1663                 :          0 :                                 rxq->xsk_queue_idx, rxq->umem->umem, &rxq->rx,
    1664                 :            :                                 &txq->tx, &rxq->fq, &rxq->cq, &cfg);
    1665                 :            :         else
    1666                 :          0 :                 ret = xsk_socket__create(&rxq->xsk, internals->if_name,
    1667                 :          0 :                                 rxq->xsk_queue_idx, rxq->umem->umem, &rxq->rx,
    1668                 :            :                                 &txq->tx, &cfg);
    1669                 :            : 
    1670         [ #  # ]:          0 :         if (ret) {
    1671                 :          0 :                 AF_XDP_LOG(ERR, "Failed to create xsk socket.\n");
    1672                 :          0 :                 goto out_umem;
    1673                 :            :         }
    1674                 :            : 
    1675         [ #  # ]:          0 :         if (!reserve_before) {
    1676                 :            :                 /* reserve fill queue of queues sharing UMEM */
    1677                 :          0 :                 ret = reserve_fill_queue(rxq->umem, reserve_size, fq_bufs, &rxq->fq);
    1678         [ #  # ]:          0 :                 if (ret) {
    1679                 :          0 :                         AF_XDP_LOG(ERR, "Failed to reserve fill queue.\n");
    1680                 :          0 :                         goto out_xsk;
    1681                 :            :                 }
    1682                 :            :         }
    1683                 :            : 
    1684                 :            :         /* insert the xsk into the xsks_map */
    1685         [ #  # ]:          0 :         if (internals->custom_prog_configured) {
    1686                 :            :                 int err, fd;
    1687                 :            : 
    1688                 :          0 :                 fd = xsk_socket__fd(rxq->xsk);
    1689                 :          0 :                 err = bpf_map_update_elem(bpf_map__fd(internals->map),
    1690                 :          0 :                                           &rxq->xsk_queue_idx, &fd, 0);
    1691         [ #  # ]:          0 :                 if (err) {
    1692                 :          0 :                         AF_XDP_LOG(ERR, "Failed to insert xsk in map.\n");
    1693                 :          0 :                         goto out_xsk;
    1694                 :            :                 }
    1695                 :            :         }
    1696                 :            : 
    1697         [ #  # ]:          0 :         if (internals->use_cni) {
    1698                 :            :                 int err, fd, map_fd;
    1699                 :            : 
    1700                 :            :                 /* get socket fd from CNI plugin */
    1701                 :          0 :                 map_fd = get_cni_fd(internals->if_name);
    1702         [ #  # ]:          0 :                 if (map_fd < 0) {
    1703                 :          0 :                         AF_XDP_LOG(ERR, "Failed to receive CNI plugin fd\n");
    1704                 :          0 :                         goto out_xsk;
    1705                 :            :                 }
    1706                 :            :                 /* get socket fd */
    1707                 :          0 :                 fd = xsk_socket__fd(rxq->xsk);
    1708                 :          0 :                 err = bpf_map_update_elem(map_fd, &rxq->xsk_queue_idx, &fd, 0);
    1709         [ #  # ]:          0 :                 if (err) {
    1710                 :          0 :                         AF_XDP_LOG(ERR, "Failed to insert unprivileged xsk in map.\n");
    1711                 :          0 :                         goto out_xsk;
    1712                 :            :                 }
    1713         [ #  # ]:          0 :         } else if (rxq->busy_budget) {
    1714                 :          0 :                 ret = configure_preferred_busy_poll(rxq);
    1715         [ #  # ]:          0 :                 if (ret) {
    1716                 :          0 :                         AF_XDP_LOG(ERR, "Failed configure busy polling.\n");
    1717                 :          0 :                         goto out_xsk;
    1718                 :            :                 }
    1719                 :            :         }
    1720                 :            : 
    1721                 :            :         return 0;
    1722                 :            : 
    1723                 :          0 : out_xsk:
    1724                 :          0 :         xsk_socket__delete(rxq->xsk);
    1725                 :          0 : out_umem:
    1726         [ #  # ]:          0 :         if (__atomic_fetch_sub(&rxq->umem->refcnt, 1, __ATOMIC_ACQUIRE) - 1 == 0)
    1727                 :          0 :                 xdp_umem_destroy(rxq->umem);
    1728                 :            : 
    1729                 :            :         return ret;
    1730                 :            : }
    1731                 :            : 
    1732                 :            : static int
    1733                 :          0 : eth_rx_queue_setup(struct rte_eth_dev *dev,
    1734                 :            :                    uint16_t rx_queue_id,
    1735                 :            :                    uint16_t nb_rx_desc,
    1736                 :            :                    unsigned int socket_id __rte_unused,
    1737                 :            :                    const struct rte_eth_rxconf *rx_conf __rte_unused,
    1738                 :            :                    struct rte_mempool *mb_pool)
    1739                 :            : {
    1740                 :          0 :         struct pmd_internals *internals = dev->data->dev_private;
    1741                 :          0 :         struct pmd_process_private *process_private = dev->process_private;
    1742                 :            :         struct pkt_rx_queue *rxq;
    1743                 :            :         int ret;
    1744                 :            : 
    1745                 :          0 :         rxq = &internals->rx_queues[rx_queue_id];
    1746                 :            : 
    1747                 :          0 :         AF_XDP_LOG(INFO, "Set up rx queue, rx queue id: %d, xsk queue id: %d\n",
    1748                 :            :                    rx_queue_id, rxq->xsk_queue_idx);
    1749                 :            : 
    1750                 :            : #ifndef XDP_UMEM_UNALIGNED_CHUNK_FLAG
    1751                 :            :         uint32_t buf_size, data_size;
    1752                 :            : 
    1753                 :            :         /* Now get the space available for data in the mbuf */
    1754                 :            :         buf_size = rte_pktmbuf_data_room_size(mb_pool) -
    1755                 :            :                 RTE_PKTMBUF_HEADROOM;
    1756                 :            :         data_size = ETH_AF_XDP_FRAME_SIZE;
    1757                 :            : 
    1758                 :            :         if (data_size > buf_size) {
    1759                 :            :                 AF_XDP_LOG(ERR, "%s: %d bytes will not fit in mbuf (%d bytes)\n",
    1760                 :            :                         dev->device->name, data_size, buf_size);
    1761                 :            :                 ret = -ENOMEM;
    1762                 :            :                 goto err;
    1763                 :            :         }
    1764                 :            : #endif
    1765                 :            : 
    1766                 :          0 :         rxq->mb_pool = mb_pool;
    1767                 :            : 
    1768         [ #  # ]:          0 :         if (xsk_configure(internals, rxq, nb_rx_desc)) {
    1769                 :          0 :                 AF_XDP_LOG(ERR, "Failed to configure xdp socket\n");
    1770                 :            :                 ret = -EINVAL;
    1771                 :          0 :                 goto err;
    1772                 :            :         }
    1773                 :            : 
    1774         [ #  # ]:          0 :         if (!rxq->busy_budget)
    1775                 :          0 :                 AF_XDP_LOG(DEBUG, "Preferred busy polling not enabled\n");
    1776                 :            : 
    1777                 :          0 :         rxq->fds[0].fd = xsk_socket__fd(rxq->xsk);
    1778                 :          0 :         rxq->fds[0].events = POLLIN;
    1779                 :            : 
    1780                 :          0 :         process_private->rxq_xsk_fds[rx_queue_id] = rxq->fds[0].fd;
    1781                 :            : 
    1782                 :          0 :         dev->data->rx_queues[rx_queue_id] = rxq;
    1783                 :          0 :         return 0;
    1784                 :            : 
    1785                 :            : err:
    1786                 :          0 :         return ret;
    1787                 :            : }
    1788                 :            : 
    1789                 :            : static int
    1790                 :          0 : eth_tx_queue_setup(struct rte_eth_dev *dev,
    1791                 :            :                    uint16_t tx_queue_id,
    1792                 :            :                    uint16_t nb_tx_desc __rte_unused,
    1793                 :            :                    unsigned int socket_id __rte_unused,
    1794                 :            :                    const struct rte_eth_txconf *tx_conf __rte_unused)
    1795                 :            : {
    1796                 :          0 :         struct pmd_internals *internals = dev->data->dev_private;
    1797                 :            :         struct pkt_tx_queue *txq;
    1798                 :            : 
    1799                 :          0 :         txq = &internals->tx_queues[tx_queue_id];
    1800                 :            : 
    1801                 :          0 :         dev->data->tx_queues[tx_queue_id] = txq;
    1802                 :          0 :         return 0;
    1803                 :            : }
    1804                 :            : 
    1805                 :            : static int
    1806                 :          0 : eth_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
    1807                 :            : {
    1808                 :          0 :         struct pmd_internals *internals = dev->data->dev_private;
    1809                 :          0 :         struct ifreq ifr = { .ifr_mtu = mtu };
    1810                 :            :         int ret;
    1811                 :            :         int s;
    1812                 :            : 
    1813                 :          0 :         s = socket(PF_INET, SOCK_DGRAM, 0);
    1814         [ #  # ]:          0 :         if (s < 0)
    1815                 :            :                 return -EINVAL;
    1816                 :            : 
    1817                 :          0 :         strlcpy(ifr.ifr_name, internals->if_name, IFNAMSIZ);
    1818                 :          0 :         ret = ioctl(s, SIOCSIFMTU, &ifr);
    1819                 :          0 :         close(s);
    1820                 :            : 
    1821         [ #  # ]:          0 :         return (ret < 0) ? -errno : 0;
    1822                 :            : }
    1823                 :            : 
    1824                 :            : static int
    1825                 :          0 : eth_dev_change_flags(char *if_name, uint32_t flags, uint32_t mask)
    1826                 :            : {
    1827                 :            :         struct ifreq ifr;
    1828                 :            :         int ret = 0;
    1829                 :            :         int s;
    1830                 :            : 
    1831                 :          0 :         s = socket(PF_INET, SOCK_DGRAM, 0);
    1832         [ #  # ]:          0 :         if (s < 0)
    1833                 :          0 :                 return -errno;
    1834                 :            : 
    1835                 :            :         strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
    1836         [ #  # ]:          0 :         if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
    1837                 :          0 :                 ret = -errno;
    1838                 :          0 :                 goto out;
    1839                 :            :         }
    1840                 :          0 :         ifr.ifr_flags &= mask;
    1841                 :          0 :         ifr.ifr_flags |= flags;
    1842         [ #  # ]:          0 :         if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
    1843                 :          0 :                 ret = -errno;
    1844                 :          0 :                 goto out;
    1845                 :            :         }
    1846                 :          0 : out:
    1847                 :          0 :         close(s);
    1848                 :          0 :         return ret;
    1849                 :            : }
    1850                 :            : 
    1851                 :            : static int
    1852                 :          0 : eth_dev_promiscuous_enable(struct rte_eth_dev *dev)
    1853                 :            : {
    1854                 :          0 :         struct pmd_internals *internals = dev->data->dev_private;
    1855                 :            : 
    1856                 :          0 :         return eth_dev_change_flags(internals->if_name, IFF_PROMISC, ~0);
    1857                 :            : }
    1858                 :            : 
    1859                 :            : static int
    1860                 :          0 : eth_dev_promiscuous_disable(struct rte_eth_dev *dev)
    1861                 :            : {
    1862                 :          0 :         struct pmd_internals *internals = dev->data->dev_private;
    1863                 :            : 
    1864                 :          0 :         return eth_dev_change_flags(internals->if_name, 0, ~IFF_PROMISC);
    1865                 :            : }
    1866                 :            : 
    1867                 :            : static const struct eth_dev_ops ops = {
    1868                 :            :         .dev_start = eth_dev_start,
    1869                 :            :         .dev_stop = eth_dev_stop,
    1870                 :            :         .dev_close = eth_dev_close,
    1871                 :            :         .dev_configure = eth_dev_configure,
    1872                 :            :         .dev_infos_get = eth_dev_info,
    1873                 :            :         .mtu_set = eth_dev_mtu_set,
    1874                 :            :         .promiscuous_enable = eth_dev_promiscuous_enable,
    1875                 :            :         .promiscuous_disable = eth_dev_promiscuous_disable,
    1876                 :            :         .rx_queue_setup = eth_rx_queue_setup,
    1877                 :            :         .tx_queue_setup = eth_tx_queue_setup,
    1878                 :            :         .link_update = eth_link_update,
    1879                 :            :         .stats_get = eth_stats_get,
    1880                 :            :         .stats_reset = eth_stats_reset,
    1881                 :            :         .get_monitor_addr = eth_get_monitor_addr,
    1882                 :            : };
    1883                 :            : 
    1884                 :            : /* CNI option works in unprivileged container environment
    1885                 :            :  * and ethernet device functionality will be reduced. So
    1886                 :            :  * additional customiszed eth_dev_ops struct is needed
    1887                 :            :  * for cni. Promiscuous enable and disable functionality
    1888                 :            :  * is removed.
    1889                 :            :  **/
    1890                 :            : static const struct eth_dev_ops ops_cni = {
    1891                 :            :         .dev_start = eth_dev_start,
    1892                 :            :         .dev_stop = eth_dev_stop,
    1893                 :            :         .dev_close = eth_dev_close,
    1894                 :            :         .dev_configure = eth_dev_configure,
    1895                 :            :         .dev_infos_get = eth_dev_info,
    1896                 :            :         .mtu_set = eth_dev_mtu_set,
    1897                 :            :         .rx_queue_setup = eth_rx_queue_setup,
    1898                 :            :         .tx_queue_setup = eth_tx_queue_setup,
    1899                 :            :         .link_update = eth_link_update,
    1900                 :            :         .stats_get = eth_stats_get,
    1901                 :            :         .stats_reset = eth_stats_reset,
    1902                 :            :         .get_monitor_addr = eth_get_monitor_addr,
    1903                 :            : };
    1904                 :            : 
    1905                 :            : /** parse busy_budget argument */
    1906                 :            : static int
    1907                 :          0 : parse_budget_arg(const char *key __rte_unused,
    1908                 :            :                   const char *value, void *extra_args)
    1909                 :            : {
    1910                 :            :         int *i = (int *)extra_args;
    1911                 :            :         char *end;
    1912                 :            : 
    1913                 :          0 :         *i = strtol(value, &end, 10);
    1914         [ #  # ]:          0 :         if (*i < 0 || *i > UINT16_MAX) {
    1915                 :          0 :                 AF_XDP_LOG(ERR, "Invalid busy_budget %i, must be >= 0 and <= %u\n",
    1916                 :            :                                 *i, UINT16_MAX);
    1917                 :          0 :                 return -EINVAL;
    1918                 :            :         }
    1919                 :            : 
    1920                 :            :         return 0;
    1921                 :            : }
    1922                 :            : 
    1923                 :            : /** parse integer from integer argument */
    1924                 :            : static int
    1925                 :          0 : parse_integer_arg(const char *key __rte_unused,
    1926                 :            :                   const char *value, void *extra_args)
    1927                 :            : {
    1928                 :            :         int *i = (int *)extra_args;
    1929                 :            :         char *end;
    1930                 :            : 
    1931                 :          0 :         *i = strtol(value, &end, 10);
    1932         [ #  # ]:          0 :         if (*i < 0) {
    1933                 :          0 :                 AF_XDP_LOG(ERR, "Argument has to be positive.\n");
    1934                 :          0 :                 return -EINVAL;
    1935                 :            :         }
    1936                 :            : 
    1937                 :            :         return 0;
    1938                 :            : }
    1939                 :            : 
    1940                 :            : /** parse name argument */
    1941                 :            : static int
    1942                 :          0 : parse_name_arg(const char *key __rte_unused,
    1943                 :            :                const char *value, void *extra_args)
    1944                 :            : {
    1945                 :            :         char *name = extra_args;
    1946                 :            : 
    1947         [ #  # ]:          0 :         if (strnlen(value, IFNAMSIZ) > IFNAMSIZ - 1) {
    1948                 :          0 :                 AF_XDP_LOG(ERR, "Invalid name %s, should be less than %u bytes.\n",
    1949                 :            :                            value, IFNAMSIZ);
    1950                 :          0 :                 return -EINVAL;
    1951                 :            :         }
    1952                 :            : 
    1953                 :            :         strlcpy(name, value, IFNAMSIZ);
    1954                 :            : 
    1955                 :          0 :         return 0;
    1956                 :            : }
    1957                 :            : 
    1958                 :            : /** parse xdp prog argument */
    1959                 :            : static int
    1960                 :          0 : parse_prog_arg(const char *key __rte_unused,
    1961                 :            :                const char *value, void *extra_args)
    1962                 :            : {
    1963                 :            :         char *path = extra_args;
    1964                 :            : 
    1965         [ #  # ]:          0 :         if (strnlen(value, PATH_MAX) == PATH_MAX) {
    1966                 :          0 :                 AF_XDP_LOG(ERR, "Invalid path %s, should be less than %u bytes.\n",
    1967                 :            :                            value, PATH_MAX);
    1968                 :          0 :                 return -EINVAL;
    1969                 :            :         }
    1970                 :            : 
    1971         [ #  # ]:          0 :         if (access(value, F_OK) != 0) {
    1972                 :          0 :                 AF_XDP_LOG(ERR, "Error accessing %s: %s\n",
    1973                 :            :                            value, strerror(errno));
    1974                 :          0 :                 return -EINVAL;
    1975                 :            :         }
    1976                 :            : 
    1977                 :            :         strlcpy(path, value, PATH_MAX);
    1978                 :            : 
    1979                 :          0 :         return 0;
    1980                 :            : }
    1981                 :            : 
    1982                 :            : static int
    1983                 :          0 : xdp_get_channels_info(const char *if_name, int *max_queues,
    1984                 :            :                                 int *combined_queues)
    1985                 :            : {
    1986                 :            :         struct ethtool_channels channels;
    1987                 :            :         struct ifreq ifr;
    1988                 :            :         int fd, ret;
    1989                 :            : 
    1990                 :          0 :         fd = socket(AF_INET, SOCK_DGRAM, 0);
    1991         [ #  # ]:          0 :         if (fd < 0)
    1992                 :            :                 return -1;
    1993                 :            : 
    1994                 :          0 :         channels.cmd = ETHTOOL_GCHANNELS;
    1995                 :          0 :         ifr.ifr_data = (void *)&channels;
    1996                 :            :         strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
    1997                 :          0 :         ret = ioctl(fd, SIOCETHTOOL, &ifr);
    1998         [ #  # ]:          0 :         if (ret) {
    1999         [ #  # ]:          0 :                 if (errno == EOPNOTSUPP) {
    2000                 :            :                         ret = 0;
    2001                 :            :                 } else {
    2002                 :          0 :                         ret = -errno;
    2003                 :          0 :                         goto out;
    2004                 :            :                 }
    2005                 :            :         }
    2006                 :            : 
    2007   [ #  #  #  # ]:          0 :         if (channels.max_combined == 0 || errno == EOPNOTSUPP) {
    2008                 :            :                 /* If the device says it has no channels, then all traffic
    2009                 :            :                  * is sent to a single stream, so max queues = 1.
    2010                 :            :                  */
    2011                 :          0 :                 *max_queues = 1;
    2012                 :          0 :                 *combined_queues = 1;
    2013                 :            :         } else {
    2014                 :          0 :                 *max_queues = channels.max_combined;
    2015                 :          0 :                 *combined_queues = channels.combined_count;
    2016                 :            :         }
    2017                 :            : 
    2018                 :          0 :  out:
    2019                 :          0 :         close(fd);
    2020                 :          0 :         return ret;
    2021                 :            : }
    2022                 :            : 
    2023                 :            : static int
    2024                 :          0 : parse_parameters(struct rte_kvargs *kvlist, char *if_name, int *start_queue,
    2025                 :            :                  int *queue_cnt, int *shared_umem, char *prog_path,
    2026                 :            :                  int *busy_budget, int *force_copy, int *use_cni)
    2027                 :            : {
    2028                 :            :         int ret;
    2029                 :            : 
    2030                 :          0 :         ret = rte_kvargs_process(kvlist, ETH_AF_XDP_IFACE_ARG,
    2031                 :            :                                  &parse_name_arg, if_name);
    2032         [ #  # ]:          0 :         if (ret < 0)
    2033                 :          0 :                 goto free_kvlist;
    2034                 :            : 
    2035                 :          0 :         ret = rte_kvargs_process(kvlist, ETH_AF_XDP_START_QUEUE_ARG,
    2036                 :            :                                  &parse_integer_arg, start_queue);
    2037         [ #  # ]:          0 :         if (ret < 0)
    2038                 :          0 :                 goto free_kvlist;
    2039                 :            : 
    2040                 :          0 :         ret = rte_kvargs_process(kvlist, ETH_AF_XDP_QUEUE_COUNT_ARG,
    2041                 :            :                                  &parse_integer_arg, queue_cnt);
    2042   [ #  #  #  # ]:          0 :         if (ret < 0 || *queue_cnt <= 0) {
    2043                 :            :                 ret = -EINVAL;
    2044                 :          0 :                 goto free_kvlist;
    2045                 :            :         }
    2046                 :            : 
    2047                 :          0 :         ret = rte_kvargs_process(kvlist, ETH_AF_XDP_SHARED_UMEM_ARG,
    2048                 :            :                                 &parse_integer_arg, shared_umem);
    2049         [ #  # ]:          0 :         if (ret < 0)
    2050                 :          0 :                 goto free_kvlist;
    2051                 :            : 
    2052                 :          0 :         ret = rte_kvargs_process(kvlist, ETH_AF_XDP_PROG_ARG,
    2053                 :            :                                  &parse_prog_arg, prog_path);
    2054         [ #  # ]:          0 :         if (ret < 0)
    2055                 :          0 :                 goto free_kvlist;
    2056                 :            : 
    2057                 :          0 :         ret = rte_kvargs_process(kvlist, ETH_AF_XDP_BUDGET_ARG,
    2058                 :            :                                 &parse_budget_arg, busy_budget);
    2059         [ #  # ]:          0 :         if (ret < 0)
    2060                 :          0 :                 goto free_kvlist;
    2061                 :            : 
    2062                 :          0 :         ret = rte_kvargs_process(kvlist, ETH_AF_XDP_FORCE_COPY_ARG,
    2063                 :            :                                 &parse_integer_arg, force_copy);
    2064         [ #  # ]:          0 :         if (ret < 0)
    2065                 :          0 :                 goto free_kvlist;
    2066                 :            : 
    2067                 :          0 :         ret = rte_kvargs_process(kvlist, ETH_AF_XDP_USE_CNI_ARG,
    2068                 :            :                                  &parse_integer_arg, use_cni);
    2069         [ #  # ]:          0 :         if (ret < 0)
    2070                 :          0 :                 goto free_kvlist;
    2071                 :            : 
    2072                 :          0 : free_kvlist:
    2073                 :          0 :         rte_kvargs_free(kvlist);
    2074                 :          0 :         return ret;
    2075                 :            : }
    2076                 :            : 
    2077                 :            : static int
    2078                 :          0 : get_iface_info(const char *if_name,
    2079                 :            :                struct rte_ether_addr *eth_addr,
    2080                 :            :                int *if_index)
    2081                 :            : {
    2082                 :            :         struct ifreq ifr;
    2083                 :          0 :         int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
    2084                 :            : 
    2085         [ #  # ]:          0 :         if (sock < 0)
    2086                 :            :                 return -1;
    2087                 :            : 
    2088                 :            :         strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
    2089         [ #  # ]:          0 :         if (ioctl(sock, SIOCGIFINDEX, &ifr))
    2090                 :          0 :                 goto error;
    2091                 :            : 
    2092                 :          0 :         *if_index = ifr.ifr_ifindex;
    2093                 :            : 
    2094         [ #  # ]:          0 :         if (ioctl(sock, SIOCGIFHWADDR, &ifr))
    2095                 :          0 :                 goto error;
    2096                 :            : 
    2097                 :            :         rte_memcpy(eth_addr, ifr.ifr_hwaddr.sa_data, RTE_ETHER_ADDR_LEN);
    2098                 :            : 
    2099                 :          0 :         close(sock);
    2100                 :          0 :         return 0;
    2101                 :            : 
    2102                 :          0 : error:
    2103                 :          0 :         close(sock);
    2104                 :          0 :         return -1;
    2105                 :            : }
    2106                 :            : 
    2107                 :            : static struct rte_eth_dev *
    2108         [ #  # ]:          0 : init_internals(struct rte_vdev_device *dev, const char *if_name,
    2109                 :            :                int start_queue_idx, int queue_cnt, int shared_umem,
    2110                 :            :                const char *prog_path, int busy_budget, int force_copy,
    2111                 :            :                int use_cni)
    2112                 :            : {
    2113                 :            :         const char *name = rte_vdev_device_name(dev);
    2114                 :          0 :         const unsigned int numa_node = dev->device.numa_node;
    2115                 :            :         struct pmd_process_private *process_private;
    2116                 :            :         struct pmd_internals *internals;
    2117                 :            :         struct rte_eth_dev *eth_dev;
    2118                 :            :         int ret;
    2119                 :            :         int i;
    2120                 :            : 
    2121                 :          0 :         internals = rte_zmalloc_socket(name, sizeof(*internals), 0, numa_node);
    2122         [ #  # ]:          0 :         if (internals == NULL)
    2123                 :            :                 return NULL;
    2124                 :            : 
    2125                 :          0 :         internals->start_queue_idx = start_queue_idx;
    2126                 :          0 :         internals->queue_cnt = queue_cnt;
    2127                 :          0 :         strlcpy(internals->if_name, if_name, IFNAMSIZ);
    2128                 :          0 :         strlcpy(internals->prog_path, prog_path, PATH_MAX);
    2129                 :          0 :         internals->custom_prog_configured = 0;
    2130                 :            : 
    2131                 :            : #ifndef ETH_AF_XDP_SHARED_UMEM
    2132                 :            :         if (shared_umem) {
    2133                 :            :                 AF_XDP_LOG(ERR, "Shared UMEM feature not available. "
    2134                 :            :                                 "Check kernel and libbpf version\n");
    2135                 :            :                 goto err_free_internals;
    2136                 :            :         }
    2137                 :            : #endif
    2138                 :          0 :         internals->shared_umem = shared_umem;
    2139                 :          0 :         internals->force_copy = force_copy;
    2140                 :          0 :         internals->use_cni = use_cni;
    2141                 :            : 
    2142         [ #  # ]:          0 :         if (xdp_get_channels_info(if_name, &internals->max_queue_cnt,
    2143                 :            :                                   &internals->combined_queue_cnt)) {
    2144                 :          0 :                 AF_XDP_LOG(ERR, "Failed to get channel info of interface: %s\n",
    2145                 :            :                                 if_name);
    2146                 :          0 :                 goto err_free_internals;
    2147                 :            :         }
    2148                 :            : 
    2149         [ #  # ]:          0 :         if (queue_cnt > internals->combined_queue_cnt) {
    2150                 :          0 :                 AF_XDP_LOG(ERR, "Specified queue count %d is larger than combined queue count %d.\n",
    2151                 :            :                                 queue_cnt, internals->combined_queue_cnt);
    2152                 :          0 :                 goto err_free_internals;
    2153                 :            :         }
    2154                 :            : 
    2155                 :          0 :         internals->rx_queues = rte_zmalloc_socket(NULL,
    2156                 :            :                                         sizeof(struct pkt_rx_queue) * queue_cnt,
    2157                 :            :                                         0, numa_node);
    2158         [ #  # ]:          0 :         if (internals->rx_queues == NULL) {
    2159                 :          0 :                 AF_XDP_LOG(ERR, "Failed to allocate memory for rx queues.\n");
    2160                 :          0 :                 goto err_free_internals;
    2161                 :            :         }
    2162                 :            : 
    2163                 :          0 :         internals->tx_queues = rte_zmalloc_socket(NULL,
    2164                 :            :                                         sizeof(struct pkt_tx_queue) * queue_cnt,
    2165                 :            :                                         0, numa_node);
    2166         [ #  # ]:          0 :         if (internals->tx_queues == NULL) {
    2167                 :          0 :                 AF_XDP_LOG(ERR, "Failed to allocate memory for tx queues.\n");
    2168                 :          0 :                 goto err_free_rx;
    2169                 :            :         }
    2170         [ #  # ]:          0 :         for (i = 0; i < queue_cnt; i++) {
    2171                 :          0 :                 internals->tx_queues[i].pair = &internals->rx_queues[i];
    2172                 :          0 :                 internals->rx_queues[i].pair = &internals->tx_queues[i];
    2173                 :          0 :                 internals->rx_queues[i].xsk_queue_idx = start_queue_idx + i;
    2174                 :          0 :                 internals->tx_queues[i].xsk_queue_idx = start_queue_idx + i;
    2175                 :          0 :                 internals->rx_queues[i].busy_budget = busy_budget;
    2176                 :            :         }
    2177                 :            : 
    2178                 :          0 :         ret = get_iface_info(if_name, &internals->eth_addr,
    2179                 :            :                              &internals->if_index);
    2180         [ #  # ]:          0 :         if (ret)
    2181                 :          0 :                 goto err_free_tx;
    2182                 :            : 
    2183                 :            :         process_private = (struct pmd_process_private *)
    2184                 :          0 :                 rte_zmalloc_socket(name, sizeof(struct pmd_process_private),
    2185                 :            :                                    RTE_CACHE_LINE_SIZE, numa_node);
    2186         [ #  # ]:          0 :         if (process_private == NULL) {
    2187                 :          0 :                 AF_XDP_LOG(ERR, "Failed to alloc memory for process private\n");
    2188                 :          0 :                 goto err_free_tx;
    2189                 :            :         }
    2190                 :            : 
    2191                 :          0 :         eth_dev = rte_eth_vdev_allocate(dev, 0);
    2192         [ #  # ]:          0 :         if (eth_dev == NULL)
    2193                 :          0 :                 goto err_free_pp;
    2194                 :            : 
    2195                 :          0 :         eth_dev->data->dev_private = internals;
    2196                 :          0 :         eth_dev->data->dev_link = pmd_link;
    2197                 :          0 :         eth_dev->data->mac_addrs = &internals->eth_addr;
    2198                 :          0 :         eth_dev->data->dev_flags |= RTE_ETH_DEV_AUTOFILL_QUEUE_XSTATS;
    2199         [ #  # ]:          0 :         if (!internals->use_cni)
    2200                 :          0 :                 eth_dev->dev_ops = &ops;
    2201                 :            :         else
    2202                 :          0 :                 eth_dev->dev_ops = &ops_cni;
    2203                 :            : 
    2204                 :          0 :         eth_dev->rx_pkt_burst = eth_af_xdp_rx;
    2205                 :          0 :         eth_dev->tx_pkt_burst = eth_af_xdp_tx;
    2206                 :          0 :         eth_dev->process_private = process_private;
    2207                 :            : 
    2208         [ #  # ]:          0 :         for (i = 0; i < queue_cnt; i++)
    2209                 :          0 :                 process_private->rxq_xsk_fds[i] = -1;
    2210                 :            : 
    2211                 :            : #if defined(XDP_UMEM_UNALIGNED_CHUNK_FLAG)
    2212                 :          0 :         AF_XDP_LOG(INFO, "Zero copy between umem and mbuf enabled.\n");
    2213                 :            : #endif
    2214                 :            : 
    2215                 :          0 :         return eth_dev;
    2216                 :            : 
    2217                 :            : err_free_pp:
    2218                 :          0 :         rte_free(process_private);
    2219                 :          0 : err_free_tx:
    2220                 :          0 :         rte_free(internals->tx_queues);
    2221                 :          0 : err_free_rx:
    2222                 :          0 :         rte_free(internals->rx_queues);
    2223                 :          0 : err_free_internals:
    2224                 :          0 :         rte_free(internals);
    2225                 :          0 :         return NULL;
    2226                 :            : }
    2227                 :            : 
    2228                 :            : /* Secondary process requests rxq fds from primary. */
    2229                 :            : static int
    2230                 :          0 : afxdp_mp_request_fds(const char *name, struct rte_eth_dev *dev)
    2231                 :            : {
    2232                 :          0 :         struct pmd_process_private *process_private = dev->process_private;
    2233                 :          0 :         struct timespec timeout = {.tv_sec = 1, .tv_nsec = 0};
    2234                 :            :         struct rte_mp_msg request, *reply;
    2235                 :            :         struct rte_mp_reply replies;
    2236                 :            :         struct ipc_hdr *request_param = (struct ipc_hdr *)request.param;
    2237                 :            :         int i, ret;
    2238                 :            : 
    2239                 :            :         /* Prepare the request */
    2240                 :            :         memset(&request, 0, sizeof(request));
    2241                 :            :         strlcpy(request.name, ETH_AF_XDP_MP_KEY, sizeof(request.name));
    2242                 :            :         strlcpy(request_param->port_name, name,
    2243                 :            :                 sizeof(request_param->port_name));
    2244                 :          0 :         request.len_param = sizeof(*request_param);
    2245                 :            : 
    2246                 :            :         /* Send the request and receive the reply */
    2247                 :          0 :         AF_XDP_LOG(DEBUG, "Sending multi-process IPC request for %s\n", name);
    2248                 :          0 :         ret = rte_mp_request_sync(&request, &replies, &timeout);
    2249   [ #  #  #  # ]:          0 :         if (ret < 0 || replies.nb_received != 1) {
    2250                 :          0 :                 AF_XDP_LOG(ERR, "Failed to request fds from primary: %d\n",
    2251                 :            :                            rte_errno);
    2252                 :          0 :                 return -1;
    2253                 :            :         }
    2254                 :          0 :         reply = replies.msgs;
    2255                 :          0 :         AF_XDP_LOG(DEBUG, "Received multi-process IPC reply for %s\n", name);
    2256         [ #  # ]:          0 :         if (dev->data->nb_rx_queues != reply->num_fds) {
    2257                 :          0 :                 AF_XDP_LOG(ERR, "Incorrect number of fds received: %d != %d\n",
    2258                 :            :                            reply->num_fds, dev->data->nb_rx_queues);
    2259                 :          0 :                 return -EINVAL;
    2260                 :            :         }
    2261                 :            : 
    2262         [ #  # ]:          0 :         for (i = 0; i < reply->num_fds; i++)
    2263                 :          0 :                 process_private->rxq_xsk_fds[i] = reply->fds[i];
    2264                 :            : 
    2265                 :          0 :         free(reply);
    2266                 :          0 :         return 0;
    2267                 :            : }
    2268                 :            : 
    2269                 :            : /* Primary process sends rxq fds to secondary. */
    2270                 :            : static int
    2271                 :          0 : afxdp_mp_send_fds(const struct rte_mp_msg *request, const void *peer)
    2272                 :            : {
    2273                 :            :         struct rte_eth_dev *dev;
    2274                 :            :         struct pmd_process_private *process_private;
    2275                 :            :         struct rte_mp_msg reply;
    2276                 :            :         const struct ipc_hdr *request_param =
    2277                 :            :                 (const struct ipc_hdr *)request->param;
    2278                 :            :         struct ipc_hdr *reply_param =
    2279                 :            :                 (struct ipc_hdr *)reply.param;
    2280                 :          0 :         const char *request_name = request_param->port_name;
    2281                 :            :         int i;
    2282                 :            : 
    2283                 :          0 :         AF_XDP_LOG(DEBUG, "Received multi-process IPC request for %s\n",
    2284                 :            :                    request_name);
    2285                 :            : 
    2286                 :            :         /* Find the requested port */
    2287                 :          0 :         dev = rte_eth_dev_get_by_name(request_name);
    2288         [ #  # ]:          0 :         if (!dev) {
    2289                 :          0 :                 AF_XDP_LOG(ERR, "Failed to get port id for %s\n", request_name);
    2290                 :          0 :                 return -1;
    2291                 :            :         }
    2292                 :          0 :         process_private = dev->process_private;
    2293                 :            : 
    2294                 :            :         /* Populate the reply with the xsk fd for each queue */
    2295                 :          0 :         reply.num_fds = 0;
    2296         [ #  # ]:          0 :         if (dev->data->nb_rx_queues > RTE_MP_MAX_FD_NUM) {
    2297                 :          0 :                 AF_XDP_LOG(ERR, "Number of rx queues (%d) exceeds max number of fds (%d)\n",
    2298                 :            :                            dev->data->nb_rx_queues, RTE_MP_MAX_FD_NUM);
    2299                 :          0 :                 return -EINVAL;
    2300                 :            :         }
    2301                 :            : 
    2302         [ #  # ]:          0 :         for (i = 0; i < dev->data->nb_rx_queues; i++)
    2303                 :          0 :                 reply.fds[reply.num_fds++] = process_private->rxq_xsk_fds[i];
    2304                 :            : 
    2305                 :            :         /* Send the reply */
    2306                 :          0 :         strlcpy(reply.name, request->name, sizeof(reply.name));
    2307                 :            :         strlcpy(reply_param->port_name, request_name,
    2308                 :            :                 sizeof(reply_param->port_name));
    2309                 :          0 :         reply.len_param = sizeof(*reply_param);
    2310                 :          0 :         AF_XDP_LOG(DEBUG, "Sending multi-process IPC reply for %s\n",
    2311                 :            :                    reply_param->port_name);
    2312         [ #  # ]:          0 :         if (rte_mp_reply(&reply, peer) < 0) {
    2313                 :          0 :                 AF_XDP_LOG(ERR, "Failed to reply to multi-process IPC request\n");
    2314                 :          0 :                 return -1;
    2315                 :            :         }
    2316                 :            :         return 0;
    2317                 :            : }
    2318                 :            : 
    2319                 :            : static int
    2320                 :          0 : rte_pmd_af_xdp_probe(struct rte_vdev_device *dev)
    2321                 :            : {
    2322                 :            :         struct rte_kvargs *kvlist;
    2323                 :          0 :         char if_name[IFNAMSIZ] = {'\0'};
    2324                 :          0 :         int xsk_start_queue_idx = ETH_AF_XDP_DFLT_START_QUEUE_IDX;
    2325                 :          0 :         int xsk_queue_cnt = ETH_AF_XDP_DFLT_QUEUE_COUNT;
    2326                 :          0 :         int shared_umem = 0;
    2327                 :          0 :         char prog_path[PATH_MAX] = {'\0'};
    2328                 :          0 :         int busy_budget = -1, ret;
    2329                 :          0 :         int force_copy = 0;
    2330         [ #  # ]:          0 :         int use_cni = 0;
    2331                 :            :         struct rte_eth_dev *eth_dev = NULL;
    2332                 :            :         const char *name = rte_vdev_device_name(dev);
    2333                 :            : 
    2334                 :          0 :         AF_XDP_LOG(INFO, "Initializing pmd_af_xdp for %s\n", name);
    2335                 :            : 
    2336         [ #  # ]:          0 :         if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
    2337                 :          0 :                 eth_dev = rte_eth_dev_attach_secondary(name);
    2338         [ #  # ]:          0 :                 if (eth_dev == NULL) {
    2339                 :          0 :                         AF_XDP_LOG(ERR, "Failed to probe %s\n", name);
    2340                 :          0 :                         return -EINVAL;
    2341                 :            :                 }
    2342                 :          0 :                 eth_dev->dev_ops = &ops;
    2343                 :          0 :                 eth_dev->device = &dev->device;
    2344                 :          0 :                 eth_dev->rx_pkt_burst = rte_eth_pkt_burst_dummy;
    2345                 :          0 :                 eth_dev->tx_pkt_burst = rte_eth_pkt_burst_dummy;
    2346                 :          0 :                 eth_dev->process_private = (struct pmd_process_private *)
    2347                 :          0 :                         rte_zmalloc_socket(name,
    2348                 :            :                                            sizeof(struct pmd_process_private),
    2349                 :            :                                            RTE_CACHE_LINE_SIZE,
    2350                 :            :                                            eth_dev->device->numa_node);
    2351         [ #  # ]:          0 :                 if (eth_dev->process_private == NULL) {
    2352                 :          0 :                         AF_XDP_LOG(ERR,
    2353                 :            :                                 "Failed to alloc memory for process private\n");
    2354                 :          0 :                         return -ENOMEM;
    2355                 :            :                 }
    2356                 :            : 
    2357                 :            :                 /* Obtain the xsk fds from the primary process. */
    2358         [ #  # ]:          0 :                 if (afxdp_mp_request_fds(name, eth_dev))
    2359                 :            :                         return -1;
    2360                 :            : 
    2361                 :          0 :                 rte_eth_dev_probing_finish(eth_dev);
    2362                 :          0 :                 return 0;
    2363                 :            :         }
    2364                 :            : 
    2365                 :          0 :         kvlist = rte_kvargs_parse(rte_vdev_device_args(dev), valid_arguments);
    2366         [ #  # ]:          0 :         if (kvlist == NULL) {
    2367                 :          0 :                 AF_XDP_LOG(ERR, "Invalid kvargs key\n");
    2368                 :          0 :                 return -EINVAL;
    2369                 :            :         }
    2370                 :            : 
    2371         [ #  # ]:          0 :         if (parse_parameters(kvlist, if_name, &xsk_start_queue_idx,
    2372                 :            :                              &xsk_queue_cnt, &shared_umem, prog_path,
    2373                 :            :                              &busy_budget, &force_copy, &use_cni) < 0) {
    2374                 :          0 :                 AF_XDP_LOG(ERR, "Invalid kvargs value\n");
    2375                 :          0 :                 return -EINVAL;
    2376                 :            :         }
    2377                 :            : 
    2378   [ #  #  #  # ]:          0 :         if (use_cni && busy_budget > 0) {
    2379                 :          0 :                 AF_XDP_LOG(ERR, "When '%s' parameter is used, '%s' parameter is not valid\n",
    2380                 :            :                         ETH_AF_XDP_USE_CNI_ARG, ETH_AF_XDP_BUDGET_ARG);
    2381                 :          0 :                 return -EINVAL;
    2382                 :            :         }
    2383                 :            : 
    2384   [ #  #  #  # ]:          0 :         if (use_cni && strnlen(prog_path, PATH_MAX)) {
    2385                 :          0 :                 AF_XDP_LOG(ERR, "When '%s' parameter is used, '%s' parameter is not valid\n",
    2386                 :            :                         ETH_AF_XDP_USE_CNI_ARG, ETH_AF_XDP_PROG_ARG);
    2387                 :          0 :                         return -EINVAL;
    2388                 :            :         }
    2389                 :            : 
    2390         [ #  # ]:          0 :         if (strlen(if_name) == 0) {
    2391                 :          0 :                 AF_XDP_LOG(ERR, "Network interface must be specified\n");
    2392                 :          0 :                 return -EINVAL;
    2393                 :            :         }
    2394                 :            : 
    2395                 :            :         /* get numa node id from net sysfs */
    2396         [ #  # ]:          0 :         if (dev->device.numa_node == SOCKET_ID_ANY) {
    2397                 :          0 :                 unsigned long numa = 0;
    2398                 :            :                 char numa_path[PATH_MAX];
    2399                 :            : 
    2400                 :            :                 snprintf(numa_path, sizeof(numa_path), "/sys/class/net/%s/device/numa_node",
    2401                 :            :                          if_name);
    2402   [ #  #  #  # ]:          0 :                 if (access(numa_path, R_OK) != 0 || eal_parse_sysfs_value(numa_path, &numa) != 0)
    2403                 :          0 :                         dev->device.numa_node = rte_socket_id();
    2404                 :            :                 else
    2405                 :          0 :                         dev->device.numa_node = numa;
    2406                 :            :         }
    2407                 :            : 
    2408         [ #  # ]:          0 :         busy_budget = busy_budget == -1 ? ETH_AF_XDP_DFLT_BUSY_BUDGET :
    2409                 :            :                                         busy_budget;
    2410                 :            : 
    2411                 :          0 :         eth_dev = init_internals(dev, if_name, xsk_start_queue_idx,
    2412                 :            :                                  xsk_queue_cnt, shared_umem, prog_path,
    2413                 :            :                                  busy_budget, force_copy, use_cni);
    2414         [ #  # ]:          0 :         if (eth_dev == NULL) {
    2415                 :          0 :                 AF_XDP_LOG(ERR, "Failed to init internals\n");
    2416                 :          0 :                 return -1;
    2417                 :            :         }
    2418                 :            : 
    2419                 :            :         /* Register IPC callback which shares xsk fds from primary to secondary */
    2420         [ #  # ]:          0 :         if (!afxdp_dev_count) {
    2421                 :          0 :                 ret = rte_mp_action_register(ETH_AF_XDP_MP_KEY, afxdp_mp_send_fds);
    2422   [ #  #  #  # ]:          0 :                 if (ret < 0 && rte_errno != ENOTSUP) {
    2423                 :          0 :                         AF_XDP_LOG(ERR, "%s: Failed to register multi-process IPC callback: %s\n",
    2424                 :            :                                    name, strerror(rte_errno));
    2425                 :          0 :                         return -1;
    2426                 :            :                 }
    2427                 :            :         }
    2428                 :          0 :         afxdp_dev_count++;
    2429                 :            : 
    2430                 :          0 :         rte_eth_dev_probing_finish(eth_dev);
    2431                 :            : 
    2432                 :          0 :         return 0;
    2433                 :            : }
    2434                 :            : 
    2435                 :            : static int
    2436                 :          0 : rte_pmd_af_xdp_remove(struct rte_vdev_device *dev)
    2437                 :            : {
    2438                 :            :         struct rte_eth_dev *eth_dev = NULL;
    2439                 :            : 
    2440                 :          0 :         AF_XDP_LOG(INFO, "Removing AF_XDP ethdev on numa socket %u\n",
    2441                 :            :                 rte_socket_id());
    2442                 :            : 
    2443         [ #  # ]:          0 :         if (dev == NULL)
    2444                 :            :                 return -1;
    2445                 :            : 
    2446                 :            :         /* find the ethdev entry */
    2447                 :          0 :         eth_dev = rte_eth_dev_allocated(rte_vdev_device_name(dev));
    2448         [ #  # ]:          0 :         if (eth_dev == NULL)
    2449                 :            :                 return 0;
    2450                 :            : 
    2451                 :          0 :         eth_dev_close(eth_dev);
    2452         [ #  # ]:          0 :         if (afxdp_dev_count == 1)
    2453                 :          0 :                 rte_mp_action_unregister(ETH_AF_XDP_MP_KEY);
    2454                 :          0 :         afxdp_dev_count--;
    2455                 :          0 :         rte_eth_dev_release_port(eth_dev);
    2456                 :            : 
    2457                 :          0 :         return 0;
    2458                 :            : }
    2459                 :            : 
    2460                 :            : static struct rte_vdev_driver pmd_af_xdp_drv = {
    2461                 :            :         .probe = rte_pmd_af_xdp_probe,
    2462                 :            :         .remove = rte_pmd_af_xdp_remove,
    2463                 :            : };
    2464                 :            : 
    2465                 :        235 : RTE_PMD_REGISTER_VDEV(net_af_xdp, pmd_af_xdp_drv);
    2466                 :            : RTE_PMD_REGISTER_PARAM_STRING(net_af_xdp,
    2467                 :            :                               "iface=<string> "
    2468                 :            :                               "start_queue=<int> "
    2469                 :            :                               "queue_count=<int> "
    2470                 :            :                               "shared_umem=<int> "
    2471                 :            :                               "xdp_prog=<string> "
    2472                 :            :                               "busy_budget=<int> "
    2473                 :            :                               "force_copy=<int> "
    2474                 :            :                               "use_cni=<int> ");

Generated by: LCOV version 1.14