Add gpe native-forward static route support 48/7048/3
authorFlorin Coras <fcoras@cisco.com>
Thu, 8 Jun 2017 04:50:57 +0000 (21:50 -0700)
committerDamjan Marion <dmarion.lists@gmail.com>
Thu, 8 Jun 2017 17:43:56 +0000 (17:43 +0000)
Change-Id: I744e7d64d94dbb302f2c1246663480f720672ee2
Signed-off-by: Florin Coras <fcoras@cisco.com>
src/vnet/lisp-gpe/lisp_gpe.api
src/vnet/lisp-gpe/lisp_gpe.c
src/vnet/lisp-gpe/lisp_gpe.h
src/vnet/lisp-gpe/lisp_gpe_api.c
src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c

index 706f20d..17ce579 100644 (file)
@@ -186,6 +186,62 @@ define gpe_get_encap_mode_reply
   u8 encap_mode;
 };
 
+/** \brief Add native fwd rpath
+    @param context - returned sender context, to match reply w/ request
+    @param retval - return code
+    @param is_add - flag to indicate add or del
+    @param table_id - table id for route path
+    @param nh_sw_if_index - next-hop sw_if_index (~0 if not set)
+    @param is_ip4 - flag to indicate if nh is ip4
+    @param nh_addr - next hop ip address
+*/
+autoreply define gpe_add_del_native_fwd_rpath
+{
+  u32 client_index;
+  u32 context;
+  u8 is_add;
+  u32 table_id;
+  u32 nh_sw_if_index;
+  u8 is_ip4;
+  u8 nh_addr[16];
+};
+
+/** \brief get GPE native fwd rpath
+    @param client_index - opaque cookie to identify the sender
+    @param context - sender context, to match reply w/ request
+*/
+define gpe_native_fwd_rpaths_get
+{
+  u32 client_index;
+  u32 context;
+  u8 is_ip4;
+};
+
+/** \brief Reply for get native fwd rpath
+    @param context - returned sender context, to match reply w/ request
+    @param retval - return code
+    @param table_id - table id for route path
+    @param nh_sw_if_index - next-hop sw_if_index (~0 if not set)
+    @param nh_addr - next hop address
+*/
+typeonly manual_print manual_endian define gpe_native_fwd_rpath
+{
+  u32 context;
+  i32 retval;
+  u32 fib_index;
+  u32 nh_sw_if_index;
+  u8 is_ip4;
+  u8 nh_addr[16];
+};
+
+manual_print manual_endian define gpe_native_fwd_rpaths_get_reply
+{
+  u32 context;
+  i32 retval;
+  u32 count;
+  vl_api_gpe_native_fwd_rpath_t entries[count];
+};
+
 /*
  * Local Variables:
  * eval: (c-set-style "gnu")
index 052410e..ea6c143 100644 (file)
@@ -22,6 +22,9 @@
 #include <vnet/lisp-gpe/lisp_gpe_fwd_entry.h>
 #include <vnet/lisp-gpe/lisp_gpe_adjacency.h>
 #include <vnet/lisp-gpe/lisp_gpe_tenant.h>
+#include <vnet/fib/fib_path_list.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/fib/fib_internal.h>
 
 /** LISP-GPE global state */
 lisp_gpe_main_t lisp_gpe_main;
@@ -387,6 +390,194 @@ VLIB_CLI_COMMAND (lisp_show_iface_command) = {
 };
 /* *INDENT-ON* */
 
