dpdk: add rte_delay_us_callback
[vpp.git] / vnet / vnet / interface.c
index 3a12085..b72dcd4 100644 (file)
@@ -39,6 +39,8 @@
 
 #include <vnet/vnet.h>
 #include <vnet/plugin/plugin.h>
+#include <vnet/fib/ip6_fib.h>
+#include <vnet/adj/adj.h>
 
 #define VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE (1 << 0)
 #define VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE (1 << 1)
@@ -238,17 +240,25 @@ unserialize_vnet_interface_state (serialize_main_t * m, va_list * va)
 static clib_error_t *
 call_elf_section_interface_callbacks (vnet_main_t * vnm, u32 if_index,
                                      u32 flags,
-                                     _vnet_interface_function_list_elt_t *
-                                     elt)
+                                     _vnet_interface_function_list_elt_t **
+                                     elts)
 {
+  _vnet_interface_function_list_elt_t *elt;
+  vnet_interface_function_priority_t prio;
   clib_error_t *error = 0;
 
-  while (elt)
+  for (prio = VNET_ITF_FUNC_PRIORITY_LOW;
+       prio <= VNET_ITF_FUNC_PRIORITY_HIGH; prio++)
     {
-      error = elt->fp (vnm, if_index, flags);
-      if (error)
-       return error;
-      elt = elt->next_interface_function;
+      elt = elts[prio];
+
+      while (elt)
+       {
+         error = elt->fp (vnm, if_index, flags);
+         if (error)
+           return error;
+         elt = elt->next_interface_function;
+       }
     }
   return error;
 }
