avf: fix race between avf process node and avf_delete_if(...)
[vpp.git] / src / plugins / avf / device.c
index 8d44bd0..62a18cc 100644 (file)
@@ -35,6 +35,7 @@
 #define PCI_DEVICE_ID_INTEL_X722_VF            0x37cd
 
 avf_main_t avf_main;
+void avf_delete_if (vlib_main_t * vm, avf_device_t * ad, int with_barrier);
 
 static pci_device_id_t avf_pci_device_ids[] = {
   {.vendor_id = PCI_VENDOR_ID_INTEL,.device_id = PCI_DEVICE_ID_INTEL_AVF},
@@ -1158,25 +1159,29 @@ avf_flag_change (vnet_main_t * vnm, vnet_hw_interface_t * hw, u32 flags)
   vlib_main_t *vm = vlib_get_main ();
   avf_main_t *am = &avf_main;
   avf_device_t *ad = vec_elt_at_index (am->devices, hw->dev_instance);
-  if (ETHERNET_INTERFACE_FLAG_CONFIG_PROMISC (flags))
-    {
-      clib_error_t *error;
-      int promisc_enabled = (flags & ETHERNET_INTERFACE_FLAG_ACCEPT_ALL) != 0;
-      u32 new_flags = promisc_enabled ?
-       ad->flags | AVF_DEVICE_F_PROMISC : ad->flags & ~AVF_DEVICE_F_PROMISC;
-
-      if (new_flags == ad->flags)
-       return flags;
+  clib_error_t *error;
+  u8 promisc_enabled;
 
-      if ((error = avf_config_promisc_mode (vm, ad, promisc_enabled)))
-       {
-         avf_log_err (ad, "%s: %U", format_clib_error, error);
-         clib_error_free (error);
-         return 0;
-       }
+  switch (flags)
+    {
+    case ETHERNET_INTERFACE_FLAG_DEFAULT_L3:
+      ad->flags &= ~AVF_DEVICE_F_PROMISC;
+      break;
+    case ETHERNET_INTERFACE_FLAG_ACCEPT_ALL:
+      ad->flags |= AVF_DEVICE_F_PROMISC;
+      break;
+    default:
+      return ~0;
+    }
 
-      ad->flags = new_flags;
+  promisc_enabled = ((ad->flags & AVF_DEVICE_F_PROMISC) != 0);
+  if ((error = avf_config_promisc_mode (vm, ad, promisc_enabled)))
+    {
+      avf_log_err (ad, "%s: %U", format_clib_error, error);
+      clib_error_free (error);
+      return ~0;
     }
+
   return 0;
 }
 
@@ -1198,7 +1203,6 @@ avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
        vlib_process_wait_for_event (vm);
 
       event_type = vlib_process_get_events (vm, &event_data);
-      vec_reset_length (event_data);
       irq = 0;
 
       switch (event_type)
@@ -1209,9 +1213,15 @@ avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
        case AVF_PROCESS_EVENT_START:
          enabled = 1;
          break;
-       case AVF_PROCESS_EVENT_STOP:
-         enabled = 0;
-         continue;
+       case AVF_PROCESS_EVENT_DELETE_IF:
+         for (int i = 0; i < vec_len (event_data); i++)
+           {
+             ad = pool_elt_at_index (am->devices, event_data[i]);
+             avf_delete_if (vm, ad, /* with_barrier */ 1);
+           }
+         if (pool_elts (am->devices) < 1)
+           enabled = 0;
+         break;
        case AVF_PROCESS_EVENT_AQ_INT:
          irq = 1;
          break;
@@ -1219,6 +1229,11 @@ avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
          ASSERT (0);
        }
 
+      vec_reset_length (event_data);
+
+      if (enabled == 0)
+       continue;
+
       /* *INDENT-OFF* */
       pool_foreach (ad, am->devices,
         {
@@ -1231,7 +1246,7 @@ avf_process (vlib_main_t * vm, vlib_node_runtime_t * rt, vlib_frame_t * f)
 }
 
 /* *INDENT-OFF* */
-VLIB_REGISTER_NODE (avf_process_node, static)  = {
+VLIB_REGISTER_NODE (avf_process_node)  = {
   .function = avf_process,
   .type = VLIB_NODE_TYPE_PROCESS,
   .name = "avf-process",
@@ -1312,17 +1327,23 @@ avf_irq_n_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h, u16 line)
 }
 
 void
-avf_delete_if (vlib_main_t * vm, avf_device_t * ad)
+avf_delete_if (vlib_main_t * vm, avf_device_t * ad, int with_barrier)
 {
   vnet_main_t *vnm = vnet_get_main ();
   avf_main_t *am = &avf_main;
   int i;
 
+  ad->flags &= ~AVF_DEVICE_F_ADMIN_UP;
+
   if (ad->hw_if_index)
     {
+      if (with_barrier)
+       vlib_worker_thread_barrier_sync (vm);
       vnet_hw_interface_set_flags (vnm, ad->hw_if_index, 0);
       vnet_hw_interface_unassign_rx_thread (vnm, ad->hw_if_index, 0);
       ethernet_delete_interface (vnm, ad->hw_if_index);
+      if (with_barrier)
+       vlib_worker_thread_barrier_release (vm);
     }
 
   vlib_pci_device_close (vm, ad->pci_dev_handle);
@@ -1501,6 +1522,13 @@ avf_create_if (vlib_main_t * vm, avf_create_if_args_t * args)
   if (error)
     goto error;
 
+  /* Indicate ability to support L3 DMAC filtering and
+   * initialize interface to L3 non-promisc mode */
+  vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, ad->hw_if_index);
+  hi->flags |= VNET_HW_INTERFACE_FLAG_SUPPORTS_MAC_FILTER;
+  ethernet_set_flags (vnm, ad->hw_if_index,
+                     ETHERNET_INTERFACE_FLAG_DEFAULT_L3);
+
   vnet_sw_interface_t *sw = vnet_get_hw_sw_interface (vnm, ad->hw_if_index);
   args->sw_if_index = ad->sw_if_index = sw->sw_if_index;
 
@@ -1519,7 +1547,7 @@ avf_create_if (vlib_main_t * vm, avf_create_if_args_t * args)
   return;
 
 error:
-  avf_delete_if (vm, ad);
+  avf_delete_if (vm, ad, /* with_barrier */ 0);
   args->rv = VNET_API_ERROR_INVALID_INTERFACE;
   args->error = clib_error_return (error, "pci-addr %U",
                                   format_vlib_pci_addr, &args->addr);