ARP proxy dumps
[vpp.git] / src / vnet / interface.c
index 1370d04..36793f1 100644 (file)
@@ -41,6 +41,7 @@
 #include <vnet/plugin/plugin.h>
 #include <vnet/fib/ip6_fib.h>
 #include <vnet/adj/adj.h>
+#include <vnet/adj/adj_mcast.h>
 
 #define VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE (1 << 0)
 #define VNET_INTERFACE_SET_FLAGS_HELPER_WANT_REDISTRIBUTE (1 << 1)
@@ -121,6 +122,22 @@ unserialize_vnet_sw_interface_set_flags (serialize_main_t * m, va_list * va)
      /* helper_flags no redistribution */ 0);
 }
 
+void
+vnet_hw_interface_set_mtu (vnet_main_t * vnm, u32 hw_if_index, u32 mtu)
+{
+  vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
+
+  if (hi->max_packet_bytes != mtu)
+    {
+      u16 l3_pad = hi->max_packet_bytes - hi->max_l3_packet_bytes[VLIB_TX];
+      hi->max_packet_bytes = mtu;
+      hi->max_l3_packet_bytes[VLIB_TX] =
+       hi->max_l3_packet_bytes[VLIB_RX] = mtu - l3_pad;
+      ethernet_set_flags (vnm, hw_if_index, ETHERNET_INTERFACE_FLAG_MTU);
+      adj_mtu_update (hw_if_index);
+    }
+}
+
 static void
 unserialize_vnet_hw_interface_set_flags (serialize_main_t * m, va_list * va)
 {
@@ -700,9 +717,10 @@ vnet_register_interface (vnet_main_t * vnm,
   vnet_feature_config_main_t *fcm;
   vnet_config_main_t *cm;
   u32 hw_index, i;
-  char *tx_node_name, *output_node_name;
+  char *tx_node_name = NULL, *output_node_name = NULL;
 
   pool_get (im->hw_interfaces, hw);
+  memset (hw, 0, sizeof (*hw));
 
   hw_index = hw - im->hw_interfaces;
   hw->hw_if_index = hw_index;
@@ -744,6 +762,9 @@ vnet_register_interface (vnet_main_t * vnm,
   hw->max_l3_packet_bytes[VLIB_RX] = ~0;
   hw->max_l3_packet_bytes[VLIB_TX] = ~0;
 
+  if (dev_class->tx_function == 0)
+    goto no_output_nodes;      /* No output/tx nodes to create */
+
   tx_node_name = (char *) format (0, "%v-tx", hw->name);
   output_node_name = (char *) format (0, "%v-output", hw->name);
 
@@ -783,18 +804,24 @@ 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 = dev_class->flatten_output_chains ?
-       vnet_interface_output_node_flatten_multiarch_select () :
-       vnet_interface_output_node_multiarch_select ();
+      node->function = vnet_interface_output_node_multiarch_select ();
       node->format_trace = format_vnet_interface_output_trace;
-      nrt = vlib_node_get_runtime (vm, hw->output_node_index);
-      nrt->function = node->function;
+      /* *INDENT-OFF* */
+      foreach_vlib_main ({
+        nrt = vlib_node_get_runtime (this_vlib_main, hw->output_node_index);
+        nrt->function = node->function;
+      });
+      /* *INDENT-ON* */
 
       node = vlib_get_node (vm, hw->tx_node_index);
       node->function = dev_class->tx_function;
       node->format_trace = dev_class->format_tx_trace;
-      nrt = vlib_node_get_runtime (vm, hw->tx_node_index);
-      nrt->function = node->function;
+      /* *INDENT-OFF* */
+      foreach_vlib_main ({
+        nrt = vlib_node_get_runtime (this_vlib_main, hw->tx_node_index);
+        nrt->function = node->function;
+      });
+      /* *INDENT-ON* */
 
       _vec_len (im->deleted_hw_interface_nodes) -= 1;
     }
@@ -827,9 +854,7 @@ vnet_register_interface (vnet_main_t * vnm,
 
       r.flags = 0;
       r.name = output_node_name;
-      r.function = dev_class->flatten_output_chains ?
-       vnet_interface_output_node_flatten_multiarch_select () :
-       vnet_interface_output_node_multiarch_select ();
+      r.function = vnet_interface_output_node_multiarch_select ();
       r.format_trace = format_vnet_interface_output_trace;
 
       {
@@ -876,11 +901,14 @@ vnet_register_interface (vnet_main_t * vnm,
   setup_output_node (vm, hw->output_node_index, hw_class);
   setup_tx_node (vm, hw->tx_node_index, dev_class);
 
+no_output_nodes:
   /* Call all up/down callbacks with zero flags when interface is created. */
   vnet_sw_interface_set_flags_helper (vnm, hw->sw_if_index, /* flags */ 0,
                                      VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
   vnet_hw_interface_set_flags_helper (vnm, hw_index, /* flags */ 0,
                                      VNET_INTERFACE_SET_FLAGS_HELPER_IS_CREATE);
+  vec_free (tx_node_name);
+  vec_free (output_node_name);
 
   return hw_index;
 }
@@ -891,7 +919,8 @@ vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index)
   vnet_interface_main_t *im = &vnm->interface_main;
   vnet_hw_interface_t *hw = vnet_get_hw_interface (vnm, hw_if_index);
   vlib_main_t *vm = vnm->vlib_main;
-
+  vnet_device_class_t *dev_class = vnet_get_device_class (vnm,
+                                                         hw->dev_class_index);
   /* If it is up, mark it down. */
   if (hw->flags != 0)
     vnet_hw_interface_set_flags (vnm, hw_if_index, /* flags */ 0);
@@ -899,44 +928,54 @@ vnet_delete_hw_interface (vnet_main_t * vnm, u32 hw_if_index)
   /* Call delete callbacks. */
   call_hw_interface_add_del_callbacks (vnm, hw_if_index, /* is_create */ 0);
 
-  /* Delete software interface corresponding to hardware interface. */
-  vnet_delete_sw_interface (vnm, hw->sw_if_index);
-
   /* Delete any sub-interfaces. */
   {
     u32 id, sw_if_index;
     /* *INDENT-OFF* */
-    hash_foreach (id, sw_if_index, hw->sub_interface_sw_if_index_by_id, ({
+    hash_foreach (id, sw_if_index, hw->sub_interface_sw_if_index_by_id,
+    ({
+      vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
+      u64 sup_and_sub_key =
+       ((u64) (si->sup_sw_if_index) << 32) | (u64) si->sub.id;
+      hash_unset_mem_free (&im->sw_if_index_by_sup_and_sub, &sup_and_sub_key);
       vnet_delete_sw_interface (vnm, sw_if_index);
     }));
+    hash_free (hw->sub_interface_sw_if_index_by_id);
     /* *INDENT-ON* */
   }
 
-  {
-    vnet_hw_interface_nodes_t *dn;
+  /* Delete software interface corresponding to hardware interface. */
+  vnet_delete_sw_interface (vnm, hw->sw_if_index);
 
-    /* *INDENT-OFF* */
-    foreach_vlib_main ({
-      vnet_interface_output_runtime_t *rt =
-        vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index);
-
-      /* Mark node runtime as deleted so output node (if called)
-       * will drop packets. */
-      rt->is_deleted = 1;
-    });
-    /* *INDENT-ON* */
+  if (dev_class->tx_function)
+    {
+      /* Put output/tx nodes into recycle pool */
+      vnet_hw_interface_nodes_t *dn;
 
-    vlib_node_rename (vm, hw->output_node_index,
-                     "interface-%d-output-deleted", hw_if_index);
-    vlib_node_rename (vm, hw->tx_node_index, "interface-%d-tx-deleted",
-                     hw_if_index);
-    vec_add2 (im->deleted_hw_interface_nodes, dn, 1);
-    dn->tx_node_index = hw->tx_node_index;
-    dn->output_node_index = hw->output_node_index;
-  }
+      /* *INDENT-OFF* */
+      foreach_vlib_main
+       ({
+         vnet_interface_output_runtime_t *rt =
+           vlib_node_get_runtime_data (this_vlib_main, hw->output_node_index);
+
+         /* Mark node runtime as deleted so output node (if called)
+          * will drop packets. */
+         rt->is_deleted = 1;
+       });
+      /* *INDENT-ON* */
+
+      vlib_node_rename (vm, hw->output_node_index,
+                       "interface-%d-output-deleted", hw_if_index);
+      vlib_node_rename (vm, hw->tx_node_index, "interface-%d-tx-deleted",
+                       hw_if_index);
+      vec_add2 (im->deleted_hw_interface_nodes, dn, 1);
+      dn->tx_node_index = hw->tx_node_index;
+      dn->output_node_index = hw->output_node_index;
+    }
 
   hash_unset_mem (im->hw_interface_by_name, hw->name);
   vec_free (hw->name);
+  vec_free (hw->hw_address);
   vec_free (hw->input_node_thread_index_by_queue);
   vec_free (hw->dq_runtime_index_by_queue);
 
@@ -959,11 +998,30 @@ vnet_hw_interface_walk_sw (vnet_main_t * vnm,
   hash_foreach (id, sw_if_index,
                 hi->sub_interface_sw_if_index_by_id,
   ({
-    fn (vnm, sw_if_index, ctx);
+    if (WALK_STOP == fn (vnm, sw_if_index, ctx))
+      break;
   }));
   /* *INDENT-ON* */
 }
 
+void
+vnet_sw_interface_walk (vnet_main_t * vnm,
+                       vnet_sw_interface_walk_t fn, void *ctx)
+{
+  vnet_interface_main_t *im;
+  vnet_sw_interface_t *si;
+
+  im = &vnm->interface_main;
+
+  /* *INDENT-OFF* */
+  pool_foreach (si, im->sw_interfaces,
+  {
+    if (WALK_STOP == fn (vnm, si, ctx))
+      break;
+  });
+  /* *INDENT-ON* */
+}
+
 static void
 serialize_vnet_hw_interface_set_class (serialize_main_t * m, va_list * va)
 {
@@ -1147,6 +1205,10 @@ vnet_hw_interface_compare (vnet_main_t * vnm,
 int
 vnet_sw_interface_is_p2p (vnet_main_t * vnm, u32 sw_if_index)
 {
+  vnet_sw_interface_t *si = vnet_get_sw_interface (vnm, sw_if_index);
+  if (si->type == VNET_SW_INTERFACE_TYPE_P2P)
+    return 1;
+
   vnet_hw_interface_t *hw = vnet_get_sup_hw_interface (vnm, sw_if_index);
   vnet_hw_interface_class_t *hc =
     vnet_get_hw_interface_class (vnm, hw->hw_class_index);
@@ -1161,6 +1223,7 @@ vnet_interface_init (vlib_main_t * vm)
   vnet_interface_main_t *im = &vnm->interface_main;
   vlib_buffer_t *b = 0;
   vnet_buffer_opaque_t *o = 0;
+  clib_error_t *error;
 
   /*
    * Keep people from shooting themselves in the foot.
@@ -1196,7 +1259,19 @@ vnet_interface_init (vlib_main_t * vm)
   vec_validate (im->combined_sw_if_counters,
                VNET_N_COMBINED_INTERFACE_COUNTER - 1);
   im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX].name = "rx";
+  im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX_UNICAST].name =
+    "rx-unicast";
+  im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX_MULTICAST].name =
+    "rx-multicast";
+  im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX_BROADCAST].name =
+    "rx-broadcast";
   im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX].name = "tx";
+  im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX_UNICAST].name =
+    "tx-unicast";
+  im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX_MULTICAST].name =
+    "tx-multicast";
+  im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX_BROADCAST].name =
+    "tx-broadcast";
 
   im->sw_if_counter_lock[0] = 0;
 
@@ -1241,15 +1316,17 @@ vnet_interface_init (vlib_main_t * vm)
       }
   }
 
-  {
-    clib_error_t *error;
+  if ((error = vlib_call_init_function (vm, vnet_interface_cli_init)))
+    return error;
 
-    if ((error = vlib_call_init_function (vm, vnet_interface_cli_init)))
-      return error;
+  vnm->interface_tag_by_sw_if_index = hash_create (0, sizeof (uword));
 
+#if VLIB_BUFFER_TRACE_TRAJECTORY > 0
+  if ((error = vlib_call_init_function (vm, trajectory_trace_init)))
     return error;
-  }
-  vnm->interface_tag_by_sw_if_index = hash_create (0, sizeof (uword));
+#endif
+
+  return 0;
 }
 
 VLIB_INIT_FUNCTION (vnet_interface_init);
@@ -1322,7 +1399,8 @@ vnet_rename_interface (vnet_main_t * vnm, u32 hw_if_index, char *new_name)
 
 static clib_error_t *
 vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
-                                            u32 hw_if_index, u64 mac_address)
+                                            u32 hw_if_index,
+                                            u8 * mac_address)
 {
   clib_error_t *error = 0;
   vnet_hw_interface_t *hi = vnet_get_hw_interface (vnm, hw_if_index);
@@ -1334,7 +1412,7 @@ vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
       if (dev_class->mac_addr_change_function)
        {
          error =
-           dev_class->mac_addr_change_function (hi, (char *) &mac_address);
+           dev_class->mac_addr_change_function (hi, (char *) mac_address);
        }
       if (!error)
        {
@@ -1343,7 +1421,7 @@ vnet_hw_interface_change_mac_address_helper (vnet_main_t * vnm,
          hw_class = vnet_get_hw_interface_class (vnm, hi->hw_class_index);
 
          if (NULL != hw_class->mac_addr_change_function)
-           hw_class->mac_addr_change_function (hi, (char *) &mac_address);
+           hw_class->mac_addr_change_function (hi, (char *) mac_address);
        }
       else
        {
@@ -1364,12 +1442,57 @@ 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,
-                                     u64 mac_address)
+                                     u8 * mac_address)
 {
   return vnet_hw_interface_change_mac_address_helper
     (vnm, hw_if_index, mac_address);
 }
 
+/* update the unnumbered state of an interface*/
+void
+vnet_sw_interface_update_unnumbered (u32 unnumbered_sw_if_index,
+                                    u32 ip_sw_if_index, u8 enable)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  vnet_sw_interface_t *si;
+  u32 was_unnum;
+
+  si = vnet_get_sw_interface (vnm, unnumbered_sw_if_index);
+  was_unnum = (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED);
+
+  if (enable)
+    {
+      si->flags |= VNET_SW_INTERFACE_FLAG_UNNUMBERED;
+      si->unnumbered_sw_if_index = ip_sw_if_index;
+
+      ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
+       [unnumbered_sw_if_index] =
+       ip4_main.
+       lookup_main.if_address_pool_index_by_sw_if_index[ip_sw_if_index];
+      ip6_main.
+       lookup_main.if_address_pool_index_by_sw_if_index
+       [unnumbered_sw_if_index] =
+       ip6_main.
+       lookup_main.if_address_pool_index_by_sw_if_index[ip_sw_if_index];
+    }
+  else
+    {
+      si->flags &= ~(VNET_SW_INTERFACE_FLAG_UNNUMBERED);
+      si->unnumbered_sw_if_index = (u32) ~ 0;
+
+      ip4_main.lookup_main.if_address_pool_index_by_sw_if_index
+       [unnumbered_sw_if_index] = ~0;
+      ip6_main.lookup_main.if_address_pool_index_by_sw_if_index
+       [unnumbered_sw_if_index] = ~0;
+    }
+
+  if (was_unnum != (si->flags & VNET_SW_INTERFACE_FLAG_UNNUMBERED))
+    {
+      ip4_sw_interface_enable_disable (unnumbered_sw_if_index, enable);
+      ip6_sw_interface_enable_disable (unnumbered_sw_if_index, enable);
+    }
+}
+
 vnet_l3_packet_type_t
 vnet_link_to_l3_proto (vnet_link_t link)
 {
@@ -1403,15 +1526,104 @@ default_build_rewrite (vnet_main_t * vnm,
 void
 default_update_adjacency (vnet_main_t * vnm, u32 sw_if_index, u32 ai)
 {
-  u8 *rewrite;
+  ip_adjacency_t *adj;
+
+  adj = adj_get (ai);
+
+  switch (adj->lookup_next_index)
+    {
+    case IP_LOOKUP_NEXT_GLEAN:
+      adj_glean_update_rewrite (ai);
+      break;
+    case IP_LOOKUP_NEXT_ARP:
+      /*
+       * default rewirte in neighbour adj
+       */
+      adj_nbr_update_rewrite
+       (ai,
+        ADJ_NBR_REWRITE_FLAG_COMPLETE,
+        vnet_build_rewrite_for_sw_interface (vnm,
+                                             sw_if_index,
+                                             adj_get_link_type (ai), NULL));
+      break;
+    case IP_LOOKUP_NEXT_MCAST:
+      /*
+       * mcast traffic also uses default rewrite string with no mcast
+       * switch time updates.
+       */
+      adj_mcast_update_rewrite
+       (ai,
+        vnet_build_rewrite_for_sw_interface (vnm,
+                                             sw_if_index,
+                                             adj_get_link_type (ai),
+                                             NULL), 0);
+      break;
+    case IP_LOOKUP_NEXT_DROP:
+    case IP_LOOKUP_NEXT_PUNT:
+    case IP_LOOKUP_NEXT_LOCAL:
+    case IP_LOOKUP_NEXT_REWRITE:
+    case IP_LOOKUP_NEXT_MCAST_MIDCHAIN:
+    case IP_LOOKUP_NEXT_MIDCHAIN:
+    case IP_LOOKUP_NEXT_ICMP_ERROR:
+    case IP_LOOKUP_N_NEXT:
+      ASSERT (0);
+      break;
+    }
+}
+
+int collect_detailed_interface_stats_flag = 0;
+
+void
+collect_detailed_interface_stats_flag_set (void)
+{
+  collect_detailed_interface_stats_flag = 1;
+}
 
-  rewrite = vnet_build_rewrite_for_sw_interface (vnm, sw_if_index,
-                                                adj_get_link_type (ai),
-                                                NULL);
+void
+collect_detailed_interface_stats_flag_clear (void)
+{
+  collect_detailed_interface_stats_flag = 0;
+}
 
-  adj_nbr_update_rewrite (ai, ADJ_NBR_REWRITE_FLAG_COMPLETE, rewrite);
+static clib_error_t *
+collect_detailed_interface_stats_cli (vlib_main_t * vm,
+                                     unformat_input_t * input,
+                                     vlib_cli_command_t * cmd)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  clib_error_t *error = NULL;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return clib_error_return (0, "expected enable | disable");
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "enable") || unformat (line_input, "on"))
+       collect_detailed_interface_stats_flag_set ();
+      else if (unformat (line_input, "disable")
+              || unformat (line_input, "off"))
+       collect_detailed_interface_stats_flag_clear ();
+      else
+       {
+         error = clib_error_return (0, "unknown input `%U'",
+                                    format_unformat_error, line_input);
+         goto done;
+       }
+    }
+
+done:
+  unformat_free (line_input);
+  return error;
 }
 
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (collect_detailed_interface_stats_command, static) = {
+  .path = "interface collect detailed-stats",
+  .short_help = "interface collect detailed-stats <enable|disable>",
+  .function = collect_detailed_interface_stats_cli,
+};
+/* *INDENT-ON* */
 
 /*
  * fd.io coding-style-patch-verification: ON