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_test.c | 522 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 522 insertions(+) (limited to 'src/vnet/fib/fib_test.c') diff --git a/src/vnet/fib/fib_test.c b/src/vnet/fib/fib_test.c index 92141ddf..3c9b8a38 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(); } -- cgit 1.2.3-korg