@@ -343,8 +353,7 @@ vnet_hw_interface_set_flags_helper (vnet_main_t * vnm, u32 hw_if_index,
        goto done;
 
       error = call_elf_section_interface_callbacks
-       (vnm, hw_if_index, is_create,
-        vnm->hw_interface_link_up_down_functions);
+       (vnm, hw_if_index, flags, vnm->hw_interface_link_up_down_functions);
 
       if (error)
        goto done;
@@ -450,8 +459,16 @@ vnet_sw_interface_set_flags_helper (vnet_main_t * vnm, u32 sw_if_index,
          mc_serialize (vm->mc_main, &vnet_sw_interface_set_flags_msg, &s);
        }
 
-      error = call_elf_section_interface_callbacks
-       (vnm, sw_if_index, flags, vnm->sw_interface_admin_up_down_functions);
+      /* set the flags now before invoking the registered clients
+       * so that the state they query is consistent with the state here notified */
+      old_flags = si->flags;
+      si->flags &= ~mask;
+      si->flags |= flags;
+      if ((flags | old_flags) & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
+       error = call_elf_section_interface_callbacks
+         (vnm, sw_if_index, flags,
+          vnm->sw_interface_admin_up_down_functions);
+      si->flags = old_flags;
 
       if (error)
        goto done;
@@ -614,6 +631,16 @@ vnet_delete_sw_interface (vnet_main_t * vnm, u32 sw_if_index)
   vnet_sw_interface_t *sw =
     pool_elt_at_index (im->sw_interfaces, sw_if_index);
 
+  /* Make sure the interface is in L3 mode (removed from L2 BD or XConnect) */
+  vlib_main_t *vm = vlib_get_main ();
+  l2_input_config_t *config;
+  config = vec_elt_at_index (l2input_main.configs, sw_if_index);
+  if (config->xconnect)
+    set_int_l2_mode (vm, vnm, MODE_L3, config->output_sw_if_index, 0, 0, 0,
+                    0);
+  if (config->xconnect || config->bridge)
+    set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0, 0, 0, 0);
+
   /* Bring down interface in case it is up. */
   if (sw->flags != 0)
     vnet_sw_interface_set_flags (vnm, sw_if_index, /* flags */ 0);
@@ -631,6 +658,7 @@ setup_tx_node (vlib_main_t * vm,
 
   n->function = dev_class->tx_function;
   n->format_trace = dev_class->format_tx_trace;
+
   vlib_register_errors (vm, node_index,
                        dev_class->tx_function_n_errors,
                        dev_class->tx_function_error_strings);
@@ -659,7 +687,9 @@ vnet_register_interface (vnet_main_t * vnm,
   vnet_hw_interface_class_t *hw_class =
     vnet_get_hw_interface_class (vnm, hw_class_index);
   vlib_main_t *vm = vnm->vlib_main;
-  u32 hw_index;
+  vnet_feature_config_main_t *fcm;
+  vnet_config_main_t *cm;
+  u32 hw_index, i;
   char *tx_node_name, *output_node_name;
 
   pool_get (im->hw_interfaces, hw);
@@ -684,11 +714,11 @@ vnet_register_interface (vnet_main_t * vnm,
 
   /* Make hardware interface point to software interface. */
   {
-    vnet_sw_interface_t sw;
-
-    memset (&sw, 0, sizeof (sw));
-    sw.type = VNET_SW_INTERFACE_TYPE_HARDWARE;
-    sw.hw_if_index = hw_index;
+    vnet_sw_interface_t sw = {
+      .type = VNET_SW_INTERFACE_TYPE_HARDWARE,
+      .flood_class = VNET_FLOOD_CLASS_NORMAL,
+      .hw_if_index = hw_index
+    };
     hw->sw_if_index = vnet_create_sw_interface_no_callbacks (vnm, &sw);
   }
 
@@ -711,6 +741,8 @@ vnet_register_interface (vnet_main_t * vnm,
     {
       vnet_hw_interface_nodes_t *hn;
       vnet_interface_output_runtime_t *rt;
+      vlib_node_t *node;
+      vlib_node_runtime_t *nrt;
 
       hn = vec_end (im->deleted_hw_interface_nodes) - 1;
 
@@ -732,6 +764,22 @@ vnet_register_interface (vnet_main_t * vnm,
       rt->sw_if_index = hw->sw_if_index;
       rt->dev_instance = hw->dev_instance;
 
+      /* The new class may differ from the old one.
+       * Functions have to be updated. */
+      node = vlib_get_node (vm, hw->output_node_index);
+      node->function = dev_class->flatten_output_chains ?
+       vnet_interface_output_node_flatten_multiarch_select () :
+       vnet_interface_output_node_multiarch_select ();
+      node->format_trace = format_vnet_interface_output_trace;
+      nrt = vlib_node_get_runtime (vm, hw->output_node_index);
+      nrt->function = node->function;
+
+      node = vlib_get_node (vm, hw->tx_node_index);
+      node->function = dev_class->tx_function;
+      node->format_trace = dev_class->format_tx_trace;
+      nrt = vlib_node_get_runtime (vm, hw->tx_node_index);
+      nrt->function = node->function;
+
       vlib_worker_thread_node_runtime_update ();
       _vec_len (im->deleted_hw_interface_nodes) -= 1;
     }
@@ -764,8 +812,8 @@ vnet_register_interface (vnet_main_t * vnm,
 
       r.flags = 0;
       r.name = output_node_name;
-      r.function = dev_class->no_flatten_output_chains ?
-       vnet_interface_output_node_no_flatten_multiarch_select () :
+      r.function = dev_class->flatten_output_chains ?
+       vnet_interface_output_node_flatten_multiarch_select () :
        vnet_interface_output_node_multiarch_select ();
       r.format_trace = format_vnet_interface_output_trace;
 
@@ -780,17 +828,34 @@ vnet_register_interface (vnet_main_t * vnm,
       }
       hw->output_node_index = vlib_register_node (vm, &r);
 
-#define _(sym,str) vlib_node_add_named_next_with_slot (vm, \
-                     hw->output_node_index, str,           \
-                     VNET_INTERFACE_OUTPUT_NEXT_##sym);
-      foreach_intf_output_feat
-#undef _
-       vlib_node_add_named_next_with_slot (vm, hw->output_node_index,
-                                           "error-drop",
-                                           VNET_INTERFACE_OUTPUT_NEXT_DROP);
+      vlib_node_add_named_next_with_slot (vm, hw->output_node_index,
+                                         "error-drop",
+                                         VNET_INTERFACE_OUTPUT_NEXT_DROP);
       vlib_node_add_next_with_slot (vm, hw->output_node_index,
                                    hw->tx_node_index,
                                    VNET_INTERFACE_OUTPUT_NEXT_TX);
+
+      /* add interface to the list of "output-interface" feature arc start nodes
+         and clone nexts from 1st interface if it exists */
+      fcm = vnet_feature_get_config_main (im->output_feature_arc_index);
+      cm = &fcm->config_main;
+      i = vec_len (cm->start_node_indices);
+      vec_validate (cm->start_node_indices, i);
+      cm->start_node_indices[i] = hw->output_node_index;
+      if (hw_index)
+       {
+         /* copy nexts from 1st interface */
+         vnet_hw_interface_t *first_hw;
+         vlib_node_t *first_node;
+
+         first_hw = vnet_get_hw_interface (vnm, /* hw_if_index */ 0);
+         first_node = vlib_get_node (vm, first_hw->output_node_index);
+
+         /* 1st 2 nexts are already added above */
+         for (i = 2; i < vec_len (first_node->next_nodes); i++)
+           vlib_node_add_next_with_slot (vm, hw->output_node_index,
+                                         first_node->next_nodes[i], i);
+       }
     }
 
   setup_output_node (vm, hw->output_node_index, hw_class);
@@ -855,6 +920,27 @@ vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index)
   pool_put (im->hw_interfaces, hw);
 }
 
+void
+vnet_hw_interface_walk_sw (vnet_main_t * vnm,
+                          u32 hw_if_index,
+                          vnet_hw_sw_interface_walk_t fn, void *ctx)
+{
+  vnet_hw_interface_t *hi;
+  u32 id, sw_if_index;
+
+  hi = vnet_get_hw_interface (vnm, hw_if_index);
+  /* the super first, then the and sub interfaces */
+  fn (vnm, hi->sw_if_index, ctx);
+
+  /* *INDENT-OFF* */
+  hash_foreach (id, sw_if_index,
+                hi->sub_interface_sw_if_index_by_id,
+  ({
+    fn (vnm, sw_if_index, ctx);
+  }));
+  /* *INDENT-ON* */
+}
+
 static void
 serialize_vnet_hw_interface_set_class (serialize_main_t * m, va_list * va)
 {
@@ -1035,6 +1121,16 @@ vnet_hw_interface_compare (vnet_main_t * vnm,
   return (word) h0->hw_instance - (word) h1->hw_instance;
 }
 
+int
+vnet_sw_interface_is_p2p (vnet_main_t * vnm, u32 sw_if_index)
+{
+  vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
+  vnet_hw_interface_class_t *hc =
+    vnet_get_hw_interface_class (vnm, hw->hw_class_index);
+
+  return (hc->flags & VNET_HW_INTERFACE_CLASS_FLAG_P2P);
+}
+
 clib_error_t *
 vnet_interface_init (vlib_main_t * vm)
 {
@@ -1111,6 +1207,12 @@ vnet_interface_init (vlib_main_t * vm)
       {
        c->index = vec_len (im->hw_interface_classes);
        hash_set_mem (im->hw_interface_class_by_name, c->name, c->index);
+
+       if (NULL == c->build_rewrite)
+         c->build_rewrite = default_build_rewrite;
+       if (NULL == c->update_adjacency)
+         c->update_adjacency = default_update_adjacency;
+
        vec_add1 (im->hw_interface_classes, c[0]);
        c = c->next_class_registration;
       }
@@ -1124,6 +1226,7 @@ vnet_interface_init (vlib_main_t * vm)
 
     return error;
   }
+  vnm->interface_tag_by_sw_if_index = hash_create (0, sizeof (uword));
 }
 
 VLIB_INIT_FUNCTION (vnet_interface_init);
@@ -1158,34 +1261,6 @@ vnet_interface_name_renumber (u32 sw_if_index, u32 new_show_dev_instance)
   return rv;
 }
 
-int
-vnet_interface_add_del_feature (vnet_main_t * vnm,
-                               vlib_main_t * vm,
-                               u32 sw_if_index,
-                               intf_output_feat_t feature, int is_add)
-{
-  vnet_sw_interface_t *sw;
-
-  sw = vnet_get_sw_interface (vnm, sw_if_index);
-
-  if (is_add)
-    {
-
-      sw->output_feature_bitmap |= (1 << feature);
-      sw->output_feature_bitmap |= (1 << INTF_OUTPUT_FEAT_DONE);
-
-    }
-  else
-    {                          /* delete */
-
-      sw->output_feature_bitmap &= ~(1 << feature);
-      if (sw->output_feature_bitmap == (1 << INTF_OUTPUT_FEAT_DONE))
-       sw->output_feature_bitmap = 0;
-
-    }
-  return 0;
-}
-
 clib_error_t *
 vnet_rename_interface (vnet_main_t * vnm, u32 hw_if_index, char *new_name)
 {
@@ -1222,6 +1297,107 @@ vnet_rename_interface (vnet_main_t * vnm, u32 hw_if_index, char *new_name)
   return error;
 }
 
+static clib_error_t *
+vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
+                                            u32 hw_if_index, u64 mac_address)
+{
+  clib_error_t *error = 0;
+  vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
+
+  if (hi->hw_address)
+    {
+      vnet_device_class_t *dev_class =
+       vnet_get_device_class (vnm, hi->dev_class_index);
+      if (dev_class->mac_addr_change_function)
+       {
+         error =
+           dev_class->mac_addr_change_function (vnet_get_hw_interface
+                                                (vnm, hw_if_index),
+                                                (char *) &mac_address);
+       }
+      if (!error)
+       {
+         ethernet_main_t *em = &ethernet_main;
+         ethernet_interface_t *ei =
+           pool_elt_at_index (em->interfaces, hi->hw_instance);
+
+         vec_validate (hi->hw_address,
+                       STRUCT_SIZE_OF (ethernet_header_t, src_address) - 1);
+         clib_memcpy (hi->hw_address, &mac_address,
+                      vec_len (hi->hw_address));
+
+         clib_memcpy (ei->address, (u8 *) & mac_address,
+                      sizeof (ei->address));
+         ethernet_arp_change_mac (vnm, hw_if_index);
+         ethernet_ndp_change_mac (vnm->vlib_main, hw_if_index);
+       }
+      else
+       {
+         error =
+           clib_error_return (0,
+                              "MAC Address Change is not supported on this interface");
+       }
+    }
+  else
+    {
+      error =
+       clib_error_return (0,
+                          "mac address change is not supported for interface index %u",
+                          hw_if_index);
+    }
+  return error;
+}
+
+clib_error_t *
+vnet_hw_interface_change_mac_address (vnet_main_t * vnm, u32 hw_if_index,
+                                     u64 mac_address)
+{
+  return vnet_hw_interface_change_mac_address_helper
+    (vnm, hw_if_index, mac_address);
+}
+
+vnet_l3_packet_type_t
+vnet_link_to_l3_proto (vnet_link_t link)
+{
+  switch (link)
+    {
+    case VNET_LINK_IP4:
+      return (VNET_L3_PACKET_TYPE_IP4);
+    case VNET_LINK_IP6:
+      return (VNET_L3_PACKET_TYPE_IP6);
+    case VNET_LINK_MPLS:
+      return (VNET_L3_PACKET_TYPE_MPLS_UNICAST);
+    case VNET_LINK_ARP:
+      return (VNET_L3_PACKET_TYPE_ARP);
+    case VNET_LINK_ETHERNET:
+      ASSERT (0);
+      break;
+    }
+  ASSERT (0);
+  return (0);
+}
+
+u8 *
+default_build_rewrite (vnet_main_t * vnm,
+                      u32 sw_if_index,
+                      vnet_link_t link_type, const void *dst_address)
+{
+  return (NULL);
+}
+
+void
+default_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
+{
+  u8 *rewrite;
+
+  rewrite = vnet_build_rewrite_for_sw_interface (vnm, sw_if_index,
+                                                adj_get_link_type (ai),
+                                                NULL);
+
+  adj_nbr_update_rewrite (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE, rewrite);
+}
+
+
 /*
  * fd.io coding-style-patch-verification: ON
  *