LCOV - code coverage report
Current view: top level - vnet/devices/tap - tap.c (source / functions) Hit Total Coverage
Test: coverage-filtered.info Lines: 291 557 52.2 %
Date: 2023-10-26 01:39:38 Functions: 12 18 66.7 %

          Line data    Source code
       1             : /*
       2             :  *------------------------------------------------------------------
       3             :  * Copyright (c) 2017 Cisco and/or its affiliates.
       4             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5             :  * you may not use this file except in compliance with the License.
       6             :  * You may obtain a copy of the License at:
       7             :  *
       8             :  *     http://www.apache.org/licenses/LICENSE-2.0
       9             :  *
      10             :  * Unless required by applicable law or agreed to in writing, software
      11             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             :  * See the License for the specific language governing permissions and
      14             :  * limitations under the License.
      15             :  *------------------------------------------------------------------
      16             :  */
      17             : 
      18             : #define _GNU_SOURCE
      19             : #include <sys/types.h>
      20             : #include <sys/stat.h>
      21             : #include <sys/socket.h>
      22             : #include <fcntl.h>
      23             : #include <net/if.h>
      24             : #include <linux/if_tun.h>
      25             : #include <sys/ioctl.h>
      26             : #include <linux/ethtool.h>
      27             : #include <linux/sockios.h>
      28             : #include <sys/eventfd.h>
      29             : #include <net/if_arp.h>
      30             : #include <limits.h>
      31             : 
      32             : #include <linux/netlink.h>
      33             : #include <linux/rtnetlink.h>
      34             : 
      35             : #include <vlib/vlib.h>
      36             : #include <vlib/physmem.h>
      37             : #include <vlib/unix/unix.h>
      38             : #include <vppinfra/linux/netns.h>
      39             : #include <vnet/ethernet/ethernet.h>
      40             : #include <vnet/ip/ip4_packet.h>
      41             : #include <vnet/ip/ip6_packet.h>
      42             : #include <vnet/devices/netlink.h>
      43             : #include <vnet/devices/virtio/virtio.h>
      44             : #include <vnet/devices/tap/tap.h>
      45             : 
      46             : tap_main_t tap_main;
      47             : 
      48             : #define tap_log_err(dev, f, ...)                        \
      49             :   vlib_log (VLIB_LOG_LEVEL_ERR, tap_main.log_default, "tap%u: " f, dev->dev_instance, ## __VA_ARGS__)
      50             : #define tap_log_dbg(dev, f, ...)                        \
      51             :   vlib_log (VLIB_LOG_LEVEL_DEBUG, tap_main.log_default, "tap%u: " f, dev->dev_instance, ## __VA_ARGS__)
      52             : 
      53             : #define _IOCTL(fd,a,...) \
      54             :   if (ioctl (fd, a, __VA_ARGS__) < 0) \
      55             :     { \
      56             :       err = clib_error_return_unix (0, "ioctl(" #a ")"); \
      57             :       tap_log_err (vif, "%U", format_clib_error, err); \
      58             :       goto error; \
      59             :     }
      60             : 
      61        8063 : VNET_HW_INTERFACE_CLASS (tun_device_hw_interface_class, static) = {
      62             :   .name = "tun-device",
      63             :   .flags = VNET_HW_INTERFACE_CLASS_FLAG_P2P,
      64             :   .tx_hash_fn_type = VNET_HASH_FN_TYPE_IP,
      65             : };
      66             : 
      67             : #define TUN_MAX_PACKET_BYTES     65355
      68             : #define TUN_MIN_PACKET_BYTES     64
      69             : #define TUN_DEFAULT_PACKET_BYTES 1500
      70             : 
      71             : static u32
      72         504 : virtio_eth_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hi,
      73             :                         u32 flags)
      74             : {
      75             :   /* nothing for now */
      76             :   //TODO On MTU change call vnet_netlink_set_if_mtu
      77         504 :   return 0;
      78             : }
      79             : 
      80             : static clib_error_t *
      81           0 : virtio_eth_set_max_frame_size (vnet_main_t *vnm, vnet_hw_interface_t *hi,
      82             :                                u32 frame_size)
      83             : {
      84             :   /* nothing for now */
      85           0 :   return 0;
      86             : }
      87             : 
      88             : #define TAP_MAX_INSTANCE 1024
      89             : 
      90             : static void
      91         372 : tap_free (vlib_main_t * vm, virtio_if_t * vif)
      92             : {
      93         372 :   virtio_main_t *mm = &virtio_main;
      94         372 :   tap_main_t *tm = &tap_main;
      95         372 :   clib_error_t *err = 0;
      96             :   int i;
      97             : 
      98         372 :   virtio_pre_input_node_disable (vm, vif);
      99             : 
     100             :   /* *INDENT-OFF* */
     101         744 :   vec_foreach_index (i, vif->vhost_fds) if (vif->vhost_fds[i] != -1)
     102         372 :     close (vif->vhost_fds[i]);
     103         744 :   vec_foreach_index (i, vif->rxq_vrings)
     104         372 :     virtio_vring_free_rx (vm, vif, RX_QUEUE (i));
     105         744 :   vec_foreach_index (i, vif->txq_vrings)
     106         372 :     virtio_vring_free_tx (vm, vif, TX_QUEUE (i));
     107             :   /* *INDENT-ON* */
     108             : 
     109         372 :   if (vif->tap_fds)
     110             :     {
     111         372 :       _IOCTL (vif->tap_fds[0], TUNSETPERSIST, (void *) (uintptr_t) 0);
     112         372 :       tap_log_dbg (vif, "TUNSETPERSIST: unset");
     113             :     }
     114           0 : error:
     115         744 :   vec_foreach_index (i, vif->tap_fds) close (vif->tap_fds[i]);
     116             : 
     117         372 :   vec_free (vif->tap_fds);
     118         372 :   vec_free (vif->vhost_fds);
     119         372 :   vec_free (vif->rxq_vrings);
     120         372 :   vec_free (vif->txq_vrings);
     121         372 :   vec_free (vif->host_if_name);
     122         372 :   vec_free (vif->net_ns);
     123         372 :   vec_free (vif->host_bridge);
     124         372 :   clib_error_free (vif->error);
     125             : 
     126         372 :   tm->tap_ids = clib_bitmap_set (tm->tap_ids, vif->id, 0);
     127         372 :   clib_memset (vif, 0, sizeof (*vif));
     128         372 :   pool_put (mm->interfaces, vif);
     129         372 : }
     130             : 
     131             : void
     132         372 : tap_create_if (vlib_main_t * vm, tap_create_if_args_t * args)
     133             : {
     134         372 :   vlib_thread_main_t *thm = vlib_get_thread_main ();
     135         372 :   vlib_physmem_main_t *vpm = &vm->physmem_main;
     136         372 :   vnet_main_t *vnm = vnet_get_main ();
     137         372 :   virtio_main_t *vim = &virtio_main;
     138         372 :   tap_main_t *tm = &tap_main;
     139             :   vnet_sw_interface_t *sw;
     140             :   vnet_hw_interface_t *hw;
     141             :   vnet_hw_if_caps_change_t cc;
     142             :   int i, num_vhost_queues;
     143         372 :   int old_netns_fd = -1;
     144         372 :   struct ifreq ifr = {.ifr_flags = IFF_NO_PI | IFF_VNET_HDR };
     145         372 :   struct ifreq get_ifr = {.ifr_flags = 0 };
     146             :   size_t hdrsz;
     147         372 :   vhost_memory_t *vhost_mem = 0;
     148         372 :   virtio_if_t *vif = 0;
     149         372 :   clib_error_t *err = 0;
     150             :   unsigned int tap_features;
     151         372 :   int tfd = -1, qfd = -1, vfd = -1, nfd = -1;
     152         372 :   char *host_if_name = 0;
     153         372 :   unsigned int offload = 0;
     154         372 :   int sndbuf = 0;
     155             : 
     156         372 :   if (args->id != ~0)
     157             :     {
     158         372 :       if (clib_bitmap_get (tm->tap_ids, args->id))
     159             :         {
     160           0 :           args->rv = VNET_API_ERROR_INVALID_INTERFACE;
     161           0 :           args->error = clib_error_return (0, "interface already exists");
     162           0 :           return;
     163             :         }
     164             :     }
     165             :   else
     166             :     {
     167           0 :       args->id = clib_bitmap_first_clear (tm->tap_ids);
     168             :     }
     169             : 
     170         372 :   if (args->id > TAP_MAX_INSTANCE)
     171             :     {
     172           0 :       args->rv = VNET_API_ERROR_UNSPECIFIED;
     173           0 :       args->error = clib_error_return (0, "cannot find free interface id");
     174           0 :       return;
     175             :     }
     176             : 
     177         372 :   pool_get_zero (vim->interfaces, vif);
     178             : 
     179         372 :   if (args->tap_flags & TAP_FLAG_TUN)
     180             :     {
     181          48 :       vif->type = VIRTIO_IF_TYPE_TUN;
     182          48 :       ifr.ifr_flags |= IFF_TUN;
     183             : 
     184             :       /*
     185             :        * From kernel 4.20, xdp support has been added in tun_sendmsg.
     186             :        * If sndbuf == INT_MAX, vhost batches the packet and processes
     187             :        * them using xdp data path for tun driver. It assumes packets
     188             :        * are ethernet frames (It needs to be fixed).
     189             :        * To avoid xdp data path in tun driver, sndbuf value should
     190             :        * be < INT_MAX.
     191             :        */
     192          48 :       sndbuf = INT_MAX - 1;
     193             :     }
     194             :   else
     195             :     {
     196         324 :       vif->type = VIRTIO_IF_TYPE_TAP;
     197         324 :       ifr.ifr_flags |= IFF_TAP;
     198         324 :       sndbuf = INT_MAX;
     199             :     }
     200             : 
     201         372 :   vif->dev_instance = vif - vim->interfaces;
     202         372 :   vif->id = args->id;
     203         372 :   vif->num_txqs = clib_max (args->num_tx_queues, thm->n_vlib_mains);
     204         372 :   vif->num_rxqs = clib_max (args->num_rx_queues, 1);
     205             : 
     206         372 :   if (args->tap_flags & TAP_FLAG_ATTACH)
     207             :     {
     208           0 :       if (args->host_if_name == NULL)
     209             :         {
     210           0 :           args->rv = VNET_API_ERROR_NO_MATCHING_INTERFACE;
     211           0 :           err = clib_error_return (0, "host_if_name is not provided");
     212           0 :           goto error;
     213             :         }
     214             :     }
     215             : 
     216             :   /* if namespace is specified, all further netlink messages should be executed
     217             :    * after we change our net namespace */
     218         372 :   if (args->host_namespace)
     219             :     {
     220         372 :       old_netns_fd = clib_netns_open (NULL /* self */);
     221         372 :       if ((nfd = clib_netns_open (args->host_namespace)) == -1)
     222             :         {
     223           0 :           args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
     224           0 :           args->error = clib_error_return_unix (0, "clib_netns_open '%s'",
     225             :                                                 args->host_namespace);
     226           0 :           goto error;
     227             :         }
     228         372 :       if (clib_setns (nfd) == -1)
     229             :         {
     230           0 :           args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
     231           0 :           args->error =
     232           0 :             clib_error_return_unix (0, "setns '%s'", args->host_namespace);
     233           0 :           goto error;
     234             :         }
     235             :     }
     236             : 
     237         372 :   if (args->host_if_name != NULL)
     238             :     {
     239         372 :       host_if_name = (char *) args->host_if_name;
     240         372 :       clib_memcpy (ifr.ifr_name, host_if_name,
     241             :                    clib_min (IFNAMSIZ, vec_len (host_if_name)));
     242             :     }
     243             : 
     244         372 :   if ((tfd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0)
     245             :     {
     246           0 :       args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
     247           0 :       args->error = clib_error_return_unix (0, "open '/dev/net/tun'");
     248           0 :       goto error;
     249             :     }
     250         372 :   vec_add1 (vif->tap_fds, tfd);
     251         372 :   tap_log_dbg (vif, "open tap fd %d", tfd);
     252             : 
     253         372 :   _IOCTL (tfd, TUNGETFEATURES, &tap_features);
     254         372 :   tap_log_dbg (vif, "TUNGETFEATURES: features 0x%lx", tap_features);
     255         372 :   if ((tap_features & IFF_VNET_HDR) == 0)
     256             :     {
     257           0 :       args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
     258           0 :       args->error = clib_error_return (0, "vhost-net backend not available");
     259           0 :       goto error;
     260             :     }
     261             : 
     262         372 :   if ((tap_features & IFF_MULTI_QUEUE) == 0)
     263             :     {
     264           0 :       if (vif->num_rxqs > 1)
     265             :         {
     266           0 :           args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
     267           0 :           args->error = clib_error_return (0, "multiqueue not supported");
     268           0 :           goto error;
     269             :         }
     270           0 :       vif->num_rxqs = vif->num_txqs = 1;
     271             :     }
     272             :   else
     273         372 :     ifr.ifr_flags |= IFF_MULTI_QUEUE;
     274             : 
     275         372 :   hdrsz = sizeof (vnet_virtio_net_hdr_v1_t);
     276         372 :   if (args->tap_flags & TAP_FLAG_GSO)
     277             :     {
     278         180 :       offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
     279         180 :       vif->gso_enabled = 1;
     280             :     }
     281         192 :   else if (args->tap_flags & TAP_FLAG_CSUM_OFFLOAD)
     282             :     {
     283          48 :       offload = TUN_F_CSUM;
     284          48 :       vif->csum_offload_enabled = 1;
     285             :     }
     286             : 
     287         372 :   _IOCTL (tfd, TUNSETIFF, (void *) &ifr);
     288         372 :   tap_log_dbg (vif, "TUNSETIFF fd %d name %s flags 0x%x", tfd,
     289             :                ifr.ifr_ifrn.ifrn_name, ifr.ifr_flags);
     290             : 
     291         372 :   vif->ifindex = if_nametoindex (ifr.ifr_ifrn.ifrn_name);
     292         372 :   tap_log_dbg (vif, "ifindex %d", vif->ifindex);
     293             : 
     294         372 :   if (!args->host_if_name)
     295           0 :     host_if_name = ifr.ifr_ifrn.ifrn_name;
     296             :   else
     297         372 :     host_if_name = (char *) args->host_if_name;
     298             : 
     299             :   /*
     300             :    * unset the persistence when attaching to existing
     301             :    * interface
     302             :    */
     303         372 :   if (args->tap_flags & TAP_FLAG_ATTACH)
     304             :     {
     305           0 :       _IOCTL (tfd, TUNSETPERSIST, (void *) (uintptr_t) 0);
     306           0 :       tap_log_dbg (vif, "TUNSETPERSIST: unset");
     307             :     }
     308             : 
     309             :   /* set the persistence */
     310         372 :   if (args->tap_flags & TAP_FLAG_PERSIST)
     311             :     {
     312           0 :       _IOCTL (tfd, TUNSETPERSIST, (void *) (uintptr_t) 1);
     313           0 :       tap_log_dbg (vif, "TUNSETPERSIST: set");
     314             : 
     315             :       /* verify persistence is set, read the flags */
     316           0 :       _IOCTL (tfd, TUNGETIFF, (void *) &get_ifr);
     317           0 :       tap_log_dbg (vif, "TUNGETIFF: flags 0x%lx", get_ifr.ifr_flags);
     318           0 :       if ((get_ifr.ifr_flags & IFF_PERSIST) == 0)
     319             :         {
     320           0 :           args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
     321           0 :           args->error = clib_error_return (0, "persistence not supported");
     322           0 :           goto error;
     323             :         }
     324             :     }
     325             : 
     326             :   /* create additional queues on the linux side.
     327             :    * we create as many linux queue pairs as we have rx queues
     328             :    */
     329         372 :   for (i = 1; i < vif->num_rxqs; i++)
     330             :     {
     331           0 :       if ((qfd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK)) < 0)
     332             :         {
     333           0 :           args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
     334           0 :           args->error = clib_error_return_unix (0, "open '/dev/net/tun'");
     335           0 :           goto error;
     336             :         }
     337           0 :       vec_add1 (vif->tap_fds, qfd);
     338           0 :       _IOCTL (qfd, TUNSETIFF, (void *) &ifr);
     339           0 :       tap_log_dbg (vif, "TUNSETIFF fd %d name %s flags 0x%x", qfd,
     340             :                    ifr.ifr_ifrn.ifrn_name, ifr.ifr_flags);
     341             :     }
     342             : 
     343         744 :   for (i = 0; i < vif->num_rxqs; i++)
     344             :     {
     345         372 :       tap_log_dbg (vif, "TUNSETVNETHDRSZ: fd %d vnet_hdr_sz %u",
     346             :                    vif->tap_fds[i], hdrsz);
     347         372 :       _IOCTL (vif->tap_fds[i], TUNSETVNETHDRSZ, &hdrsz);
     348             : 
     349         372 :       tap_log_dbg (vif, "TUNSETSNDBUF: fd %d sndbuf %d", vif->tap_fds[i],
     350             :                    sndbuf);
     351         372 :       _IOCTL (vif->tap_fds[i], TUNSETSNDBUF, &sndbuf);
     352             : 
     353         372 :       tap_log_dbg (vif, "TUNSETOFFLOAD: fd %d offload 0x%lx", vif->tap_fds[i],
     354             :                    offload);
     355         372 :       _IOCTL (vif->tap_fds[i], TUNSETOFFLOAD, offload);
     356             : 
     357         372 :       if (fcntl (vif->tap_fds[i], F_SETFL, O_NONBLOCK) < 0)
     358             :         {
     359           0 :           err = clib_error_return_unix (0, "fcntl(tfd, F_SETFL, O_NONBLOCK)");
     360           0 :           tap_log_err (vif, "set nonblocking: %U", format_clib_error, err);
     361           0 :           goto error;
     362             :         }
     363             :     }
     364             : 
     365             :   /* open as many vhost-net fds as required and set ownership */
     366         372 :   num_vhost_queues = clib_max (vif->num_rxqs, vif->num_txqs);
     367         744 :   for (i = 0; i < num_vhost_queues; i++)
     368             :     {
     369         372 :       if ((vfd = open ("/dev/vhost-net", O_RDWR | O_NONBLOCK)) < 0)
     370             :         {
     371           0 :           args->rv = VNET_API_ERROR_SYSCALL_ERROR_1;
     372           0 :           args->error = clib_error_return_unix (0, "open '/dev/vhost-net'");
     373           0 :           goto error;
     374             :         }
     375         372 :       vec_add1 (vif->vhost_fds, vfd);
     376         372 :       virtio_log_debug (vif, "open vhost-net fd %d qpair %u", vfd, i);
     377         372 :       _IOCTL (vfd, VHOST_SET_OWNER, 0);
     378         372 :       virtio_log_debug (vif, "VHOST_SET_OWNER: fd %u", vfd);
     379             :     }
     380             : 
     381         372 :   _IOCTL (vif->vhost_fds[0], VHOST_GET_FEATURES, &vif->remote_features);
     382         372 :   virtio_log_debug (vif, "VHOST_GET_FEATURES: features 0x%lx",
     383             :                     vif->remote_features);
     384             : 
     385         372 :   if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF)) == 0)
     386             :     {
     387           0 :       args->rv = VNET_API_ERROR_UNSUPPORTED;
     388           0 :       args->error = clib_error_return (0, "vhost-net backend doesn't support "
     389             :                                        "VIRTIO_NET_F_MRG_RXBUF feature");
     390           0 :       goto error;
     391             :     }
     392             : 
     393         372 :   if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC)) ==
     394             :       0)
     395             :     {
     396           0 :       args->rv = VNET_API_ERROR_UNSUPPORTED;
     397           0 :       args->error = clib_error_return (0, "vhost-net backend doesn't support "
     398             :                                        "VIRTIO_RING_F_INDIRECT_DESC feature");
     399           0 :       goto error;
     400             :     }
     401             : 
     402         372 :   if ((vif->remote_features & VIRTIO_FEATURE (VIRTIO_F_VERSION_1)) == 0)
     403             :     {
     404           0 :       args->rv = VNET_API_ERROR_UNSUPPORTED;
     405           0 :       args->error = clib_error_return (0, "vhost-net backend doesn't support "
     406             :                                        "VIRTIO_F_VERSION_1 features");
     407           0 :       goto error;
     408             :     }
     409             : 
     410         372 :   vif->features |= VIRTIO_FEATURE (VIRTIO_NET_F_MRG_RXBUF);
     411         372 :   vif->features |= VIRTIO_FEATURE (VIRTIO_F_VERSION_1);
     412         372 :   vif->features |= VIRTIO_FEATURE (VIRTIO_RING_F_INDIRECT_DESC);
     413             : 
     414         372 :   virtio_set_net_hdr_size (vif);
     415             : 
     416         372 :   if (vif->type == VIRTIO_IF_TYPE_TAP)
     417             :     {
     418         324 :       if (ethernet_mac_address_is_zero (args->host_mac_addr.bytes))
     419         324 :         ethernet_mac_address_generate (args->host_mac_addr.bytes);
     420         648 :       args->error = vnet_netlink_set_link_addr (vif->ifindex,
     421         324 :                                                 args->host_mac_addr.bytes);
     422         324 :       if (args->error)
     423             :         {
     424           0 :           args->rv = VNET_API_ERROR_NETLINK_ERROR;
     425           0 :           goto error;
     426             :         }
     427             : 
     428         324 :       if (args->host_bridge)
     429             :         {
     430           0 :           args->error = vnet_netlink_set_link_master (vif->ifindex,
     431             :                                                       (char *)
     432           0 :                                                       args->host_bridge);
     433           0 :           if (args->error)
     434             :             {
     435           0 :               args->rv = VNET_API_ERROR_NETLINK_ERROR;
     436           0 :               goto error;
     437             :             }
     438             :         }
     439             :     }
     440             : 
     441         372 :   if (args->host_ip4_prefix_len)
     442             :     {
     443         372 :       args->error = vnet_netlink_add_ip4_addr (vif->ifindex,
     444         186 :                                                &args->host_ip4_addr,
     445         186 :                                                args->host_ip4_prefix_len);
     446         186 :       if (args->error)
     447             :         {
     448           0 :           args->rv = VNET_API_ERROR_NETLINK_ERROR;
     449           0 :           goto error;
     450             :         }
     451             :     }
     452             : 
     453         372 :   if (args->host_ip6_prefix_len)
     454             :     {
     455         372 :       args->error = vnet_netlink_add_ip6_addr (vif->ifindex,
     456         186 :                                                &args->host_ip6_addr,
     457         186 :                                                args->host_ip6_prefix_len);
     458         186 :       if (args->error)
     459             :         {
     460           0 :           args->rv = VNET_API_ERROR_NETLINK_ERROR;
     461           0 :           goto error;
     462             :         }
     463             :     }
     464             : 
     465         372 :   args->error = vnet_netlink_set_link_state (vif->ifindex, 1 /* UP */ );
     466         372 :   if (args->error)
     467             :     {
     468           0 :       args->rv = VNET_API_ERROR_NETLINK_ERROR;
     469           0 :       goto error;
     470             :     }
     471             : 
     472         372 :   if (args->host_ip4_gw_set)
     473             :     {
     474          24 :       args->error = vnet_netlink_add_ip4_route (0, 0, &args->host_ip4_gw);
     475          24 :       if (args->error)
     476             :         {
     477           0 :           args->rv = VNET_API_ERROR_NETLINK_ERROR;
     478           0 :           goto error;
     479             :         }
     480             :     }
     481             : 
     482         372 :   if (args->host_ip6_gw_set)
     483             :     {
     484          24 :       args->error = vnet_netlink_add_ip6_route (0, 0, &args->host_ip6_gw);
     485          24 :       if (args->error)
     486             :         {
     487           0 :           args->rv = VNET_API_ERROR_NETLINK_ERROR;
     488           0 :           goto error;
     489             :         }
     490             :     }
     491             : 
     492         372 :   if (args->host_mtu_set)
     493             :     {
     494           0 :       args->error =
     495           0 :         vnet_netlink_set_link_mtu (vif->ifindex, args->host_mtu_size);
     496           0 :       if (args->error)
     497             :         {
     498           0 :           args->rv = VNET_API_ERROR_NETLINK_ERROR;
     499           0 :           goto error;
     500             :         }
     501             :     }
     502         372 :   else if (tm->host_mtu_size != 0)
     503             :     {
     504           0 :       args->error =
     505           0 :         vnet_netlink_set_link_mtu (vif->ifindex, tm->host_mtu_size);
     506           0 :       if (args->error)
     507             :         {
     508           0 :           args->rv = VNET_API_ERROR_NETLINK_ERROR;
     509           0 :           goto error;
     510             :         }
     511           0 :       args->host_mtu_set = 1;
     512           0 :       args->host_mtu_size = tm->host_mtu_size;
     513             :     }
     514             : 
     515             :   /* switch back to old net namespace */
     516         372 :   if (args->host_namespace)
     517             :     {
     518         372 :       if (clib_setns (old_netns_fd) == -1)
     519             :         {
     520           0 :           args->rv = VNET_API_ERROR_SYSCALL_ERROR_2;
     521           0 :           args->error = clib_error_return_unix (0, "setns '%s'",
     522             :                                                 args->host_namespace);
     523           0 :           goto error;
     524             :         }
     525             :     }
     526             : 
     527         744 :   for (i = 0; i < num_vhost_queues; i++)
     528             :     {
     529         744 :       if (i < vif->num_rxqs && (args->error =
     530         372 :                                 virtio_vring_init (vm, vif, RX_QUEUE (i),
     531         372 :                                                    args->rx_ring_sz)))
     532             :         {
     533           0 :           args->rv = VNET_API_ERROR_INIT_FAILED;
     534           0 :           goto error;
     535             :         }
     536             : 
     537         744 :       if (i < vif->num_txqs && (args->error =
     538         372 :                                 virtio_vring_init (vm, vif, TX_QUEUE (i),
     539         372 :                                                    args->tx_ring_sz)))
     540             :         {
     541           0 :           args->rv = VNET_API_ERROR_INIT_FAILED;
     542           0 :           goto error;
     543             :         }
     544             :     }
     545             : 
     546             :   /* setup features and memtable */
     547         372 :   i = sizeof (vhost_memory_t) + sizeof (vhost_memory_region_t);
     548         372 :   vhost_mem = clib_mem_alloc (i);
     549         372 :   clib_memset (vhost_mem, 0, i);
     550         372 :   vhost_mem->nregions = 1;
     551         372 :   vhost_mem->regions[0].memory_size = vpm->max_size;
     552         372 :   vhost_mem->regions[0].guest_phys_addr = vpm->base_addr;
     553         372 :   vhost_mem->regions[0].userspace_addr =
     554         372 :     vhost_mem->regions[0].guest_phys_addr;
     555             : 
     556         744 :   for (i = 0; i < vhost_mem->nregions; i++)
     557         372 :     virtio_log_debug (vif, "memtable region %u memory_size 0x%lx "
     558             :                       "guest_phys_addr 0x%lx userspace_addr 0x%lx", i,
     559             :                       vhost_mem->regions[0].memory_size,
     560             :                       vhost_mem->regions[0].guest_phys_addr,
     561             :                       vhost_mem->regions[0].userspace_addr);
     562             : 
     563             : 
     564         744 :   for (i = 0; i < num_vhost_queues; i++)
     565             :     {
     566         372 :       int fd = vif->vhost_fds[i];
     567         372 :       _IOCTL (fd, VHOST_SET_FEATURES, &vif->features);
     568         372 :       virtio_log_debug (vif, "VHOST_SET_FEATURES: fd %u features 0x%lx",
     569             :                         fd, vif->features);
     570         372 :       _IOCTL (fd, VHOST_SET_MEM_TABLE, vhost_mem);
     571         372 :       virtio_log_debug (vif, "VHOST_SET_MEM_TABLE: fd %u", fd);
     572             :     }
     573             : 
     574             :   /* finish initializing queue pair */
     575        1116 :   for (i = 0; i < num_vhost_queues * 2; i++)
     576             :     {
     577         744 :       vhost_vring_addr_t addr = { 0 };
     578         744 :       vhost_vring_state_t state = { 0 };
     579         744 :       vhost_vring_file_t file = { 0 };
     580             :       vnet_virtio_vring_t *vring;
     581         744 :       u16 qp = i >> 1;
     582         744 :       int fd = vif->vhost_fds[qp];
     583             : 
     584         744 :       if (i & 1)
     585             :         {
     586         372 :           if (qp >= vif->num_txqs)
     587           0 :             continue;
     588         372 :           vring = vec_elt_at_index (vif->txq_vrings, qp);
     589             :         }
     590             :       else
     591             :         {
     592         372 :           if (qp >= vif->num_rxqs)
     593           0 :             continue;
     594         372 :           vring = vec_elt_at_index (vif->rxq_vrings, qp);
     595             :         }
     596             : 
     597         744 :       addr.index = state.index = file.index = vring->queue_id & 1;
     598         744 :       state.num = vring->queue_size;
     599         744 :       virtio_log_debug (vif, "VHOST_SET_VRING_NUM fd %d index %u num %u", fd,
     600             :                         state.index, state.num);
     601         744 :       _IOCTL (fd, VHOST_SET_VRING_NUM, &state);
     602             : 
     603         744 :       addr.flags = 0;
     604         744 :       addr.desc_user_addr = pointer_to_uword (vring->desc);
     605         744 :       addr.avail_user_addr = pointer_to_uword (vring->avail);
     606         744 :       addr.used_user_addr = pointer_to_uword (vring->used);
     607             : 
     608         744 :       virtio_log_debug (vif, "VHOST_SET_VRING_ADDR fd %d index %u flags 0x%x "
     609             :                         "desc_user_addr 0x%lx avail_user_addr 0x%lx "
     610             :                         "used_user_addr 0x%lx", fd, addr.index,
     611             :                         addr.flags, addr.desc_user_addr, addr.avail_user_addr,
     612             :                         addr.used_user_addr);
     613         744 :       _IOCTL (fd, VHOST_SET_VRING_ADDR, &addr);
     614             : 
     615         744 :       file.fd = vring->call_fd;
     616         744 :       virtio_log_debug (vif, "VHOST_SET_VRING_CALL fd %d index %u call_fd %d",
     617             :                         fd, file.index, file.fd);
     618         744 :       _IOCTL (fd, VHOST_SET_VRING_CALL, &file);
     619             : 
     620         744 :       file.fd = vring->kick_fd;
     621         744 :       virtio_log_debug (vif, "VHOST_SET_VRING_KICK fd %d index %u kick_fd %d",
     622             :                         fd, file.index, file.fd);
     623         744 :       _IOCTL (fd, VHOST_SET_VRING_KICK, &file);
     624             : 
     625         744 :       file.fd = vif->tap_fds[qp % vif->num_rxqs];
     626         744 :       virtio_log_debug (vif, "VHOST_NET_SET_BACKEND fd %d index %u tap_fd %d",
     627             :                         fd, file.index, file.fd);
     628         744 :       _IOCTL (fd, VHOST_NET_SET_BACKEND, &file);
     629             :     }
     630             : 
     631         372 :   if (vif->type == VIRTIO_IF_TYPE_TAP)
     632             :     {
     633         324 :       if (!args->mac_addr_set)
     634         324 :         ethernet_mac_address_generate (args->mac_addr.bytes);
     635             : 
     636         324 :       clib_memcpy (vif->mac_addr, args->mac_addr.bytes, 6);
     637         324 :       if (args->host_bridge)
     638           0 :         vif->host_bridge = format (0, "%s%c", args->host_bridge, 0);
     639             :     }
     640         372 :   vif->host_if_name = format (0, "%s%c", host_if_name, 0);
     641         372 :   if (args->host_namespace)
     642         372 :     vif->net_ns = format (0, "%s%c", args->host_namespace, 0);
     643         372 :   vif->host_mtu_size = args->host_mtu_size;
     644         372 :   vif->tap_flags = args->tap_flags;
     645         372 :   clib_memcpy (vif->host_mac_addr, args->host_mac_addr.bytes, 6);
     646         372 :   vif->host_ip4_prefix_len = args->host_ip4_prefix_len;
     647         372 :   vif->host_ip6_prefix_len = args->host_ip6_prefix_len;
     648         372 :   if (args->host_ip4_prefix_len)
     649         186 :     clib_memcpy (&vif->host_ip4_addr, &args->host_ip4_addr, 4);
     650         372 :   if (args->host_ip6_prefix_len)
     651         186 :     clib_memcpy (&vif->host_ip6_addr, &args->host_ip6_addr, 16);
     652             : 
     653         372 :   if (vif->type != VIRTIO_IF_TYPE_TUN)
     654             :     {
     655         324 :       vnet_eth_interface_registration_t eir = {};
     656             : 
     657         324 :       eir.dev_class_index = virtio_device_class.index;
     658         324 :       eir.dev_instance = vif->dev_instance;
     659         324 :       eir.address = vif->mac_addr;
     660         324 :       eir.cb.flag_change = virtio_eth_flag_change;
     661         324 :       eir.cb.set_max_frame_size = virtio_eth_set_max_frame_size;
     662         324 :       vif->hw_if_index = vnet_eth_register_interface (vnm, &eir);
     663             :     }
     664             :   else
     665             :     {
     666          48 :       vif->hw_if_index = vnet_register_interface
     667             :         (vnm, virtio_device_class.index,
     668          48 :          vif->dev_instance /* device instance */ ,
     669          48 :          tun_device_hw_interface_class.index, vif->dev_instance);
     670             : 
     671             :     }
     672         372 :   tm->tap_ids = clib_bitmap_set (tm->tap_ids, vif->id, 1);
     673         372 :   sw = vnet_get_hw_sw_interface (vnm, vif->hw_if_index);
     674         372 :   vif->sw_if_index = sw->sw_if_index;
     675         372 :   args->sw_if_index = vif->sw_if_index;
     676         372 :   args->rv = 0;
     677         372 :   hw = vnet_get_hw_interface (vnm, vif->hw_if_index);
     678         372 :   cc.mask = VNET_HW_IF_CAP_INT_MODE | VNET_HW_IF_CAP_TCP_GSO |
     679             :             VNET_HW_IF_CAP_TX_TCP_CKSUM | VNET_HW_IF_CAP_TX_UDP_CKSUM;
     680         372 :   cc.val = VNET_HW_IF_CAP_INT_MODE;
     681             : 
     682         372 :   if (args->tap_flags & TAP_FLAG_GSO)
     683         180 :     cc.val |= VNET_HW_IF_CAP_TCP_GSO | VNET_HW_IF_CAP_TX_TCP_CKSUM |
     684             :               VNET_HW_IF_CAP_TX_UDP_CKSUM;
     685         192 :   else if (args->tap_flags & TAP_FLAG_CSUM_OFFLOAD)
     686          48 :     cc.val |= VNET_HW_IF_CAP_TX_TCP_CKSUM | VNET_HW_IF_CAP_TX_UDP_CKSUM;
     687             : 
     688         372 :   if ((args->tap_flags & TAP_FLAG_GSO)
     689         180 :       && (args->tap_flags & TAP_FLAG_GRO_COALESCE))
     690             :     {
     691         108 :       virtio_set_packet_coalesce (vif);
     692             :     }
     693         372 :   if (vif->type == VIRTIO_IF_TYPE_TUN)
     694             :     {
     695          48 :       hw->min_frame_size = TUN_MIN_PACKET_BYTES;
     696          48 :       vnet_hw_interface_set_mtu (
     697             :         vnm, hw->hw_if_index,
     698          48 :         args->host_mtu_size ? args->host_mtu_size : TUN_DEFAULT_PACKET_BYTES);
     699             :     }
     700             : 
     701         372 :   vnet_hw_if_change_caps (vnm, vif->hw_if_index, &cc);
     702         372 :   virtio_pre_input_node_enable (vm, vif);
     703         372 :   virtio_vring_set_rx_queues (vm, vif);
     704         372 :   virtio_vring_set_tx_queues (vm, vif);
     705             : 
     706         372 :   vif->per_interface_next_index = ~0;
     707         372 :   vnet_hw_interface_set_flags (vnm, vif->hw_if_index,
     708             :                                VNET_HW_INTERFACE_FLAG_LINK_UP);
     709             :   /*
     710             :    * Host tun/tap driver link carrier state is "up" at creation. The
     711             :    * driver never changes this unless the backend (VPP) changes it using
     712             :    * TUNSETCARRIER ioctl(). See tap_set_carrier().
     713             :    */
     714         372 :   vif->host_carrier_up = 1;
     715             : 
     716         372 :   goto done;
     717             : 
     718           0 : error:
     719           0 :   if (err)
     720             :     {
     721           0 :       ASSERT (args->error == 0);
     722           0 :       args->error = err;
     723           0 :       args->rv = VNET_API_ERROR_SYSCALL_ERROR_3;
     724             :     }
     725             : 
     726           0 :   tap_log_err (vif, "%U", format_clib_error, args->error);
     727           0 :   tap_free (vm, vif);
     728         372 : done:
     729         372 :   if (vhost_mem)
     730         372 :     clib_mem_free (vhost_mem);
     731         372 :   if (old_netns_fd != -1)
     732             :     {
     733             :       /* in case we errored with a switched netns */
     734         372 :       clib_setns (old_netns_fd);
     735         372 :       close (old_netns_fd);
     736             :     }
     737         372 :   if (nfd != -1)
     738         372 :     close (nfd);
     739             : }
     740             : 
     741             : int
     742         624 : tap_delete_if (vlib_main_t * vm, u32 sw_if_index)
     743             : {
     744         624 :   vnet_main_t *vnm = vnet_get_main ();
     745         624 :   virtio_main_t *mm = &virtio_main;
     746             :   virtio_if_t *vif;
     747             :   vnet_hw_interface_t *hw;
     748             : 
     749         624 :   hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
     750         624 :   if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
     751         252 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     752             : 
     753         372 :   vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
     754             : 
     755         372 :   if ((vif->type != VIRTIO_IF_TYPE_TAP) && (vif->type != VIRTIO_IF_TYPE_TUN))
     756           0 :     return VNET_API_ERROR_INVALID_INTERFACE;
     757             : 
     758             :   /* bring down the interface */
     759         372 :   vnet_hw_interface_set_flags (vnm, vif->hw_if_index, 0);
     760         372 :   vnet_sw_interface_set_flags (vnm, vif->sw_if_index, 0);
     761             : 
     762         372 :   if (vif->type == VIRTIO_IF_TYPE_TAP)
     763         324 :     ethernet_delete_interface (vnm, vif->hw_if_index);
     764             :   else                          /* VIRTIO_IF_TYPE_TUN */
     765          48 :     vnet_delete_hw_interface (vnm, vif->hw_if_index);
     766         372 :   vif->hw_if_index = ~0;
     767             : 
     768         372 :   tap_free (vm, vif);
     769             : 
     770         372 :   return 0;
     771             : }
     772             : 
     773             : int
     774           0 : tap_csum_offload_enable_disable (vlib_main_t * vm, u32 sw_if_index,
     775             :                                  int enable_disable)
     776             : {
     777           0 :   vnet_main_t *vnm = vnet_get_main ();
     778           0 :   virtio_main_t *mm = &virtio_main;
     779             :   virtio_if_t *vif;
     780             :   vnet_hw_interface_t *hw;
     781             :   vnet_hw_if_caps_change_t cc;
     782           0 :   clib_error_t *err = 0;
     783           0 :   int i = 0;
     784             : 
     785           0 :   hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
     786             : 
     787           0 :   if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
     788           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     789             : 
     790           0 :   vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
     791             : 
     792           0 :   const unsigned int csum_offload_on = TUN_F_CSUM;
     793           0 :   const unsigned int csum_offload_off = 0;
     794           0 :   unsigned int offload = enable_disable ? csum_offload_on : csum_offload_off;
     795           0 :   vec_foreach_index (i, vif->tap_fds)
     796           0 :     _IOCTL (vif->tap_fds[i], TUNSETOFFLOAD, offload);
     797           0 :   vif->gso_enabled = 0;
     798           0 :   vif->packet_coalesce = 0;
     799             : 
     800           0 :   cc.mask = VNET_HW_IF_CAP_TCP_GSO | VNET_HW_IF_CAP_L4_TX_CKSUM;
     801           0 :   if (enable_disable)
     802             :     {
     803           0 :       cc.val = VNET_HW_IF_CAP_L4_TX_CKSUM;
     804           0 :       vif->csum_offload_enabled = 1;
     805             :     }
     806             :   else
     807             :     {
     808           0 :       cc.val = 0;
     809           0 :       vif->csum_offload_enabled = 0;
     810             :     }
     811           0 :   vnet_hw_if_change_caps (vnm, vif->hw_if_index, &cc);
     812             : 
     813           0 : error:
     814           0 :   if (err)
     815             :     {
     816           0 :       clib_warning ("Error %s checksum offload on sw_if_index %d",
     817             :                     enable_disable ? "enabling" : "disabling", sw_if_index);
     818           0 :       return VNET_API_ERROR_SYSCALL_ERROR_3;
     819             :     }
     820           0 :   return 0;
     821             : }
     822             : 
     823             : int
     824           0 : tap_gso_enable_disable (vlib_main_t * vm, u32 sw_if_index, int enable_disable,
     825             :                         int is_packet_coalesce)
     826             : {
     827           0 :   vnet_main_t *vnm = vnet_get_main ();
     828           0 :   virtio_main_t *mm = &virtio_main;
     829             :   virtio_if_t *vif;
     830             :   vnet_hw_interface_t *hw;
     831             :   vnet_hw_if_caps_change_t cc;
     832           0 :   clib_error_t *err = 0;
     833           0 :   int i = 0;
     834             : 
     835           0 :   hw = vnet_get_sup_hw_interface_api_visible_or_null (vnm, sw_if_index);
     836             : 
     837           0 :   if (hw == NULL || virtio_device_class.index != hw->dev_class_index)
     838           0 :     return VNET_API_ERROR_INVALID_SW_IF_INDEX;
     839             : 
     840           0 :   vif = pool_elt_at_index (mm->interfaces, hw->dev_instance);
     841             : 
     842           0 :   const unsigned int gso_on = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
     843           0 :   const unsigned int gso_off = 0;
     844           0 :   unsigned int offload = enable_disable ? gso_on : gso_off;
     845           0 :   vec_foreach_index (i, vif->tap_fds)
     846           0 :     _IOCTL (vif->tap_fds[i], TUNSETOFFLOAD, offload);
     847             : 
     848           0 :   cc.mask = VNET_HW_IF_CAP_TCP_GSO | VNET_HW_IF_CAP_L4_TX_CKSUM;
     849             : 
     850           0 :   if (enable_disable)
     851             :     {
     852           0 :       cc.val = cc.mask;
     853           0 :       vif->gso_enabled = 1;
     854           0 :       vif->csum_offload_enabled = 1;
     855           0 :       if (is_packet_coalesce)
     856           0 :         virtio_set_packet_coalesce (vif);
     857             :     }
     858             :   else
     859             :     {
     860           0 :       cc.val = 0;
     861           0 :       vif->gso_enabled = 0;
     862           0 :       vif->csum_offload_enabled = 0;
     863           0 :       vif->packet_coalesce = 0;
     864             :     }
     865           0 :   vnet_hw_if_change_caps (vnm, vif->hw_if_index, &cc);
     866             : 
     867           0 : error:
     868           0 :   if (err)
     869             :     {
     870           0 :       clib_warning ("Error %s gso on sw_if_index %d",
     871             :                     enable_disable ? "enabling" : "disabling", sw_if_index);
     872           0 :       return VNET_API_ERROR_SYSCALL_ERROR_3;
     873             :     }
     874           0 :   return 0;
     875             : }
     876             : 
     877             : int
     878           0 : tap_dump_ifs (tap_interface_details_t ** out_tapids)
     879             : {
     880           0 :   vnet_main_t *vnm = vnet_get_main ();
     881           0 :   virtio_main_t *mm = &virtio_main;
     882             :   virtio_if_t *vif;
     883             :   vnet_virtio_vring_t *vring;
     884             :   vnet_hw_interface_t *hi;
     885           0 :   tap_interface_details_t *r_tapids = NULL;
     886           0 :   tap_interface_details_t *tapid = NULL;
     887             : 
     888             :   /* *INDENT-OFF* */
     889           0 :   pool_foreach (vif, mm->interfaces) {
     890           0 :     if ((vif->type != VIRTIO_IF_TYPE_TAP)
     891           0 :       && (vif->type != VIRTIO_IF_TYPE_TUN))
     892           0 :       continue;
     893           0 :     vec_add2(r_tapids, tapid, 1);
     894           0 :     clib_memset (tapid, 0, sizeof (*tapid));
     895           0 :     tapid->id = vif->id;
     896           0 :     tapid->sw_if_index = vif->sw_if_index;
     897           0 :     hi = vnet_get_hw_interface (vnm, vif->hw_if_index);
     898           0 :     clib_memcpy(tapid->dev_name, hi->name,
     899             :                 MIN (ARRAY_LEN (tapid->dev_name) - 1, vec_len (hi->name)));
     900           0 :     vring = vec_elt_at_index (vif->rxq_vrings, RX_QUEUE_ACCESS(0));
     901           0 :     tapid->rx_ring_sz = vring->queue_size;
     902           0 :     vring = vec_elt_at_index (vif->txq_vrings, TX_QUEUE_ACCESS(0));
     903           0 :     tapid->tx_ring_sz = vring->queue_size;
     904           0 :     tapid->tap_flags = vif->tap_flags;
     905           0 :     clib_memcpy(&tapid->host_mac_addr, vif->host_mac_addr, 6);
     906           0 :     if (vif->host_if_name)
     907             :       {
     908           0 :         clib_memcpy(tapid->host_if_name, vif->host_if_name,
     909             :                     MIN (ARRAY_LEN (tapid->host_if_name) - 1,
     910             :                     vec_len (vif->host_if_name)));
     911             :       }
     912           0 :     if (vif->net_ns)
     913             :       {
     914           0 :         clib_memcpy(tapid->host_namespace, vif->net_ns,
     915             :                     MIN (ARRAY_LEN (tapid->host_namespace) - 1,
     916             :                     vec_len (vif->net_ns)));
     917             :       }
     918           0 :     if (vif->host_bridge)
     919             :       {
     920           0 :         clib_memcpy(tapid->host_bridge, vif->host_bridge,
     921             :                     MIN (ARRAY_LEN (tapid->host_bridge) - 1,
     922             :                     vec_len (vif->host_bridge)));
     923             :       }
     924           0 :     if (vif->host_ip4_prefix_len)
     925           0 :       clib_memcpy(tapid->host_ip4_addr.as_u8, &vif->host_ip4_addr, 4);
     926           0 :     tapid->host_ip4_prefix_len = vif->host_ip4_prefix_len;
     927           0 :     if (vif->host_ip6_prefix_len)
     928           0 :       clib_memcpy(tapid->host_ip6_addr.as_u8, &vif->host_ip6_addr, 16);
     929           0 :     tapid->host_ip6_prefix_len = vif->host_ip6_prefix_len;
     930           0 :     tapid->host_mtu_size = vif->host_mtu_size;
     931             :   }
     932             :   /* *INDENT-ON* */
     933             : 
     934           0 :   *out_tapids = r_tapids;
     935             : 
     936           0 :   return 0;
     937             : }
     938             : 
     939             : /*
     940             :  * Set host tap/tun interface carrier state so it will appear to host
     941             :  * applications that the interface's link state changed.
     942             :  *
     943             :  * If the kernel we're building against does not have support for the
     944             :  * TUNSETCARRIER ioctl command, do nothing.
     945             :  */
     946             : int
     947           0 : tap_set_carrier (u32 hw_if_index, u32 carrier_up)
     948             : {
     949           0 :   int ret = 0;
     950             : #ifdef TUNSETCARRIER
     951           0 :   vnet_main_t *vnm = vnet_get_main ();
     952           0 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
     953           0 :   virtio_main_t *mm = &virtio_main;
     954             :   virtio_if_t *vif;
     955             :   int *fd;
     956             : 
     957           0 :   vif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
     958           0 :   vec_foreach (fd, vif->tap_fds)
     959             :   {
     960           0 :     ret = ioctl (*fd, TUNSETCARRIER, &carrier_up);
     961           0 :     if (ret < 0)
     962             :       {
     963           0 :         clib_warning ("ioctl (TUNSETCARRIER) returned %d", ret);
     964           0 :         break;
     965             :       }
     966             :   }
     967           0 :   if (!ret)
     968           0 :     vif->host_carrier_up = (carrier_up != 0);
     969             : #endif
     970             : 
     971           0 :   return ret;
     972             : }
     973             : 
     974             : static clib_error_t *
     975         575 : tap_mtu_config (vlib_main_t * vm, unformat_input_t * input)
     976             : {
     977         575 :   tap_main_t *tm = &tap_main;
     978             : 
     979         575 :   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     980             :     {
     981           0 :       if (unformat (input, "host-mtu %d", &tm->host_mtu_size))
     982             :         ;
     983             :       else
     984           0 :         return clib_error_return (0, "unknown input `%U'",
     985             :                                   format_unformat_error, input);
     986             :     }
     987             : 
     988         575 :   return 0;
     989             : }
     990             : 
     991             : /*
     992             :  * Set host tap/tun interface speed in Mbps.
     993             :  */
     994             : int
     995           0 : tap_set_speed (u32 hw_if_index, u32 speed)
     996             : {
     997           0 :   vnet_main_t *vnm = vnet_get_main ();
     998           0 :   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
     999           0 :   virtio_main_t *mm = &virtio_main;
    1000             :   virtio_if_t *vif;
    1001           0 :   int old_netns_fd = -1;
    1002           0 :   int nfd = -1;
    1003           0 :   int ctl_fd = -1;
    1004             :   struct ifreq ifr;
    1005             :   struct ethtool_cmd ecmd;
    1006           0 :   int ret = -1;
    1007             : 
    1008           0 :   vif = pool_elt_at_index (mm->interfaces, hi->dev_instance);
    1009             : 
    1010           0 :   if (vif->net_ns)
    1011             :     {
    1012           0 :       old_netns_fd = clib_netns_open (NULL /* self */);
    1013           0 :       if ((nfd = clib_netns_open (vif->net_ns)) == -1)
    1014             :         {
    1015           0 :           clib_warning ("Cannot open netns");
    1016           0 :           goto done;
    1017             :         }
    1018           0 :       if (clib_setns (nfd) == -1)
    1019             :         {
    1020           0 :           clib_warning ("Cannot set ns");
    1021           0 :           goto done;
    1022             :         }
    1023             :     }
    1024             : 
    1025           0 :   if ((ctl_fd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
    1026             :     {
    1027           0 :       clib_warning ("Cannot open control socket");
    1028           0 :       goto done;
    1029             :     }
    1030             : 
    1031           0 :   ecmd.cmd = ETHTOOL_GSET;
    1032           0 :   clib_memset (&ifr, 0, sizeof (ifr));
    1033           0 :   clib_memcpy (ifr.ifr_name, vif->host_if_name,
    1034             :                strlen ((const char *) vif->host_if_name));
    1035           0 :   ifr.ifr_data = (void *) &ecmd;
    1036           0 :   if ((ret = ioctl (ctl_fd, SIOCETHTOOL, &ifr)) < 0)
    1037             :     {
    1038           0 :       clib_warning ("Cannot get device settings");
    1039           0 :       goto done;
    1040             :     }
    1041             : 
    1042           0 :   if (ethtool_cmd_speed (&ecmd) != speed)
    1043             :     {
    1044           0 :       ecmd.cmd = ETHTOOL_SSET;
    1045           0 :       ethtool_cmd_speed_set (&ecmd, speed);
    1046           0 :       if ((ret = ioctl (ctl_fd, SIOCETHTOOL, &ifr)) < 0)
    1047             :         {
    1048           0 :           clib_warning ("Cannot set device settings");
    1049           0 :           goto done;
    1050             :         }
    1051             :     }
    1052             : 
    1053           0 : done:
    1054           0 :   if (old_netns_fd != -1)
    1055             :     {
    1056           0 :       if (clib_setns (old_netns_fd) == -1)
    1057             :         {
    1058           0 :           clib_warning ("Cannot set old ns");
    1059             :         }
    1060           0 :       close (old_netns_fd);
    1061             :     }
    1062           0 :   if (nfd != -1)
    1063           0 :     close (nfd);
    1064           0 :   if (ctl_fd != -1)
    1065           0 :     close (ctl_fd);
    1066             : 
    1067           0 :   return ret;
    1068             : }
    1069             : 
    1070             : /* tap { host-mtu <size> } configuration. */
    1071        7514 : VLIB_CONFIG_FUNCTION (tap_mtu_config, "tap");
    1072             : 
    1073             : static clib_error_t *
    1074         575 : tap_init (vlib_main_t * vm)
    1075             : {
    1076         575 :   tap_main_t *tm = &tap_main;
    1077         575 :   clib_error_t *error = 0;
    1078             : 
    1079         575 :   tm->log_default = vlib_log_register_class ("tap", 0);
    1080         575 :   vlib_log_debug (tm->log_default, "initialized");
    1081             : 
    1082         575 :   tm->host_mtu_size = 0;
    1083             : 
    1084         575 :   return error;
    1085             : }
    1086             : 
    1087       77183 : VLIB_INIT_FUNCTION (tap_init);
    1088             : 
    1089             : /*
    1090             :  * fd.io coding-style-patch-verification: ON
    1091             :  *
    1092             :  * Local Variables:
    1093             :  * eval: (c-set-style "gnu")
    1094             :  * End:
    1095             :  */

Generated by: LCOV version 1.14