dpdk: allow configure individual VMBUS devices 82/29882/32
authorVladimir Ratnikov <vratnikov@netgate.com>
Wed, 11 Nov 2020 13:00:48 +0000 (08:00 -0500)
committerMatthew Smith <mgsmith@netgate.com>
Mon, 11 Jan 2021 20:40:23 +0000 (20:40 +0000)
now startup.conf supports confuguration for VMBUS
devices as for PCI devices for whitelisting/blacklisting

dpdk { dev fa5a6e7a-cf3a-4b98-9569-addb479b84bc }
 with sub-configuration as for PCI devices
dpdk { blacklist fa5a6e7a-cf3a-4b98-9569-addb479b84bc }
 where fa5a6e7a-cf3a-4b98-9569-addb479b84bc - example of UUID

struct vlib_vmbus_addr_t changed to union with UUID described
 fields

Added device_config_index_by_vmbus_addr
      blacklist_by_vmbus_addr
to enumerate available device configs

hash_key is as_u32[0] field(last 4 bytes of UUID)
Lost of precision against full UUID, but 2^32 is enough
to handle all the devices available

Added is_blacklisted check while creating vnet devices in
order to supress creation of dev if it's blacklisted

Type: feature

Signed-off-by: Vladimir Ratnikov <vratnikov@netgate.com>
Change-Id: Id82611e54fed082190e488c7e5fbe14ecbe5b2ab

src/plugins/dpdk/device/common.c
src/plugins/dpdk/device/dpdk.h
src/plugins/dpdk/device/init.c
src/vlib/linux/vmbus.c
src/vlib/vmbus/vmbus.c
src/vlib/vmbus/vmbus.h

index 0c43bfe..2521abd 100644 (file)
@@ -260,6 +260,19 @@ dpdk_get_pci_device (const struct rte_eth_dev_info *info)
     return NULL;
 }
 
+/* If this device is VMBUS return pointer to info, otherwise NULL */
+struct rte_vmbus_device *
+dpdk_get_vmbus_device (const struct rte_eth_dev_info *info)
+{
+  const struct rte_bus *bus;
+
+  bus = rte_bus_find_by_device (info->device);
+  if (bus && !strcmp (bus->name, "vmbus"))
+    return container_of (info->device, struct rte_vmbus_device, device);
+  else
+    return NULL;
+}
+
 /*
  * fd.io coding-style-patch-verification: ON
  *
index c81f23d..504bac5 100644 (file)
@@ -32,6 +32,7 @@
 #include <rte_per_lcore.h>
 #include <rte_interrupts.h>
 #include <rte_pci.h>
+#include <rte_bus_vmbus.h>
 #include <rte_ether.h>
 #include <rte_ethdev.h>
 #include <rte_ring.h>
@@ -52,6 +53,7 @@
 #endif
 
 #include <vlib/pci/pci.h>
+#include <vlib/vmbus/vmbus.h>
 #include <vnet/flow/flow.h>
 
 extern vnet_device_class_t dpdk_device_class;
@@ -250,9 +252,21 @@ typedef struct
   _ (num_tx_desc) \
   _ (rss_fn)
 
+typedef enum
+{
+  VNET_DEV_ADDR_PCI,
+  VNET_DEV_ADDR_VMBUS,
+  VNET_DEV_ADDR_ANY,
+} dpdk_device_addr_type_t;
+
 typedef struct
 {
-  vlib_pci_addr_t pci_addr;
+  union
+  {
+    vlib_pci_addr_t pci_addr;
+    vlib_vmbus_addr_t vmbus_addr;
+  };
+  dpdk_device_addr_type_t dev_addr_type;
   u8 *name;
   u8 is_blacklisted;
   u8 vlan_strip_offload;
@@ -302,9 +316,12 @@ typedef struct
   dpdk_device_config_t default_devconf;
   dpdk_device_config_t *dev_confs;
   uword *device_config_index_by_pci_addr;
+  uword *device_config_index_by_vmbus_addr;
 
   /* devices blacklist by pci vendor_id, device_id */
   u32 *blacklist_by_pci_vendor_and_device;
