fib: Crash when specify a big prefix length from CLI.
[vpp.git] / src / vnet / ip / lookup.c
index 5d4e137..80a35fe 100644 (file)
@@ -49,7 +49,6 @@
 #include <vnet/dpo/punt_dpo.h>
 #include <vnet/dpo/receive_dpo.h>
 #include <vnet/dpo/ip_null_dpo.h>
-#include <vnet/dpo/l3_proxy_dpo.h>
 
 /**
  * @file
@@ -120,13 +119,51 @@ format_ip_flow_hash_config (u8 * s, va_list * args)
 {
   flow_hash_config_t flow_hash_config = va_arg (*args, u32);
 
-#define _(n,v) if (flow_hash_config & v) s = format (s, "%s ", #n);
+#define _(n, b, v)                                                            \
+  if (flow_hash_config & v)                                                   \
+    s = format (s, "%s ", #n);
   foreach_flow_hash_bit;
 #undef _
 
   return s;
 }
 
+uword
+unformat_ip_flow_hash_config (unformat_input_t *input, va_list *args)
+{
+  flow_hash_config_t *flow_hash_config = va_arg (*args, flow_hash_config_t *);
+  uword start_index = unformat_check_input (input);
+  int matched_once = 0;
+
+  if (unformat (input, "default"))
+    {
+      *flow_hash_config = IP_FLOW_HASH_DEFAULT;
+      return 1;
+    }
+  while (!unformat_is_eof (input) &&
+        !is_white_space (unformat_peek_input (input)))
+    {
+      if (unformat (input, "%_,"))
+       ;
+#define _(a, b, c)                                                            \
+  else if (unformat (input, "%_" #a))                                         \
+  {                                                                           \
+    *flow_hash_config |= c;                                                   \
+    matched_once = 1;                                                         \
+  }
+      foreach_flow_hash_bit
+#undef _
+       else
+      {
+       /* Roll back to our start */
+       input->index = start_index;
+       return 0;
+      }
+    }
+
+  return matched_once;
+}
+
 u8 *
 format_ip_adjacency_packet_data (u8 * s, va_list * args)
 {
@@ -183,6 +220,27 @@ const ip46_address_t zero_addr = {
             0, 0},
 };
 
+bool
+fib_prefix_validate (const fib_prefix_t *prefix)
+{
+  if (FIB_PROTOCOL_IP4 == prefix->fp_proto)
+    {
+      if (prefix->fp_len > 32)
+       {
+         return false;
+       }
+    }
+
+  if (FIB_PROTOCOL_IP6 == prefix->fp_proto)
+    {
+      if (prefix->fp_len > 128)
+       {
+         return false;
+       }
+    }
+  return true;
+}
+
 static clib_error_t *
 vnet_ip_route_cmd (vlib_main_t * vm,
                   unformat_input_t * main_input, vlib_cli_command_t * cmd)
@@ -303,22 +361,25 @@ vnet_ip_route_cmd (vlib_main_t * vm,
        }
       else if (0 < vec_len (rpaths))
        {
-         u32 k, n, incr;
-         ip46_address_t dst = prefixs[i].fp_addr;
+         u32 k, n;
          f64 t[2];
          n = count;
          t[0] = vlib_time_now (vm);
-         incr = 1 << ((FIB_PROTOCOL_IP4 == prefixs[0].fp_proto ? 32 : 128) -
-                      prefixs[i].fp_len);
 
          for (k = 0; k < n; k++)
            {
              fib_prefix_t rpfx = {
                .fp_len = prefixs[i].fp_len,
                .fp_proto = prefixs[i].fp_proto,
-               .fp_addr = dst,
+               .fp_addr = prefixs[i].fp_addr,
              };
 
+             if (!fib_prefix_validate (&rpfx))
+               {
+                 vlib_cli_output (vm, "Invalid prefix len: %d", rpfx.fp_len);
+                 continue;
+               }
+
              if (is_del)
                fib_table_entry_path_remove2 (fib_index,
                                              &rpfx, FIB_SOURCE_CLI, rpaths);
@@ -328,21 +389,7 @@ vnet_ip_route_cmd (vlib_main_t * vm,
                                           FIB_SOURCE_CLI,
                                           FIB_ENTRY_FLAG_NONE, rpaths);
 
-             if (FIB_PROTOCOL_IP4 == prefixs[0].fp_proto)
-               {
-                 dst.ip4.as_u32 =
-                   clib_host_to_net_u32 (incr +
-                                         clib_net_to_host_u32 (dst.
-                                                               ip4.as_u32));
-               }
-             else
-               {
-                 int bucket = (incr < 64 ? 0 : 1);
-                 dst.ip6.as_u64[bucket] =
-                   clib_host_to_net_u64 (incr +
-                                         clib_net_to_host_u64 (dst.ip6.as_u64
-                                                               [bucket]));
-               }
+             fib_prefix_increment (&prefixs[i]);
            }
 
          t[1] = vlib_time_now (vm);
@@ -398,29 +445,35 @@ vnet_ip_table_cmd (vlib_main_t * vm,
        }
     }
 