+/** CLI command to show GPE fwd native route path. */
+static clib_error_t *
+gpe_show_native_fwd_rpath_command_fn (vlib_main_t * vm,
+                                     unformat_input_t * input,
+                                     vlib_cli_command_t * cmd)
+{
+  lisp_gpe_main_t *lgm = &lisp_gpe_main;
+  fib_route_path_t *rpath;
+
+  if (vec_len (lgm->native_fwd_rpath[IP4]))
+    {
+      vec_foreach (rpath, lgm->native_fwd_rpath[IP4])
+      {
+       vlib_cli_output (vm, "nh: %U fib_index %u sw_if_index %u",
+                        format_ip46_address, &rpath->frp_addr, 1,
+                        rpath->frp_fib_index, rpath->frp_sw_if_index);
+      }
+    }
+  if (vec_len (lgm->native_fwd_rpath[IP6]))
+    {
+      vec_foreach (rpath, lgm->native_fwd_rpath[IP6])
+      {
+       vlib_cli_output (vm, "nh: %U fib_index %u sw_if_index %u",
+                        format_ip46_address, &rpath->frp_addr, 1,
+                        rpath->frp_fib_index, rpath->frp_sw_if_index);
+      }
+    }
+  return 0;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (gpe_show_native_fwd_rpath_command) = {
+    .path = "show gpe native-forward",
+    .short_help = "show gpe native-forward",
+    .function = gpe_show_native_fwd_rpath_command_fn,
+};
+/* *INDENT-ON* */
+
+void
+gpe_update_native_fwd_path (u8 ip_version)
+{
+  lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
+  lisp_gpe_fwd_entry_t *lfe;
+  fib_prefix_t fib_prefix;
+  u32 *lfei;
+
+  vec_foreach (lfei, lgm->native_fwd_lfes[ip_version])
+  {
+    lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, lfei[0]);
+    ip_prefix_to_fib_prefix (&lfe->key->rmt.ippref, &fib_prefix);
+    fib_table_entry_update (lfe->eid_fib_index, &fib_prefix, FIB_SOURCE_LISP,
+                           FIB_ENTRY_FLAG_NONE,
+                           lgm->native_fwd_rpath[ip_version]);
+  }
+}
+
+int
+vnet_gpe_add_del_native_fwd_rpath (vnet_gpe_native_fwd_rpath_args_t * a)
+{
+  lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
+  fib_route_path_t *rpath;
+  u8 ip_version;
+
+  ip_version = a->rpath.frp_proto == FIB_PROTOCOL_IP4 ? IP4 : IP6;
+
+  if (a->is_add)
+    {
+      vec_add1 (lgm->native_fwd_rpath[ip_version], a->rpath);
+    }
+  else
+    {
+      vec_foreach (rpath, lgm->native_fwd_rpath[ip_version])
+      {
+       if (!fib_route_path_cmp (rpath, &a->rpath))
+         {
+           vec_del1 (lgm->native_fwd_rpath[ip_version],
+                     rpath - lgm->native_fwd_rpath[ip_version]);
+           break;
+         }
+      }
+    }
+  gpe_update_native_fwd_path (ip_version);
+  return 0;
+}
+
+/**
+ * CLI command to add action for native forward.
+ */
+static clib_error_t *
+gpe_native_forward_command_fn (vlib_main_t * vm, unformat_input_t * input,
+                              vlib_cli_command_t * cmd)
+{
+  vnet_main_t *vnm = vnet_get_main ();
+  unformat_input_t _line_input, *line_input = &_line_input;
+  vnet_api_error_t rv;
+  fib_route_path_t rpath;
+  u32 table_id = ~0;
+  vnet_gpe_native_fwd_rpath_args_t _a, *a = &_a;
+  u8 is_add = 1;
+  clib_error_t *error = 0;
+
+  /* Get a line of input. */
+  if (!unformat_user (input, unformat_line_input, line_input))
+    return 0;
+
+  memset (&rpath, 0, sizeof (rpath));
+
+  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+    {
+      if (unformat (line_input, "table %d", &table_id))
+       ;
+      else if (unformat (line_input, "del"))
+       is_add = 0;
+      else if (unformat (line_input, "via %U %U",
+                        unformat_ip4_address,
+                        &rpath.frp_addr.ip4,
+                        unformat_vnet_sw_interface, vnm,
+                        &rpath.frp_sw_if_index))
+       {
+         rpath.frp_weight = 1;
+         rpath.frp_proto = FIB_PROTOCOL_IP4;
+       }
+      else if (unformat (line_input, "via %U %U",
+                        unformat_ip6_address,
+                        &rpath.frp_addr.ip6,
+                        unformat_vnet_sw_interface, vnm,
+                        &rpath.frp_sw_if_index))
+       {
+         rpath.frp_weight = 1;
+         rpath.frp_proto = FIB_PROTOCOL_IP6;
+       }
+      else if (unformat (line_input, "via %U",
+                        unformat_ip4_address, &rpath.frp_addr.ip4))
+       {
+         rpath.frp_weight = 1;
+         rpath.frp_sw_if_index = ~0;
+         rpath.frp_proto = FIB_PROTOCOL_IP4;
+       }
+      else if (unformat (line_input, "via %U",
+                        unformat_ip6_address, &rpath.frp_addr.ip6))
+       {
+         rpath.frp_weight = 1;
+         rpath.frp_sw_if_index = ~0;
+         rpath.frp_proto = FIB_PROTOCOL_IP6;
+       }
+      else
+       {
+         return clib_error_return (0, "parse error: '%U'",
+                                   format_unformat_error, line_input);
+       }
+    }
+
+  if ((u32) ~ 0 == table_id)
+    {
+      rpath.frp_fib_index = 0;
+    }
+  else
+    {
+      rpath.frp_fib_index = fib_table_find (rpath.frp_proto, table_id);
+      if ((u32) ~ 0 == rpath.frp_fib_index)
+       {
+         error = clib_error_return (0, "Nonexistent table id %d", table_id);
+         goto done;
+       }
+    }
+
+  a->rpath = rpath;
+  a->is_add = is_add;
+
+  rv = vnet_gpe_add_del_native_fwd_rpath (a);
+  if (rv)
+    {
+      return clib_error_return (0, "Error: couldn't add path!");
+    }
+
+done:
+  return error;
+}
+
+/* *INDENT-OFF* */
+VLIB_CLI_COMMAND (gpe_native_forward_command) = {
+    .path = "gpe native-forward",
+    .short_help = "gpe native-forward [del] via <nh-ip-addr> [iface] "
+       "[table <table>]",
+    .function = gpe_native_forward_command_fn,
+};
+/* *INDENT-ON* */
+
 /** Format LISP-GPE status. */
 u8 *
 format_vnet_lisp_gpe_status (u8 * s, va_list * args)