+  /* devices blacklist by VMBUS address */
+  u32 *blacklist_by_vmbus_addr;
 
 } dpdk_config_main_t;
 
@@ -459,6 +476,8 @@ clib_error_t *unformat_rss_fn (unformat_input_t * input, uword * rss_fn);
 
 struct rte_pci_device *dpdk_get_pci_device (const struct rte_eth_dev_info
                                            *info);
+struct rte_vmbus_device *
+dpdk_get_vmbus_device (const struct rte_eth_dev_info *info);
 void dpdk_cli_reference (void);
 
 #if CLI_DEBUG
index 19898b1..f3d228c 100644 (file)
@@ -249,9 +249,11 @@ dpdk_lib_init (dpdk_main_t * dm)
       int vlan_off;
       struct rte_eth_dev_info dev_info;
       struct rte_pci_device *pci_dev;
+      struct rte_vmbus_device *vmbus_dev;
       dpdk_portid_t next_port_id;
       dpdk_device_config_t *devconf = 0;
       vlib_pci_addr_t pci_addr;
+      vlib_vmbus_addr_t vmbus_addr;
       uword *p = 0;
 
       if (!rte_eth_dev_is_valid_port(i))
@@ -278,20 +280,42 @@ dpdk_lib_init (dpdk_main_t * dm)
                        pci_addr.as_u32);
        }
 
+      vmbus_dev = dpdk_get_vmbus_device (&dev_info);
+
+      if (vmbus_dev)
+       {
+         unformat_input_t input_vmbus;
+
+         unformat_init_vector (&input_vmbus, (u8 *) dev_info.device->name);
+         if (unformat (&input_vmbus, "%U", unformat_vlib_vmbus_addr,
+                       &vmbus_addr))
+           {
+             p = hash_get (dm->conf->device_config_index_by_vmbus_addr,
+                           vmbus_addr.as_u32[0]);
+           }
+       }
+
+      if (p)
+       {
+         devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]);
+         /* If device is blacklisted, we should skip it */
+         if (devconf->is_blacklisted)
+           {
+             continue;
+           }
+       }
+      else
+       devconf = &dm->conf->default_devconf;
 
       /* Create vnet interface */
       vec_add2_aligned (dm->devices, xd, 1, CLIB_CACHE_LINE_BYTES);
       xd->nb_rx_desc = DPDK_NB_RX_DESC_DEFAULT;
       xd->nb_tx_desc = DPDK_NB_TX_DESC_DEFAULT;
       xd->cpu_socket = (i8) rte_eth_dev_socket_id (i);
-
       if (p)
        {
-         devconf = pool_elt_at_index (dm->conf->dev_confs, p[0]);
          xd->name = devconf->name;
        }
-      else
-       devconf = &dm->conf->default_devconf;
 
       /* Handle representor devices that share the same PCI ID */
       if (dev_info.switch_info.domain_id != RTE_ETH_DEV_SWITCH_DOMAIN_ID_INVALID)
@@ -876,9 +900,9 @@ dpdk_bind_devices_to_uio (dpdk_config_main_t * conf)
 
        if (!p)
           {
-          skipped:
-            continue;
-          }
+         skipped_pci:
+           continue;
+         }
 
        devconf = pool_elt_at_index (conf->dev_confs, p[0]);
       }
@@ -902,12 +926,13 @@ dpdk_bind_devices_to_uio (dpdk_config_main_t * conf)
                 hash_set (conf->device_config_index_by_pci_addr, addr->as_u32,
                           devconf - conf->dev_confs);
                 devconf->pci_addr.as_u32 = addr->as_u32;
-                devconf->is_blacklisted = 1;
-                goto skipped;
-              }
-            else /* explicitly whitelisted, ignore the device blacklist  */
-              break;
-          }
+               devconf->dev_addr_type = VNET_DEV_ADDR_PCI;
+               devconf->is_blacklisted = 1;
+               goto skipped_pci;
+             }
+           else /* explicitly whitelisted, ignore the device blacklist  */
+             break;
+         }
       }
 
     /* virtio */
