VPP-363: add ability to change mac address of the interface
[vpp.git] / vnet / vnet / interface.c
index 772c3bc..ca0df9d 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <vnet/vnet.h>
 #include <vnet/plugin/plugin.h>
+#include <vnet/fib/ip6_fib.h>
 
 #define VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE (1 << 0)
 #define VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE (1 << 1)
@@ -449,8 +450,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;
@@ -1221,6 +1230,62 @@ 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);
+
+         clib_memcpy (hi->hw_address, (u8 *) & mac_address,
+                      sizeof (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);
+}
+
 /*
  * fd.io coding-style-patch-verification: ON
  *