index f040564..660f8a6 100644 (file)
@@ -163,6 +163,10 @@ typedef struct lisp_gpe_main
   uword *lisp_stats_index_by_key;
   vlib_combined_counter_main_t counters;
 
+  /** Native fwd data structures */
+  fib_route_path_t *native_fwd_rpath[2];
+  u32 *native_fwd_lfes[2];
+
   /** convenience */
   vlib_main_t *vlib_main;
   vnet_main_t *vnet_main;
@@ -269,6 +273,12 @@ typedef struct
   };
 } vnet_lisp_gpe_add_del_fwd_entry_args_t;
 
+typedef struct
+{
+  fib_route_path_t rpath;
+  u8 is_add;
+} vnet_gpe_native_fwd_rpath_args_t;
+
 typedef struct
 {
   u32 fwd_entry_index;
@@ -313,7 +323,7 @@ u8 vnet_lisp_stats_enable_disable_state (void);
 vnet_api_error_t vnet_lisp_stats_enable_disable (u8 enable);
 lisp_api_stats_t *vnet_lisp_get_stats (void);
 int vnet_lisp_flush_stats (void);
-
+int vnet_gpe_add_del_native_fwd_rpath (vnet_gpe_native_fwd_rpath_args_t * a);
 #endif /* included_vnet_lisp_gpe_h */
 
 /*
index ab081b3..4df743c 100644 (file)
@@ -27,7 +27,7 @@
 #include <vnet/lisp-gpe/lisp_gpe_tunnel.h>
 #include <vnet/lisp-gpe/lisp_gpe_fwd_entry.h>
 #include <vnet/lisp-gpe/lisp_gpe_tenant.h>
-
+#include <vnet/fib/fib_table.h>
 #include <vnet/vnet_msg_enum.h>
 
 #define vl_api_gpe_locator_pair_t_endian vl_noop_handler
 
 #include <vlibapi/api_helper_macros.h>
 
-#define foreach_vpe_api_msg                             \
-_(GPE_ADD_DEL_FWD_ENTRY, gpe_add_del_fwd_entry)               \
-_(GPE_FWD_ENTRIES_GET, gpe_fwd_entries_get)                   \
-_(GPE_FWD_ENTRY_PATH_DUMP, gpe_fwd_entry_path_dump)           \
-_(GPE_ENABLE_DISABLE, gpe_enable_disable)                     \
-_(GPE_ADD_DEL_IFACE, gpe_add_del_iface)                       \
-_(GPE_FWD_ENTRY_VNIS_GET, gpe_fwd_entry_vnis_get)             \
-_(GPE_SET_ENCAP_MODE, gpe_set_encap_mode)                     \
-_(GPE_GET_ENCAP_MODE, gpe_get_encap_mode)
+#define foreach_vpe_api_msg                                    \
+_(GPE_ADD_DEL_FWD_ENTRY, gpe_add_del_fwd_entry)                \
+_(GPE_FWD_ENTRIES_GET, gpe_fwd_entries_get)                    \
+_(GPE_FWD_ENTRY_PATH_DUMP, gpe_fwd_entry_path_dump)            \
+_(GPE_ENABLE_DISABLE, gpe_enable_disable)                      \
+_(GPE_ADD_DEL_IFACE, gpe_add_del_iface)                        \
+_(GPE_FWD_ENTRY_VNIS_GET, gpe_fwd_entry_vnis_get)              \
+_(GPE_SET_ENCAP_MODE, gpe_set_encap_mode)                      \
+_(GPE_GET_ENCAP_MODE, gpe_get_encap_mode)                      \
+_(GPE_ADD_DEL_NATIVE_FWD_RPATH, gpe_add_del_native_fwd_rpath)  \
+_(GPE_NATIVE_FWD_RPATHS_GET, gpe_native_fwd_rpaths_get)
 
 static locator_pair_t *
 unformat_gpe_loc_pairs (void *locs, u32 rloc_num)
@@ -435,6 +437,92 @@ vl_api_gpe_get_encap_mode_t_handler (vl_api_gpe_get_encap_mode_t * mp)
   /* *INDENT-ON* */
 }
 