@@ -1002,6 +1027,7 @@ dpdk_bind_devices_to_uio (dpdk_config_main_t * conf)
                      devconf - conf->dev_confs);
            devconf->pci_addr.as_u32 = addr->as_u32;
          }
+       devconf->dev_addr_type = VNET_DEV_ADDR_PCI;
        devconf->is_blacklisted = 1;
        clib_error_report (error);
       }
@@ -1016,16 +1042,72 @@ dpdk_bind_vmbus_devices_to_uio (dpdk_config_main_t * conf)
 {
   clib_error_t *error;
   vlib_vmbus_addr_t *addrs, *addr = 0;
+  int num_whitelisted = vec_len (conf->dev_confs);
+  int i;
 
   addrs = vlib_vmbus_get_all_dev_addrs ();
 
   /* *INDENT-OFF* */
   vec_foreach (addr, addrs)
     {
-      error = vlib_vmbus_bind_to_uio (addr);
+      dpdk_device_config_t *devconf = 0;
+      if (num_whitelisted)
+       {
+         uword *p = hash_get (conf->device_config_index_by_vmbus_addr,
+                              addr->as_u32[0]);
+         if (!p)
+           {
+             /* No devices blacklisted, but have whitelisted. blacklist all
+              * non-whitelisted */
+             pool_get (conf->dev_confs, devconf);
+             hash_set (conf->device_config_index_by_vmbus_addr,
+                       addr->as_u32[0], devconf - conf->dev_confs);
+             devconf->vmbus_addr = *addr;
+             devconf->dev_addr_type = VNET_DEV_ADDR_VMBUS;
+             devconf->is_blacklisted = 1;
+           skipped_vmbus:
+             continue;
+           }
+
+         devconf = pool_elt_at_index (conf->dev_confs, p[0]);
+       }
+
+      /* Enforce Device blacklist by vmbus_addr */
+      for (i = 0; i < vec_len (conf->blacklist_by_vmbus_addr); i++)
+       {
+         u32 vmbus_as_u32 = conf->blacklist_by_vmbus_addr[i];
+         if (vmbus_as_u32 == addr->as_u32[0])
+           {
+             if (devconf == 0)
+               {
+                 /* Device not whitelisted */
+                 pool_get (conf->dev_confs, devconf);
+                 hash_set (conf->device_config_index_by_vmbus_addr,
+                           addr->as_u32[0], devconf - conf->dev_confs);
+                 devconf->vmbus_addr = *addr;
+                 devconf->dev_addr_type = VNET_DEV_ADDR_VMBUS;
+                 devconf->is_blacklisted = 1;
+                 goto skipped_vmbus;
+               }
+             else
+               {
+                 break;
+               }
+           }
+       }
 
+      error = vlib_vmbus_bind_to_uio (addr);
       if (error)
        {
+         if (devconf == 0)
+           {
+             pool_get (conf->dev_confs, devconf);
+             hash_set (conf->device_config_index_by_vmbus_addr,
+                       addr->as_u32[0], devconf - conf->dev_confs);
+             devconf->vmbus_addr = *addr;
+           }
+         devconf->dev_addr_type = VNET_DEV_ADDR_VMBUS;
+         devconf->is_blacklisted = 1;
          clib_error_report (error);
        }
     }
@@ -1033,36 +1115,66 @@ dpdk_bind_vmbus_devices_to_uio (dpdk_config_main_t * conf)
 }
 
 static clib_error_t *