-  if (~0 == table_id)
-    {
-      error = clib_error_return (0, "No table id");
-      goto done;
-    }
-  else if (0 == table_id)
+  if (0 == table_id)
     {
       error = clib_error_return (0, "Can't change the default table");
       goto done;
     }
   else
-    {
-      if (is_add)
        {
-         ip_table_create (fproto, table_id, 0, name);
-       }
-      else
-       {
-         ip_table_delete (fproto, table_id, 0);
+         if (is_add)
+           {
+             if (~0 == table_id)
+               {
+                 table_id = ip_table_get_unused_id (fproto);
+                 vlib_cli_output (vm, "%u\n", table_id);
+               }
+             ip_table_create (fproto, table_id, 0, name);
+           }
+         else
+           {
+             if (~0 == table_id)
+               {
+                 error = clib_error_return (0, "No table id");
+                 goto done;
+               }
+             ip_table_delete (fproto, table_id, 0);
+           }
        }
-    }
 
 done:
+  vec_free (name);
   unformat_free (line_input);
   return error;
 }
@@ -439,6 +492,71 @@ vnet_ip6_table_cmd (vlib_main_t * vm,
   return (vnet_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP6));
 }
 
+clib_error_t *
+vnet_show_ip_table_cmd (vlib_main_t *vm, unformat_input_t *main_input,
+                       vlib_cli_command_t *cmd, fib_protocol_t fproto)
+{
+  unformat_input_t _line_input, *line_input = &_line_input;
+  fib_table_t *fib, *fibs;
+  clib_error_t *error = NULL;
+  u32 table_id = ~0, fib_index;
+  /* Get a line of input. */
+  if (unformat_user (main_input, unformat_line_input, line_input))
+    {
+      while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+       {
+         if (unformat (line_input, "%d", &table_id))
+           ;
+         else
+           {
+             error = unformat_parse_error (line_input);
+             goto done;
+           }
+       }
+      unformat_free (line_input);
+    }
+
+  fibs = (fproto == FIB_PROTOCOL_IP4) ? ip4_main.fibs : ip6_main.fibs;
+
+  if (table_id != (u32) ~0)
+    {
+      fib_index = fib_table_find (fproto, table_id);
+      if (fib_index == (u32) ~0)
+       {
+         error = clib_error_return (0, "Couldn't find table with table_id %u",
+                                    table_id);
+         goto done;
+       }
+
+      fib = fib_table_get (fib_index, fproto);
+      vlib_cli_output (vm, "[%u] table_id:%u %v", fib->ft_index,
+                      fib->ft_table_id, fib->ft_desc);
+    }
+  else
+    {
+      pool_foreach (fib, fibs)
+       vlib_cli_output (vm, "[%u] table_id:%u %v", fib->ft_index,
+                        fib->ft_table_id, fib->ft_desc);
+    }
+
+done:
+  return error;
+}
+
+clib_error_t *
+vnet_show_ip4_table_cmd (vlib_main_t *vm, unformat_input_t *main_input,
+                        vlib_cli_command_t *cmd)
+{
+  return (vnet_show_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP4));
+}
+
+clib_error_t *
+vnet_show_ip6_table_cmd (vlib_main_t *vm, unformat_input_t *main_input,
+                        vlib_cli_command_t *cmd)
+{
+  return (vnet_show_ip_table_cmd (vm, main_input, cmd, FIB_PROTOCOL_IP6));
+}
+
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (vlib_cli_ip_command, static) = {
   .path = "ip",
@@ -497,7 +615,13 @@ VLIB_CLI_COMMAND (vlib_cli_show_ip6_command, static) = {
 /* *INDENT-OFF* */
 VLIB_CLI_COMMAND (ip_route_command, static) = {
   .path = "ip route",
-  .short_help = "ip route [add|del] [count <n>] <dst-ip-addr>/<width> [table <table-id>] via [next-hop-address] [next-hop-interface] [next-hop-table <value>] [weight <value>] [preference <value>] [udp-encap-id <value>] [ip4-lookup-in-table <value>] [ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] [resolve-via-host] [resolve-via-connected] [rx-ip4 <interface>] [out-labels <value value value>]",
+  .short_help = "ip route [add|del] [count <n>] <dst-ip-addr>/<width> [table "
+               "<table-id>] via [next-hop-address] [next-hop-interface] "
+               "[next-hop-table <value>] [weight <value>] [preference "
+               "<value>] [udp-encap <value>] [ip4-lookup-in-table <value>] "
+               "[ip6-lookup-in-table <value>] [mpls-lookup-in-table <value>] "
+               "[resolve-via-host] [resolve-via-connected] [rx-ip4 "
+               "<interface>] [out-labels <value value value>]",
   .function = vnet_ip_route_cmd,
   .is_mp_safe = 1,
 };
@@ -531,6 +655,18 @@ VLIB_CLI_COMMAND (ip6_table_command, static) = {
   .function = vnet_ip6_table_cmd,
 };
 
+VLIB_CLI_COMMAND (show_ip4_table_command, static) = {
+  .path = "show ip table",
+  .short_help = "show ip table <table-id>",
+  .function = vnet_show_ip4_table_cmd,
+};
+
+VLIB_CLI_COMMAND (show_ip6_table_command, static) = {
+  .path = "show ip6 table",
+  .short_help = "show ip6 table <table-id>",
+  .function = vnet_show_ip6_table_cmd,
+};
+
 static clib_error_t *
 ip_table_bind_cmd (vlib_main_t * vm,
                    unformat_input_t * input,
@@ -560,7 +696,7 @@ ip_table_bind_cmd (vlib_main_t * vm,
       goto done;
     }
 
-  rv = ip_table_bind (fproto, sw_if_index, table_id, 0);
+  rv = ip_table_bind (fproto, sw_if_index, table_id);
 
   if (VNET_API_ERROR_ADDRESS_FOUND_FOR_INTERFACE == rv)
     {
@@ -699,7 +835,7 @@ vnet_ip_mroute_cmd (vlib_main_t * vm,
                         &pfx.fp_src_addr.ip4,
                         unformat_ip4_address, &pfx.fp_grp_addr.ip4))
        {
-         pfx.fp_proto = FIB_PROTOCOL_IP4;
+         payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
          pfx.fp_len = 64;
        }
       else if (unformat (line_input, "%U %U",
@@ -707,7 +843,7 @@ vnet_ip_mroute_cmd (vlib_main_t * vm,
                         &pfx.fp_src_addr.ip6,
                         unformat_ip6_address, &pfx.fp_grp_addr.ip6))
        {
-         pfx.fp_proto = FIB_PROTOCOL_IP6;
+         payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
          pfx.fp_len = 256;
        }
       else if (unformat (line_input, "%U/%d",
@@ -715,27 +851,27 @@ vnet_ip_mroute_cmd (vlib_main_t * vm,
                         &pfx.fp_grp_addr.ip4, &pfx.fp_len))
        {
          clib_memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4));
-         pfx.fp_proto = FIB_PROTOCOL_IP4;
+         payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
        }
       else if (unformat (line_input, "%U/%d",
                         unformat_ip6_address,
                         &pfx.fp_grp_addr.ip6, &pfx.fp_len))
        {
          clib_memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6));
-         pfx.fp_proto = FIB_PROTOCOL_IP6;
+         payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
        }
       else if (unformat (line_input, "%U",
                         unformat_ip4_address, &pfx.fp_grp_addr.ip4))
        {
          clib_memset (&pfx.fp_src_addr.ip4, 0, sizeof (pfx.fp_src_addr.ip4));
-         pfx.fp_proto = FIB_PROTOCOL_IP4;
+         payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP4;
          pfx.fp_len = 32;
        }
       else if (unformat (line_input, "%U",
                         unformat_ip6_address, &pfx.fp_grp_addr.ip6))
        {
          clib_memset (&pfx.fp_src_addr.ip6, 0, sizeof (pfx.fp_src_addr.ip6));
-         pfx.fp_proto = FIB_PROTOCOL_IP6;
+         payload_proto = pfx.fp_proto = FIB_PROTOCOL_IP6;
          pfx.fp_len = 128;
        }
       else if (unformat (line_input, "via local Forward"))
@@ -816,8 +952,8 @@ vnet_ip_mroute_cmd (vlib_main_t * vm,
                mfib_table_entry_path_remove (fib_index,
                                              &pfx, MFIB_SOURCE_CLI, rpaths);
              else
-               mfib_table_entry_path_update (fib_index,
-                                             &pfx, MFIB_SOURCE_CLI, rpaths);
+               mfib_table_entry_path_update (fib_index, &pfx, MFIB_SOURCE_CLI,
+                                             MFIB_ENTRY_FLAG_NONE, rpaths);
            }
 
          if (FIB_PROTOCOL_IP4 == pfx.fp_proto)
@@ -899,251 +1035,6 @@ VLIB_CLI_COMMAND (ip_mroute_command, static) =
 };
 /* *INDENT-ON* */
 
