interface: callback to manage extra MAC addresses
[vpp.git] / src / vnet / interface.c
index e04ba9b..0b4d78a 100644 (file)
 #include <vnet/adj/adj_mcast.h>
 #include <vnet/l2/l2_input.h>
 
-#define VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE (1 << 0)
-#define VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE (1 << 1)
+typedef enum vnet_interface_helper_flags_t_
+{
+  VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE = (1 << 0),
+  VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE = (1 << 1),
+} vnet_interface_helper_flags_t;
 
 static clib_error_t *vnet_hw_interface_set_flags_helper (vnet_main_t * vnm,
                                                         u32 hw_if_index,
-                                                        u32 flags,
-                                                        u32 helper_flags);
+                                                        vnet_hw_interface_flags_t
+                                                        flags,
+                                                        vnet_interface_helper_flags_t
+                                                        helper_flags);
 
 static clib_error_t *vnet_sw_interface_set_flags_helper (vnet_main_t * vnm,
                                                         u32 sw_if_index,
-                                                        u32 flags,
-                                                        u32 helper_flags);
+                                                        vnet_sw_interface_flags_t
+                                                        flags,
+                                                        vnet_interface_helper_flags_t
+                                                        helper_flags);
 
 static clib_error_t *vnet_hw_interface_set_class_helper (vnet_main_t * vnm,
                                                         u32 hw_if_index,
@@ -102,52 +109,17 @@ unserialize_vec_vnet_sw_hw_interface_state (serialize_main_t * m,
     }
 }
 
-static void
-serialize_vnet_sw_hw_interface_set_flags (serialize_main_t * m, va_list * va)
+static vnet_sw_interface_flags_t
+vnet_hw_interface_flags_to_sw (vnet_hw_interface_flags_t hwf)
 {
-  vnet_sw_hw_interface_state_t *s =
-    va_arg (*va, vnet_sw_hw_interface_state_t *);
-  serialize (m, serialize_vec_vnet_sw_hw_interface_state, s, 1);
-}
+  vnet_sw_interface_flags_t swf = VNET_SW_INTERFACE_FLAG_NONE;
 
-static void
-unserialize_vnet_sw_interface_set_flags (serialize_main_t * m, va_list * va)
-{
-  CLIB_UNUSED (mc_main_t * mc) = va_arg (*va, mc_main_t *);
-  vnet_sw_hw_interface_state_t s;
+  if (hwf & VNET_HW_INTERFACE_FLAG_LINK_UP)
+    swf |= VNET_SW_INTERFACE_FLAG_ADMIN_UP;
 
-  unserialize (m, unserialize_vec_vnet_sw_hw_interface_state, &s, 1);
-
-  vnet_sw_interface_set_flags_helper
-    (vnet_get_main (), s.sw_hw_if_index, s.flags,
-     /* helper_flags no redistribution */ 0);
+  return (swf);
 }
 
-static void
-unserialize_vnet_hw_interface_set_flags (serialize_main_t * m, va_list * va)
-{
-  CLIB_UNUSED (mc_main_t * mc) = va_arg (*va, mc_main_t *);
-  vnet_sw_hw_interface_state_t s;
-
-  unserialize (m, unserialize_vec_vnet_sw_hw_interface_state, &s, 1);
-
-  vnet_hw_interface_set_flags_helper
-    (vnet_get_main (), s.sw_hw_if_index, s.flags,
-     /* helper_flags no redistribution */ 0);
-}
-
-MC_SERIALIZE_MSG (vnet_sw_interface_set_flags_msg, static) =
-{
-.name = "vnet_sw_interface_set_flags",.serialize =
-    serialize_vnet_sw_hw_interface_set_flags,.unserialize =
-    unserialize_vnet_sw_interface_set_flags,};
-
-MC_SERIALIZE_MSG (vnet_hw_interface_set_flags_msg, static) =
-{
-.name = "vnet_hw_interface_set_flags",.serialize =
-    serialize_vnet_sw_hw_interface_set_flags,.unserialize =
-    unserialize_vnet_hw_interface_set_flags,};
-
 void
 serialize_vnet_interface_state (serialize_main_t * m, va_list * va)
 {
@@ -189,7 +161,7 @@ serialize_vnet_interface_state (serialize_main_t * m, va_list * va)
       {
        vec_add2 (sts, st, 1);
        st->sw_hw_if_index = hif->hw_if_index;
-       st->flags = hif->flags;
+       st->flags = vnet_hw_interface_flags_to_sw(hif->flags);
       }
   }));
   /* *INDENT-ON* */