-dpdk_device_config (dpdk_config_main_t * conf, vlib_pci_addr_t pci_addr,
-                   unformat_input_t * input, u8 is_default)
+dpdk_device_config (dpdk_config_main_t *conf, void *addr,
+                   dpdk_device_addr_type_t addr_type, unformat_input_t *input,
+                   u8 is_default)
 {
   clib_error_t *error = 0;
   uword *p;
-  dpdk_device_config_t *devconf;
+  dpdk_device_config_t *devconf = 0;
   unformat_input_t sub_input;
 
   if (is_default)
     {
       devconf = &conf->default_devconf;
     }
-  else
+  else if (addr_type == VNET_DEV_ADDR_PCI)
     {
-      p = hash_get (conf->device_config_index_by_pci_addr, pci_addr.as_u32);
+      p = hash_get (conf->device_config_index_by_pci_addr,
+                   ((vlib_pci_addr_t *) (addr))->as_u32);
 
       if (!p)
        {
          pool_get (conf->dev_confs, devconf);
-         hash_set (conf->device_config_index_by_pci_addr, pci_addr.as_u32,
+         hash_set (conf->device_config_index_by_pci_addr,
+                   ((vlib_pci_addr_t *) (addr))->as_u32,
                    devconf - conf->dev_confs);
        }
       else
        return clib_error_return (0,
                                  "duplicate configuration for PCI address %U",
-                                 format_vlib_pci_addr, &pci_addr);
+                                 format_vlib_pci_addr, addr);
+    }
+  else if (addr_type == VNET_DEV_ADDR_VMBUS)
+    {
+      p = hash_get (conf->device_config_index_by_vmbus_addr,
+                   ((vlib_vmbus_addr_t *) (addr))->as_u32[0]);
+
+      if (!p)
+       {
+         pool_get (conf->dev_confs, devconf);
+         hash_set (conf->device_config_index_by_vmbus_addr,
+                   ((vlib_vmbus_addr_t *) (addr))->as_u32[0],
+                   devconf - conf->dev_confs);
+       }
+      else
+       return clib_error_return (
+         0, "duplicate configuration for VMBUS address %U",
+         format_vlib_vmbus_addr, addr);
     }
 
-  devconf->pci_addr.as_u32 = pci_addr.as_u32;
-  devconf->tso = DPDK_DEVICE_TSO_DEFAULT;
+  if (addr_type == VNET_DEV_ADDR_PCI)
+    {
+      devconf->pci_addr.as_u32 = ((vlib_pci_addr_t *) (addr))->as_u32;
+      devconf->tso = DPDK_DEVICE_TSO_DEFAULT;
+      devconf->dev_addr_type = VNET_DEV_ADDR_PCI;
+    }
+  else if (addr_type == VNET_DEV_ADDR_VMBUS)
+    {
+      devconf->vmbus_addr = *((vlib_vmbus_addr_t *) (addr));
+      devconf->tso = DPDK_DEVICE_TSO_DEFAULT;
+      devconf->dev_addr_type = VNET_DEV_ADDR_VMBUS;
+    }
 
   if (!input)
     return 0;
@@ -1124,11 +1236,10 @@ dpdk_device_config (dpdk_config_main_t * conf, vlib_pci_addr_t pci_addr,
   else if (devconf->workers &&
           clib_bitmap_count_set_bits (devconf->workers) !=
           devconf->num_rx_queues)
-    error =
-      clib_error_return (0,
-                        "%U: number of worker threads must be "
-                        "equal to number of rx queues", format_vlib_pci_addr,
-                        &pci_addr);
+    error = clib_error_return (0,
+                              "%U: number of worker threads must be "
+                              "equal to number of rx queues",
+                              format_vlib_pci_addr, addr);
 
   return error;
 }
@@ -1171,7 +1282,8 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
   dpdk_config_main_t *conf = &dpdk_config_main;
   vlib_thread_main_t *tm = vlib_get_thread_main ();
   dpdk_device_config_t *devconf;
-  vlib_pci_addr_t pci_addr;
+  vlib_pci_addr_t pci_addr = { 0 };
+  vlib_vmbus_addr_t vmbus_addr = { 0 };
   unformat_input_t sub_input;
   uword default_hugepage_sz, x;
   u8 *s, *tmp = 0;
@@ -1189,6 +1301,7 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
     format (0, "%s/hugepages%c", vlib_unix_get_runtime_dir (), 0);
 
   conf->device_config_index_by_pci_addr = hash_create (0, sizeof (uword));
+  conf->device_config_index_by_vmbus_addr = hash_create (0, sizeof (uword));
 
   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
     {
@@ -1217,8 +1330,7 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
                         &sub_input))
        {
          error =
-           dpdk_device_config (conf, (vlib_pci_addr_t) (u32) ~ 1, &sub_input,
-                               1);
+           dpdk_device_config (conf, 0, VNET_DEV_ADDR_ANY, &sub_input, 1);
 
          if (error)
            return error;
@@ -1228,7 +1340,8 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
            (input, "dev %U %U", unformat_vlib_pci_addr, &pci_addr,
             unformat_vlib_cli_sub_input, &sub_input))
        {
-         error = dpdk_device_config (conf, pci_addr, &sub_input, 0);
+         error = dpdk_device_config (conf, &pci_addr, VNET_DEV_ADDR_PCI,
+                                     &sub_input, 0);
 
          if (error)
            return error;
@@ -1237,7 +1350,30 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
        }
       else if (unformat (input, "dev %U", unformat_vlib_pci_addr, &pci_addr))
        {
-         error = dpdk_device_config (conf, pci_addr, 0, 0);
+         error =
+           dpdk_device_config (conf, &pci_addr, VNET_DEV_ADDR_PCI, 0, 0);
+
+         if (error)
+           return error;
+
+         num_whitelisted++;
+       }
+      else if (unformat (input, "dev %U %U", unformat_vlib_vmbus_addr,
+                        &vmbus_addr, unformat_vlib_cli_sub_input, &sub_input))
+       {
+         error = dpdk_device_config (conf, &vmbus_addr, VNET_DEV_ADDR_VMBUS,
+                                     &sub_input, 0);
+
+         if (error)
+           return error;
+
+         num_whitelisted++;
+       }
+      else if (unformat (input, "dev %U", unformat_vlib_vmbus_addr,
+                        &vmbus_addr))
+       {
+         error =
+           dpdk_device_config (conf, &vmbus_addr, VNET_DEV_ADDR_VMBUS, 0, 0);
 
          if (error)
            return error;
@@ -1259,6 +1395,11 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
          tmp = format (0, "--no-pci%c", 0);
          vec_add1 (conf->eal_init_args, tmp);
        }
