From a4e63e5593d53692b8085dc666f8670ece135f32 Mon Sep 17 00:00:00 2001 From: Florin Coras Date: Wed, 7 Jun 2017 21:50:57 -0700 Subject: Add gpe native-forward static route support Change-Id: I744e7d64d94dbb302f2c1246663480f720672ee2 Signed-off-by: Florin Coras --- src/vnet/lisp-gpe/lisp_gpe.api | 56 ++++++++++ src/vnet/lisp-gpe/lisp_gpe.c | 191 +++++++++++++++++++++++++++++++++ src/vnet/lisp-gpe/lisp_gpe.h | 12 ++- src/vnet/lisp-gpe/lisp_gpe_api.c | 108 +++++++++++++++++-- src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c | 51 ++++++++- 5 files changed, 402 insertions(+), 16 deletions(-) diff --git a/src/vnet/lisp-gpe/lisp_gpe.api b/src/vnet/lisp-gpe/lisp_gpe.api index 706f20d4..17ce579f 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.api +++ b/src/vnet/lisp-gpe/lisp_gpe.api @@ -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") diff --git a/src/vnet/lisp-gpe/lisp_gpe.c b/src/vnet/lisp-gpe/lisp_gpe.c index 052410e2..ea6c143d 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.c +++ b/src/vnet/lisp-gpe/lisp_gpe.c @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include /** 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 [iface] " + "[table ]", + .function = gpe_native_forward_command_fn, +}; +/* *INDENT-ON* */ + /** Format LISP-GPE status. */ u8 * format_vnet_lisp_gpe_status (u8 * s, va_list * args) diff --git a/src/vnet/lisp-gpe/lisp_gpe.h b/src/vnet/lisp-gpe/lisp_gpe.h index f0405644..660f8a66 100644 --- a/src/vnet/lisp-gpe/lisp_gpe.h +++ b/src/vnet/lisp-gpe/lisp_gpe.h @@ -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 */ /* diff --git a/src/vnet/lisp-gpe/lisp_gpe_api.c b/src/vnet/lisp-gpe/lisp_gpe_api.c index ab081b35..4df743cd 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_api.c +++ b/src/vnet/lisp-gpe/lisp_gpe_api.c @@ -27,7 +27,7 @@ #include #include #include - +#include #include #define vl_api_gpe_locator_pair_t_endian vl_noop_handler @@ -51,15 +51,17 @@ #include -#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. diff --git a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c index 0b7b0fef..395b493a 100644 --- a/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c +++ b/src/vnet/lisp-gpe/lisp_gpe_fwd_entry.c @@ -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); } } -- cgit 1.2.3-korg