From 88fc83eb716bf07f4634de6de5b569f795a56418 Mon Sep 17 00:00:00 2001 From: Neale Ranns Date: Wed, 5 Apr 2017 08:11:14 -0700 Subject: BFD-FIB interactions - single-hop BFD: attach a delegate to the appropriate adjacency - multi-hop BFD [not supported yet]: attach a delegate to the FIB entry. adjacency/fib_entry state tracks the BFD session state. when the state is down the object does not contribute forwarding hence and hence dependent objects will not use it. For example, if a route is ECMP via two adjacencies and one of them is BFD down, then only the other is used to forward (i.e. we don't drop half the traffic). Change-Id: I0ef53e20e73b067001a132cd0a3045408811a822 Signed-off-by: Neale Ranns --- src/vnet/fib/fib_attached_export.c | 75 +++--- src/vnet/fib/fib_attached_export.h | 4 +- src/vnet/fib/fib_bfd.c | 197 ++++++++++++++ src/vnet/fib/fib_entry.c | 50 ++-- src/vnet/fib/fib_entry.h | 1 + src/vnet/fib/fib_entry_cover.c | 45 ---- src/vnet/fib/fib_entry_cover.h | 5 - src/vnet/fib/fib_entry_delegate.c | 100 +++++++ src/vnet/fib/fib_entry_delegate.h | 33 +++ src/vnet/fib/fib_path.c | 52 ++-- src/vnet/fib/fib_test.c | 522 +++++++++++++++++++++++++++++++++++++ src/vnet/fib/ip4_fib.c | 16 +- src/vnet/fib/ip6_fib.c | 21 +- 13 files changed, 983 insertions(+), 138 deletions(-) create mode 100644 src/vnet/fib/fib_bfd.c (limited to 'src/vnet/fib') diff --git a/src/vnet/fib/fib_attached_export.c b/src/vnet/fib/fib_attached_export.c index 715e63e7246..cc8ebc8653e 100644 --- a/src/vnet/fib/fib_attached_export.c +++ b/src/vnet/fib/fib_attached_export.c @@ -514,67 +514,52 @@ fib_attached_export_cover_update (fib_entry_t *fib_entry) } u8* -fib_ae_import_format (fib_entry_t *fib_entry, +fib_ae_import_format (fib_node_index_t impi, u8* s) { - fib_entry_delegate_t *fed; - - fed = fib_entry_delegate_get(fib_entry, - FIB_ENTRY_DELEGATE_ATTACHED_IMPORT); - - if (NULL != fed) - { - fib_node_index_t *index; - fib_ae_import_t *import; - - import = pool_elt_at_index(fib_ae_import_pool, fed->fd_index); + fib_node_index_t *index; + fib_ae_import_t *import; - s = format(s, "\n Attached-Import:%d:[", (import - fib_ae_import_pool)); - s = format(s, "export-prefix:%U ", format_fib_prefix, &import->faei_prefix); - s = format(s, "export-entry:%d ", import->faei_export_entry); - s = format(s, "export-sibling:%d ", import->faei_export_sibling); - s = format(s, "exporter:%d ", import->faei_exporter); - s = format(s, "export-fib:%d ", import->faei_export_fib); + import = pool_elt_at_index(fib_ae_import_pool, impi); - s = format(s, "import-entry:%d ", import->faei_import_entry); - s = format(s, "import-fib:%d ", import->faei_import_fib); + s = format(s, "\n Attached-Import:%d:[", (import - fib_ae_import_pool)); + s = format(s, "export-prefix:%U ", format_fib_prefix, &import->faei_prefix); + s = format(s, "export-entry:%d ", import->faei_export_entry); + s = format(s, "export-sibling:%d ", import->faei_export_sibling); + s = format(s, "exporter:%d ", import->faei_exporter); + s = format(s, "export-fib:%d ", import->faei_export_fib); + + s = format(s, "import-entry:%d ", import->faei_import_entry); + s = format(s, "import-fib:%d ", import->faei_import_fib); - s = format(s, "importeds:["); - vec_foreach(index, import->faei_importeds) - { - s = format(s, "%d, ", *index); - } - s = format(s, "]]"); + s = format(s, "importeds:["); + vec_foreach(index, import->faei_importeds) + { + s = format(s, "%d, ", *index); } + s = format(s, "]]"); return (s); } u8* -fib_ae_export_format (fib_entry_t *fib_entry, +fib_ae_export_format (fib_node_index_t expi, u8* s) { - fib_entry_delegate_t *fed; - - fed = fib_entry_delegate_get(fib_entry, - FIB_ENTRY_DELEGATE_ATTACHED_EXPORT); - - if (NULL != fed) - { - fib_node_index_t *index; - fib_ae_export_t *export; + fib_node_index_t *index; + fib_ae_export_t *export; - export = pool_elt_at_index(fib_ae_export_pool, fed->fd_list); + export = pool_elt_at_index(fib_ae_export_pool, expi); - s = format(s, "\n Attached-Export:%d:[", (export - fib_ae_export_pool)); - s = format(s, "export-entry:%d ", export->faee_ei); + s = format(s, "\n Attached-Export:%d:[", (export - fib_ae_export_pool)); + s = format(s, "export-entry:%d ", export->faee_ei); - s = format(s, "importers:["); - vec_foreach(index, export->faee_importers) - { - s = format(s, "%d, ", *index); - } - s = format(s, "]]"); + s = format(s, "importers:["); + vec_foreach(index, export->faee_importers) + { + s = format(s, "%d, ", *index); } + s = format(s, "]]"); + return (s); } diff --git a/src/vnet/fib/fib_attached_export.h b/src/vnet/fib/fib_attached_export.h index fa28a6e13b8..d4c2b57c379 100644 --- a/src/vnet/fib/fib_attached_export.h +++ b/src/vnet/fib/fib_attached_export.h @@ -51,7 +51,7 @@ extern void fib_attached_export_covered_removed(fib_entry_t *cover, extern void fib_attached_export_cover_change(fib_entry_t *fib_entry); extern void fib_attached_export_cover_update(fib_entry_t *fib_entry); -extern u8* fib_ae_import_format(fib_entry_t *fib_entry, u8*s); -extern u8* fib_ae_export_format(fib_entry_t *fib_entry, u8*s); +extern u8* fib_ae_import_format(fib_node_index_t impi, u8*s); +extern u8* fib_ae_export_format(fib_node_index_t expi, u8*s); #endif diff --git a/src/vnet/fib/fib_bfd.c b/src/vnet/fib/fib_bfd.c new file mode 100644 index 00000000000..e5affb8de49 --- /dev/null +++ b/src/vnet/fib/fib_bfd.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2016 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include + +static fib_bfd_state_t +fib_bfd_bfd_state_to_fib (bfd_state_e bstate) +{ + switch (bstate) + { + case BFD_STATE_up: + return (FIB_BFD_STATE_UP); + case BFD_STATE_down: + case BFD_STATE_admin_down: + case BFD_STATE_init: + return (FIB_BFD_STATE_DOWN); + } + return (FIB_BFD_STATE_DOWN); +} + +static void +fib_bfd_update_walk (fib_node_index_t fei) +{ + /* + * initiate a backwalk of dependent children + * to notify of the state change of this entry. + */ + fib_node_back_walk_ctx_t ctx = { + .fnbw_reason = FIB_NODE_BW_REASON_FLAG_EVALUATE, + }; + fib_walk_sync(FIB_NODE_TYPE_ENTRY, fei, &ctx); +} + +/** + * @brief Callback function registered with BFD module to receive notifications + * of the CRUD of BFD sessions + * would be static but for the fact it's called from the unit-tests + */ +void +fib_bfd_notify (bfd_listen_event_e event, + const bfd_session_t *session) +{ + fib_entry_delegate_t *fed; + const bfd_udp_key_t *key; + fib_node_index_t fei; + + if (BFD_HOP_TYPE_MULTI != session->hop_type) + { + /* + * multi-hop BFD sessions attach directly to the FIB entry + * single-hop adj to the associate adjacency. + */ + return; + } + + key = &session->udp.key; + + fib_prefix_t pfx = { + .fp_addr = key->peer_addr, + .fp_proto = (ip46_address_is_ip4 (&key->peer_addr) ? + FIB_PROTOCOL_IP4: + FIB_PROTOCOL_IP6), + .fp_len = (ip46_address_is_ip4 (&key->peer_addr) ? + 32: + 128), + }; + + /* + * get the FIB entry + */ + fei = fib_table_lookup_exact_match(key->fib_index, &pfx); + + switch (event) + { + case BFD_LISTEN_EVENT_CREATE: + /* + * The creation of a new session + */ + if ((FIB_NODE_INDEX_INVALID != fei) && + (fed = fib_entry_delegate_get(fib_entry_get(fei), + FIB_ENTRY_DELEGATE_BFD))) + { + /* + * already got state for this entry + */ + } + else + { + /* + * source and lock the entry. add the delegate + */ + fei = fib_table_entry_special_add(key->fib_index, + &pfx, + FIB_SOURCE_RR, + FIB_ENTRY_FLAG_NONE, + ADJ_INDEX_INVALID); + fib_entry_lock(fei); + + fed = fib_entry_delegate_find_or_add(fib_entry_get(fei), + FIB_ENTRY_DELEGATE_BFD); + + /* + * pretend the session is up and skip the walk. + * If we set it down then we get traffic loss on new children. + * if we walk then we lose traffic for existing children. Wait + * for the first BFD UP/DOWN before we let the session's state + * influence forwarding. + */ + fed->fd_bfd_state = FIB_BFD_STATE_UP; + } + break; + + case BFD_LISTEN_EVENT_UPDATE: + /* + * state change up/dowm and + */ + ASSERT(FIB_NODE_INDEX_INVALID != fei); + + fed = fib_entry_delegate_get(fib_entry_get(fei), + FIB_ENTRY_DELEGATE_BFD); + + if (NULL != fed) + { + fed->fd_bfd_state = fib_bfd_bfd_state_to_fib(session->local_state); + fib_bfd_update_walk(fei); + } + /* + * else + * no BFD state + */ + break; + + case BFD_LISTEN_EVENT_DELETE: + /* + * session has been removed. + */ + if (FIB_NODE_INDEX_INVALID == fei) + { + /* + * no FIB entry + */ + } + else if (fib_entry_delegate_get(fib_entry_get(fei), + FIB_ENTRY_DELEGATE_BFD)) + { + /* + * has an associated BFD tracking delegate + * usource the entry and remove the BFD tracking deletgate + */ + fib_entry_delegate_remove(fib_entry_get(fei), + FIB_ENTRY_DELEGATE_BFD); + fib_bfd_update_walk(fei); + + fib_table_entry_special_remove(key->fib_index, + &pfx, + FIB_SOURCE_RR); + fib_entry_unlock(fei); + } + /* + * else + * no BFD associated state + */ + break; + } +} + +static clib_error_t * +fib_bfd_main_init (vlib_main_t * vm) +{ + clib_error_t * error = NULL; + + if ((error = vlib_call_init_function (vm, bfd_main_init))) + return (error); + + bfd_register_listener(fib_bfd_notify); + + return (error); +} + +VLIB_INIT_FUNCTION (fib_bfd_main_init); diff --git a/src/vnet/fib/fib_entry.c b/src/vnet/fib/fib_entry.c index 6ac5461d76c..dac1fce995f 100644 --- a/src/vnet/fib/fib_entry.c +++ b/src/vnet/fib/fib_entry.c @@ -99,7 +99,6 @@ format_fib_entry (u8 * s, va_list * args) fib_entry_src_t *src; fib_node_index_t fei; fib_source_t source; - u32 n_covered; int level; fei = va_arg (*args, fib_node_index_t); @@ -143,14 +142,6 @@ format_fib_entry (u8 * s, va_list * args) } })); - n_covered = fib_entry_cover_get_size(fib_entry); - if (n_covered > 0) { - s = format(s, "\n tracking %d covered: ", n_covered); - s = fib_entry_cover_list_format(fib_entry, s); - } - s = fib_ae_import_format(fib_entry, s); - s = fib_ae_export_format(fib_entry, s); - s = format (s, "\n forwarding: "); } else @@ -179,20 +170,17 @@ format_fib_entry (u8 * s, va_list * args) fib_entry_delegate_type_t fdt; fib_entry_delegate_t *fed; - FOR_EACH_DELEGATE_CHAIN(fib_entry, fdt, fed, + s = format (s, " Delegates:\n"); + FOR_EACH_DELEGATE(fib_entry, fdt, fed, { - s = format(s, " %U-chain\n %U", - format_fib_forw_chain_type, - fib_entry_delegate_type_to_chain_type(fdt), - format_dpo_id, &fed->fd_dpo, 2); - s = format(s, "\n"); + s = format(s, " %U\n", format_fib_entry_deletegate, fed); }); } } if (level >= FIB_ENTRY_FORMAT_DETAIL2) { - s = format(s, "\nchildren:"); + s = format(s, " Children:"); s = fib_node_children_format(fib_entry->fe_node.fn_children, s); } @@ -1339,6 +1327,36 @@ fib_entry_get_best_source (fib_node_index_t entry_index) return (fib_entry_src_get_source(bsrc)); } +/** + * Return !0 is the entry is reoslved, i.e. will return a valid forwarding + * chain + */ +int +fib_entry_is_resolved (fib_node_index_t fib_entry_index) +{ + fib_entry_delegate_t *fed; + fib_entry_t *fib_entry; + + fib_entry = fib_entry_get(fib_entry_index); + + fed = fib_entry_delegate_get(fib_entry, FIB_ENTRY_DELEGATE_BFD); + + if (NULL == fed) + { + /* + * no BFD tracking - resolved + */ + return (!0); + } + else + { + /* + * defer to the state of the BFD tracking + */ + return (FIB_BFD_STATE_UP == fed->fd_bfd_state); + } +} + static int fib_ip4_address_compare (const ip4_address_t * a1, const ip4_address_t * a2) diff --git a/src/vnet/fib/fib_entry.h b/src/vnet/fib/fib_entry.h index 12fa9eb4e9b..a3f75e6084a 100644 --- a/src/vnet/fib/fib_entry.h +++ b/src/vnet/fib/fib_entry.h @@ -525,6 +525,7 @@ extern int fib_entry_is_sourced(fib_node_index_t fib_entry_index, fib_source_t source); extern fib_node_index_t fib_entry_get_path_list(fib_node_index_t fib_entry_index); +extern int fib_entry_is_resolved(fib_node_index_t fib_entry_index); extern void fib_entry_module_init(void); diff --git a/src/vnet/fib/fib_entry_cover.c b/src/vnet/fib/fib_entry_cover.c index 147c5daa4fd..814df578a62 100644 --- a/src/vnet/fib/fib_entry_cover.c +++ b/src/vnet/fib/fib_entry_cover.c @@ -106,51 +106,6 @@ fib_entry_cover_walk (fib_entry_t *cover, &ctx); } -u32 -fib_entry_cover_get_size (fib_entry_t *cover) -{ - fib_entry_delegate_t *fed; - - fed = fib_entry_delegate_get(cover, FIB_ENTRY_DELEGATE_COVERED); - - if (NULL == fed) - return (0); - - return (fib_node_list_get_size(fed->fd_list)); -} - -typedef struct fib_entry_cover_list_format_ctx_t_ { - u8 *s; -} fib_entry_cover_list_format_ctx_t; - -static int -fib_entry_covered_list_format_one (fib_entry_t *cover, - fib_node_index_t covered, - void *args) -{ - fib_entry_cover_list_format_ctx_t * ctx = args; - - ctx->s = format(ctx->s, "%d, ", covered); - - /* continue */ - return (1); -} - -u8* -fib_entry_cover_list_format (fib_entry_t *fib_entry, - u8 *s) -{ - fib_entry_cover_list_format_ctx_t ctx = { - .s = s, - }; - - fib_entry_cover_walk(fib_entry, - fib_entry_covered_list_format_one, - &ctx); - - return (ctx.s); -} - static int fib_entry_cover_change_one (fib_entry_t *cover, fib_node_index_t covered, diff --git a/src/vnet/fib/fib_entry_cover.h b/src/vnet/fib/fib_entry_cover.h index fbbbc211dc9..500d5b33244 100644 --- a/src/vnet/fib/fib_entry_cover.h +++ b/src/vnet/fib/fib_entry_cover.h @@ -39,9 +39,4 @@ extern void fib_entry_cover_change_notify(fib_node_index_t cover_index, fib_node_index_t covered_index); extern void fib_entry_cover_update_notify(fib_entry_t *cover); -extern u32 fib_entry_cover_get_size(fib_entry_t *cover); - -extern u8* fib_entry_cover_list_format(fib_entry_t *fib_entry, - u8 *s); - #endif diff --git a/src/vnet/fib/fib_entry_delegate.c b/src/vnet/fib/fib_entry_delegate.c index 70840b160a1..41af14f2245 100644 --- a/src/vnet/fib/fib_entry_delegate.c +++ b/src/vnet/fib/fib_entry_delegate.c @@ -15,6 +15,7 @@ #include #include +#include static fib_entry_delegate_t * fib_entry_delegate_find_i (const fib_entry_t *fib_entry, @@ -149,8 +150,107 @@ fib_entry_delegate_type_to_chain_type (fib_entry_delegate_type_t fdt) case FIB_ENTRY_DELEGATE_COVERED: case FIB_ENTRY_DELEGATE_ATTACHED_IMPORT: case FIB_ENTRY_DELEGATE_ATTACHED_EXPORT: + case FIB_ENTRY_DELEGATE_BFD: break; } ASSERT(0); return (FIB_FORW_CHAIN_TYPE_UNICAST_IP4); } + +/** + * typedef for printing a delegate + */ +typedef u8 * (*fib_entry_delegate_format_t)(const fib_entry_delegate_t *fed, + u8 *s); + +/** + * Print a delegate that represents a forwarding chain + */ +static u8 * +fib_entry_delegate_fmt_fwd_chain (const fib_entry_delegate_t *fed, + u8 *s) +{ + s = format(s, "%U-chain\n %U", + format_fib_forw_chain_type, + fib_entry_delegate_type_to_chain_type(fed->fd_type), + format_dpo_id, &fed->fd_dpo, 2); + + return (s); +} + +/** + * Print a delegate that represents cover tracking + */ +static u8 * +fib_entry_delegate_fmt_covered (const fib_entry_delegate_t *fed, + u8 *s) +{ + s = format(s, "covered:["); + s = fib_node_children_format(fed->fd_list, s); + s = format(s, "]"); + + return (s); +} + +/** + * Print a delegate that represents attached-import tracking + */ +static u8 * +fib_entry_delegate_fmt_import (const fib_entry_delegate_t *fed, + u8 *s) +{ + s = format(s, "import:%U", fib_ae_import_format, fed->fd_index); + + return (s); +} + +/** + * Print a delegate that represents attached-export tracking + */ +static u8 * +fib_entry_delegate_fmt_export (const fib_entry_delegate_t *fed, + u8 *s) +{ + s = format(s, "export:%U", fib_ae_export_format, fed->fd_index); + + return (s); +} + +/** + * Print a delegate that represents BFD tracking + */ +static u8 * +fib_entry_delegate_fmt_bfd (const fib_entry_delegate_t *fed, + u8 *s) +{ + s = format(s, "BFD:%d", fed->fd_bfd_state); + + return (s); +} + +/** + * A delegate type to formatter map + */ +static fib_entry_delegate_format_t fed_formatters[] = +{ + [FIB_ENTRY_DELEGATE_CHAIN_UNICAST_IP4] = fib_entry_delegate_fmt_fwd_chain, + [FIB_ENTRY_DELEGATE_CHAIN_UNICAST_IP6] = fib_entry_delegate_fmt_fwd_chain, + [FIB_ENTRY_DELEGATE_CHAIN_MPLS_EOS] = fib_entry_delegate_fmt_fwd_chain, + [FIB_ENTRY_DELEGATE_CHAIN_MPLS_NON_EOS] = fib_entry_delegate_fmt_fwd_chain, + [FIB_ENTRY_DELEGATE_CHAIN_ETHERNET] = fib_entry_delegate_fmt_fwd_chain, + [FIB_ENTRY_DELEGATE_CHAIN_NSH] = fib_entry_delegate_fmt_fwd_chain, + [FIB_ENTRY_DELEGATE_COVERED] = fib_entry_delegate_fmt_covered, + [FIB_ENTRY_DELEGATE_ATTACHED_IMPORT] = fib_entry_delegate_fmt_import, + [FIB_ENTRY_DELEGATE_ATTACHED_EXPORT] = fib_entry_delegate_fmt_export, + [FIB_ENTRY_DELEGATE_BFD] = fib_entry_delegate_fmt_bfd, +}; + +u8 * +format_fib_entry_deletegate (u8 * s, va_list * args) +{ + fib_entry_delegate_t *fed; + + fed = va_arg (*args, fib_entry_delegate_t *); + + return (fed_formatters[fed->fd_type](fed, s)); +} diff --git a/src/vnet/fib/fib_entry_delegate.h b/src/vnet/fib/fib_entry_delegate.h index d9183c5f181..333d357c120 100644 --- a/src/vnet/fib/fib_entry_delegate.h +++ b/src/vnet/fib/fib_entry_delegate.h @@ -42,6 +42,10 @@ typedef enum fib_entry_delegate_type_t_ { * to their respective cover */ FIB_ENTRY_DELEGATE_COVERED, + /** + * BFD session state + */ + FIB_ENTRY_DELEGATE_BFD, /** * Attached import/export functionality */ @@ -61,6 +65,28 @@ typedef enum fib_entry_delegate_type_t_ { } \ } \ } +#define FOR_EACH_DELEGATE(_entry, _fdt, _fed, _body) \ +{ \ + for (_fdt = FIB_ENTRY_DELEGATE_CHAIN_UNICAST_IP4; \ + _fdt <= FIB_ENTRY_DELEGATE_ATTACHED_EXPORT; \ + _fdt++) \ + { \ + _fed = fib_entry_delegate_get(_entry, _fdt); \ + if (NULL != _fed) { \ + _body; \ + } \ + } \ +} + +/** + * Distillation of the BFD session states into a go/no-go for using + * the associated tracked FIB entry + */ +typedef enum fib_bfd_state_t_ +{ + FIB_BFD_STATE_UP, + FIB_BFD_STATE_DOWN, +} fib_bfd_state_t; /** * A Delagate is a means to implmenet the Delagation design pattern; the extension of an @@ -103,6 +129,11 @@ typedef struct fib_entry_delegate_t_ * For the cover tracking. The node list; */ fib_node_list_t fd_list; + + /** + * BFD state + */ + fib_bfd_state_t fd_bfd_state; }; } fib_entry_delegate_t; @@ -122,4 +153,6 @@ extern fib_forward_chain_type_t fib_entry_delegate_type_to_chain_type( extern fib_entry_delegate_type_t fib_entry_chain_type_to_delegate_type( fib_forward_chain_type_t type); +extern u8 *format_fib_entry_deletegate(u8 * s, va_list * args); + #endif diff --git a/src/vnet/fib/fib_path.c b/src/vnet/fib/fib_path.c index 928a9d432be..6b202a97824 100644 --- a/src/vnet/fib/fib_path.c +++ b/src/vnet/fib/fib_path.c @@ -558,12 +558,6 @@ fib_path_attached_next_hop_set (fib_path_t *path) * resolve directly via the adjacnecy discribed by the * interface and next-hop */ - if (!vnet_sw_interface_is_admin_up(vnet_get_main(), - path->attached_next_hop.fp_interface)) - { - path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED; - } - dpo_set(&path->fp_dpo, DPO_ADJACENCY, fib_proto_to_dpo(path->fp_nh_proto), @@ -578,6 +572,13 @@ fib_path_attached_next_hop_set (fib_path_t *path) path->fp_sibling = adj_child_add(path->fp_dpo.dpoi_index, FIB_NODE_TYPE_PATH, fib_path_get_index(path)); + + if (!vnet_sw_interface_is_admin_up(vnet_get_main(), + path->attached_next_hop.fp_interface) || + !adj_is_up(path->fp_dpo.dpoi_index)) + { + path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED; + } } /* @@ -653,6 +654,19 @@ fib_path_recursive_adj_update (fib_path_t *path, load_balance_map_path_state_change(fib_path_get_index(path)); } } + /* + * check for over-riding factors on the FIB entry itself + */ + if (!fib_entry_is_resolved(path->fp_via_fib)) + { + path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED; + dpo_copy(&via_dpo, drop_dpo_get(fib_proto_to_dpo(path->fp_nh_proto))); + + /* + * PIC edge trigger. let the load-balance maps know + */ + load_balance_map_path_state_change(fib_path_get_index(path)); + } /* * update the path's contributed DPO @@ -855,15 +869,16 @@ FIXME comment vnet_get_main(), path->attached_next_hop.fp_interface); - if (if_is_up) - { - path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED; - } - ai = fib_path_attached_next_hop_get_adj( path, fib_proto_to_link(path->fp_nh_proto)); + path->fp_oper_flags &= ~FIB_PATH_OPER_FLAG_RESOLVED; + if (if_is_up && adj_is_up(ai)) + { + path->fp_oper_flags |= FIB_PATH_OPER_FLAG_RESOLVED; + } + dpo_set(&path->fp_dpo, DPO_ADJACENCY, fib_proto_to_dpo(path->fp_nh_proto), ai); @@ -1684,11 +1699,11 @@ fib_path_contribute_urpf (fib_node_index_t path_index, { fib_path_t *path; - if (!fib_path_is_resolved(path_index)) - return; - path = fib_path_get(path_index); + /* + * resolved and unresolved paths contribute to the RPF list. + */ switch (path->fp_type) { case FIB_PATH_TYPE_ATTACHED_NEXT_HOP: @@ -1700,7 +1715,14 @@ fib_path_contribute_urpf (fib_node_index_t path_index, break; case FIB_PATH_TYPE_RECURSIVE: - fib_entry_contribute_urpf(path->fp_via_fib, urpf); + if (FIB_NODE_INDEX_INVALID != path->fp_via_fib) + { + /* + * there's unresolved due to constraints, and there's unresolved + * due to ain't go no via. can't do nowt w'out via. + */ + fib_entry_contribute_urpf(path->fp_via_fib, urpf); + } break; case FIB_PATH_TYPE_EXCLUSIVE: diff --git a/src/vnet/fib/fib_test.c b/src/vnet/fib/fib_test.c index 92141ddfce1..3c9b8a38fe1 100644 --- a/src/vnet/fib/fib_test.c +++ b/src/vnet/fib/fib_test.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -33,6 +34,11 @@ #include #include +/* + * Add debugs for passing tests + */ +static int fib_test_do_debug; + #define FIB_TEST_I(_cond, _comment, _args...) \ ({ \ int _evald = (_cond); \ @@ -40,6 +46,9 @@ fformat(stderr, "FAIL:%d: " _comment "\n", \ __LINE__, ##_args); \ } else { \ + if (fib_test_do_debug) \ + fformat(stderr, "PASS:%d: " _comment "\n", \ + __LINE__, ##_args); \ } \ _evald; \ }) @@ -6735,6 +6744,509 @@ fib_test_walk (void) return (0); } +/* + * declaration of the otherwise static callback functions + */ +void fib_bfd_notify (bfd_listen_event_e event, + const bfd_session_t *session); +void adj_bfd_notify (bfd_listen_event_e event, + const bfd_session_t *session); + +/** + * Test BFD session interaction with FIB + */ +static int +fib_test_bfd (void) +{ + fib_node_index_t fei; + test_main_t *tm; + int n_feis; + + /* via 10.10.10.1 */ + ip46_address_t nh_10_10_10_1 = { + .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a01), + }; + /* via 10.10.10.2 */ + ip46_address_t nh_10_10_10_2 = { + .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a02), + }; + /* via 10.10.10.10 */ + ip46_address_t nh_10_10_10_10 = { + .ip4.as_u32 = clib_host_to_net_u32(0x0a0a0a0a), + }; + n_feis = fib_entry_pool_size(); + + tm = &test_main; + + /* + * add interface routes. we'll assume this works. it's tested elsewhere + */ + fib_prefix_t pfx_10_10_10_10_s_24 = { + .fp_len = 24, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_addr = nh_10_10_10_10, + }; + + fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_24, + FIB_SOURCE_INTERFACE, + (FIB_ENTRY_FLAG_CONNECTED | + FIB_ENTRY_FLAG_ATTACHED), + FIB_PROTOCOL_IP4, + NULL, + tm->hw[0]->sw_if_index, + ~0, // invalid fib index + 1, // weight + NULL, + FIB_ROUTE_PATH_FLAG_NONE); + + fib_prefix_t pfx_10_10_10_10_s_32 = { + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + .fp_addr = nh_10_10_10_10, + }; + fib_table_entry_update_one_path(0, &pfx_10_10_10_10_s_32, + FIB_SOURCE_INTERFACE, + (FIB_ENTRY_FLAG_CONNECTED | + FIB_ENTRY_FLAG_LOCAL), + FIB_PROTOCOL_IP4, + NULL, + tm->hw[0]->sw_if_index, + ~0, // invalid fib index + 1, // weight + NULL, + FIB_ROUTE_PATH_FLAG_NONE); + + /* + * A BFD session via a neighbour we do not yet know + */ + bfd_session_t bfd_10_10_10_1 = { + .udp = { + .key = { + .fib_index = 0, + .peer_addr = nh_10_10_10_1, + }, + }, + .hop_type = BFD_HOP_TYPE_MULTI, + .local_state = BFD_STATE_init, + }; + + fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1); + + /* + * A new entry will be created that forwards via the adj + */ + adj_index_t ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, + VNET_LINK_IP4, + &nh_10_10_10_1, + tm->hw[0]->sw_if_index); + fib_prefix_t pfx_10_10_10_1_s_32 = { + .fp_addr = nh_10_10_10_1, + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + }; + fib_test_lb_bucket_t adj_o_10_10_10_1 = { + .type = FT_LB_ADJ, + .adj = { + .adj = ai_10_10_10_1, + }, + }; + + fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32); + FIB_TEST(fib_test_validate_entry(fei, + FIB_FORW_CHAIN_TYPE_UNICAST_IP4, + 1, + &adj_o_10_10_10_1), + "BFD sourced %U via %U", + format_fib_prefix, &pfx_10_10_10_1_s_32, + format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE); + + /* + * Delete the BFD session. Expect the fib_entry to be removed + */ + fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1); + + fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32); + FIB_TEST(FIB_NODE_INDEX_INVALID == fei, + "BFD sourced %U removed", + format_fib_prefix, &pfx_10_10_10_1_s_32); + + /* + * Add the BFD source back + */ + fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1); + + /* + * source the entry via the ADJ fib + */ + fei = fib_table_entry_update_one_path(0, + &pfx_10_10_10_1_s_32, + FIB_SOURCE_ADJ, + FIB_ENTRY_FLAG_ATTACHED, + FIB_PROTOCOL_IP4, + &nh_10_10_10_1, + tm->hw[0]->sw_if_index, + ~0, // invalid fib index + 1, + NULL, + FIB_ROUTE_PATH_FLAG_NONE); + + /* + * Delete the BFD session. Expect the fib_entry to remain + */ + fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1); + + fei = fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32); + FIB_TEST(fib_test_validate_entry(fei, + FIB_FORW_CHAIN_TYPE_UNICAST_IP4, + 1, + &adj_o_10_10_10_1), + "BFD sourced %U remains via %U", + format_fib_prefix, &pfx_10_10_10_1_s_32, + format_ip_adjacency, ai_10_10_10_1, FORMAT_IP_ADJACENCY_NONE); + + /* + * Add the BFD source back + */ + fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1); + + /* + * Create another ADJ FIB + */ + fib_prefix_t pfx_10_10_10_2_s_32 = { + .fp_addr = nh_10_10_10_2, + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + }; + fib_table_entry_update_one_path(0, + &pfx_10_10_10_2_s_32, + FIB_SOURCE_ADJ, + FIB_ENTRY_FLAG_ATTACHED, + FIB_PROTOCOL_IP4, + &nh_10_10_10_2, + tm->hw[0]->sw_if_index, + ~0, // invalid fib index + 1, + NULL, + FIB_ROUTE_PATH_FLAG_NONE); + /* + * A BFD session for the new ADJ FIB + */ + bfd_session_t bfd_10_10_10_2 = { + .udp = { + .key = { + .fib_index = 0, + .peer_addr = nh_10_10_10_2, + }, + }, + .hop_type = BFD_HOP_TYPE_MULTI, + .local_state = BFD_STATE_init, + }; + + fib_bfd_notify (BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_2); + + /* + * remove the adj-fib source whilst the session is present + * then add it back + */ + fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ); + fib_table_entry_update_one_path(0, + &pfx_10_10_10_2_s_32, + FIB_SOURCE_ADJ, + FIB_ENTRY_FLAG_ATTACHED, + FIB_PROTOCOL_IP4, + &nh_10_10_10_2, + tm->hw[0]->sw_if_index, + ~0, // invalid fib index + 1, + NULL, + FIB_ROUTE_PATH_FLAG_NONE); + + /* + * Before adding a recursive via the BFD tracked ADJ-FIBs, + * bring one of the sessions UP, leave the other down + */ + bfd_10_10_10_1.local_state = BFD_STATE_up; + fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1); + bfd_10_10_10_2.local_state = BFD_STATE_down; + fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2); + + /* + * A recursive prefix via both of the ADJ FIBs + */ + fib_prefix_t pfx_200_0_0_0_s_24 = { + .fp_proto = FIB_PROTOCOL_IP4, + .fp_len = 32, + .fp_addr = { + .ip4.as_u32 = clib_host_to_net_u32(0xc8000000), + }, + }; + const dpo_id_t *dpo_10_10_10_1, *dpo_10_10_10_2; + + dpo_10_10_10_1 = + fib_entry_contribute_ip_forwarding( + fib_table_lookup_exact_match(0, &pfx_10_10_10_1_s_32)); + dpo_10_10_10_2 = + fib_entry_contribute_ip_forwarding( + fib_table_lookup_exact_match(0, &pfx_10_10_10_2_s_32)); + + fib_test_lb_bucket_t lb_o_10_10_10_1 = { + .type = FT_LB_O_LB, + .lb = { + .lb = dpo_10_10_10_1->dpoi_index, + }, + }; + fib_test_lb_bucket_t lb_o_10_10_10_2 = { + .type = FT_LB_O_LB, + .lb = { + .lb = dpo_10_10_10_2->dpoi_index, + }, + }; + + /* + * A prefix via the adj-fib that is BFD down => DROP + */ + fei = fib_table_entry_path_add(0, + &pfx_200_0_0_0_s_24, + FIB_SOURCE_API, + FIB_ENTRY_FLAG_NONE, + FIB_PROTOCOL_IP4, + &nh_10_10_10_2, + ~0, // recursive + 0, // default fib index + 1, + NULL, + FIB_ROUTE_PATH_FLAG_NONE); + FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)), + "%U resolves via drop", + format_fib_prefix, &pfx_200_0_0_0_s_24); + + /* + * add a path via the UP BFD adj-fib. + * we expect that the DOWN BFD ADJ FIB is not used. + */ + fei = fib_table_entry_path_add(0, + &pfx_200_0_0_0_s_24, + FIB_SOURCE_API, + FIB_ENTRY_FLAG_NONE, + FIB_PROTOCOL_IP4, + &nh_10_10_10_1, + ~0, // recursive + 0, // default fib index + 1, + NULL, + FIB_ROUTE_PATH_FLAG_NONE); + + FIB_TEST(fib_test_validate_entry(fei, + FIB_FORW_CHAIN_TYPE_UNICAST_IP4, + 1, + &lb_o_10_10_10_1), + "Recursive %U only UP BFD adj-fibs", + format_fib_prefix, &pfx_200_0_0_0_s_24); + + /* + * Send a BFD state change to UP - both sessions are now up + * the recursive prefix should LB over both + */ + bfd_10_10_10_2.local_state = BFD_STATE_up; + fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2); + + + FIB_TEST(fib_test_validate_entry(fei, + FIB_FORW_CHAIN_TYPE_UNICAST_IP4, + 2, + &lb_o_10_10_10_1, + &lb_o_10_10_10_2), + "Recursive %U via both UP BFD adj-fibs", + format_fib_prefix, &pfx_200_0_0_0_s_24); + + /* + * Send a BFD state change to DOWN + * the recursive prefix should exclude the down + */ + bfd_10_10_10_2.local_state = BFD_STATE_down; + fib_bfd_notify (BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_2); + + + FIB_TEST(fib_test_validate_entry(fei, + FIB_FORW_CHAIN_TYPE_UNICAST_IP4, + 1, + &lb_o_10_10_10_1), + "Recursive %U via only UP", + format_fib_prefix, &pfx_200_0_0_0_s_24); + + /* + * Delete the BFD session while it is in the DOWN state. + * FIB should consider the entry's state as back up + */ + fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_2); + + FIB_TEST(fib_test_validate_entry(fei, + FIB_FORW_CHAIN_TYPE_UNICAST_IP4, + 2, + &lb_o_10_10_10_1, + &lb_o_10_10_10_2), + "Recursive %U via both UP BFD adj-fibs post down session delete", + format_fib_prefix, &pfx_200_0_0_0_s_24); + + /* + * Delete the BFD other session while it is in the UP state. + */ + fib_bfd_notify (BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1); + + FIB_TEST(fib_test_validate_entry(fei, + FIB_FORW_CHAIN_TYPE_UNICAST_IP4, + 2, + &lb_o_10_10_10_1, + &lb_o_10_10_10_2), + "Recursive %U via both UP BFD adj-fibs post up session delete", + format_fib_prefix, &pfx_200_0_0_0_s_24); + + /* + * cleaup + */ + fib_table_entry_delete(0, &pfx_200_0_0_0_s_24, FIB_SOURCE_API); + fib_table_entry_delete(0, &pfx_10_10_10_1_s_32, FIB_SOURCE_ADJ); + fib_table_entry_delete(0, &pfx_10_10_10_2_s_32, FIB_SOURCE_ADJ); + + fib_table_entry_delete(0, &pfx_10_10_10_10_s_32, FIB_SOURCE_INTERFACE); + fib_table_entry_delete(0, &pfx_10_10_10_10_s_24, FIB_SOURCE_INTERFACE); + + adj_unlock(ai_10_10_10_1); + /* + * test no-one left behind + */ + FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone"); + FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed"); + + /* + * Single-hop BFD tests + */ + bfd_10_10_10_1.hop_type = BFD_HOP_TYPE_SINGLE; + bfd_10_10_10_1.udp.key.sw_if_index = tm->hw[0]->sw_if_index; + + adj_bfd_notify(BFD_LISTEN_EVENT_CREATE, &bfd_10_10_10_1); + + ai_10_10_10_1 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, + VNET_LINK_IP4, + &nh_10_10_10_1, + tm->hw[0]->sw_if_index); + /* + * whilst the BFD session is not signalled, the adj is up + */ + FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on uninit session"); + + /* + * bring the BFD session up + */ + bfd_10_10_10_1.local_state = BFD_STATE_up; + adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1); + FIB_TEST(adj_is_up(ai_10_10_10_1), "Adj state up on UP session"); + + /* + * bring the BFD session down + */ + bfd_10_10_10_1.local_state = BFD_STATE_down; + adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1); + FIB_TEST(!adj_is_up(ai_10_10_10_1), "Adj state down on DOWN session"); + + + /* + * add an attached next hop FIB entry via the down adj + */ + fib_prefix_t pfx_5_5_5_5_s_32 = { + .fp_addr = { + .ip4 = { + .as_u32 = clib_host_to_net_u32(0x05050505), + }, + }, + .fp_len = 32, + .fp_proto = FIB_PROTOCOL_IP4, + }; + + fei = fib_table_entry_path_add(0, + &pfx_5_5_5_5_s_32, + FIB_SOURCE_CLI, + FIB_ENTRY_FLAG_NONE, + FIB_PROTOCOL_IP4, + &nh_10_10_10_1, + tm->hw[0]->sw_if_index, + ~0, // invalid fib index + 1, + NULL, + FIB_ROUTE_PATH_FLAG_NONE); + FIB_TEST(load_balance_is_drop(fib_entry_contribute_ip_forwarding(fei)), + "%U resolves via drop", + format_fib_prefix, &pfx_5_5_5_5_s_32); + + /* + * Add a path via an ADJ that is up + */ + adj_index_t ai_10_10_10_2 = adj_nbr_add_or_lock(FIB_PROTOCOL_IP4, + VNET_LINK_IP4, + &nh_10_10_10_2, + tm->hw[0]->sw_if_index); + + fib_test_lb_bucket_t adj_o_10_10_10_2 = { + .type = FT_LB_ADJ, + .adj = { + .adj = ai_10_10_10_2, + }, + }; + adj_o_10_10_10_1.adj.adj = ai_10_10_10_1; + + fei = fib_table_entry_path_add(0, + &pfx_5_5_5_5_s_32, + FIB_SOURCE_CLI, + FIB_ENTRY_FLAG_NONE, + FIB_PROTOCOL_IP4, + &nh_10_10_10_2, + tm->hw[0]->sw_if_index, + ~0, // invalid fib index + 1, + NULL, + FIB_ROUTE_PATH_FLAG_NONE); + + FIB_TEST(fib_test_validate_entry(fei, + FIB_FORW_CHAIN_TYPE_UNICAST_IP4, + 1, + &adj_o_10_10_10_2), + "BFD sourced %U via %U", + format_fib_prefix, &pfx_5_5_5_5_s_32, + format_ip_adjacency, ai_10_10_10_2, FORMAT_IP_ADJACENCY_NONE); + + /* + * Bring up the down session - should now LB + */ + bfd_10_10_10_1.local_state = BFD_STATE_up; + adj_bfd_notify(BFD_LISTEN_EVENT_UPDATE, &bfd_10_10_10_1); + FIB_TEST(fib_test_validate_entry(fei, + FIB_FORW_CHAIN_TYPE_UNICAST_IP4, + 2, + &adj_o_10_10_10_1, + &adj_o_10_10_10_2), + "BFD sourced %U via noth adjs", + format_fib_prefix, &pfx_5_5_5_5_s_32); + + /* + * remove the BFD session state from the adj + */ + adj_bfd_notify(BFD_LISTEN_EVENT_DELETE, &bfd_10_10_10_1); + + /* + * clean-up + */ + fib_table_entry_delete(0, &pfx_5_5_5_5_s_32, FIB_SOURCE_CLI); + adj_unlock(ai_10_10_10_1); + adj_unlock(ai_10_10_10_2); + + /* + * test no-one left behind + */ + FIB_TEST((n_feis == fib_entry_pool_size()), "Entries gone"); + FIB_TEST(0 == adj_nbr_db_size(), "All adjacencies removed"); + return (0); +} + static int lfib_test (void) { @@ -7119,6 +7631,11 @@ fib_test (vlib_main_t * vm, res = 0; fib_test_mk_intf(4); + if (unformat (input, "debug")) + { + fib_test_do_debug = 1; + } + if (unformat (input, "ip")) { res += fib_test_v4(); @@ -7140,6 +7657,10 @@ fib_test (vlib_main_t * vm, { res += fib_test_walk(); } + else if (unformat (input, "bfd")) + { + res += fib_test_bfd(); + } else { /* @@ -7151,6 +7672,7 @@ fib_test (vlib_main_t * vm, res += fib_test_v4(); res += fib_test_v6(); res += fib_test_ae(); + res += fib_test_bfd(); res += fib_test_label(); res += lfib_test(); } diff --git a/src/vnet/fib/ip4_fib.c b/src/vnet/fib/ip4_fib.c index 98d4e52fa07..b03186e82d0 100644 --- a/src/vnet/fib/ip4_fib.c +++ b/src/vnet/fib/ip4_fib.c @@ -477,12 +477,15 @@ static void ip4_fib_table_show_one (ip4_fib_t *fib, vlib_main_t * vm, ip4_address_t *address, - u32 mask_len) + u32 mask_len, + int detail) { vlib_cli_output(vm, "%U", format_fib_entry, ip4_fib_table_lookup(fib, address, mask_len), - FIB_ENTRY_FORMAT_DETAIL); + (detail ? + FIB_ENTRY_FORMAT_DETAIL2 : + FIB_ENTRY_FORMAT_DETAIL)); } static clib_error_t * @@ -496,6 +499,7 @@ ip4_show_fib (vlib_main_t * vm, ip4_address_t matching_address; u32 matching_mask = 32; int i, table_id = -1, fib_index = ~0; + int detail = 0; verbose = 1; matching = 0; @@ -506,6 +510,9 @@ ip4_show_fib (vlib_main_t * vm, || unformat (input, "sum")) verbose = 0; + else if (unformat (input, "detail") || unformat (input, "det")) + detail = 1; + else if (unformat (input, "mtrie")) mtrie = 1; @@ -563,7 +570,8 @@ ip4_show_fib (vlib_main_t * vm, } else { - ip4_fib_table_show_one(fib, vm, &matching_address, matching_mask); + ip4_fib_table_show_one(fib, vm, &matching_address, + matching_mask, detail); } })); @@ -717,7 +725,7 @@ ip4_show_fib (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (ip4_show_fib_command, static) = { .path = "show ip fib", - .short_help = "show ip fib [summary] [table ] [index ] [[/]] [mtrie]", + .short_help = "show ip fib [summary] [table ] [index ] [[/]] [mtrie] [detail]", .function = ip4_show_fib, }; /* *INDENT-ON* */ diff --git a/src/vnet/fib/ip6_fib.c b/src/vnet/fib/ip6_fib.c index 0ee029d3116..002971400fe 100644 --- a/src/vnet/fib/ip6_fib.c +++ b/src/vnet/fib/ip6_fib.c @@ -560,12 +560,15 @@ static void ip6_fib_table_show_one (ip6_fib_t *fib, vlib_main_t * vm, ip6_address_t *address, - u32 mask_len) + u32 mask_len, + int detail) { vlib_cli_output(vm, "%U", format_fib_entry, ip6_fib_table_lookup(fib->index, address, mask_len), - FIB_ENTRY_FORMAT_DETAIL); + (detail ? + FIB_ENTRY_FORMAT_DETAIL2: + FIB_ENTRY_FORMAT_DETAIL)); } typedef struct { @@ -573,8 +576,9 @@ typedef struct { u64 count_by_prefix_length[129]; } count_routes_in_fib_at_prefix_length_arg_t; -static void count_routes_in_fib_at_prefix_length -(BVT(clib_bihash_kv) * kvp, void *arg) +static void +count_routes_in_fib_at_prefix_length (BVT(clib_bihash_kv) * kvp, + void *arg) { count_routes_in_fib_at_prefix_length_arg_t * ap = arg; int mask_width; @@ -600,6 +604,7 @@ ip6_show_fib (vlib_main_t * vm, ip6_address_t matching_address; u32 mask_len = 128; int table_id = -1, fib_index = ~0; + int detail = 0; verbose = 1; matching = 0; @@ -610,6 +615,10 @@ ip6_show_fib (vlib_main_t * vm, unformat (input, "summary") || unformat (input, "sum")) verbose = 0; + + else if (unformat (input, "detail") || + unformat (input, "det")) + detail = 1; else if (unformat (input, "%U/%d", unformat_ip6_address, &matching_address, &mask_len)) @@ -667,7 +676,7 @@ ip6_show_fib (vlib_main_t * vm, } else { - ip6_fib_table_show_one(fib, vm, &matching_address, mask_len); + ip6_fib_table_show_one(fib, vm, &matching_address, mask_len, detail); } })); @@ -771,7 +780,7 @@ ip6_show_fib (vlib_main_t * vm, /* *INDENT-OFF* */ VLIB_CLI_COMMAND (ip6_show_fib_command, static) = { .path = "show ip6 fib", - .short_help = "show ip6 fib [summary] [table ] [index ] [[/]]", + .short_help = "show ip6 fib [summary] [table ] [index ] [[/]] [detail]", .function = ip6_show_fib, }; /* *INDENT-ON* */ -- cgit 1.2.3-korg