summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Kotucek <pkotucek@cisco.com>2016-09-26 10:40:02 +0200
committerDamjan Marion <dmarion.lists@gmail.com>2016-09-30 19:08:24 +0000
commitc631f2de6dd06b4cbb92bf8398839b882344fd25 (patch)
tree42e5bd96a33deecaaa5589a32e696896805a4d39
parent83486fb3ef0f25f9787f9aa898eafc6562f1540e (diff)
VPP-363: add ability to change mac address of the interface
Added ability to change interface address. Added new CLI and API functions. Change-Id: Ia336bc75ad8c5858c26f39af851485c4c6f19f58 Signed-off-by: Pavel Kotucek <pkotucek@cisco.com>
-rw-r--r--vnet/vnet/devices/dpdk/device.c1
-rw-r--r--vnet/vnet/ethernet/arp.c37
-rw-r--r--vnet/vnet/ethernet/ethernet.h2
-rw-r--r--vnet/vnet/fib/ip6_fib.h2
-rw-r--r--vnet/vnet/interface.c57
-rw-r--r--vnet/vnet/interface.h7
-rw-r--r--vnet/vnet/interface_cli.c48
-rw-r--r--vnet/vnet/interface_funcs.h5
-rw-r--r--vnet/vnet/ip/ip6_neighbor.c20
9 files changed, 179 insertions, 0 deletions
diff --git a/vnet/vnet/devices/dpdk/device.c b/vnet/vnet/devices/dpdk/device.c
index 5d1fcf60d2d..cd22d8a4689 100644
--- a/vnet/vnet/devices/dpdk/device.c
+++ b/vnet/vnet/devices/dpdk/device.c
@@ -1275,6 +1275,7 @@ VNET_DEVICE_CLASS (dpdk_device_class) = {
.rx_redirect_to_node = dpdk_set_interface_next_node,
.no_flatten_output_chains = 1,
.name_renumber = dpdk_device_renumber,
+ .mac_addr_change_function = dpdk_set_mac_address,
};
VLIB_DEVICE_TX_FUNCTION_MULTIARCH (dpdk_device_class, dpdk_interface_tx)
diff --git a/vnet/vnet/ethernet/arp.c b/vnet/vnet/ethernet/arp.c
index 541355f9f89..7d6184381c9 100644
--- a/vnet/vnet/ethernet/arp.c
+++ b/vnet/vnet/ethernet/arp.c
@@ -2343,6 +2343,43 @@ arp_term_init (vlib_main_t * vm)
VLIB_INIT_FUNCTION (arp_term_init);
+void
+change_arp_mac (u32 sw_if_index, ethernet_arp_ip4_entry_t * e)
+{
+ if (e->sw_if_index == sw_if_index)
+ {
+
+ if (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_IP4])
+ {
+ // the update rewrite function takes the dst mac (which is not changing)
+ // the new source mac will be retrieved from the interface
+ // when the full rewrite is constructed.
+ adj_nbr_update_rewrite (e->adj_index[FIB_LINK_IP4],
+ e->ethernet_address);
+ }
+ if (ADJ_INDEX_INVALID != e->adj_index[FIB_LINK_MPLS])
+ {
+ adj_nbr_update_rewrite (e->adj_index[FIB_LINK_MPLS],
+ e->ethernet_address);
+ }
+
+ }
+}
+
+void
+ethernet_arp_change_mac (vnet_main_t * vnm, u32 sw_if_index)
+{
+ ethernet_arp_main_t *am = &ethernet_arp_main;
+ ethernet_arp_ip4_entry_t *e;
+
+ /* *INDENT-OFF* */
+ pool_foreach (e, am->ip4_entry_pool,
+ ({
+ change_arp_mac (sw_if_index, e);
+ }));
+ /* *INDENT-ON* */
+}
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/vnet/vnet/ethernet/ethernet.h b/vnet/vnet/ethernet/ethernet.h
index 3b2ef875290..1855b9144db 100644
--- a/vnet/vnet/ethernet/ethernet.h
+++ b/vnet/vnet/ethernet/ethernet.h
@@ -536,6 +536,8 @@ int vnet_add_del_ip4_arp_change_event (vnet_main_t * vnm,
uword type_opaque,
uword data, int is_add);
+void ethernet_arp_change_mac (vnet_main_t * vnm, u32 sw_if_index);
+
extern vlib_node_registration_t ethernet_input_node;
#endif /* included_ethernet_h */
diff --git a/vnet/vnet/fib/ip6_fib.h b/vnet/vnet/fib/ip6_fib.h
index f6af993a3c2..3668234ec27 100644
--- a/vnet/vnet/fib/ip6_fib.h
+++ b/vnet/vnet/fib/ip6_fib.h
@@ -57,6 +57,8 @@ u32 ip6_fib_table_fwding_lookup(ip6_main_t * im,
u32 fib_index,
const ip6_address_t * dst);
+void ethernet_ndp_change_mac (vlib_main_t * vm, u32 sw_if_index);
+
/**
* @biref return the DPO that the LB stacks on.
*/
diff --git a/vnet/vnet/interface.c b/vnet/vnet/interface.c
index 595ed1432bc..ca0df9d1073 100644
--- a/vnet/vnet/interface.c
+++ b/vnet/vnet/interface.c
@@ -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)
@@ -1229,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
*
diff --git a/vnet/vnet/interface.h b/vnet/vnet/interface.h
index 9f032e987bb..5fbf830c01c 100644
--- a/vnet/vnet/interface.h
+++ b/vnet/vnet/interface.h
@@ -55,6 +55,10 @@ typedef clib_error_t *(vnet_subif_add_del_function_t)
(struct vnet_main_t * vnm, u32 if_index,
struct vnet_sw_interface_t * template, int is_add);
+/* Interface set mac address callback. */
+typedef clib_error_t *(vnet_interface_set_mac_address_function_t)
+ (struct vnet_hw_interface_t * hi, char *address);
+
typedef struct _vnet_interface_function_list_elt
{
struct _vnet_interface_function_list_elt *next_interface_function;
@@ -151,6 +155,9 @@ typedef struct _vnet_device_class
/* Do not splice vnet_interface_output_node into TX path */
u8 no_flatten_output_chains;
+ /* Function to set mac address. */
+ vnet_interface_set_mac_address_function_t *mac_addr_change_function;
+
} vnet_device_class_t;
#define VNET_DEVICE_CLASS(x,...) \
diff --git a/vnet/vnet/interface_cli.c b/vnet/vnet/interface_cli.c
index 611ce28140b..03b51332bae 100644
--- a/vnet/vnet/interface_cli.c
+++ b/vnet/vnet/interface_cli.c
@@ -1027,6 +1027,54 @@ VLIB_CLI_COMMAND (set_interface_mtu_cmd, static) = {
};
/* *INDENT-ON* */
+static clib_error_t *
+set_interface_mac_address (vlib_main_t * vm, unformat_input_t * input,
+ vlib_cli_command_t * cmd)
+{
+ vnet_main_t *vnm = vnet_get_main ();
+ clib_error_t *error = 0;
+ u32 sw_if_index = ~0;
+ u64 mac = 0;
+
+ if (!unformat_user (input, unformat_vnet_sw_interface, vnm, &sw_if_index))
+ {
+ error = clib_error_return (0, "unknown interface `%U'",
+ format_unformat_error, input);
+ goto done;
+ }
+ if (!unformat_user (input, unformat_ethernet_address, &mac))
+ {
+ error = clib_error_return (0, "expected mac address `%U'",
+ format_unformat_error, input);
+ goto done;
+ }
+ error = vnet_hw_interface_change_mac_address (vnm, sw_if_index, mac);
+done:
+ return error;
+}
+
+/*?
+ * The '<em>set interface mac address </em>' command allows to set MAC address of given interface.
+ * In case of NIC interfaces the one has to support MAC address change. A side effect of MAC address
+ * change are changes of MAC addresses in FIB tables (ipv4 and ipv6).
+ *
+ * @cliexpar
+ * @parblock
+ * Example of how to change MAC Address of interface:
+ * @cliexcmd{set interface mac address GigabitEthernet0/8/0 aa:bb:cc:dd:ee:01}
+ * @cliexcmd{set interface mac address host-vpp0 aa:bb:cc:dd:ee:02}
+ * @cliexcmd{set interface mac address tap-0 aa:bb:cc:dd:ee:03}
+ * @cliexcmd{set interface mac address pg0 aa:bb:cc:dd:ee:04}
+ * @endparblock
+?*/
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (set_interface_mac_address_cmd, static) = {
+ .path = "set interface mac address",
+ .short_help = "set interface mac address <intfc> <mac-address>",
+ .function = set_interface_mac_address,
+};
+/* *INDENT-ON* */
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/vnet/vnet/interface_funcs.h b/vnet/vnet/interface_funcs.h
index 735d47ec192..f603a03e77b 100644
--- a/vnet/vnet/interface_funcs.h
+++ b/vnet/vnet/interface_funcs.h
@@ -173,6 +173,11 @@ void vnet_hw_interface_init_for_class (vnet_main_t * vnm, u32 hw_if_index,
clib_error_t *vnet_rename_interface (vnet_main_t * vnm, u32 hw_if_index,
char *new_name);
+/* Change interface mac address*/
+clib_error_t *vnet_hw_interface_change_mac_address (vnet_main_t * vnm,
+ u32 hw_if_index,
+ u64 mac_address);
+
/* Formats sw/hw interface. */
format_function_t format_vnet_hw_interface;
format_function_t format_vnet_sw_interface;
diff --git a/vnet/vnet/ip/ip6_neighbor.c b/vnet/vnet/ip/ip6_neighbor.c
index 11df776e1fc..5d059e9b9cf 100644
--- a/vnet/vnet/ip/ip6_neighbor.c
+++ b/vnet/vnet/ip/ip6_neighbor.c
@@ -3472,3 +3472,23 @@ int vnet_ip6_nd_term (vlib_main_t * vm,
return 0;
}
+
+void
+ethernet_ndp_change_mac (vlib_main_t * vm, u32 sw_if_index)
+{
+ ip6_neighbor_main_t * nm = &ip6_neighbor_main;
+ ip6_neighbor_t * n;
+
+ /* *INDENT-OFF* */
+ pool_foreach (n, nm->neighbor_pool, ({
+ if (n->key.sw_if_index == sw_if_index)
+ {
+ if (ADJ_INDEX_INVALID != n->adj_index)
+ {
+ adj_nbr_update_rewrite(n->adj_index,
+ n->link_layer_address);
+ }
+ }
+ }));
+ /* *INDENT-ON* */
+}