LCOV - code coverage report
Current view: top level - root/contrail/vrouter/dpdk - vr_dpdk_tapdev.c (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 17 315 5.4 %
Date: 2026-08-03 02:19:58 Functions: 3 13 23.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2016 Semihalf.
       3             :  *
       4             :  * This program is free software; you can redistribute it and/or
       5             :  * modify it under the terms of the GNU General Public License as
       6             :  * published by the Free Software Foundation version 2.
       7             :  *
       8             :  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
       9             :  * kind, whether express or implied; without even the implied warranty
      10             :  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      11             :  * GNU General Public License for more details.
      12             :  *
      13             :  * vr_dpdk_tapdev.c -- DPDK tap device
      14             :  *
      15             :  */
      16             : 
      17             : #include "vr_dpdk.h"
      18             : #include "vhost.h"
      19             : // #include "vr_packet.h"
      20             : 
      21             : #include <rte_errno.h>
      22             : #include <rte_ethdev.h>
      23             : #include <rte_port_ring.h>
      24             : #include <rte_malloc.h>
      25             : 
      26             : #include <fcntl.h>
      27             : #include <linux/if.h>
      28             : #include <linux/if_tun.h>
      29             : #include <sys/ioctl.h>
      30             : #include <sys/stat.h>
      31             : #include <sys/types.h>
      32             : #include <sys/socket.h>
      33             : #include <netinet/in.h>
      34             : #include <linux/netlink.h>
      35             : #include <linux/rtnetlink.h>
      36             : 
      37             : /*
      38             :  * vr_dpdk_tapdev_init - initializes TAP device using specified Ethernet port.
      39             :  *
      40             :  * Returns 0 on success, < 0 otherwise.
      41             :  */
      42             : int
      43           0 : vr_dpdk_tapdev_init(struct vr_interface *vif)
      44             : {
      45             :     int i, fd;
      46           0 :     struct vr_dpdk_tapdev *tapdev = NULL;
      47             :     struct ifreq ifr;
      48             :     struct sockaddr_nl tap_nl_addr;
      49             : 
      50           0 :     RTE_LOG(INFO, VROUTER, "    creating TAP device %s\n", vif->vif_name);
      51             : 
      52             :     /* If vif is vhost0, reuse previously existed slot if any. */
      53           0 :     if (vif_is_vhost(vif)) {
      54           0 :         for (i = 0; i < VR_DPDK_MAX_TAP_INTERFACES; i++) {
      55           0 :             if ((vr_dpdk.tapdevs[i].tapdev_vhost_fd > 0) &&
      56           0 :                 (!strncmp((char *)vif->vif_name, vr_dpdk.tapdevs[i].tapdev_name,
      57             :                 VR_INTERFACE_NAME_LEN - 1))) {
      58           0 :                RTE_LOG(INFO, VROUTER, "    TAP device %s already exists\n",
      59             :                        vif->vif_name);
      60           0 :                tapdev = &vr_dpdk.tapdevs[i];
      61           0 :                fd = tapdev->tapdev_fd = tapdev->tapdev_vhost_fd;
      62           0 :                goto enable_tap;
      63             :             }
      64             :         }
      65             :     }
      66             : 
      67             :     /* Find an empty TAP slot. */
      68           0 :     for (i = 0; i < VR_DPDK_MAX_TAP_INTERFACES; i++) {
      69           0 :          if (vr_dpdk.tapdevs[i].tapdev_fd <= 0) {
      70           0 :              tapdev = &vr_dpdk.tapdevs[i];
      71           0 :              break;
      72             :          }
      73             :     }
      74             : 
      75           0 :     if (tapdev == NULL) {
      76           0 :         RTE_LOG(ERR, VROUTER, "    error allocating TAP device %s\n",
      77             :             vif->vif_name);
      78           0 :         return -ENOMEM;
      79             :     }
      80             : 
      81             :     /* Open TUN device. */
      82           0 :     fd = open("/dev/net/tun", O_RDWR | O_NONBLOCK);
      83           0 :     if (fd == -1) {
      84           0 :         RTE_LOG(ERR, VROUTER, "    error opening TAP device %s: %s (%d)\n",
      85             :             vif->vif_name, rte_strerror(errno), errno);
      86           0 :         goto error;
      87             :     }
      88             : 
      89             :     /* Create TAP interface. */
      90           0 :     memset(&ifr, 0, sizeof(ifr));
      91           0 :     memcpy(ifr.ifr_name, (char *)vif->vif_name, sizeof(ifr.ifr_name) - 1);
      92           0 :     if (vif_is_vhost(vif))
      93           0 :         tapdev->tapdev_vhost_fd = fd;
      94             :     else
      95           0 :         tapdev->tapdev_vhost_fd = -1;
      96           0 :     ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
      97           0 :     if (ioctl(fd, TUNSETIFF, &ifr) < 0) {
      98           0 :         RTE_LOG(ERR, VROUTER, "    error creating TAP interface %s: %s (%d)\n",
      99             :             vif->vif_name, rte_strerror(errno), errno);
     100           0 :         goto error;
     101             :     }
     102             : 
     103           0 : enable_tap:
     104             :     /* Enable TAP device. */
     105           0 :     vif->vif_os = tapdev;
     106           0 :     tapdev->tapdev_vif = vif;
     107           0 :     memset(tapdev->tapdev_name, 0, VR_INTERFACE_NAME_LEN);
     108           0 :     memcpy(tapdev->tapdev_name, (char *)vif->vif_name,
     109             :            VR_INTERFACE_NAME_LEN - 1);
     110           0 :     synchronize_rcu();
     111           0 :     tapdev->tapdev_fd = fd;
     112             : 
     113             :     /* Create tap netlink socket for link up/down mtu change notifications */
     114           0 :     if(vif_is_vhost(vif) && (vr_dpdk.tap_nl_fd <= 0)) {
     115           0 :         vr_dpdk.tap_nl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
     116           0 :         if (vr_dpdk.tap_nl_fd < 0) {
     117           0 :             RTE_LOG(ERR, VROUTER, "    error creating tap netlink socket\n");
     118           0 :             goto error;
     119             :         }
     120             : 
     121           0 :         memset ((void *) &tap_nl_addr, 0, sizeof (tap_nl_addr));
     122           0 :         tap_nl_addr.nl_family = AF_NETLINK;
     123           0 :         tap_nl_addr.nl_pid = getpid ();
     124           0 :         tap_nl_addr.nl_groups = RTMGRP_LINK;
     125           0 :         if (bind(vr_dpdk.tap_nl_fd,
     126             :                (struct sockaddr *) &tap_nl_addr, sizeof (tap_nl_addr)) < 0) {
     127           0 :             RTE_LOG(ERR, VROUTER, "    error binding tap netlink socket\n");
     128           0 :             goto error;
     129             :         }
     130             :     }
     131             : 
     132           0 :     return 0;
     133             : 
     134           0 : error:
     135           0 :     if (tapdev->tapdev_fd > 0) {
     136           0 :         close(tapdev->tapdev_fd);
     137           0 :         tapdev->tapdev_fd = -1;
     138             :     }
     139             : 
     140           0 :     if (vr_dpdk.tap_nl_fd > 0) {
     141           0 :         close(vr_dpdk.tap_nl_fd);
     142           0 :         vr_dpdk.tap_nl_fd = -1;
     143             :     }
     144             : 
     145           0 :     return -EINVAL;
     146             : }
     147             : 
     148             : /*
     149             :  * vr_dpdk_tapdev_release - release TAP device.
     150             :  *
     151             :  * Returns 0 on success, < 0 otherwise.
     152             :  */
     153             : int
     154          49 : vr_dpdk_tapdev_release(struct vr_interface *vif)
     155             : {
     156             :     unsigned lcore_id;
     157             :     struct rte_mbuf *mbuf;
     158          49 :     struct vr_dpdk_tapdev *tapdev = vif->vif_os;
     159             :     int fd;
     160             : 
     161          49 :     if (tapdev != NULL)
     162           0 :         fd = tapdev->tapdev_fd;
     163             :     else
     164          49 :         return 0;
     165             : 
     166           0 :     RTE_LOG(INFO, VROUTER, "    releasing vif %u TAP device %s\n",
     167             :             vif->vif_idx, vif->vif_name);
     168             : 
     169           0 :     if (fd > 0) {
     170           0 :         tapdev->tapdev_fd = -1;
     171           0 :         synchronize_rcu();
     172           0 :         if (tapdev->tapdev_vhost_fd < 0)
     173           0 :             close(fd);
     174             :     }
     175             : 
     176           0 :     vif->vif_os = NULL;
     177           0 :     tapdev->tapdev_vif = NULL;
     178             : 
     179             :     /* Drop RX and TX mbufs. */
     180           0 :     if (tapdev->tapdev_rx_ring) {
     181           0 :         while (rte_ring_sc_dequeue(tapdev->tapdev_rx_ring,
     182           0 :                     (void **)&mbuf) == 0) {
     183           0 :             rte_pktmbuf_free(mbuf);
     184             :         }
     185             :     }
     186             : 
     187           0 :     RTE_LCORE_FOREACH(lcore_id) {
     188           0 :         if (tapdev->tapdev_tx_rings[lcore_id]) {
     189           0 :             while (rte_ring_sc_dequeue(tapdev->tapdev_tx_rings[lcore_id],
     190           0 :                         (void **)&mbuf) == 0) {
     191           0 :                 rte_pktmbuf_free(mbuf);
     192             :             }
     193             :         }
     194             :     }
     195             : 
     196           0 :     return 0;
     197             : }
     198             : 
     199             : /*
     200             :  * dpdk_tapdev_rx_queue_release - release TAP RX queue.
     201             :  */
     202             : static void
     203           0 : dpdk_tapdev_rx_queue_release(unsigned lcore_id,
     204             :         unsigned queue_index __attribute__((unused)),
     205             :         struct vr_interface *vif)
     206             : {
     207           0 :     struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
     208           0 :     struct vr_dpdk_queue *rx_queue = &lcore->lcore_rx_queues[vif->vif_idx];
     209           0 :     struct vr_dpdk_queue_params *rx_queue_params
     210           0 :                         = &lcore->lcore_rx_queue_params[vif->vif_idx];
     211             : 
     212             :     /* Free the queue. */
     213           0 :     if (rx_queue->rxq_ops.f_free(rx_queue->q_queue_h)) {
     214           0 :         RTE_LOG(ERR, VROUTER, "    error freeing lcore %u TAP device RX queue\n",
     215             :                     lcore_id);
     216             :     }
     217             : 
     218             :     /* Reset the queue. */
     219           0 :     vrouter_put_interface(rx_queue->q_vif);
     220           0 :     memset(rx_queue, 0, sizeof(*rx_queue));
     221           0 :     memset(rx_queue_params, 0, sizeof(*rx_queue_params));
     222           0 : }
     223             : 
     224             : 
     225             : /*
     226             :  * vr_dpdk_tapdev_rx_queue_init - init TAP RX queue.
     227             :  *
     228             :  * Returns queue pointer on success, NULL otherwise.
     229             :  */
     230             : struct vr_dpdk_queue *
     231           0 : vr_dpdk_tapdev_rx_queue_init(unsigned lcore_id, struct vr_interface *vif,
     232             :     unsigned queue_id)
     233             : {
     234           0 :     struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
     235           0 :     const unsigned socket_id = rte_lcore_to_socket_id(lcore_id);
     236           0 :     unsigned vif_idx = vif->vif_idx;
     237           0 :     struct vr_dpdk_tapdev *tapdev = vif->vif_os;
     238           0 :     struct vr_dpdk_queue *rx_queue = &lcore->lcore_rx_queues[vif_idx];
     239           0 :     struct vr_dpdk_queue_params *rx_queue_params
     240             :                     = &lcore->lcore_rx_queue_params[vif_idx];
     241             : 
     242             :     /* Init queue. */
     243           0 :     rx_queue->rxq_ops = rte_port_ring_reader_ops;
     244           0 :     rx_queue->q_queue_h = NULL;
     245           0 :     rx_queue->q_vif = vrouter_get_interface(vif->vif_rid, vif_idx);
     246             : 
     247             :     /* Allocate RX ring if needed. */
     248           0 :     if (tapdev->tapdev_rx_ring == NULL) {
     249           0 :         tapdev->tapdev_rx_ring = vr_dpdk_ring_allocate(lcore_id,
     250             :             "tapdev_rx_ring", vr_dpdk_rx_ring_sz,
     251             :             RING_F_SP_ENQ | RING_F_SC_DEQ);
     252           0 :         if (tapdev->tapdev_rx_ring == NULL)
     253           0 :             goto error;
     254             :     }
     255             : 
     256             :     /* Create the queue. */
     257           0 :     struct rte_port_ring_reader_params reader_params = {
     258           0 :         .ring = tapdev->tapdev_rx_ring,
     259             :     };
     260           0 :     rx_queue->q_queue_h = rx_queue->rxq_ops.f_create(&reader_params,
     261             :                                                         socket_id);
     262           0 :     if (rx_queue->q_queue_h == NULL)
     263           0 :         goto error;
     264             : 
     265           0 :     rx_queue->vring_queue_id = queue_id;
     266             :     /* Store queue params. */
     267           0 :     rx_queue_params->qp_release_op = &dpdk_tapdev_rx_queue_release;
     268           0 :     rx_queue_params->qp_ring.ring_p = tapdev->tapdev_rx_ring;
     269             : 
     270           0 :     return rx_queue;
     271             : 
     272           0 : error:
     273           0 :     RTE_LOG(ERR, VROUTER,
     274             :         "    error initializing tapdev %s RX queue\n", vif->vif_name);
     275           0 :     return NULL;
     276             : }
     277             : 
     278             : /*
     279             :  * dpdk_tapdev_tx_queue_release - release TAP TX queue.
     280             :  */
     281             : static void
     282           0 : dpdk_tapdev_tx_queue_release(unsigned lcore_id, unsigned queue_index,
     283             :         struct vr_interface *vif)
     284             : {
     285           0 :     struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
     286           0 :     struct vr_dpdk_queue *tx_queue =
     287           0 :         &lcore->lcore_tx_queues[vif->vif_idx][queue_index];
     288           0 :     struct vr_dpdk_queue_params *tx_queue_params
     289           0 :         = &lcore->lcore_tx_queue_params[vif->vif_idx][queue_index];
     290             : 
     291           0 :     tx_queue->txq_ops.f_tx = NULL;
     292             :     rte_wmb();
     293             : 
     294             :     /* Flush and free the queue. */
     295           0 :     if (tx_queue->txq_ops.f_free(tx_queue->q_queue_h)) {
     296           0 :         RTE_LOG(ERR, VROUTER, "    error freeing lcore %u TAP device TX queue\n",
     297             :                     lcore_id);
     298             :     }
     299             : 
     300             :     /* Reset the queue. */
     301           0 :     vrouter_put_interface(tx_queue->q_vif);
     302           0 :     memset(tx_queue, 0, sizeof(*tx_queue));
     303           0 :     memset(tx_queue_params, 0, sizeof(*tx_queue_params));
     304           0 : }
     305             : 
     306             : /*
     307             :  * vr_dpdk_tapdev_tx_queue_init - init TAP TX queue.
     308             :  *
     309             :  * Returns queue pointer on success, NULL otherwise.
     310             :  */
     311             : struct vr_dpdk_queue *
     312           0 : vr_dpdk_tapdev_tx_queue_init(unsigned lcore_id, struct vr_interface *vif,
     313             :     unsigned queue_id)
     314             : {
     315           0 :     struct vr_dpdk_lcore *lcore = vr_dpdk.lcores[lcore_id];
     316           0 :     const unsigned socket_id = rte_lcore_to_socket_id(lcore_id);
     317           0 :     unsigned vif_idx = vif->vif_idx;
     318           0 :     struct vr_dpdk_tapdev *tapdev = vif->vif_os;
     319           0 :     struct vr_dpdk_queue *tx_queue = &lcore->lcore_tx_queues[vif_idx][0];
     320           0 :     struct vr_dpdk_queue_params *tx_queue_params
     321             :                     = &lcore->lcore_tx_queue_params[vif_idx][0];
     322             : 
     323             :     /* Init queue. */
     324           0 :     tx_queue->txq_ops = rte_port_ring_writer_ops;
     325           0 :     tx_queue->q_queue_h = NULL;
     326           0 :     tx_queue->q_vif = vrouter_get_interface(vif->vif_rid, vif_idx);
     327             : 
     328             :     /* Allocate TX ring if needed. */
     329           0 :     if (tapdev->tapdev_tx_rings[lcore_id] == NULL) {
     330           0 :         tapdev->tapdev_tx_rings[lcore_id] = vr_dpdk_ring_allocate(lcore_id,
     331             :             "tapdev_tx_ring", vr_dpdk_tx_ring_sz,
     332             :             RING_F_SP_ENQ | RING_F_SC_DEQ);
     333           0 :         if (tapdev->tapdev_tx_rings[lcore_id] == NULL)
     334           0 :             goto error;
     335             :     }
     336             : 
     337             :     /* Create the queue. */
     338           0 :     struct rte_port_ring_writer_params writer_params = {
     339           0 :         .ring = tapdev->tapdev_tx_rings[lcore_id],
     340             :         .tx_burst_sz = VR_DPDK_TX_BURST_SZ,
     341             :     };
     342           0 :     tx_queue->q_queue_h = tx_queue->txq_ops.f_create(&writer_params,
     343             :                                                         socket_id);
     344           0 :     if (tx_queue->q_queue_h == NULL)
     345           0 :         goto error;
     346             : 
     347             :     /* Store queue params. */
     348           0 :     tx_queue_params->qp_release_op = &dpdk_tapdev_tx_queue_release;
     349           0 :     tx_queue_params->qp_ring.ring_p = tapdev->tapdev_tx_rings[lcore_id];
     350             : 
     351           0 :     return tx_queue;
     352             : 
     353           0 : error:
     354           0 :     RTE_LOG(ERR, VROUTER,
     355             :         "    error initializing tapdev %s TX queue\n", vif->vif_name);
     356           0 :     return NULL;
     357             : }
     358             : 
     359             : /*
     360             :  * vr_dpdk_tapdev_rx_burst - RX a burst of packets from the TAP device.
     361             :  *
     362             :  * Returns number of actual packets received, or 0 otherwise.
     363             :  */
     364             : unsigned
     365           0 : vr_dpdk_tapdev_rx_burst(struct vr_dpdk_tapdev *tapdev, struct rte_mbuf **mbufs,
     366             :     unsigned num, int datapath)
     367             : {
     368             :     int i, fd;
     369           0 :     unsigned ret = 0;
     370             :     struct rte_mbuf *mbuf;
     371             :     struct vr_interface *vif;
     372             :     struct vr_interface_stats *stats;
     373           0 :     unsigned lcore_id = rte_lcore_id();
     374             :     ssize_t len;
     375             : 
     376           0 :     fd = tapdev->tapdev_fd;
     377           0 :     if (unlikely(fd <= 0))
     378           0 :         return 0;
     379             : 
     380           0 :     for (i = 0; i < num; i++) {
     381           0 :         vif = tapdev->tapdev_vif;
     382             : 
     383           0 :         if (datapath && vif_is_vhost(vif))
     384           0 :             continue;
     385             : 
     386           0 :         stats = vif_get_stats(vif, lcore_id);
     387             : 
     388           0 :         mbuf = rte_pktmbuf_alloc(vr_dpdk.rss_mempool);
     389           0 :         if (unlikely(mbuf == NULL)) {
     390           0 :             stats->vis_dev_inombufs++;
     391           0 :             break;
     392             :         }
     393             : 
     394             :         /* TODO: need a separate syscall counter for devices. */
     395           0 :         stats->vis_port_isyscalls++;
     396           0 :         len = read(fd, rte_pktmbuf_mtod(mbuf, void *),
     397           0 :                 (mbuf->buf_len - rte_pktmbuf_headroom(mbuf)));
     398           0 :         if (unlikely(len <= 0)) {
     399             :             /* No packets to receive. */
     400           0 :             rte_pktmbuf_free(mbuf);
     401           0 :             break;
     402             :         } else {
     403           0 :             ret++;
     404             : 
     405           0 :             mbuf->pkt_len = mbuf->data_len = len;
     406           0 :             stats->vis_dev_ibytes += len;
     407           0 :             stats->vis_dev_ipackets++;
     408           0 :             mbufs[i] = mbuf;
     409             :        }
     410             :    }
     411           0 :    return ret;
     412             : }
     413             : 
     414             : /*
     415             :  * vr_dpdk_tapdev_dequeue_burst - dequeue a burst of packets from the TAP device.
     416             :  *
     417             :  * Returns number of actual packets dequeued, or 0 otherwise.
     418             :  */
     419             : unsigned
     420           0 : vr_dpdk_tapdev_dequeue_burst(struct vr_dpdk_tapdev *tapdev, struct rte_mbuf **mbufs,
     421             :     unsigned num)
     422             : {
     423             :     int fd;
     424             : 
     425           0 :     fd = tapdev->tapdev_fd;
     426           0 :     if (unlikely(fd <= 0))
     427           0 :         return 0;
     428             : 
     429             :     /* Try to RX from the TAP. */
     430           0 :     if (likely(tapdev->tapdev_rx_ring != NULL)) {
     431           0 :         return rte_ring_sc_dequeue_burst(tapdev->tapdev_rx_ring,
     432             :                 (void **)mbufs, num, NULL);
     433             :     }
     434           0 :     return 0;
     435             : }
     436             : 
     437             : /*
     438             :  * vr_dpdk_tapdev_tx_burst - TX a burst of packets to the TAP device.
     439             :  *
     440             :  * Returns number of actual packets sent, or 0 otherwise.
     441             :  */
     442             : unsigned
     443           0 : vr_dpdk_tapdev_tx_burst(struct vr_dpdk_tapdev *tapdev, struct rte_mbuf **mbufs,
     444             :         unsigned num, int datapath)
     445             : {
     446             :     int i, fd;
     447           0 :     unsigned ret = 0;
     448             :     struct rte_mbuf *mbuf;
     449             :     struct vr_interface *vif;
     450             :     struct vr_interface_stats *stats;
     451           0 :     unsigned lcore_id = rte_lcore_id();
     452             :     ssize_t len;
     453             : 
     454           0 :     fd = tapdev->tapdev_fd;
     455           0 :     if (unlikely(fd <= 0))
     456           0 :         return 0;
     457             : 
     458           0 :     for (i = 0; i < num; i++) {
     459           0 :         vif = tapdev->tapdev_vif;
     460             : 
     461           0 :         if (datapath && vif_is_vhost(vif))
     462           0 :             continue;
     463             : 
     464           0 :         stats = vif_get_stats(vif, lcore_id);
     465           0 :         mbuf = mbufs[i];
     466             : 
     467             :         /* TODO: need a separate syscall counter for devices. */
     468           0 :         stats->vis_port_osyscalls++;
     469           0 :         len = write(fd, rte_pktmbuf_mtod(mbufs[i], void *),
     470           0 :             rte_pktmbuf_data_len(mbuf));
     471           0 :         if (unlikely(len != (ssize_t)rte_pktmbuf_data_len(mbufs[i]))) {
     472             :             /* Error sending packet. */
     473           0 :             stats->vis_dev_oerrors++;
     474           0 :             break;
     475             :         } else {
     476           0 :             stats->vis_dev_obytes += len;
     477           0 :             stats->vis_dev_opackets++;
     478           0 :             ret++;
     479             :         }
     480           0 :         rte_pktmbuf_free(mbuf);
     481             :     }
     482             : 
     483           0 :    return ret;
     484             : }
     485             : 
     486             : /*
     487             :  * vr_dpdk_tapdev_enqueue_burst - enqueue a burst of packets to the TAP device.
     488             :  *
     489             :  * Returns number of actual packets enqueued, or 0 otherwise.
     490             :  */
     491             : unsigned
     492           0 : vr_dpdk_tapdev_enqueue_burst(struct vr_dpdk_tapdev *tapdev, struct rte_mbuf **mbufs,
     493             :         unsigned num)
     494             : {
     495             :     int fd;
     496           0 :     unsigned lcore_id = rte_lcore_id();
     497             : 
     498           0 :     fd = tapdev->tapdev_fd;
     499           0 :     if (unlikely(fd <= 0))
     500           0 :         return 0;
     501             : 
     502           0 :     if (likely(tapdev->tapdev_tx_rings[lcore_id] != NULL)) {
     503           0 :         return rte_ring_sp_enqueue_burst(tapdev->tapdev_tx_rings[lcore_id],
     504             :             (void **)mbufs, num, NULL);
     505             :     }
     506             : 
     507           0 :    return 0;
     508             : }
     509             : 
     510             : /*
     511             :  * vr_dpdk_tapdev_rxtx -- RX/TX to/from all the TAP devices.
     512             :  *
     513             :  * Returns total number of packets processed.
     514             :  */
     515             : uint64_t
     516     2825387 : vr_dpdk_tapdev_rxtx(void)
     517             : {
     518             :     int i, fd;
     519             :     struct vr_dpdk_tapdev *tapdev;
     520             :     struct rte_mbuf *mbuf;
     521             :     struct vr_interface *vif;
     522             :     struct vr_interface_stats *stats;
     523             :     unsigned lcore_id;
     524     2825387 :     uint64_t total_pkts = 0;
     525             :     unsigned nb_pkts;
     526             : 
     527    48031579 :     for (i = 0; i < VR_DPDK_MAX_TAP_INTERFACES; i++) {
     528    45206192 :         tapdev = &vr_dpdk.tapdevs[i];
     529             : 
     530    45206192 :         fd = tapdev->tapdev_fd;
     531    45206192 :         if (fd > 0) {
     532           0 :             vif = tapdev->tapdev_vif;
     533           0 :             stats = vif_get_stats(vif, rte_lcore_id());
     534             : 
     535             :             /* Try to RX from the TAP. */
     536           0 :             if (likely(tapdev->tapdev_rx_ring != NULL)) {
     537           0 :                 nb_pkts = vr_dpdk_tapdev_rx_burst(tapdev, &mbuf, 1,
     538             :                                                   VR_DPDK_MGMTPATH);
     539             : 
     540           0 :                 if (likely(nb_pkts > 0)) {
     541           0 :                     total_pkts++;
     542           0 :                     if (unlikely(rte_ring_sp_enqueue(tapdev->tapdev_rx_ring,
     543             :                         mbuf) != 0)) {
     544           0 :                         rte_pktmbuf_free(mbuf);
     545           0 :                         stats->vis_dev_ierrors++;
     546             :                     }
     547             :                 }
     548             :             }
     549             : 
     550             :             /* Now try to TX to the TAP. */
     551           0 :             RTE_LCORE_FOREACH(lcore_id) {
     552           0 :                 if (likely(tapdev->tapdev_tx_rings[lcore_id] != NULL)) {
     553           0 :                     if (likely(rte_ring_sc_dequeue(
     554             :                         tapdev->tapdev_tx_rings[lcore_id],
     555             :                         (void **)&mbuf) == 0))
     556             :                     {
     557           0 :                         total_pkts++;
     558           0 :                         nb_pkts = vr_dpdk_tapdev_tx_burst(tapdev, &mbuf, 1,
     559             :                                                           VR_DPDK_MGMTPATH);
     560             : 
     561           0 :                         if (likely(nb_pkts > 0)) {
     562           0 :                             total_pkts++;
     563             :                         } else {
     564           0 :                             rte_pktmbuf_free(mbuf);
     565             :                         }
     566             :                     }
     567             :                 } /* if TAP TX ring. */
     568             :             } /* for each lcore. */
     569             :         } /* if TAP FD. */
     570             :     } /* for all TAP devices. */
     571             : 
     572     2825387 :     return total_pkts;
     573             : }
     574             : 
     575           0 : static void vr_dpdk_handle_vhost0_notification(uint32_t mtu, uint32_t if_up)
     576             : {
     577             :     static int vhost_mtu = 1500; /* Default MTU */
     578             : 
     579             :     struct vr_interface *vif;
     580           0 :     struct vrouter *router = vrouter_get(0);
     581           0 :     struct vr_dpdk_ethdev *ethdev = NULL;
     582           0 :     uint8_t slave_port_id, port_id = 0;
     583           0 :     int ret = 0, i;
     584             : 
     585           0 :     if (router->vr_eth_if[0])
     586           0 :         ethdev = (struct vr_dpdk_ethdev *)router->vr_eth_if[0]->vif_os;
     587             : 
     588           0 :     if (ethdev == NULL) {
     589           0 :         RTE_LOG(ERR, VROUTER, "%s error: NULL ethdev\n", __func__);
     590           0 :         return;
     591             :     }
     592             : 
     593           0 :     port_id = ethdev->ethdev_port_id;
     594             : 
     595           0 :     if (vhost_mtu != mtu) {
     596             :         /*
     597             :          * TODO: DPDK bond PMD does not implement mtu_set op, so we need to
     598             :          * set the MTU manually for all the slaves.
     599             :          */
     600           0 :         if (ethdev->ethdev_nb_slaves > 0) {
     601           0 :             RTE_LOG(INFO, VROUTER, "Changing bond eth device %" PRIu8 " MTU\n", port_id);
     602             : 
     603           0 :             rte_eth_devices[port_id].data->mtu = mtu;
     604           0 :             for (i = 0; i < ethdev->ethdev_nb_slaves; i++) {
     605           0 :                 slave_port_id = ethdev->ethdev_slaves[i];
     606           0 :                 RTE_LOG(INFO, VROUTER,
     607             :                         "    changing bond member eth device %" PRIu8 " MTU to %u\n",
     608             :                         slave_port_id, mtu);
     609             : 
     610           0 :                 ret =  rte_eth_dev_set_mtu(slave_port_id, mtu);
     611           0 :                 if (ret < 0) {
     612             :                     /*
     613             :                      * Do not return error as some NICs (such as X710) do not allow setting
     614             :                      * the MTU while the NIC is up and running. The max_rx_pkt_len is anyway
     615             :                      * set to support jumbo frames, so continue further here to set vif_mtu.
     616             :                      */
     617           0 :                     RTE_LOG(DEBUG, VROUTER,
     618             :                             "    error changing bond member eth device %" PRIu8 " MTU: %s (%d)\n",
     619             :                             slave_port_id, rte_strerror(-ret), -ret);
     620             :                 }
     621             :             }
     622             :         } else {
     623           0 :             RTE_LOG(INFO, VROUTER, "Changing eth device MTU to %u\n", mtu);
     624             : 
     625           0 :             rte_eth_devices[port_id].data->mtu = mtu;
     626           0 :             ret =  rte_eth_dev_set_mtu(port_id, mtu);
     627           0 :             if (ret < 0) {
     628             :                 /*
     629             :                  * Do not return error as some NICs (such as X710) do not allow setting
     630             :                  * the MTU while the NIC is up and running. The max_rx_pkt_len is anyway
     631             :                  * set to support jumbo frames, so continue further here to set vif_mtu.
     632             :                  */
     633           0 :                 RTE_LOG(DEBUG, VROUTER,
     634             :                         "Error changing eth device MTU: %s (%d)\n",
     635             :                         rte_strerror(-ret), -ret);
     636             :             }
     637             :         }
     638             : 
     639             :         /* On success, inform vrouter about new MTU */
     640           0 :         for (i = 0; i < router->vr_max_interfaces; i++) {
     641           0 :             vif = __vrouter_get_interface(router, i);
     642           0 :             if (vif && (vif->vif_type == VIF_TYPE_PHYSICAL)) {
     643             :                /* Ethernet header size */
     644           0 :                mtu += sizeof(struct vr_eth);
     645           0 :                if (vr_dpdk.vlan_tag != VLAN_ID_INVALID) {
     646             :                    /* 802.1q header size */
     647           0 :                    mtu += sizeof(uint32_t);
     648             :                }
     649           0 :                vif->vif_mtu = mtu;
     650           0 :                if (vif->vif_bridge[0])
     651           0 :                    vif->vif_bridge[0]->vif_mtu = mtu;
     652             :             }
     653             :         }
     654             : 
     655             :         /* Save the new MTU */
     656           0 :         vhost_mtu = mtu;
     657             :     }
     658             : 
     659             : }
     660             : 
     661     2825387 : void vr_dpdk_tapdev_handle_notifications(void)
     662             : {
     663             :     int32_t status;
     664             :     char buf[4096];
     665     2825387 :     struct iovec iov = {buf, sizeof buf};
     666             :     struct sockaddr_nl snl;
     667     2825387 :     struct msghdr msg = {(void *) &snl, sizeof snl, &iov, 1, NULL, 0, 0};
     668             :     struct nlmsghdr *h;
     669             :     struct ifinfomsg *ifi;
     670             : 
     671     2825387 :     status = recvmsg(vr_dpdk.tap_nl_fd, &msg, MSG_DONTWAIT);
     672     2825387 :     if (status <= 0) {
     673             :         /* Nothing to process */
     674     2825387 :         return;
     675             :     }
     676             : 
     677           0 :     for (h = (struct nlmsghdr *) buf; NLMSG_OK (h, (unsigned int) status);
     678           0 :          h = NLMSG_NEXT (h, status))
     679             :     {
     680             :         /* Finish reading */
     681           0 :         if (h->nlmsg_type == NLMSG_DONE)
     682           0 :           return;
     683             : 
     684             :         /* Message is some kind of error */
     685           0 :         if (h->nlmsg_type == NLMSG_ERROR) {
     686           0 :             RTE_LOG(ERR, VROUTER, "read_netlink: Message error\n");
     687           0 :             return; /* Error */
     688             :         }
     689             : 
     690           0 :         if (h->nlmsg_type == RTM_NEWLINK) {
     691             :             int len;
     692             :             struct rtattr *attribute;
     693           0 :             char *ifname = NULL;
     694           0 :             uint32_t mtu = 0;
     695             : 
     696           0 :             ifi = NLMSG_DATA (h);
     697             : 
     698           0 :             len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
     699             : 
     700             :             /* loop over all attributes for the NEWLINK message */
     701           0 :             for (attribute = IFLA_RTA(ifi); RTA_OK(attribute, len);
     702           0 :                                            attribute = RTA_NEXT(attribute, len))
     703             :             {
     704           0 :                 switch(attribute->rta_type) {
     705           0 :                     case IFLA_IFNAME:
     706           0 :                         ifname = (char*) RTA_DATA(attribute);
     707           0 :                         break;
     708           0 :                     case IFLA_MTU:
     709           0 :                         mtu = *(uint32_t*) RTA_DATA(attribute);
     710           0 :                         break;
     711           0 :                     default:
     712           0 :                         break;
     713             :                 }
     714             :             }
     715             : 
     716           0 :             if (ifname && (strncmp(ifname, VHOST_IFNAME, (strlen(VHOST_IFNAME) + 1)) == 0)) {
     717           0 :                 RTE_LOG(INFO, VROUTER, "Notification received for vhost0\n");
     718           0 :                 vr_dpdk_handle_vhost0_notification
     719           0 :                                  (mtu, (ifi->ifi_flags & IFF_UP));
     720             :             }
     721             :         }
     722             :     }
     723             : }

Generated by: LCOV version 1.14