summaryrefslogtreecommitdiffstats
path: root/src/vnet/fib
diff options
context:
space:
mode:
authorNeale Ranns <nranns@cisco.com>2017-04-05 08:11:14 -0700
committerDamjan Marion <dmarion.lists@gmail.com>2017-04-06 15:18:44 +0000
commit88fc83eb716bf07f4634de6de5b569f795a56418 (patch)
tree4c8037b62cb6a57209aef4e28ae273d0ba4e40e7 /src/vnet/fib
parent5ee51f8ed616f14f3b32ae8857d383fefa02d861 (diff)
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 <nranns@cisco.com>
Diffstat (limited to 'src/vnet/fib')
-rw-r--r--src/vnet/fib/fib_attached_export.c75
-rw-r--r--src/vnet/fib/fib_attached_export.h4
-rw-r--r--src/vnet/fib/fib_bfd.c197
-rw-r--r--src/vnet/fib/fib_entry.c50
-rw-r--r--src/vnet/fib/fib_entry.h1
-rw-r--r--src/vnet/fib/fib_entry_cover.c45
-rw-r--r--src/vnet/fib/fib_entry_cover.h5
-rw-r--r--src/vnet/fib/fib_entry_delegate.c100
-rw-r--r--src/vnet/fib/fib_entry_delegate.h33
-rw-r--r--src/vnet/fib/fib_path.c52
-rw-r--r--src/vnet/fib/fib_test.c522
-rw-r--r--src/vnet/fib/ip4_fib.c16
-rw-r--r--src/vnet/fib/ip6_fib.c21
13 files changed, 983 insertions, 138 deletions
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 <vnet/bfd/bfd_main.h>
+
+#include <vnet/fib/fib_entry_delegate.h>
+#include <vnet/fib/fib_entry.h>
+#include <vnet/fib/fib_table.h>
+#include <vnet/fib/fib_walk.h>
+
+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 <vnet/fib/fib_entry_delegate.h>
#include <vnet/fib/fib_entry.h>
+#include <vnet/fib/fib_attached_export.h>
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
@@ -43,6 +43,10 @@ typedef enum fib_entry_delegate_type_t_ {
*/
FIB_ENTRY_DELEGATE_COVERED,
/**
+ * BFD session state
+ */
+ FIB_ENTRY_DELEGATE_BFD,
+ /**
* Attached import/export functionality
*/
FIB_ENTRY_DELEGATE_ATTACHED_IMPORT,
@@ -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 <vnet/dpo/drop_dpo.h>
#include <vnet/dpo/receive_dpo.h>
#include <vnet/dpo/ip_null_dpo.h>
+#include <vnet/bfd/bfd_main.h>
#include <vnet/mpls/mpls.h>
@@ -33,6 +34,11 @@
#include <vnet/fib/fib_node_list.h>
#include <vnet/fib/fib_urpf_list.h>
+/*
+ * 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 <table-id>] [index <fib-id>] [<ip4-addr>[/<mask>]] [mtrie]",
+ .short_help = "show ip fib [summary] [table <table-id>] [index <fib-id>] [<ip4-addr>[/<mask>]] [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 <table-id>] [index <fib-id>] [<ip6-addr>[/<width>]]",
+ .short_help = "show ip6 fib [summary] [table <table-id>] [index <fib-id>] [<ip6-addr>[/<width>]] [detail]",
.function = ip6_show_fib,
};
/* *INDENT-ON* */