+      else if (unformat (input, "blacklist %U", unformat_vlib_vmbus_addr,
+                        &vmbus_addr))
+       {
+         vec_add1 (conf->blacklist_by_vmbus_addr, vmbus_addr.as_u32[0]);
+       }
       else
        if (unformat
            (input, "blacklist %x:%x:%x.%x", &domain, &bus, &device, &func))
@@ -1434,23 +1575,21 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
     /* default per-device config items */
     foreach_dpdk_device_config_item
 
-    /* copy vlan_strip config from default device */
-       if (devconf->vlan_strip_offload == 0 &&
-               conf->default_devconf.vlan_strip_offload > 0)
-               devconf->vlan_strip_offload =
-                       conf->default_devconf.vlan_strip_offload;
+      /* copy vlan_strip config from default device */
+      _ (vlan_strip_offload)
 
-       /* copy tso config from default device */
-       _(tso)
+      /* copy tso config from default device */
+      (tso)
 
-       /* copy tso config from default device */
-       _(devargs)
+      /* copy tso config from default device */
+      (devargs)
 
-       /* copy rss_queues config from default device */
-       _(rss_queues)
+      /* copy rss_queues config from default device */
+      (rss_queues)
 
-    /* add DPDK EAL whitelist/blacklist entry */
-    if (num_whitelisted > 0 && devconf->is_blacklisted == 0)
+      /* add DPDK EAL whitelist/blacklist entry */
+      if (num_whitelisted > 0 && devconf->is_blacklisted == 0 &&
+         devconf->dev_addr_type == VNET_DEV_ADDR_PCI)
     {
          tmp = format (0, "-a%c", 0);
          vec_add1 (conf->eal_init_args, tmp);
@@ -1464,7 +1603,8 @@ dpdk_config (vlib_main_t * vm, unformat_input_t * input)
          }
          vec_add1 (conf->eal_init_args, tmp);
     }