@@ -199,6 +171,17 @@ serialize_vnet_interface_state (serialize_main_t * m, va_list * va)
   vec_free (sts);
 }
 
+static vnet_hw_interface_flags_t
+vnet_sw_interface_flags_to_hw (vnet_sw_interface_flags_t swf)
+{
+  vnet_hw_interface_flags_t hwf = VNET_HW_INTERFACE_FLAG_NONE;
+
+  if (swf & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
+    hwf |= VNET_HW_INTERFACE_FLAG_LINK_UP;
+
+  return (hwf);
+}
+
 void
 unserialize_vnet_interface_state (serialize_main_t * m, va_list * va)
 {
@@ -234,8 +217,11 @@ unserialize_vnet_interface_state (serialize_main_t * m, va_list * va)
 
   vec_unserialize (m, &sts, unserialize_vec_vnet_sw_hw_interface_state);
   vec_foreach (st, sts)
-    vnet_hw_interface_set_flags_helper (vnm, st->sw_hw_if_index, st->flags,
-                                       /* no distribute */ 0);
+  {
+    vnet_hw_interface_set_flags_helper
+      (vnm, st->sw_hw_if_index, vnet_sw_interface_flags_to_hw (st->flags),
+       /* no distribute */ 0);
+  }
   vec_free (sts);
 }
 
@@ -301,27 +287,22 @@ call_sw_interface_add_del_callbacks (vnet_main_t * vnm, u32 sw_if_index,
     (vnm, sw_if_index, is_create, vnm->sw_interface_add_del_functions);
 }
 
-#define VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE (1 << 0)
-#define VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE (1 << 1)
-
 static clib_error_t *
 vnet_hw_interface_set_flags_helper (vnet_main_t * vnm, u32 hw_if_index,
-                                   u32 flags, u32 helper_flags)
+                                   vnet_hw_interface_flags_t flags,
+                                   vnet_interface_helper_flags_t
+                                   helper_flags)
 {
   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
   vnet_hw_interface_class_t *hw_class =
     vnet_get_hw_interface_class (vnm, hi->hw_class_index);
-  vnet_device_class_t *dev_class =
-    vnet_get_device_class (vnm, hi->dev_class_index);
-  vlib_main_t *vm = vnm->vlib_main;
   u32 mask;
   clib_error_t *error = 0;
   u32 is_create =
     (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE) != 0;
 
   mask =
-    (VNET_HW_INTERFACE_FLAG_LINK_UP | VNET_HW_INTERFACE_FLAG_DUPLEX_MASK |
-     VNET_HW_INTERFACE_FLAG_SPEED_MASK);
+    (VNET_HW_INTERFACE_FLAG_LINK_UP | VNET_HW_INTERFACE_FLAG_DUPLEX_MASK);
   flags &= mask;
 
   /* Call hardware interface add/del callbacks. */
@@ -332,19 +313,6 @@ vnet_hw_interface_set_flags_helper (vnet_main_t * vnm, u32 hw_if_index,
   if (!is_create && (hi->flags & mask) == flags)
     goto done;
 
-  /* Some interface classes do not redistribute (e.g. are local). */
-  if (!dev_class->redistribute)
-    helper_flags &= ~VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE;
-
-  if (vm->mc_main
-      && (helper_flags & VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE))
-    {
-      vnet_sw_hw_interface_state_t s;
-      s.sw_hw_if_index = hw_if_index;
-      s.flags = flags;
-      mc_serialize (vm->mc_main, &vnet_hw_interface_set_flags_msg, &s);
-    }
-
   if ((hi->flags & VNET_HW_INTERFACE_FLAG_LINK_UP) !=
       (flags & VNET_HW_INTERFACE_FLAG_LINK_UP))
     {
@@ -370,10 +338,11 @@ done:
 
 static clib_error_t *
 vnet_sw_interface_set_flags_helper (vnet_main_t * vnm, u32 sw_if_index,
-                                   u32 flags, u32 helper_flags)
+                                   vnet_sw_interface_flags_t flags,
+                                   vnet_interface_helper_flags_t
+                                   helper_flags)
 {
   vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
-  vlib_main_t *vm = vnm->vlib_main;
   u32 mask;
   clib_error_t *error = 0;
   u32 is_create =
@@ -425,15 +394,6 @@ vnet_sw_interface_set_flags_helper (vnet_main_t * vnm, u32 sw_if_index,
            }
        }
 
-      /* Donot change state for slave link of bonded interfaces */
-      if (si->flags & VNET_SW_INTERFACE_FLAG_BOND_SLAVE)
-       {
-         error = clib_error_return
-           (0, "not allowed as %U belong to a BondEthernet interface",
-            format_vnet_sw_interface_name, vnm, si);
-         goto done;
-       }
-
       /* Already in the desired state? */
       if ((si->flags & mask) == flags)
        goto done;
@@ -451,16 +411,6 @@ vnet_sw_interface_set_flags_helper (vnet_main_t * vnm, u32 sw_if_index,
              ~VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE;
        }
 
-      if (vm->mc_main
-         && (helper_flags &
-             VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE))
-       {
-         vnet_sw_hw_interface_state_t s;
-         s.sw_hw_if_index = sw_if_index;
-         s.flags = flags;
-         mc_serialize (vm->mc_main, &vnet_sw_interface_set_flags_msg, &s);
-       }
-
       /* 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;
@@ -539,7 +489,8 @@ done:
 }
 
 clib_error_t *
-vnet_hw_interface_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
+vnet_hw_interface_set_flags (vnet_main_t * vnm, u32 hw_if_index,
+                            vnet_hw_interface_flags_t flags)
 {
   return vnet_hw_interface_set_flags_helper
     (vnm, hw_if_index, flags,
@@ -547,13 +498,38 @@ vnet_hw_interface_set_flags (vnet_main_t * vnm, u32 hw_if_index, u32 flags)
 }
 
 clib_error_t *
-vnet_sw_interface_set_flags (vnet_main_t * vnm, u32 sw_if_index, u32 flags)
+vnet_sw_interface_set_flags (vnet_main_t * vnm, u32 sw_if_index,
+                            vnet_sw_interface_flags_t flags)
 {
   return vnet_sw_interface_set_flags_helper
     (vnm, sw_if_index, flags,
      VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE);
 }
 
+void
+vnet_sw_interface_admin_up (vnet_main_t * vnm, u32 sw_if_index)
+{
+  u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
+
+  if (!(flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP))
+    {
+      flags |= VNET_SW_INTERFACE_FLAG_ADMIN_UP;
+      vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
+    }
+}
+
+void
+vnet_sw_interface_admin_down (vnet_main_t * vnm, u32 sw_if_index)
+{
+  u32 flags = vnet_sw_interface_get_flags (vnm, sw_if_index);
+
+  if (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP)
+    {
+      flags &= ~(VNET_SW_INTERFACE_FLAG_ADMIN_UP);
+      vnet_sw_interface_set_flags (vnm, sw_if_index, flags);
+    }
+}
+
 static u32
 vnet_create_sw_interface_no_callbacks (vnet_main_t * vnm,
                                       vnet_sw_interface_t * template)
@@ -650,10 +626,11 @@ vnet_delete_sw_interface (vnet_main_t * vnm, u32 sw_if_index)
     {
       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);
+       set_int_l2_mode (vm, vnm, MODE_L3, config->output_sw_if_index, 0,
+                        L2_BD_PORT_TYPE_NORMAL, 0, 0);
       if (config->xconnect || config->bridge)
-       set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0, 0, 0, 0);
+       set_int_l2_mode (vm, vnm, MODE_L3, sw_if_index, 0,
+                        L2_BD_PORT_TYPE_NORMAL, 0, 0);
     }
   vnet_clear_sw_interface_tag (vnm, sw_if_index);
 
@@ -790,7 +767,8 @@ vnet_register_interface (vnet_main_t * vnm,
   char *tx_node_name = NULL, *output_node_name = NULL;
 
   pool_get (im->hw_interfaces, hw);
-  memset (hw, 0, sizeof (*hw));
+  clib_memset (hw, 0, sizeof (*hw));
+  hw->trace_classify_table_index = ~0;
 
   hw_index = hw - im->hw_interfaces;
   hw->hw_if_index = hw_index;
@@ -872,7 +850,7 @@ vnet_register_interface (vnet_main_t * vnm,
       /* 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 = vnet_interface_output_node_multiarch_select ();
+      node->function = vnet_interface_output_node;
       node->format_trace = format_vnet_interface_output_trace;
       /* *INDENT-OFF* */
       foreach_vlib_main ({
@@ -903,7 +881,7 @@ vnet_register_interface (vnet_main_t * vnm,
        .is_deleted = 0,
       };
 
-      memset (&r, 0, sizeof (r));
+      clib_memset (&r, 0, sizeof (r));
       r.type = VLIB_NODE_TYPE_INTERNAL;
       r.runtime_data = &rt;
       r.runtime_data_bytes = sizeof (rt);
@@ -922,13 +900,14 @@ vnet_register_interface (vnet_main_t * vnm,
 
       r.flags = 0;
       r.name = output_node_name;
-      r.function = vnet_interface_output_node_multiarch_select ();
+      r.function = vnet_interface_output_node;
       r.format_trace = format_vnet_interface_output_trace;
 
       {
        static char *e[] = {
          "interface is down",
          "interface is deleted",
+         "no buffers to segment GSO",
        };
 
        r.n_errors = ARRAY_LEN (e);
@@ -1109,42 +1088,6 @@ vnet_sw_interface_walk (vnet_main_t * vnm,
   /* *INDENT-ON* */
 }
 
-static void
-serialize_vnet_hw_interface_set_class (serialize_main_t * m, va_list * va)
-{
-  u32 hw_if_index = va_arg (*va, u32);
-  char *hw_class_name = va_arg (*va, char *);
-  serialize_integer (m, hw_if_index, sizeof (hw_if_index));
-  serialize_cstring (m, hw_class_name);
-}
-
-static void
-unserialize_vnet_hw_interface_set_class (serialize_main_t * m, va_list * va)
-{
-  CLIB_UNUSED (mc_main_t * mc) = va_arg (*va, mc_main_t *);
-  vnet_main_t *vnm = vnet_get_main ();
-  u32 hw_if_index;
-  char *hw_class_name;
-  uword *p;
-  clib_error_t *error;
-
-  unserialize_integer (m, &hw_if_index, sizeof (hw_if_index));
-  unserialize_cstring (m, &hw_class_name);
-  p =
-    hash_get (vnm->interface_main.hw_interface_class_by_name, hw_class_name);
-  ASSERT (p != 0);
-  error = vnet_hw_interface_set_class_helper (vnm, hw_if_index, p[0],
-                                             /* redistribute */ 0);
-  if (error)
-    clib_error_report (error);
-}
-
-MC_SERIALIZE_MSG (vnet_hw_interface_set_class_msg, static) =
-{
-.name = "vnet_hw_interface_set_class",.serialize =
-    serialize_vnet_hw_interface_set_class,.unserialize =
-    unserialize_vnet_hw_interface_set_class,};
-
 void
 vnet_hw_interface_init_for_class (vnet_main_t * vnm, u32 hw_if_index,
                                  u32 hw_class_index, u32 hw_instance)
@@ -1196,13 +1139,6 @@ vnet_hw_interface_set_class_helper (vnet_main_t * vnm, u32 hw_if_index,
                                  "%v class cannot be changed from %s to %s",
                                  hi->name, old_class->name, new_class->name);
 
-      if (vnm->vlib_main->mc_main)
-       {
-         mc_serialize (vnm->vlib_main->mc_main,
-                       &vnet_hw_interface_set_class_msg, hw_if_index,
-                       new_class->name);
-         return 0;
-       }
     }
 
   if (old_class->hw_class_change)
@@ -1240,11 +1176,6 @@ vnet_hw_interface_rx_redirect_to_node_helper (vnet_main_t * vnm,
   vnet_device_class_t *dev_class = vnet_get_device_class
     (vnm, hi->dev_class_index);
 
-  if (redistribute)
-    {
-      /* $$$$ fixme someday maybe */
-      ASSERT (vnm->vlib_main->mc_main == 0);
-    }
   if (dev_class->rx_redirect_to_node)
     {
       dev_class->rx_redirect_to_node (vnm, hw_if_index, node_index);
@@ -1330,9 +1261,8 @@ vnet_interface_init (vlib_main_t * vm)
         sizeof (b->opaque), sizeof (vnet_buffer_opaque_t));
     }
 
-  im->sw_if_counter_lock = clib_mem_alloc_aligned (CLIB_CACHE_LINE_BYTES,
-                                                  CLIB_CACHE_LINE_BYTES);
-  im->sw_if_counter_lock[0] = 1;       /* should be no need */
+  clib_spinlock_init (&im->sw_if_counter_lock);
+  clib_spinlock_lock (&im->sw_if_counter_lock);        /* should be no need */
 
   vec_validate (im->sw_if_counters, VNET_N_SIMPLE_INTERFACE_COUNTER - 1);
 #define _(E,n,p)                                                       \
@@ -1347,7 +1277,7 @@ vnet_interface_init (vlib_main_t * vm)
   im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_##E].stat_segment_name = "/" #p "/" #n;
   foreach_combined_interface_counter_name
 #undef _
-    im->sw_if_counter_lock[0] = 0;
+    clib_spinlock_unlock (&im->sw_if_counter_lock);
 
   im->device_class_by_name = hash_create_string ( /* size */ 0,
                                                 sizeof (uword));
@@ -1366,7 +1296,7 @@ vnet_interface_init (vlib_main_t * vm)
            vlib_node_fn_registration_t *fnr = c->tx_fn_registrations;
            int priority = -1;
 
-           /* to avoid confusion, please remove ".tx_function" statiement
+           /* to avoid confusion, please remove ".tx_function" statement
               from VNET_DEVICE_CLASS() if using function candidates */
            ASSERT (c->tx_function == 0);
 
@@ -1411,6 +1341,11 @@ vnet_interface_init (vlib_main_t * vm)
       }
   }
 
+  im->gso_interface_count = 0;
+  /* init per-thread data */
+  vec_validate_aligned (im->per_thread_data, vlib_num_workers (),
+                       CLIB_CACHE_LINE_BYTES);
+
   if ((error = vlib_call_init_function (vm, vnet_interface_cli_init)))
     return error;
 
@@ -1492,10 +1427,52 @@ vnet_rename_interface (vnet_main_t * vnm, u32 hw_if_index, char *new_name)
   return error;
 }
 
+clib_error_t *
+vnet_hw_interface_add_del_mac_address (vnet_main_t * vnm,
+                                      u32 hw_if_index,
+                                      const u8 * mac_address, u8 is_add)
+{
+  clib_error_t *error = 0;
+  vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
+
+  vnet_device_class_t *dev_class =
+    vnet_get_device_class (vnm, hi->dev_class_index);
+
+  if (!hi->hw_address)
+    {
+      error =
+       clib_error_return
+       (0, "Secondary MAC Addresses not supported for interface index %u",
+        hw_if_index);
+      goto done;
+    }
+
+  if (dev_class->mac_addr_add_del_function)
+    error = dev_class->mac_addr_add_del_function (hi, mac_address, is_add);
+
+  if (!error)
+    {
+      vnet_hw_interface_class_t *hw_class;
+
+      hw_class = vnet_get_hw_interface_class (vnm, hi->hw_class_index);
+
+      if (NULL != hw_class->mac_addr_add_del_function)
+       error = hw_class->mac_addr_add_del_function (hi, mac_address, is_add);
+    }
+
+  /* If no errors, add to the list of secondary MACs on the ethernet intf */
+  if (!error)
+    ethernet_interface_add_del_address (&ethernet_main, hw_if_index,
+                                       mac_address, is_add);
+
+done:
+  return error;
+}
+
 static clib_error_t *
 vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
                                             u32 hw_if_index,
-                                            u8 * mac_address)
+                                            const u8 * mac_address)
 {
   clib_error_t *error = 0;
   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
@@ -1540,7 +1517,7 @@ vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
 
 clib_error_t *
 vnet_hw_interface_change_mac_address (vnet_main_t * vnm, u32 hw_if_index,
-                                     u8 * mac_address)
+                                     const u8 * mac_address)
 {
   return vnet_hw_interface_change_mac_address_helper
     (vnm, hw_if_index, mac_address);
@@ -1652,7 +1629,7 @@ default_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
     case IP_LOOKUP_NEXT_ARP:
     case IP_LOOKUP_NEXT_BCAST:
       /*
-       * default rewirte in neighbour adj
+       * default rewrite in neighbour adj
        */
       adj_nbr_update_rewrite
        (ai,