-clib_error_t *
-vnet_ip_container_proxy_add_del (vnet_ip_container_proxy_args_t * args)
-{
-  u32 fib_index;
-
-  if (!vnet_sw_interface_is_api_valid (vnet_get_main (), args->sw_if_index))
-    return clib_error_return_code (0, VNET_API_ERROR_INVALID_INTERFACE, 0,
-                                  "invalid sw_if_index");
-
-  fib_index = fib_table_get_table_id_for_sw_if_index (args->prefix.fp_proto,
-                                                     args->sw_if_index);
-  if (args->is_add)
-    {
-      dpo_id_t proxy_dpo = DPO_INVALID;
-      l3_proxy_dpo_add_or_lock (fib_proto_to_dpo (args->prefix.fp_proto),
-                               args->sw_if_index, &proxy_dpo);
-      fib_table_entry_special_dpo_add (fib_index,
-                                      &args->prefix,
-                                      FIB_SOURCE_PROXY,
-                                      FIB_ENTRY_FLAG_EXCLUSIVE, &proxy_dpo);
-      dpo_reset (&proxy_dpo);
-    }
-  else
-    {
-      fib_table_entry_special_remove (fib_index, &args->prefix,
-                                     FIB_SOURCE_PROXY);
-    }
-  return 0;
-}
-
-u8
-ip_container_proxy_is_set (fib_prefix_t * pfx, u32 sw_if_index)
-{
-  u32 fib_index;
-  fib_node_index_t fei;
-  const dpo_id_t *dpo;
-  l3_proxy_dpo_t *l3p;
-  load_balance_t *lb0;
-
-  fib_index = fib_table_get_table_id_for_sw_if_index (pfx->fp_proto,
-                                                     sw_if_index);
-  if (fib_index == ~0)
-    return 0;
-
-  fei = fib_table_lookup_exact_match (fib_index, pfx);
-  if (fei == FIB_NODE_INDEX_INVALID)
-    return 0;
-
-  dpo = fib_entry_contribute_ip_forwarding (fei);
-  lb0 = load_balance_get (dpo->dpoi_index);
-  dpo = load_balance_get_bucket_i (lb0, 0);
-  if (dpo->dpoi_type != DPO_L3_PROXY)
-    return 0;
-
-  l3p = l3_proxy_dpo_get (dpo->dpoi_index);
-  return (l3p->l3p_sw_if_index == sw_if_index);
-}
-
-typedef struct ip_container_proxy_walk_ctx_t_
-{
-  ip_container_proxy_cb_t cb;
-  void *ctx;
-} ip_container_proxy_walk_ctx_t;
-
-static fib_table_walk_rc_t
-ip_container_proxy_fib_table_walk (fib_node_index_t fei, void *arg)
-{
-  ip_container_proxy_walk_ctx_t *ctx = arg;
-  const fib_prefix_t *pfx;
-  const dpo_id_t *dpo;
-  load_balance_t *lb;
-  l3_proxy_dpo_t *l3p;
-
-  pfx = fib_entry_get_prefix (fei);
-  if (fib_entry_is_sourced (fei, FIB_SOURCE_PROXY))
-    {
-      dpo = fib_entry_contribute_ip_forwarding (fei);
-      lb = load_balance_get (dpo->dpoi_index);
-      dpo = load_balance_get_bucket_i (lb, 0);
-      l3p = l3_proxy_dpo_get (dpo->dpoi_index);
-      ctx->cb (pfx, l3p->l3p_sw_if_index, ctx->ctx);
-    }
-
-  return FIB_TABLE_WALK_CONTINUE;
-}
-
-void
-ip_container_proxy_walk (ip_container_proxy_cb_t cb, void *ctx)
-{
-  fib_table_t *fib_table;
-  ip_container_proxy_walk_ctx_t wctx = {
-    .cb = cb,
-    .ctx = ctx,
-  };
-
-  /* *INDENT-OFF* */
-  pool_foreach (fib_table, ip4_main.fibs,
-  ({
-    fib_table_walk(fib_table->ft_index,
-                   FIB_PROTOCOL_IP4,
-                   ip_container_proxy_fib_table_walk,
-                   &wctx);
-  }));
-  pool_foreach (fib_table, ip6_main.fibs,
-  ({
-    fib_table_walk(fib_table->ft_index,
-                   FIB_PROTOCOL_IP6,
-                   ip_container_proxy_fib_table_walk,
-                   &wctx);
-  }));
-  /* *INDENT-ON* */
-}
-
-clib_error_t *
-ip_container_cmd (vlib_main_t * vm,
-                 unformat_input_t * main_input, vlib_cli_command_t * cmd)
-{
-  unformat_input_t _line_input, *line_input = &_line_input;
-  fib_prefix_t pfx;
-  u32 is_del, addr_set = 0;
-  vnet_main_t *vnm;
-  u32 sw_if_index;
-
-  vnm = vnet_get_main ();
-  is_del = 0;
-  sw_if_index = ~0;
-  clib_memset (&pfx, 0, sizeof (pfx));
-
-  /* Get a line of input. */
-  if (!unformat_user (main_input, unformat_line_input, line_input))
-    return 0;
-
-  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (line_input, "%U", unformat_ip4_address, &pfx.fp_addr.ip4))
-       {
-         pfx.fp_proto = FIB_PROTOCOL_IP4;
-         pfx.fp_len = 32;
-         addr_set = 1;
-       }
-      else if (unformat (line_input, "%U",
-                        unformat_ip6_address, &pfx.fp_addr.ip6))
-       {
-         pfx.fp_proto = FIB_PROTOCOL_IP6;
-         pfx.fp_len = 128;
-         addr_set = 1;
-       }
-      else if (unformat (line_input, "%U",
-                        unformat_vnet_sw_interface, vnm, &sw_if_index))
-       ;
-      else if (unformat (line_input, "del"))
-       is_del = 1;
-      else
-       {
-         unformat_free (line_input);
-         return (clib_error_return (0, "unknown input '%U'",
-                                    format_unformat_error, line_input));
-       }
-    }
-
-  if (~0 == sw_if_index || !addr_set)
-    {
-      unformat_free (line_input);
-      vlib_cli_output (vm, "interface and address must be set");
-      return 0;
-    }
-
-  vnet_ip_container_proxy_args_t args = {
-    .prefix = pfx,
-    .sw_if_index = sw_if_index,
-    .is_add = !is_del,
-  };
-  vnet_ip_container_proxy_add_del (&args);
-  unformat_free (line_input);
-  return (NULL);
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (ip_container_command_node, static) = {
-  .path = "ip container",
-  .function = ip_container_cmd,
-  .short_help = "ip container <address> <interface>",
-  .is_mp_safe = 1,
-};
-/* *INDENT-ON* */
-
-clib_error_t *
-show_ip_container_cmd_fn (vlib_main_t * vm, unformat_input_t * main_input,
-                         vlib_cli_command_t * cmd)
-{
-  unformat_input_t _line_input, *line_input = &_line_input;
-  vnet_main_t *vnm = vnet_get_main ();
-  fib_prefix_t pfx;
-  u32 sw_if_index = ~0;
-  u8 has_proxy;
-
-  if (!unformat_user (main_input, unformat_line_input, line_input))
-    return 0;
-  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
-    {
-      if (unformat (line_input, "%U", unformat_ip4_address, &pfx.fp_addr.ip4))
-       {
-         pfx.fp_proto = FIB_PROTOCOL_IP4;
-         pfx.fp_len = 32;
-       }
-      else if (unformat (line_input, "%U",
-                        unformat_ip6_address, &pfx.fp_addr.ip6))
-       {
-         pfx.fp_proto = FIB_PROTOCOL_IP6;
-         pfx.fp_len = 128;
-       }
-      else if (unformat (line_input, "%U",
-                        unformat_vnet_sw_interface, vnm, &sw_if_index))
-       ;
-      else
-       {
-         unformat_free (line_input);
-         return (clib_error_return (0, "unknown input '%U'",
-                                    format_unformat_error, line_input));
-       }
-    }
-
-  if (~0 == sw_if_index)
-    {
-      unformat_free (line_input);
-      vlib_cli_output (vm, "no interface");
-      return (clib_error_return (0, "no interface"));
-    }
-
-  has_proxy = ip_container_proxy_is_set (&pfx, sw_if_index);
-  vlib_cli_output (vm, "ip container proxy is: %s", has_proxy ? "on" : "off");
-
-  unformat_free (line_input);
-  return 0;
-}
-
-/* *INDENT-OFF* */
-VLIB_CLI_COMMAND (show_ip_container_command, static) = {
-  .path = "show ip container",
-  .function = show_ip_container_cmd_fn,
-  .short_help = "show ip container <address> <interface>",
-  .is_mp_safe = 1,
-};
-/* *INDENT-ON* */
-
 /*
  * fd.io coding-style-patch-verification: ON
  *