-    else if (num_whitelisted == 0 && devconf->is_blacklisted != 0)
+    else if (num_whitelisted == 0 && devconf->is_blacklisted != 0 &&
+            devconf->dev_addr_type == VNET_DEV_ADDR_PCI)
     {
          tmp = format (0, "-b%c", 0);
          vec_add1 (conf->eal_init_args, tmp);
index 2fc438b..d50b539 100644 (file)
@@ -118,8 +118,8 @@ linux_vmbus_main_t linux_vmbus_main;
  * "f2c086b2-ff2e-11e8-88de-7bad0a57de05" and convert
  * it to u8[16]
  */
-static uword
-unformat_vlib_vmbus_addr (unformat_input_t * input, va_list * args)
+uword
+unformat_vlib_vmbus_addr (unformat_input_t *input, va_list *args)
 {
   vlib_vmbus_addr_t *addr = va_arg (*args, vlib_vmbus_addr_t *);
   uword ret = 0;
@@ -137,8 +137,8 @@ unformat_vlib_vmbus_addr (unformat_input_t * input, va_list * args)
 }
 
 /* Convert bus address to standard UUID string */
-static u8 *
-format_vlib_vmbus_addr (u8 * s, va_list * va)
+u8 *
+format_vlib_vmbus_addr (u8 *s, va_list *va)
 {
   vlib_vmbus_addr_t *addr = va_arg (*va, vlib_vmbus_addr_t *);
   char tmp[40];
@@ -297,15 +297,21 @@ vlib_vmbus_bind_to_uio (vlib_vmbus_addr_t * addr)
       vec_reset_length (s);
       s = format (s, "%s/%s/new_id%c", sysfs_vmbus_drv_path, uio_drv_name, 0);
       error = clib_sysfs_write ((char *) s, "%s", netvsc_uuid);
-
+      /* If device already exists, we can bind/unbind/override driver */
       if (error)
        {
-         close (fd);
-         goto done;
+         if (error->code == EEXIST)
+           {
+             clib_error_free (error);
+           }
+         else
+           {
+             close (fd);
+             goto done;
+           }
        }
 
       uio_new_id_needed = 0;
-
     }
 
   error = vlib_vmbus_raise_lower (fd, ifname);
index eadf5f1..045e2dd 100644 (file)
 #include <net/if.h>
 
 /* this is a stub replaced by the Linux specfic version */
-vlib_vmbus_addr_t * __attribute__ ((weak)) vlib_vmbus_get_all_dev_addrs ()
+vlib_vmbus_addr_t *__clib_weak
+vlib_vmbus_get_all_dev_addrs ()
 {
   return NULL;
 }
 
+u8 *__clib_weak
+format_vlib_vmbus_addr (u8 *s, va_list *va)
+{
+  return 0;
+}
+
+uword __clib_weak
+unformat_vlib_vmbus_addr (unformat_input_t *input, va_list *args)
+{
+  return 0;
+}
+
 clib_error_t *
 vmbus_bus_init (vlib_main_t * vm)
 {
index 0927b89..7df62ab 100644 (file)
 
 #include <vlib/vlib.h>
 
-typedef struct
+typedef union
 {
   u8 guid[16];
+  u32 as_u32[4];
 } vlib_vmbus_addr_t;
+
 typedef u32 vlib_vmbus_dev_handle_t;
 
 vlib_vmbus_addr_t *vlib_vmbus_get_all_dev_addrs ();
@@ -33,6 +35,8 @@ uword vlib_vmbus_get_private_data (vlib_vmbus_dev_handle_t h);
 void vlib_vmbus_set_private_data (vlib_vmbus_dev_handle_t h,
                                  uword private_data);
 
+format_function_t format_vlib_vmbus_addr;
+unformat_function_t unformat_vlib_vmbus_addr;
 clib_error_t *vlib_vmbus_bind_to_uio (vlib_vmbus_addr_t * addr);
 #endif /* included_vlib_vmbus_h */