af_packet: set mac address support 58/6758/4
authorRay Kinsella <ray.kinsella@intel.com>
Thu, 18 May 2017 10:56:28 +0000 (11:56 +0100)
committerDamjan Marion <dmarion.lists@gmail.com>
Sat, 20 May 2017 10:53:57 +0000 (10:53 +0000)
Added support to the interfaces mac address.
Resolved an fd leak when the interface is a bridge.

Change-Id: I6608c51b11a50bd0ae4aabe0dc5788c4301b5a1e
Signed-off-by: Ray Kinsella <ray.kinsella@intel.com>
src/vnet/devices/af_packet/device.c

index 2a17e6b..4607d88 100644 (file)
  */
 
 #include <linux/if_packet.h>
+#include <sys/socket.h>
 #include <sys/ioctl.h>
 #include <net/if.h>
+#include <net/if_arp.h>
 
 #include <vlib/vlib.h>
 #include <vlib/unix/unix.h>
@@ -212,7 +214,7 @@ af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
 
   /* if interface is a bridge ignore */
   if (apif->host_if_index < 0)
-    return 0;                  /* no error */
+    goto error;                        /* no error */
 
   /* use host_if_index in case host name has changed */
   ifr.ifr_ifindex = apif->host_if_index;
@@ -220,6 +222,7 @@ af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
     {
       clib_unix_warning ("af_packet_%s ioctl could not retrieve eth name",
                         apif->host_if_name);
+      goto error;
     }
 
   apif->is_admin_up = (flags & VNET_SW_INTERFACE_FLAG_ADMIN_UP) != 0;
@@ -228,6 +231,7 @@ af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
     {
       clib_unix_warning ("af_packet_%s error: %d",
                         apif->is_admin_up ? "up" : "down", rv);
+      goto error;
     }
 
   if (apif->is_admin_up)
@@ -245,10 +249,12 @@ af_packet_interface_admin_up_down (vnet_main_t * vnm, u32 hw_if_index,
     {
       clib_unix_warning ("af_packet_%s error: %d",
                         apif->is_admin_up ? "up" : "down", rv);
+      goto error;
     }
 
   vnet_hw_interface_set_flags (vnm, hw_if_index, hw_flags);
 
+error:
   close (fd);
 
   return 0;                    /* no error */
@@ -263,6 +269,45 @@ af_packet_subif_add_del_function (vnet_main_t * vnm,
   return 0;
 }
 
+static clib_error_t *af_packet_set_mac_address_function
+  (struct vnet_hw_interface_t *hi, char *address)
+{
+  af_packet_main_t *apm = &af_packet_main;
+  af_packet_if_t *apif =
+    pool_elt_at_index (apm->interfaces, hi->dev_instance);
+  int rv, fd = socket (AF_UNIX, SOCK_DGRAM, 0);
+  struct ifreq ifr;
+
+  /* if interface is a bridge ignore */
+  if (apif->host_if_index < 0)
+    goto error;                        /* no error */
+
+  /* use host_if_index in case host name has changed */
+  ifr.ifr_ifindex = apif->host_if_index;
+  if ((rv = ioctl (fd, SIOCGIFNAME, &ifr)) < 0)
+    {
+      clib_unix_warning
+       ("af_packet_%s ioctl could not retrieve eth name, error: %d",
+        apif->host_if_name, rv);
+      goto error;
+    }
+
+  clib_memcpy (ifr.ifr_hwaddr.sa_data, address, 6);
+  ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+
+  if ((rv = ioctl (fd, SIOCSIFHWADDR, &ifr)) < 0)
+    {
+      clib_unix_warning ("af_packet_%s ioctl could not set mac, error: %d",
+                        apif->host_if_name, rv);
+      goto error;
+    }
+
+error:
+  close (fd);
+
+  return 0;                    /* no error */
+}
+
 /* *INDENT-OFF* */
 VNET_DEVICE_CLASS (af_packet_device_class) = {
   .name = "af-packet",
@@ -276,6 +321,7 @@ VNET_DEVICE_CLASS (af_packet_device_class) = {
   .clear_counters = af_packet_clear_hw_interface_counters,
   .admin_up_down_function = af_packet_interface_admin_up_down,
   .subif_add_del_function = af_packet_subif_add_del_function,
+  .mac_addr_change_function = af_packet_set_mac_address_function,
 };
 
 VLIB_DEVICE_TX_FUNCTION_MULTIARCH (af_packet_device_class,