+static void
+  vl_api_gpe_add_del_native_fwd_rpath_t_handler
+  (vl_api_gpe_add_del_native_fwd_rpath_t * mp)
+{
+  vl_api_gpe_add_del_fwd_entry_reply_t *rmp;
+  vnet_gpe_native_fwd_rpath_args_t _a, *a = &_a;
+  int rv = 0;
+
+  memset (a, 0, sizeof (a[0]));
+
+  if (mp->is_ip4)
+    clib_memcpy (&a->rpath.frp_addr, mp->nh_addr, sizeof (ip4_address_t));
+  else
+    clib_memcpy (&a->rpath.frp_addr, mp->nh_addr, sizeof (ip6_address_t));
+
+  a->is_add = mp->is_add;
+  a->rpath.frp_proto = mp->is_ip4 ? FIB_PROTOCOL_IP4 : FIB_PROTOCOL_IP6;
+  a->rpath.frp_fib_index = fib_table_find (a->rpath.frp_proto,
+                                          clib_net_to_host_u32
+                                          (mp->table_id));
+  a->rpath.frp_sw_if_index = clib_net_to_host_u32 (mp->nh_sw_if_index);
+  a->rpath.frp_weight = 1;
+
+  rv = vnet_gpe_add_del_native_fwd_rpath (a);
+  REPLY_MACRO (VL_API_GPE_ADD_DEL_NATIVE_FWD_RPATH_REPLY);
+}
+
+static void
+gpe_native_fwd_rpaths_copy (vl_api_gpe_native_fwd_rpath_t * dst,
+                           fib_route_path_t * src)
+{
+  fib_route_path_t *e;
+  u32 i = 0;
+
+  vec_foreach (e, src)
+  {
+    memset (&dst[i], 0, sizeof (*dst));
+    clib_memcpy (&dst[i], e, sizeof (fib_route_path_t *));
+  }
+}
+
+static void
+gpe_native_fwd_rpath_t_host_to_net (vl_api_gpe_native_fwd_rpath_t * e)
+{
+  e->fib_index = clib_host_to_net_u32 (e->fib_index);
+  e->nh_sw_if_index = clib_host_to_net_u32 (e->nh_sw_if_index);
+}
+
+static void
+  gpe_native_fwd_rpaths_get_reply_t_host_to_net
+  (vl_api_gpe_native_fwd_rpaths_get_reply_t * mp)
+{
+  u32 i;
+  vl_api_gpe_native_fwd_rpath_t *e;
+
+  for (i = 0; i < mp->count; i++)
+    {
+      e = &mp->entries[i];
+      gpe_native_fwd_rpath_t_host_to_net (e);
+    }
+  mp->count = clib_host_to_net_u32 (mp->count);
+}
+
+static void
+vl_api_gpe_native_fwd_rpaths_get_t_handler (vl_api_gpe_native_fwd_rpaths_get_t
+                                           * mp)
+{
+  lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
+  vl_api_gpe_native_fwd_rpaths_get_reply_t *rmp;
+  u32 size = 0;
+  int rv = 0;
+
+  size = vec_len (lgm->native_fwd_rpath[mp->is_ip4])
+    * sizeof (vl_api_gpe_native_fwd_rpath_t);
+
+  /* *INDENT-OFF* */
+  REPLY_MACRO4 (VL_API_GPE_NATIVE_FWD_RPATHS_GET_REPLY, size,
+  {
+    rmp->count = vec_len (lgm->native_fwd_rpath[mp->is_ip4]);
+    gpe_native_fwd_rpaths_copy (rmp->entries,
+                               lgm->native_fwd_rpath[mp->is_ip4]);
+    gpe_native_fwd_rpaths_get_reply_t_host_to_net (rmp);
+  });
+  /* *INDENT-ON* */
+}
+
 /*
  * gpe_api_hookup
  * Add vpe's API message handlers to the table.
index 0b7b0fe..395b493 100644 (file)
@@ -279,14 +279,46 @@ ip_src_fib_add_route (u32 src_fib_index,
   vec_free (rpaths);
 }
 
+static void
+gpe_native_fwd_add_del_lfe (lisp_gpe_fwd_entry_t * lfe, u8 is_add)
+{
+  lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
+  u8 found = 0, ip_version;
+  u32 *lfei, new_lfei;
+  ip_version = ip_prefix_version (&lfe->key->rmt.ippref);
+
+  new_lfei = lfe - lgm->lisp_fwd_entry_pool;
+  vec_foreach (lfei, lgm->native_fwd_lfes[ip_version])
+  {
+    lfe = pool_elt_at_index (lgm->lisp_fwd_entry_pool, lfei[0]);
+    if (lfei[0] == new_lfei)
+      {
+       found = 1;
+       break;
+      }
+  }
+
+  if (is_add)
+    {
+      if (!found)
+       vec_add1 (lgm->native_fwd_lfes[ip_version], new_lfei);
+    }
+  else
+    {
+      if (found)
+       vec_del1 (lgm->native_fwd_lfes[ip_version], lfei[0]);
+    }
+}
 
 static void
 create_fib_entries (lisp_gpe_fwd_entry_t * lfe)
 {
+  lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
   dpo_proto_t dproto;
   ip_prefix_t ippref;
-  dproto = (ip_prefix_version (&lfe->key->rmt.ippref) == IP4 ?
-           DPO_PROTO_IP4 : DPO_PROTO_IP6);
+  fib_prefix_t fib_prefix;
+  u8 ip_version = ip_prefix_version (&lfe->key->rmt.ippref);
+  dproto = (ip_version == IP4 ? DPO_PROTO_IP4 : DPO_PROTO_IP6);
 
   if (lfe->is_src_dst)
     {
@@ -306,11 +338,19 @@ create_fib_entries (lisp_gpe_fwd_entry_t * lfe)
 
       switch (lfe->action)
        {
+       case LISP_FORWARD_NATIVE:
+         /* TODO handle route overlaps with fib and default route */
+         if (vec_len (lgm->native_fwd_rpath[ip_version]))
+           {
+             ip_prefix_to_fib_prefix (&lfe->key->rmt.ippref, &fib_prefix);
+             fib_table_entry_update (lfe->eid_fib_index, &fib_prefix,
+                                     FIB_SOURCE_LISP, FIB_ENTRY_FLAG_NONE,
+                                     lgm->native_fwd_rpath[ip_version]);
+             gpe_native_fwd_add_del_lfe (lfe, 1);
+             break;
+           }
        case LISP_NO_ACTION:
          /* TODO update timers? */
-       case LISP_FORWARD_NATIVE:
-         /* TODO check if route/next-hop for eid exists in fib and add
-          * more specific for the eid with the next-hop found */
        case LISP_SEND_MAP_REQUEST:
          /* insert tunnel that always sends map-request */
          dpo_copy (&dpo, lisp_cp_dpo_get (dproto));
@@ -343,6 +383,7 @@ delete_fib_entries (lisp_gpe_fwd_entry_t * lfe)
       ip_prefix_to_fib_prefix (&lfe->key->rmt.ippref, &dst_fib_prefix);
       fib_table_entry_delete (lfe->src_fib_index, &dst_fib_prefix,
                              FIB_SOURCE_LISP);
+      gpe_native_fwd_add_del_lfe (lfe, 0);
     }
 }