VPP-363: add ability to change mac address of the interface
[vpp.git] / vnet / vnet / interface_cli.c
index 7b9f545..03b5133 100644 (file)
  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
+/**
+ * @file
+ * Interface CLI.
+ */
+
 #include <vnet/vnet.h>
 #include <vnet/ip/ip.h>
 #include <vppinfra/bitmap.h>
+#include <vnet/fib/ip4_fib.h>
+#include <vnet/fib/ip6_fib.h>
 
 static int
 compare_interface_names (void *a1, void *a2)
@@ -157,6 +164,34 @@ done:
 }
 
 /* *INDENT-OFF* */
+/*?
+ * Displays various information about the state of the current terminal
+ * session.
+ *
+ * @cliexpar
+ * @cliexstart{show hardware}
+ * Name                Link  Hardware
+ * GigabitEthernet2/0/0               up   GigabitEthernet2/0/0
+ * Ethernet address 00:50:56:b7:7c:83
+ * Intel 82545em_copper
+ *   link up, media 1000T full-duplex, master,
+ *   0 unprocessed, 384 total buffers on rx queue 0 ring
+ *   237 buffers in driver rx cache
+ *   rx total packets                                    1816
+ *   rx total bytes                                    181084
+ *   rx good packets                                     1816
+ *   rx good bytes                                     181084
+ *   rx 65 127 byte packets                              1586
+ *   rx 256 511 byte packets                              230
+ *   tx total packets                                     346
+ *   tx total bytes                                     90224
+ *   tx good packets                                      346
+ *   tx good bytes                                      88840
+ *   tx 64 byte packets                                     1
+ *   tx 65 127 byte packets                               115
+ *   tx 256 511 byte packets                              230
+ * @cliexend
+ ?*/
 VLIB_CLI_COMMAND (show_hw_interfaces_command, static) = {
   .path = "show hardware-interfaces",
   .short_help = "show hardware-interfaces [brief|verbose|detail] [bond] [<if-name1> <if-name2> ...]",
@@ -257,8 +292,8 @@ show_sw_interfaces (vlib_main_t * vm,
          fib_index6 = vec_elt (im6->fib_index_by_sw_if_index,
                                si->sw_if_index);
 
-       fib4 = vec_elt_at_index (im4->fibs, fib_index4);
-       fib6 = vec_elt_at_index (im6->fibs, fib_index6);
+       fib4 = ip4_fib_get (fib_index4);
+       fib6 = ip6_fib_get (fib_index6);
 
        if (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED)
          vlib_cli_output
@@ -432,7 +467,9 @@ VLIB_CLI_COMMAND (clear_interface_counters_command, static) = {
 };
 /* *INDENT-ON* */
 
-/** \detail
+/**
+ * Parse subinterface names.
+ *
  * The following subinterface syntax is supported. The first two are for
  * backwards compatability:
  *
@@ -599,7 +636,6 @@ create_sub_interfaces (vlib_main_t * vm,
   else if (unformat (input, "%d-%d", &id_min, &id_max))
     {
       template.sub.eth.flags.one_tag = 1;
-      template.sub.eth.outer_vlan_id = id_min;
       template.sub.eth.flags.exact_match = 1;
       if (id_min > id_max)
        goto id_error;
@@ -652,6 +688,9 @@ create_sub_interfaces (vlib_main_t * vm,
       template.type = VNET_SW_INTERFACE_TYPE_SUB;
       template.sup_sw_if_index = hi->sw_if_index;
       template.sub.id = id;
+      if (id_min < id_max)
+       template.sub.eth.outer_vlan_id = id;
+
       error = vnet_create_sw_interface (vnm, &template, &sw_if_index);
       if (error)
        goto done;
@@ -667,8 +706,52 @@ done:
 }
 
 /* *INDENT-OFF* */
+/*?
+ * Create vlan subinterfaces
+ *
+ * @cliexpar
+ * @cliexstart{create sub-interfaces}
+ *
+ * To create a vlan subinterface 11 to process packets on 802.1q VLAN id 11, use:
+ *
+ *  vpp# create sub GigabitEthernet2/0/0 11
+ *
+ * This shorthand is equivalent to:
+ *  vpp# create sub GigabitEthernet2/0/0 11 dot1q 11 exact-match
+ *
+ * You can specify a subinterface number that is different from the vlan id:
+ *  vpp# create sub GigabitEthernet2/0/0 11 dot1q 100
+ *
+ * You can create qinq and q-in-any interfaces:
+ *  vpp# create sub GigabitEthernet2/0/0 11 dot1q 100 inner-dot1q 200
+ *  vpp# create sub GigabitEthernet2/0/0 12 dot1q 100 inner-dot1q any
+ *
+ * You can also create dot1ad interfaces:
+ *  vpp# create sub GigabitEthernet2/0/0 11 dot1ad 11
+ *  vpp# create sub GigabitEthernet2/0/0 12 dot1q 100 inner-dot1q 200
+ *
+ * Subinterfaces can be configured as either exact-match or non-exact match.
+ * Non-exact match is the CLI default. If exact-match is specified,
+ * packets must have the same number of vlan tags as the configuration.
+ * For non-exact-match, packets must at least that number of tags.
+ * L3 (routed) interfaces must be configured as exact-match.
+ * L2 interfaces are typically configured as non-exact-match.
+ *
+ * For example, a packet with outer vlan 100 and inner 200 would match this interface:
+ *  vpp# create sub GigabitEthernet2/0/0 5 dot1q 100
+ *
+ * but would not match this interface:
+ *  vpp# create sub GigabitEthernet2/0/0 5 dot1q 100 exact-match
+ *
+ * There are two special subinterfaces that can be configured. Subinterface untagged has no vlan tags:
+ *  vpp# create sub GigabitEthernet2/0/0 5 untagged
+ *
+ * The subinterface default matches any packet that does not match any other subinterface:
+ *  vpp# create sub GigabitEthernet2/0/0 7 default
+ * @cliexend
+ ?*/
 VLIB_CLI_COMMAND (create_sub_interfaces_command, static) = {
-  .path = "create sub-interface",
+  .path = "create sub-interfaces",
   .short_help = "create sub-interfaces <nn>[-<nn>] [dot1q|dot1ad|default|untagged]",
   .function = create_sub_interfaces,
 };
@@ -705,7 +788,17 @@ done:
   return error;
 }
 
+
 /* *INDENT-OFF* */
+/*?
+ * Interface admin up/down
+ *
+ * @cliexpar
+ * @cliexstart{set interface state}
+ *  vpp# set interface state GigabitEthernet2/0/0 up
+ *  vpp# set interface state GigabitEthernet2/0/0 down
+ * @cliexend
+ ?*/
 VLIB_CLI_COMMAND (set_state_command, static) = {
   .path = "set interface state",
   .short_help = "Set interface state",
@@ -724,27 +817,17 @@ set_unnumbered (vlib_main_t * vm,
   int is_set = 0;
   int is_del = 0;
 
-  while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
-    {
-
-      if (unformat (input, "%U use %U",
-                   unformat_vnet_sw_interface, vnm, &unnumbered_sw_if_index,
-                   unformat_vnet_sw_interface, vnm,
-                   &inherit_from_sw_if_index))
-       is_set = 1;
-      else if (unformat (input, "del %U",
-                        unformat_vnet_sw_interface,
-                        vnm, &unnumbered_sw_if_index))
-       is_del = 1;
-      else
-       {
-         if (is_set || is_del)
-           break;
-         else
-           return clib_error_return
-             (0, "parse error '%U'", format_unformat_error, input);
-       }
-    }
+  if (unformat (input, "%U use %U",
+               unformat_vnet_sw_interface, vnm, &unnumbered_sw_if_index,
+               unformat_vnet_sw_interface, vnm, &inherit_from_sw_if_index))
+    is_set = 1;
+  else if (unformat (input, "del %U",
+                    unformat_vnet_sw_interface, vnm,
+                    &unnumbered_sw_if_index))
+    is_del = 1;
+  else
+    return clib_error_return (0, "parse error '%U'",
+                             format_unformat_error, input);
 
   si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index);
   if (is_del)
@@ -752,7 +835,7 @@ set_unnumbered (vlib_main_t * vm,
       si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
       si->unnumbered_sw_if_index = (u32) ~ 0;
     }
-  else
+  else if (is_set)
     {
       si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED;
       si->unnumbered_sw_if_index = inherit_from_sw_if_index;
@@ -764,7 +847,7 @@ set_unnumbered (vlib_main_t * vm,
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (set_unnumbered_command, static) = {
   .path = "set interface unnumbered",
-  .short_help = "set interface unnumbered [<intfc> use <intfc>][del <intfc>]",
+  .short_help = "set interface unnumbered [<intfc> use <intfc> | del <intfc>]",
   .function = set_unnumbered,
 };
 /* *INDENT-ON* */
@@ -944,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
  *