diff options
63 files changed, 633 insertions, 775 deletions
diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c index f391c13847..aada6e555f 100644 --- a/bgpd/bgp_addpath.c +++ b/bgpd/bgp_addpath.c @@ -361,8 +361,7 @@ void bgp_addpath_type_changed(struct bgp *bgp) } } -int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, - uint8_t paths) +int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, uint16_t paths) { int action = CAPABILITY_ACTION_UNSET; @@ -392,8 +391,7 @@ int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, * change take effect. */ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, - enum bgp_addpath_strat addpath_type, - uint8_t paths) + enum bgp_addpath_strat addpath_type, uint16_t paths) { struct bgp *bgp = peer->bgp; enum bgp_addpath_strat old_type; diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h index c267ebe43e..f1ff98ea7a 100644 --- a/bgpd/bgp_addpath.h +++ b/bgpd/bgp_addpath.h @@ -62,13 +62,11 @@ bool bgp_addpath_tx_path(enum bgp_addpath_strat strat, * Change the type of addpath used for a peer. */ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi, - enum bgp_addpath_strat addpath_type, - uint8_t paths); + enum bgp_addpath_strat addpath_type, uint16_t paths); void bgp_addpath_update_ids(struct bgp *bgp, struct bgp_dest *dest, afi_t afi, safi_t safi); void bgp_addpath_type_changed(struct bgp *bgp); -extern int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, - uint8_t paths); +extern int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, uint16_t paths); #endif diff --git a/bgpd/bgp_nexthop.h b/bgpd/bgp_nexthop.h index 0280960da8..5014eb8f34 100644 --- a/bgpd/bgp_nexthop.h +++ b/bgpd/bgp_nexthop.h @@ -38,7 +38,7 @@ struct bgp_nexthop_cache { uint32_t metric; /* Nexthop number and nexthop linked list.*/ - uint8_t nexthop_num; + uint16_t nexthop_num; /* This flag is set to TRUE for a bnc that is gateway IP overlay index * nexthop. diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 8719af56b3..59566ee6d6 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -347,12 +347,11 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop, &p.u.prefix6)) ifindex = pi->peer->connection->su.sin6.sin6_scope_id; - if (!is_bgp_static_route && orig_prefix - && prefix_same(&p, orig_prefix)) { + if (!is_bgp_static_route && orig_prefix && prefix_same(&p, orig_prefix) && + CHECK_FLAG(bgp_route->flags, BGP_FLAG_IMPORT_CHECK)) { if (BGP_DEBUG(nht, NHT)) { - zlog_debug( - "%s(%pFX): prefix loops through itself", - __func__, &p); + zlog_debug("%s(%pFX): prefix loops through itself (import-check enabled)", + __func__, &p); } return 0; } @@ -761,7 +760,7 @@ static void bgp_nht_ifp_table_handle(struct bgp *bgp, { struct bgp_nexthop_cache *bnc; struct nexthop *nhop; - uint8_t other_nh_count; + uint16_t other_nh_count; bool nhop_ll_found = false; bool nhop_found = false; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 8dbb4e3b04..475b709a07 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -14506,7 +14506,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, struct bgp_adj_out *adj = NULL; struct bgp_dest *dest; struct bgp *bgp; - struct attr attr; + struct attr attr, attr_unchanged; int ret; struct update_subgroup *subgrp; struct peer_af *paf = NULL; @@ -14686,6 +14686,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, } attr = *ain->attr; + attr_unchanged = *ain->attr; route_filtered = false; /* Filter prefix using distribute list, @@ -14741,9 +14742,8 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, json_ar, json_net, "%pFX", rn_p); } else - route_vty_out_tmp(vty, bgp, dest, rn_p, - &attr, safi, use_json, - json_ar, wide); + route_vty_out_tmp(vty, bgp, dest, rn_p, &attr_unchanged, + safi, use_json, json_ar, wide); bgp_attr_flush(&attr); (*output_count)++; } diff --git a/configure.ac b/configure.ac index e1aa05b869..e8036fcff1 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ([2.69]) -AC_INIT([frr], [10.2-dev], [https://github.com/frrouting/frr/issues]) +AC_INIT([frr], [10.3-dev], [https://github.com/frrouting/frr/issues]) PACKAGE_URL="https://frrouting.org/" AC_SUBST([PACKAGE_URL]) PACKAGE_FULLNAME="FRRouting" diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index 887f27eec5..e0b3a4dca1 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -1064,7 +1064,7 @@ static void lfa_calc_reach_nodes(struct isis_spftree *spftree, for (ALL_QUEUE_ELEMENTS_RO(&spftree->paths, node, vertex)) { char buf[VID2STR_BUFFER]; - if (!VTYPE_IS(vertex->type)) + if (vertex->type != VTYPE_NONPSEUDO_IS && vertex->type != VTYPE_NONPSEUDO_TE_IS) continue; /* Skip root node. */ diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 7286a692f5..0f0c900ec2 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -4297,14 +4297,6 @@ static int lib_interface_isis_multi_topology_common( switch (event) { case NB_EV_VALIDATE: - circuit = nb_running_get_entry(dnode, NULL, false); - if (circuit && circuit->area && circuit->area->oldmetric) { - snprintf( - errmsg, errmsg_len, - "Multi topology IS-IS can only be used with wide metrics"); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c index abd42f359f..05088d52d1 100644 --- a/lib/grammar_sandbox_main.c +++ b/lib/grammar_sandbox_main.c @@ -40,7 +40,7 @@ int main(int argc, char **argv) vty_init(master, true); lib_cmd_init(); - nb_init(master, NULL, 0, false); + nb_init(master, NULL, 0, false, false); vty_stdio(vty_do_exit); diff --git a/lib/libfrr.c b/lib/libfrr.c index a1982841d3..f2247a48e5 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -820,7 +820,8 @@ struct event_loop *frr_init(void) log_ref_vty_init(); lib_error_init(); - nb_init(master, di->yang_modules, di->n_yang_modules, true); + nb_init(master, di->yang_modules, di->n_yang_modules, true, + (di->flags & FRR_LOAD_YANG_LIBRARY) != 0); if (nb_db_init() != NB_OK) flog_warn(EC_LIB_NB_DATABASE, "%s: failed to initialize northbound database", diff --git a/lib/libfrr.h b/lib/libfrr.h index 7ed7be4d98..df537e2e3b 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -46,6 +46,11 @@ extern "C" { * is responsible for calling frr_vty_serv() itself. */ #define FRR_MANUAL_VTY_START (1 << 7) +/* If FRR_LOAD_YANG_LIBRARY is set then libyang will be told to load and + * implement it's internal ietf-yang-library implementation. This should + * normally only be done from mgmtd. + */ +#define FRR_LOAD_YANG_LIBRARY (1 << 8) PREDECL_DLIST(log_args); struct log_arg { @@ -351,7 +351,6 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_BFD_DEST_REPLAY), DESC_ENTRY(ZEBRA_REDISTRIBUTE_ROUTE_ADD), DESC_ENTRY(ZEBRA_REDISTRIBUTE_ROUTE_DEL), - DESC_ENTRY(ZEBRA_VRF_UNREGISTER), DESC_ENTRY(ZEBRA_VRF_ADD), DESC_ENTRY(ZEBRA_VRF_DELETE), DESC_ENTRY(ZEBRA_VRF_LABEL), diff --git a/lib/northbound.c b/lib/northbound.c index 2dae21341e..a385cc9ece 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -2701,7 +2701,7 @@ void nb_validate_callbacks(void) void nb_init(struct event_loop *tm, const struct frr_yang_module_info *const modules[], - size_t nmodules, bool db_enabled) + size_t nmodules, bool db_enabled, bool load_library) { struct yang_module *loaded[nmodules], **loadedp = loaded; @@ -2717,7 +2717,7 @@ void nb_init(struct event_loop *tm, nb_db_enabled = db_enabled; - yang_init(true, explicit_compile); + yang_init(true, explicit_compile, load_library); /* Load YANG modules and their corresponding northbound callbacks. */ for (size_t i = 0; i < nmodules; i++) { diff --git a/lib/northbound.h b/lib/northbound.h index dd3fbf8f73..97a1d31e57 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -1703,10 +1703,12 @@ void nb_validate_callbacks(void); * * db_enabled * Set this to record the transactions in the transaction log. + * + * load_library + * Set this to have libyang to load/implement the ietf-yang-library. */ -extern void nb_init(struct event_loop *tm, - const struct frr_yang_module_info *const modules[], - size_t nmodules, bool db_enabled); +extern void nb_init(struct event_loop *tm, const struct frr_yang_module_info *const modules[], + size_t nmodules, bool db_enabled, bool load_library); /* * Finish the northbound layer gracefully. Should be called only when the daemon diff --git a/lib/yang.c b/lib/yang.c index 14d5b118c6..b847b8b77b 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -976,7 +976,7 @@ void yang_debugging_set(bool enable) } } -struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile) +struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile, bool load_library) { struct ly_ctx *ctx = NULL; const char *yang_models_path = YANG_MODELS_PATH; @@ -994,7 +994,9 @@ struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile) YANG_MODELS_PATH); } - options = LY_CTX_NO_YANGLIBRARY | LY_CTX_DISABLE_SEARCHDIR_CWD; + options = LY_CTX_DISABLE_SEARCHDIR_CWD; + if (!load_library) + options |= LY_CTX_NO_YANGLIBRARY; if (explicit_compile) options |= LY_CTX_EXPLICIT_COMPILE; err = ly_ctx_new(yang_models_path, options, &ctx); @@ -1007,7 +1009,7 @@ struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile) return ctx; } -void yang_init(bool embedded_modules, bool defer_compile) +void yang_init(bool embedded_modules, bool defer_compile, bool load_library) { /* Initialize libyang global parameters that affect all containers. */ ly_set_log_clb(ly_zlog_cb @@ -1019,7 +1021,7 @@ void yang_init(bool embedded_modules, bool defer_compile) ly_log_options(LY_LOLOG | LY_LOSTORE); /* Initialize libyang container for native models. */ - ly_native_ctx = yang_ctx_new_setup(embedded_modules, defer_compile); + ly_native_ctx = yang_ctx_new_setup(embedded_modules, defer_compile, load_library); if (!ly_native_ctx) { flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); exit(1); diff --git a/lib/yang.h b/lib/yang.h index c4fc78b8ae..52857ecf00 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -607,9 +607,11 @@ extern struct yang_data *yang_data_list_find(const struct list *list, * explicit_compile * True if the caller will later call ly_ctx_compile to compile all loaded * modules at once. + * load_library + * Set this to have libyang to load/implement the ietf-yang-library. */ -extern struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, - bool explicit_compile); +extern struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile, + bool load_library); /* * Enable or disable libyang verbose debugging. @@ -727,8 +729,10 @@ extern const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf, * Specify whether libyang should attempt to look for embedded YANG modules. * defer_compile * Hold off on compiling modules until yang_init_loading_complete is called. + * load_library + * Set this to have libyang to load/implement the ietf-yang-library. */ -extern void yang_init(bool embedded_modules, bool defer_compile); +extern void yang_init(bool embedded_modules, bool defer_compile, bool load_library); /* * Should be called after yang_init and all yang_module_load()s have been done, diff --git a/lib/yang_translator.c b/lib/yang_translator.c index 005f6422f3..b7599e0a71 100644 --- a/lib/yang_translator.c +++ b/lib/yang_translator.c @@ -166,7 +166,7 @@ struct yang_translator *yang_translator_load(const char *path) RB_INSERT(yang_translators, &yang_translators, translator); /* Initialize the translator libyang context. */ - translator->ly_ctx = yang_ctx_new_setup(false, false); + translator->ly_ctx = yang_ctx_new_setup(false, false, false); if (!translator->ly_ctx) { flog_warn(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); goto error; @@ -512,7 +512,7 @@ static unsigned int yang_module_nodes_count(const struct lys_module *module) void yang_translator_init(void) { - ly_translator_ctx = yang_ctx_new_setup(true, false); + ly_translator_ctx = yang_ctx_new_setup(true, false, false); if (!ly_translator_ctx) { flog_err(EC_LIB_LIBYANG, "%s: ly_ctx_new() failed", __func__); exit(1); diff --git a/lib/zclient.h b/lib/zclient.h index 2877b347d8..91c0c9ed6d 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -124,7 +124,6 @@ typedef enum { ZEBRA_BFD_DEST_REPLAY, ZEBRA_REDISTRIBUTE_ROUTE_ADD, ZEBRA_REDISTRIBUTE_ROUTE_DEL, - ZEBRA_VRF_UNREGISTER, ZEBRA_VRF_ADD, ZEBRA_VRF_DELETE, ZEBRA_VRF_LABEL, diff --git a/mgmtd/mgmt.c b/mgmtd/mgmt.c index 02c54b9215..cfadad4829 100644 --- a/mgmtd/mgmt.c +++ b/mgmtd/mgmt.c @@ -57,9 +57,6 @@ void mgmt_init(void) /* Initialize MGMTD Transaction module */ mgmt_txn_init(mm, mm->master); - /* Add yang-library module */ - yang_module_load("ietf-yang-library", NULL); - /* Initialize the MGMTD Frontend Adapter Module */ mgmt_fe_adapter_init(mm->master); diff --git a/mgmtd/mgmt_main.c b/mgmtd/mgmt_main.c index e181d0da5e..1880d94415 100644 --- a/mgmtd/mgmt_main.c +++ b/mgmtd/mgmt_main.c @@ -214,7 +214,7 @@ FRR_DAEMON_INFO(mgmtd, MGMTD, .n_yang_modules = array_size(mgmt_yang_modules), /* avoid libfrr trying to read our config file for us */ - .flags = FRR_MANUAL_VTY_START | FRR_NO_SPLIT_CONFIG, + .flags = FRR_MANUAL_VTY_START | FRR_NO_SPLIT_CONFIG | FRR_LOAD_YANG_LIBRARY, ); /* clang-format on */ diff --git a/pimd/pim_autorp.c b/pimd/pim_autorp.c index 1f4d0c65af..35347a2790 100644 --- a/pimd/pim_autorp.c +++ b/pimd/pim_autorp.c @@ -290,8 +290,8 @@ static bool pim_autorp_add_rp(struct pim_autorp *autorp, pim_addr rpaddr, event_add_timer(router->master, autorp_rp_holdtime, trp, holdtime, &(trp->hold_timer)); if (PIM_DEBUG_AUTORP) - zlog_debug("%s: Started %u second hold timer for RP %pI4", - __func__, holdtime, &rp->addr); + zlog_debug("%s: Started %u second hold timer for RP %pI4", __func__, + holdtime, &trp->addr); } else { /* If hold time is zero, make sure there doesn't exist a hold timer for it already */ event_cancel(&trp->hold_timer); diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 030b933e09..5a161c4f16 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -573,7 +573,7 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, ifindex_t first_ifindex; struct interface *ifp = NULL; uint32_t hash_val = 0, mod_val = 0; - uint8_t nh_iter = 0, found = 0; + uint16_t nh_iter = 0, found = 0; uint32_t i, num_nbrs = 0; struct pim_interface *pim_ifp; @@ -947,7 +947,7 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, struct interface *ifps[router->multipath], *ifp; int first_ifindex; int found = 0; - uint8_t i = 0; + uint16_t i = 0; uint32_t hash_val = 0, mod_val = 0; uint32_t num_nbrs = 0; struct pim_interface *pim_ifp; diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index e74b375dc6..d064f714a5 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -23,7 +23,7 @@ struct pim_nexthop_cache { uint32_t metric; uint32_t distance; /* Nexthop number and nexthop linked list. */ - uint8_t nexthop_num; + uint16_t nexthop_num; struct nexthop *nexthop; int64_t last_update; uint16_t flags; diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index d5faa33ca8..17002464e1 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -1355,7 +1355,7 @@ static void bgp_startup(void) zprivs_init(&bgpd_privs); master = event_master_create(NULL); - nb_init(master, NULL, 0, false); + nb_init(master, NULL, 0, false, false); bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new()); bgp_option_set(BGP_OPT_NO_LISTEN); vrf_init(NULL, NULL, NULL, NULL); diff --git a/tests/helpers/c/main.c b/tests/helpers/c/main.c index 9cb395bb1f..344af82fca 100644 --- a/tests/helpers/c/main.c +++ b/tests/helpers/c/main.c @@ -143,7 +143,7 @@ int main(int argc, char **argv) vty_init(master, false); lib_cmd_init(); debug_init(); - nb_init(master, NULL, 0, false); + nb_init(master, NULL, 0, false, false); /* OSPF vty inits. */ test_vty_init(); diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index 93009a1b84..e5a8f7a513 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -546,7 +546,7 @@ int main(int argc, char **argv) cmd_init(1); cmd_hostname_set("test"); vty_init(master, false); - yang_init(true, false); + yang_init(true, false, false); if (debug) zlog_aux_init("NONE: ", LOG_DEBUG); else diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c index 6401971435..342a91cc79 100644 --- a/tests/lib/cli/common_cli.c +++ b/tests/lib/cli/common_cli.c @@ -77,7 +77,7 @@ int main(int argc, char **argv) for (yangcount = 0; test_yang_modules && test_yang_modules[yangcount]; yangcount++) ; - nb_init(master, test_yang_modules, yangcount, false); + nb_init(master, test_yang_modules, yangcount, false, false); test_init(argc, argv); diff --git a/tests/lib/cli/test_commands.c b/tests/lib/cli/test_commands.c index 0034c2af89..9873383fdc 100644 --- a/tests/lib/cli/test_commands.c +++ b/tests/lib/cli/test_commands.c @@ -197,7 +197,7 @@ static void test_init(void) cmd_init(1); debug_init(); - nb_init(master, NULL, 0, false); + nb_init(master, NULL, 0, false, false); install_node(&bgp_node); install_node(&rip_node); diff --git a/tests/lib/northbound/test_oper_data.c b/tests/lib/northbound/test_oper_data.c index 74a0dfe6cc..fdc9e53ca3 100644 --- a/tests/lib/northbound/test_oper_data.c +++ b/tests/lib/northbound/test_oper_data.c @@ -461,7 +461,7 @@ int main(int argc, char **argv) vty_init(master, false); lib_cmd_init(); debug_init(); - nb_init(master, modules, array_size(modules), false); + nb_init(master, modules, array_size(modules), false, false); install_element(ENABLE_NODE, &test_rpc_cmd); diff --git a/tests/lib/test_grpc.cpp b/tests/lib/test_grpc.cpp index 2f0282704e..379a8688a7 100644 --- a/tests/lib/test_grpc.cpp +++ b/tests/lib/test_grpc.cpp @@ -111,8 +111,7 @@ static void static_startup(void) static_debug_init(); master = event_master_create(NULL); - nb_init(master, staticd_yang_modules, array_size(staticd_yang_modules), - false); + nb_init(master, staticd_yang_modules, array_size(staticd_yang_modules), false, false); static_zebra_init(); vty_init(master, true); diff --git a/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py b/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py index c97fc5f0eb..5662e5935b 100644 --- a/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py +++ b/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py @@ -831,7 +831,6 @@ def test_bgp_with_loopback_interface(request): for bgp_neighbor in topo["routers"][routerN]["bgp"]["address_family"]["ipv4"][ "unicast" ]["neighbor"].keys(): - # Adding ['source_link'] = 'lo' key:value pair topo["routers"][routerN]["bgp"]["address_family"]["ipv4"]["unicast"][ "neighbor" @@ -876,294 +875,6 @@ def test_bgp_with_loopback_interface(request): write_test_footer(tc_name) -def test_bgp_with_loopback_with_same_subnet_p1(request): - """ - Verify routes not installed in zebra when /32 routes received - with loopback BGP session subnet - """ - - tgen = get_topogen() - if BGP_CONVERGENCE is not True: - pytest.skip("skipped because of BGP Convergence failure") - - # test case name - tc_name = request.node.name - write_test_header(tc_name) - - # Creating configuration from JSON - reset_config_on_routers(tgen) - step("Delete BGP seesion created initially") - input_dict_r1 = { - "r1": {"bgp": {"delete": True}}, - "r2": {"bgp": {"delete": True}}, - "r3": {"bgp": {"delete": True}}, - "r4": {"bgp": {"delete": True}}, - } - result = create_router_bgp(tgen, topo, input_dict_r1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - step("Create BGP session over loop address") - topo_modify = deepcopy(topo) - - for routerN in sorted(topo["routers"].keys()): - for addr_type in ADDR_TYPES: - for bgp_neighbor in topo_modify["routers"][routerN]["bgp"][ - "address_family" - ][addr_type]["unicast"]["neighbor"].keys(): - - # Adding ['source_link'] = 'lo' key:value pair - topo_modify["routers"][routerN]["bgp"]["address_family"][addr_type][ - "unicast" - ]["neighbor"][bgp_neighbor]["dest_link"] = { - "lo": {"source_link": "lo", "ebgp_multihop": 2} - } - - result = create_router_bgp(tgen, topo_modify["routers"]) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - step("Disable IPv6 BGP nbr from ipv4 address family") - raw_config = { - "r1": { - "raw_config": [ - "router bgp {}".format(topo["routers"]["r1"]["bgp"]["local_as"]), - "address-family ipv4 unicast", - "no neighbor {} activate".format( - topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0] - ), - "no neighbor {} activate".format( - topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0] - ), - ] - }, - "r2": { - "raw_config": [ - "router bgp {}".format(topo["routers"]["r2"]["bgp"]["local_as"]), - "address-family ipv4 unicast", - "no neighbor {} activate".format( - topo["routers"]["r1"]["links"]["lo"]["ipv6"].split("/")[0] - ), - "no neighbor {} activate".format( - topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0] - ), - ] - }, - "r3": { - "raw_config": [ - "router bgp {}".format(topo["routers"]["r3"]["bgp"]["local_as"]), - "address-family ipv4 unicast", - "no neighbor {} activate".format( - topo["routers"]["r1"]["links"]["lo"]["ipv6"].split("/")[0] - ), - "no neighbor {} activate".format( - topo["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0] - ), - "no neighbor {} activate".format( - topo["routers"]["r4"]["links"]["lo"]["ipv6"].split("/")[0] - ), - ] - }, - "r4": { - "raw_config": [ - "router bgp {}".format(topo["routers"]["r4"]["bgp"]["local_as"]), - "address-family ipv4 unicast", - "no neighbor {} activate".format( - topo["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0] - ), - ] - }, - } - - step("Configure kernel routes") - result = apply_raw_config(tgen, raw_config) - assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) - - r1_ipv4_lo = topo["routers"]["r1"]["links"]["lo"]["ipv4"] - r1_ipv6_lo = topo["routers"]["r1"]["links"]["lo"]["ipv6"] - r2_ipv4_lo = topo["routers"]["r2"]["links"]["lo"]["ipv4"] - r2_ipv6_lo = topo["routers"]["r2"]["links"]["lo"]["ipv6"] - r3_ipv4_lo = topo["routers"]["r3"]["links"]["lo"]["ipv4"] - r3_ipv6_lo = topo["routers"]["r3"]["links"]["lo"]["ipv6"] - r4_ipv4_lo = topo["routers"]["r4"]["links"]["lo"]["ipv4"] - r4_ipv6_lo = topo["routers"]["r4"]["links"]["lo"]["ipv6"] - - r1_r2 = topo["routers"]["r1"]["links"]["r2"]["ipv6"].split("/")[0] - r2_r1 = topo["routers"]["r2"]["links"]["r1"]["ipv6"].split("/")[0] - r1_r3 = topo["routers"]["r1"]["links"]["r3"]["ipv6"].split("/")[0] - r3_r1 = topo["routers"]["r3"]["links"]["r1"]["ipv6"].split("/")[0] - r2_r3 = topo["routers"]["r2"]["links"]["r3"]["ipv6"].split("/")[0] - r3_r2 = topo["routers"]["r3"]["links"]["r2"]["ipv6"].split("/")[0] - r3_r4 = topo["routers"]["r3"]["links"]["r4"]["ipv6"].split("/")[0] - r4_r3 = topo["routers"]["r4"]["links"]["r3"]["ipv6"].split("/")[0] - - r1_r2_ipv4 = topo["routers"]["r1"]["links"]["r2"]["ipv4"].split("/")[0] - r2_r1_ipv4 = topo["routers"]["r2"]["links"]["r1"]["ipv4"].split("/")[0] - r1_r3_ipv4 = topo["routers"]["r1"]["links"]["r3"]["ipv4"].split("/")[0] - r3_r1_ipv4 = topo["routers"]["r3"]["links"]["r1"]["ipv4"].split("/")[0] - r2_r3_ipv4 = topo["routers"]["r2"]["links"]["r3"]["ipv4"].split("/")[0] - r3_r2_ipv4 = topo["routers"]["r3"]["links"]["r2"]["ipv4"].split("/")[0] - r3_r4_ipv4 = topo["routers"]["r3"]["links"]["r4"]["ipv4"].split("/")[0] - r4_r3_ipv4 = topo["routers"]["r4"]["links"]["r3"]["ipv4"].split("/")[0] - - r1_r2_intf = topo["routers"]["r1"]["links"]["r2"]["interface"] - r2_r1_intf = topo["routers"]["r2"]["links"]["r1"]["interface"] - r1_r3_intf = topo["routers"]["r1"]["links"]["r3"]["interface"] - r3_r1_intf = topo["routers"]["r3"]["links"]["r1"]["interface"] - r2_r3_intf = topo["routers"]["r2"]["links"]["r3"]["interface"] - r3_r2_intf = topo["routers"]["r3"]["links"]["r2"]["interface"] - r3_r4_intf = topo["routers"]["r3"]["links"]["r4"]["interface"] - r4_r3_intf = topo["routers"]["r4"]["links"]["r3"]["interface"] - - ipv4_list = [ - ("r1", r1_r2_intf, r2_ipv4_loopback), - ("r1", r1_r3_intf, r3_ipv4_loopback), - ("r2", r2_r1_intf, r1_ipv4_loopback), - ("r2", r2_r3_intf, r3_ipv4_loopback), - ("r3", r3_r1_intf, r1_ipv4_loopback), - ("r3", r3_r2_intf, r2_ipv4_loopback), - ("r3", r3_r4_intf, r4_ipv4_loopback), - ("r4", r4_r3_intf, r3_ipv4_loopback), - ] - - ipv6_list = [ - ("r1", r1_r2_intf, r2_ipv6_loopback, r2_r1), - ("r1", r1_r3_intf, r3_ipv6_loopback, r3_r1), - ("r2", r2_r1_intf, r1_ipv6_loopback, r1_r2), - ("r2", r2_r3_intf, r3_ipv6_loopback, r3_r2), - ("r3", r3_r1_intf, r1_ipv6_loopback, r1_r3), - ("r3", r3_r2_intf, r2_ipv6_loopback, r2_r3), - ("r3", r3_r4_intf, r4_ipv6_loopback, r4_r3), - ("r4", r4_r3_intf, r3_ipv6_loopback, r3_r4), - ] - - for dut, intf, loop_addr in ipv4_list: - result = addKernelRoute(tgen, dut, intf, loop_addr) - assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) - - for dut, intf, loop_addr, next_hop in ipv6_list: - result = addKernelRoute(tgen, dut, intf, loop_addr, next_hop) - assert result is True, "Testcase {}:Failed \n Error: {}".format(tc_name, result) - - step("Configure static routes") - - input_dict = { - "r1": { - "static_routes": [ - {"network": r2_ipv4_loopback, "next_hop": r2_r1_ipv4}, - {"network": r3_ipv4_loopback, "next_hop": r3_r1_ipv4}, - {"network": r2_ipv6_loopback, "next_hop": r2_r1}, - {"network": r3_ipv6_loopback, "next_hop": r3_r1}, - ] - }, - "r2": { - "static_routes": [ - {"network": r1_ipv4_loopback, "next_hop": r1_r2_ipv4}, - {"network": r3_ipv4_loopback, "next_hop": r3_r2_ipv4}, - {"network": r1_ipv6_loopback, "next_hop": r1_r2}, - {"network": r3_ipv6_loopback, "next_hop": r3_r2}, - ] - }, - "r3": { - "static_routes": [ - {"network": r1_ipv4_loopback, "next_hop": r1_r3_ipv4}, - {"network": r2_ipv4_loopback, "next_hop": r2_r3_ipv4}, - {"network": r4_ipv4_loopback, "next_hop": r4_r3_ipv4}, - {"network": r1_ipv6_loopback, "next_hop": r1_r3}, - {"network": r2_ipv6_loopback, "next_hop": r2_r3}, - {"network": r4_ipv6_loopback, "next_hop": r4_r3}, - ] - }, - "r4": { - "static_routes": [ - {"network": r3_ipv4_loopback, "next_hop": r3_r4_ipv4}, - {"network": r3_ipv6_loopback, "next_hop": r3_r4}, - ] - }, - } - result = create_static_routes(tgen, input_dict) - assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - - step("Verify BGP session convergence") - - result = verify_bgp_convergence(tgen, topo_modify) - assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - - step("Configure redistribute connected on R2 and R4") - input_dict_1 = { - "r2": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": {"redistribute": [{"redist_type": "connected"}]} - }, - "ipv6": { - "unicast": {"redistribute": [{"redist_type": "connected"}]} - }, - } - } - }, - "r4": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": {"redistribute": [{"redist_type": "connected"}]} - }, - "ipv6": { - "unicast": {"redistribute": [{"redist_type": "connected"}]} - }, - } - } - }, - } - - result = create_router_bgp(tgen, topo, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) - - step("Verify Ipv4 and Ipv6 network installed in R1 RIB but not in FIB") - input_dict_r1 = { - "r1": { - "static_routes": [ - {"network": "1.0.2.17/32"}, - {"network": "2001:db8:f::2:17/128"}, - ] - } - } - - dut = "r1" - protocol = "bgp" - for addr_type in ADDR_TYPES: - result = verify_fib_routes( - tgen, addr_type, dut, input_dict_r1, expected=False - ) # pylint: disable=E1123 - assert result is not True, ( - "Testcase {} : Failed \n " - "Expected: Routes should not be present in {} FIB \n " - "Found: {}".format(tc_name, dut, result) - ) - - step("Verify Ipv4 and Ipv6 network installed in r3 RIB but not in FIB") - input_dict_r3 = { - "r3": { - "static_routes": [ - {"network": "1.0.4.17/32"}, - {"network": "2001:db8:f::4:17/128"}, - ] - } - } - dut = "r3" - protocol = "bgp" - for addr_type in ADDR_TYPES: - result = verify_fib_routes( - tgen, addr_type, dut, input_dict_r1, expected=False - ) # pylint: disable=E1123 - assert result is not True, ( - "Testcase {} : Failed \n " - "Expected: Routes should not be present in {} FIB \n " - "Found: {}".format(tc_name, dut, result) - ) - - write_test_footer(tc_name) - - if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py index 1506b02e5d..905c3e2b66 100644 --- a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py +++ b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py @@ -546,13 +546,7 @@ def test_verify_default_originate_route_with_non_default_VRF_p1(request): tc_name, result ) - result = verify_rib( - tgen, - addr_type, - "r2", - static_routes_input, - next_hop=DEFAULT_ROUTE_NXT_HOP_R1[addr_type], - ) + result = verify_rib(tgen, addr_type, "r2", static_routes_input) assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result ) diff --git a/tests/topotests/bgp_received_routes_with_soft_inbound/__init__.py b/tests/topotests/bgp_received_routes_with_soft_inbound/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_received_routes_with_soft_inbound/__init__.py diff --git a/tests/topotests/bgp_received_routes_with_soft_inbound/r1/frr.conf b/tests/topotests/bgp_received_routes_with_soft_inbound/r1/frr.conf new file mode 100644 index 0000000000..01dd4f3c5a --- /dev/null +++ b/tests/topotests/bgp_received_routes_with_soft_inbound/r1/frr.conf @@ -0,0 +1,17 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as external + address-family ipv4 unicast + neighbor 192.168.1.2 route-map r2 in + neighbor 192.168.1.2 soft-reconfiguration inbound + exit-address-family +! +route-map r2 permit 10 + set as-path prepend 65000 65000 65000 +exit +! diff --git a/tests/topotests/bgp_received_routes_with_soft_inbound/r2/frr.conf b/tests/topotests/bgp_received_routes_with_soft_inbound/r2/frr.conf new file mode 100644 index 0000000000..86dd8e3389 --- /dev/null +++ b/tests/topotests/bgp_received_routes_with_soft_inbound/r2/frr.conf @@ -0,0 +1,14 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + address-family ipv4 unicast + network 10.0.0.2/32 + exit-address-family +! diff --git a/tests/topotests/bgp_received_routes_with_soft_inbound/test_bgp_received_routes_with_soft_inbound.py b/tests/topotests/bgp_received_routes_with_soft_inbound/test_bgp_received_routes_with_soft_inbound.py new file mode 100644 index 0000000000..0b933add2f --- /dev/null +++ b/tests/topotests/bgp_received_routes_with_soft_inbound/test_bgp_received_routes_with_soft_inbound.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_received_routes_with_soft_inbound(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "10.0.0.2/32": [ + { + "valid": True, + "path": "65000 65000 65000 65002", + "nexthops": [ + { + "ip": "192.168.1.2", + } + ], + } + ] + } + } + + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + def _bgp_check_receveived_routes(): + output = json.loads( + r1.vtysh_cmd( + "show bgp ipv4 unicast neighbors 192.168.1.2 received-routes json" + ) + ) + expected = { + "receivedRoutes": { + "10.0.0.2/32": { + "valid": True, + "path": "65002", + "nextHop": "192.168.1.2", + } + } + } + + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_receveived_routes, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_self_prefix/__init__.py b/tests/topotests/bgp_self_prefix/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_self_prefix/__init__.py diff --git a/tests/topotests/bgp_self_prefix/r1/frr.conf b/tests/topotests/bgp_self_prefix/r1/frr.conf new file mode 100644 index 0000000000..879afb1947 --- /dev/null +++ b/tests/topotests/bgp_self_prefix/r1/frr.conf @@ -0,0 +1,19 @@ +! +int lo + ip address 10.0.0.1/32 +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.0.2 remote-as internal + neighbor 10.0.0.2 update-source lo + neighbor 10.0.0.2 next-hop-self + neighbor 10.0.0.3 remote-as external + neighbor 10.0.0.3 update-source lo + neighbor 10.0.0.3 next-hop-self +! +ip route 10.0.0.2/32 192.168.1.2 +ip route 10.0.0.3/32 192.168.1.3 diff --git a/tests/topotests/bgp_self_prefix/r2/frr.conf b/tests/topotests/bgp_self_prefix/r2/frr.conf new file mode 100644 index 0000000000..eb0db356ea --- /dev/null +++ b/tests/topotests/bgp_self_prefix/r2/frr.conf @@ -0,0 +1,20 @@ +! +int lo + ip address 10.0.0.2/32 +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.0.1 remote-as internal + neighbor 10.0.0.1 timers 1 3 + neighbor 10.0.0.1 timers connect 1 + neighbor 10.0.0.1 update-source lo + neighbor 10.0.0.1 next-hop-self + address-family ipv4 unicast + network 10.0.0.2/32 + exit-address-family +! +ip route 10.0.0.1/32 192.168.1.1 diff --git a/tests/topotests/bgp_self_prefix/r3/frr.conf b/tests/topotests/bgp_self_prefix/r3/frr.conf new file mode 100644 index 0000000000..e2348f4a68 --- /dev/null +++ b/tests/topotests/bgp_self_prefix/r3/frr.conf @@ -0,0 +1,20 @@ +! +int lo + ip address 10.0.0.3/32 +! +int r3-eth0 + ip address 192.168.1.3/24 +! +router bgp 65003 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.0.1 remote-as external + neighbor 10.0.0.1 timers 1 3 + neighbor 10.0.0.1 timers connect 1 + neighbor 10.0.0.1 update-source lo + neighbor 10.0.0.1 next-hop-self + address-family ipv4 unicast + network 10.0.0.3/32 + exit-address-family +! +ip route 10.0.0.1/32 192.168.1.1 diff --git a/tests/topotests/bgp_self_prefix/test_bgp_self_prefix.py b/tests/topotests/bgp_self_prefix/test_bgp_self_prefix.py new file mode 100644 index 0000000000..1045800368 --- /dev/null +++ b/tests/topotests/bgp_self_prefix/test_bgp_self_prefix.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis <donatas@opensourcerouting.org> +# + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2", "r3")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_self_prefix(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r3 = tgen.gears["r3"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "10.0.0.2/32": [ + { + "valid": True, + "path": "", + "nexthops": [ + {"ip": "10.0.0.2", "hostname": "r2", "afi": "ipv4"} + ], + } + ], + "10.0.0.3/32": [ + { + "valid": True, + "path": "65003", + "nexthops": [ + {"ip": "10.0.0.3", "hostname": "r3", "afi": "ipv4"} + ], + } + ], + } + } + + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + def _bgp_check_received_routes(): + output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast json")) + expected = { + "routes": { + "10.0.0.2/32": [ + { + "valid": True, + "bestpath": True, + "nexthops": [ + {"ip": "10.0.0.1", "hostname": "r1", "afi": "ipv4"} + ], + } + ], + } + } + + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_received_routes, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see 10.0.0.2/32" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index cb71112af3..f34c48b890 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -3371,7 +3371,7 @@ def verify_rib( found_hops = [ rib_r["ip"] for rib_r in rib_routes_json[st_rt][0]["nexthops"] - if "ip" in rib_r + if "ip" in rib_r and "active" in rib_r ] # If somehow key "ip" is not found in nexthops JSON diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py index 7941e5c1d2..14dd61b077 100644 --- a/tests/topotests/lib/topogen.py +++ b/tests/topotests/lib/topogen.py @@ -492,7 +492,16 @@ class Topogen(object): "Errors found post shutdown - details follow: {}".format(errors) ) - self.net.stop() + try: + self.net.stop() + + except OSError as error: + # OSError exception is raised when mininet tries to stop switch + # though switch is stopped once but mininet tries to stop same + # switch again, where it ended up with exception + + logger.info(error) + logger.info("Exception ignored: switch is already stopped") def get_exabgp_cmd(self): if not self.exabgp_cmd: diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 53bb6513e2..08a1f1e07e 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -1163,7 +1163,12 @@ def pim_delete_move_lines(lines_to_add, lines_to_del): ctx_keys[0] in pim_disable and ctx_keys[0].startswith("interface") and line - and (line.startswith("ip pim ") or line.startswith("ip multicast ")) + and ( + line.startswith("ip pim ") + or line.startswith("no ip pim ") + or line.startswith("ip multicast ") + or line.startswith("no ip multicast ") + ) ): lines_to_del_to_del.append((ctx_keys, line)) diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c index a879811363..046dc9e99e 100644 --- a/tools/gen_northbound_callbacks.c +++ b/tools/gen_northbound_callbacks.c @@ -448,7 +448,7 @@ int main(int argc, char *argv[]) if (argc != 1) usage(EXIT_FAILURE); - yang_init(false, true); + yang_init(false, true, false); if (search_path) ly_ctx_set_searchdir(ly_native_ctx, search_path); diff --git a/tools/gen_yang_deviations.c b/tools/gen_yang_deviations.c index 251643c69e..c2e7fd91c6 100644 --- a/tools/gen_yang_deviations.c +++ b/tools/gen_yang_deviations.c @@ -52,7 +52,7 @@ int main(int argc, char *argv[]) if (argc != 1) usage(EXIT_FAILURE); - yang_init(false, false); + yang_init(false, false, false); /* Load YANG module. */ module = yang_module_load(argv[0], NULL); diff --git a/vrrpd/vrrp_packet.c b/vrrpd/vrrp_packet.c index 36494c7df8..a2fb2bc321 100644 --- a/vrrpd/vrrp_packet.c +++ b/vrrpd/vrrp_packet.c @@ -234,7 +234,7 @@ ssize_t vrrp_pkt_parse_datagram(int family, int version, bool ipv4_ph, } else if (family == AF_INET6) { struct cmsghdr *c; - for (c = CMSG_FIRSTHDR(m); c != NULL; CMSG_NXTHDR(m, c)) { + for (c = CMSG_FIRSTHDR(m); c != NULL; c = CMSG_NXTHDR(m, c)) { if (c->cmsg_level == IPPROTO_IPV6 && c->cmsg_type == IPV6_HOPLIMIT) break; diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 1d2f9e695f..d594fc2c86 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -1336,7 +1336,7 @@ static void fpm_enqueue_l3vni_table(struct hash_bucket *bucket, void *arg) struct zebra_l3vni *zl3vni = bucket->data; fra->zl3vni = zl3vni; - hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, zl3vni); + hash_iterate(zl3vni->rmac_table, fpm_enqueue_rmac_table, fra); } static void fpm_rmac_send(struct event *t) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 5fb908eb0d..8beae125d2 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1032,212 +1032,6 @@ netlink_put_intf_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx) return netlink_batch_add_msg(bth, ctx, netlink_intf_msg_encoder, false); } -int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) -{ - int len; - struct ifaddrmsg *ifa; - struct rtattr *tb[IFA_MAX + 1]; - struct interface *ifp; - void *addr; - void *broad; - uint8_t flags = 0; - char *label = NULL; - struct zebra_ns *zns; - uint32_t metric = METRIC_MAX; - uint32_t kernel_flags = 0; - - frrtrace(3, frr_zebra, netlink_interface_addr, h, ns_id, startup); - - zns = zebra_ns_lookup(ns_id); - ifa = NLMSG_DATA(h); - - if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) { - flog_warn( - EC_ZEBRA_UNKNOWN_FAMILY, - "Invalid address family: %u received from kernel interface addr change: %s", - ifa->ifa_family, nl_msg_type_to_str(h->nlmsg_type)); - return 0; - } - - if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR) - return 0; - - len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg)); - if (len < 0) { - zlog_err( - "%s: Message received from netlink is of a broken size: %d %zu", - __func__, h->nlmsg_len, - (size_t)NLMSG_LENGTH(sizeof(struct ifaddrmsg))); - return -1; - } - - netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len); - - ifp = if_lookup_by_index_per_ns(zns, ifa->ifa_index); - if (ifp == NULL) { - if (startup) { - /* During startup, failure to lookup the referenced - * interface should not be an error, so we have - * downgraded this condition to warning, and we permit - * the startup interface state retrieval to continue. - */ - flog_warn(EC_LIB_INTERFACE, - "%s: can't find interface by index %d", - __func__, ifa->ifa_index); - return 0; - } else { - flog_err(EC_LIB_INTERFACE, - "%s: can't find interface by index %d", - __func__, ifa->ifa_index); - return -1; - } - } - - /* Flags passed through */ - if (tb[IFA_FLAGS]) - kernel_flags = *(int *)RTA_DATA(tb[IFA_FLAGS]); - else - kernel_flags = ifa->ifa_flags; - - if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */ - { - char buf[BUFSIZ]; - zlog_debug("%s %s %s flags 0x%x:", __func__, - nl_msg_type_to_str(h->nlmsg_type), ifp->name, - kernel_flags); - if (tb[IFA_LOCAL]) - zlog_debug(" IFA_LOCAL %s/%d", - inet_ntop(ifa->ifa_family, - RTA_DATA(tb[IFA_LOCAL]), buf, - BUFSIZ), - ifa->ifa_prefixlen); - if (tb[IFA_ADDRESS]) - zlog_debug(" IFA_ADDRESS %s/%d", - inet_ntop(ifa->ifa_family, - RTA_DATA(tb[IFA_ADDRESS]), buf, - BUFSIZ), - ifa->ifa_prefixlen); - if (tb[IFA_BROADCAST]) - zlog_debug(" IFA_BROADCAST %s/%d", - inet_ntop(ifa->ifa_family, - RTA_DATA(tb[IFA_BROADCAST]), buf, - BUFSIZ), - ifa->ifa_prefixlen); - if (tb[IFA_LABEL] && strcmp(ifp->name, RTA_DATA(tb[IFA_LABEL]))) - zlog_debug(" IFA_LABEL %s", - (char *)RTA_DATA(tb[IFA_LABEL])); - - if (tb[IFA_CACHEINFO]) { - struct ifa_cacheinfo *ci = RTA_DATA(tb[IFA_CACHEINFO]); - zlog_debug(" IFA_CACHEINFO pref %d, valid %d", - ci->ifa_prefered, ci->ifa_valid); - } - } - - /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */ - if (tb[IFA_LOCAL] == NULL) - tb[IFA_LOCAL] = tb[IFA_ADDRESS]; - if (tb[IFA_ADDRESS] == NULL) - tb[IFA_ADDRESS] = tb[IFA_LOCAL]; - - /* local interface address */ - addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL); - - /* is there a peer address? */ - if (tb[IFA_ADDRESS] - && memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), - RTA_PAYLOAD(tb[IFA_ADDRESS]))) { - broad = RTA_DATA(tb[IFA_ADDRESS]); - SET_FLAG(flags, ZEBRA_IFA_PEER); - } else - /* seeking a broadcast address */ - broad = (tb[IFA_BROADCAST] ? RTA_DATA(tb[IFA_BROADCAST]) - : NULL); - - /* addr is primary key, SOL if we don't have one */ - if (addr == NULL) { - zlog_debug("%s: Local Interface Address is NULL for %s", - __func__, ifp->name); - return -1; - } - - /* Flags. */ - if (kernel_flags & IFA_F_SECONDARY) - SET_FLAG(flags, ZEBRA_IFA_SECONDARY); - - /* Label */ - if (tb[IFA_LABEL]) - label = (char *)RTA_DATA(tb[IFA_LABEL]); - - if (label && strcmp(ifp->name, label) == 0) - label = NULL; - - if (tb[IFA_RT_PRIORITY]) - metric = *(uint32_t *)RTA_DATA(tb[IFA_RT_PRIORITY]); - - /* Register interface address to the interface. */ - if (ifa->ifa_family == AF_INET) { - if (ifa->ifa_prefixlen > IPV4_MAX_BITLEN) { - zlog_err( - "Invalid prefix length: %u received from kernel interface addr change: %s", - ifa->ifa_prefixlen, - nl_msg_type_to_str(h->nlmsg_type)); - return -1; - } - - if (h->nlmsg_type == RTM_NEWADDR) - connected_add_ipv4(ifp, flags, (struct in_addr *)addr, - ifa->ifa_prefixlen, - (struct in_addr *)broad, label, - metric); - else if (CHECK_FLAG(flags, ZEBRA_IFA_PEER)) { - /* Delete with a peer address */ - connected_delete_ipv4( - ifp, flags, (struct in_addr *)addr, - ifa->ifa_prefixlen, broad); - } else - connected_delete_ipv4( - ifp, flags, (struct in_addr *)addr, - ifa->ifa_prefixlen, NULL); - } - - if (ifa->ifa_family == AF_INET6) { - if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) { - zlog_err( - "Invalid prefix length: %u received from kernel interface addr change: %s", - ifa->ifa_prefixlen, - nl_msg_type_to_str(h->nlmsg_type)); - return -1; - } - if (h->nlmsg_type == RTM_NEWADDR) { - /* Only consider valid addresses; we'll not get a - * notification from - * the kernel till IPv6 DAD has completed, but at init - * time, Quagga - * does query for and will receive all addresses. - */ - if (!(kernel_flags - & (IFA_F_DADFAILED | IFA_F_TENTATIVE))) - connected_add_ipv6(ifp, flags, - (struct in6_addr *)addr, - (struct in6_addr *)broad, - ifa->ifa_prefixlen, label, - metric); - } else - connected_delete_ipv6(ifp, (struct in6_addr *)addr, - NULL, ifa->ifa_prefixlen); - } - - /* - * Linux kernel does not send route delete on interface down/addr del - * so we have to re-process routes it owns (i.e. kernel routes) - */ - if (h->nlmsg_type != RTM_NEWADDR) - rib_update(RIB_UPDATE_KERNEL); - - return 0; -} - /* * Parse and validate an incoming interface address change message, * generating a dplane context object. diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h index 9b31906a17..dc1f71cb77 100644 --- a/zebra/if_netlink.h +++ b/zebra/if_netlink.h @@ -12,9 +12,6 @@ extern "C" { #endif -extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, - int startup); - /* * Parse an incoming interface address change message, generate a dplane * context object for processing. diff --git a/zebra/rib.h b/zebra/rib.h index 4293b5f240..5fedb07335 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -408,9 +408,6 @@ extern struct route_entry *rib_match_multicast(afi_t afi, vrf_id_t vrf_id, union g_addr *gaddr, struct route_node **rn_out); -extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, - vrf_id_t vrf_id); - extern void rib_update(enum rib_update_event event); extern void rib_update_table(struct route_table *table, enum rib_update_event event, int rtype); @@ -637,6 +634,10 @@ extern pid_t pid; extern uint32_t rt_table_main_id; +void route_entry_dump_nh(const struct route_entry *re, const char *straddr, + const struct vrf *re_vrf, + const struct nexthop *nexthop); + /* Name of hook calls */ #define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results" diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 75e4396e92..dc679ed495 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -591,12 +591,9 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, return nh; } -static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, - struct nexthop_group *ng, - struct rtmsg *rtm, - struct rtnexthop *rtnh, - struct rtattr **tb, - void *prefsrc, vrf_id_t vrf_id) +static uint16_t parse_multipath_nexthops_unicast(ns_id_t ns_id, struct nexthop_group *ng, + struct rtmsg *rtm, struct rtnexthop *rtnh, + struct rtattr **tb, void *prefsrc, vrf_id_t vrf_id) { void *gate = NULL; struct interface *ifp = NULL; @@ -721,7 +718,7 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, rtnh = RTNH_NEXT(rtnh); } - uint8_t nhop_num = nexthop_group_nexthop_num(ng); + uint16_t nhop_num = nexthop_group_nexthop_num(ng); return nhop_num; } @@ -1000,7 +997,7 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, (struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]); if (!nhe_id) { - uint8_t nhop_num; + uint16_t nhop_num; /* Use temporary list of nexthops; parse * message payload's nexthops. @@ -2644,11 +2641,9 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) /* Char length to debug ID with */ #define ID_LENGTH 10 -static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, - uint32_t id, - const struct nh_grp *z_grp, - const uint8_t count, bool resilient, - const struct nhg_resilience *nhgr) +static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, uint32_t id, + const struct nh_grp *z_grp, const uint16_t count, + bool resilient, const struct nhg_resilience *nhgr) { struct nexthop_grp grp[count]; /* Need space for max group size, "/", and null term */ @@ -3285,7 +3280,7 @@ static int netlink_nexthop_process_group(struct rtattr **tb, struct nh_grp *z_grp, int z_grp_size, struct nhg_resilience *nhgr) { - uint8_t count = 0; + uint16_t count = 0; /* linux/nexthop.h group struct */ struct nexthop_grp *n_grp = NULL; @@ -3358,7 +3353,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) struct nexthop nh = {.weight = 1}; struct nh_grp grp[MULTIPATH_NUM] = {}; /* Count of nexthops in group array */ - uint8_t grp_count = 0; + uint16_t grp_count = 0; struct rtattr *tb[NHA_MAX + 1] = {}; frrtrace(3, frr_zebra, netlink_nexthop_change, h, ns_id, startup); diff --git a/zebra/tc_netlink.c b/zebra/tc_netlink.c index 19667e66ac..3c4db0090c 100644 --- a/zebra/tc_netlink.c +++ b/zebra/tc_netlink.c @@ -661,27 +661,6 @@ netlink_put_tc_filter_update_msg(struct nl_batch *bth, } /* - * Request filters from the kernel - */ -static int netlink_request_filters(struct zebra_ns *zns, int family, int type, - ifindex_t ifindex) -{ - struct { - struct nlmsghdr n; - struct tcmsg tc; - } req; - - memset(&req, 0, sizeof(req)); - req.n.nlmsg_type = type; - req.n.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); - req.tc.tcm_family = family; - req.tc.tcm_ifindex = ifindex; - - return netlink_request(&zns->netlink_cmd, &req); -} - -/* * Request queue discipline from the kernel */ static int netlink_request_qdiscs(struct zebra_ns *zns, int family, int type) @@ -852,23 +831,4 @@ int netlink_qdisc_read(struct zebra_ns *zns) return 0; } -int netlink_tfilter_read_for_interface(struct zebra_ns *zns, ifindex_t ifindex) -{ - int ret; - struct zebra_dplane_info dp_info; - - zebra_dplane_info_from_zns(&dp_info, zns, true); - - ret = netlink_request_filters(zns, AF_UNSPEC, RTM_GETTFILTER, ifindex); - if (ret < 0) - return ret; - - ret = netlink_parse_info(netlink_tfilter_change, &zns->netlink_cmd, - &dp_info, 0, true); - if (ret < 0) - return ret; - - return 0; -} - #endif /* HAVE_NETLINK */ diff --git a/zebra/tc_netlink.h b/zebra/tc_netlink.h index 5e95e6c1d8..300c53b6f5 100644 --- a/zebra/tc_netlink.h +++ b/zebra/tc_netlink.h @@ -50,8 +50,6 @@ netlink_put_tc_filter_update_msg(struct nl_batch *bth, */ extern int netlink_qdisc_read(struct zebra_ns *zns); -extern int netlink_tfilter_read_for_interface(struct zebra_ns *zns, - ifindex_t ifindex); extern int netlink_tfilter_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index c45c61a208..7dae75bacc 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -517,7 +517,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, struct zapi_nexthop *api_nh; struct nexthop *nexthop; const struct prefix *p, *src_p; - uint8_t count = 0; + uint16_t count = 0; afi_t afi; size_t stream_size = MAX(ZEBRA_MAX_PACKET_SIZ, sizeof(struct zapi_route)); @@ -2477,22 +2477,6 @@ stream_failure: return; } -/* Unregister all information in a VRF. */ -static void zread_vrf_unregister(ZAPI_HANDLER_ARGS) -{ - int i; - afi_t afi; - - for (afi = AFI_IP; afi < AFI_MAX; afi++) { - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - vrf_bitmap_unset(&client->redist[afi][i], - zvrf_id(zvrf)); - vrf_bitmap_unset(&client->redist_default[afi], zvrf_id(zvrf)); - vrf_bitmap_unset(&client->ridinfo[afi], zvrf_id(zvrf)); - vrf_bitmap_unset(&client->neighinfo[afi], zvrf_id(zvrf)); - } -} - /* * Validate incoming zapi mpls lsp / labels message */ @@ -4055,7 +4039,6 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { #if HAVE_BFDD > 0 [ZEBRA_BFD_DEST_REPLAY] = zebra_ptm_bfd_dst_replay, #endif /* HAVE_BFDD */ - [ZEBRA_VRF_UNREGISTER] = zread_vrf_unregister, [ZEBRA_VRF_LABEL] = zread_vrf_label, [ZEBRA_BFD_CLIENT_REGISTER] = zebra_ptm_bfd_client_register, [ZEBRA_INTERFACE_ENABLE_RADV] = zebra_interface_radv_enable, diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 75147e7136..00e990e856 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -86,7 +86,7 @@ struct dplane_nexthop_info { struct nexthop_group ng; struct nh_grp nh_grp[MULTIPATH_NUM]; - uint8_t nh_grp_count; + uint16_t nh_grp_count; }; /* @@ -2316,7 +2316,7 @@ dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx) return ctx->u.rinfo.nhe.nh_grp; } -uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx) +uint16_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); return ctx->u.rinfo.nhe.nh_grp_count; diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 0e9a8bfb99..a3318bf5e9 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -597,7 +597,7 @@ const struct nexthop_group * dplane_ctx_get_nhe_ng(const struct zebra_dplane_ctx *ctx); const struct nh_grp * dplane_ctx_get_nhe_nh_grp(const struct zebra_dplane_ctx *ctx); -uint8_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx); +uint16_t dplane_ctx_get_nhe_nh_grp_count(const struct zebra_dplane_ctx *ctx); /* Accessors for LSP information */ diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 4ee9dc5fcf..1519246c17 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -625,9 +625,8 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2) return nhe1->id == nhe2->id; } -static int zebra_nhg_process_grp(struct nexthop_group *nhg, - struct nhg_connected_tree_head *depends, - struct nh_grp *grp, uint8_t count, +static int zebra_nhg_process_grp(struct nexthop_group *nhg, struct nhg_connected_tree_head *depends, + struct nh_grp *grp, uint16_t count, struct nhg_resilience *resilience) { nhg_connected_tree_init(depends); @@ -982,7 +981,7 @@ static struct nexthop *nhg_ctx_get_nh(struct nhg_ctx *ctx) return &ctx->u.nh; } -static uint8_t nhg_ctx_get_count(const struct nhg_ctx *ctx) +static uint16_t nhg_ctx_get_count(const struct nhg_ctx *ctx) { return ctx->count; } @@ -1028,9 +1027,8 @@ done: XFREE(MTYPE_NHG_CTX, *ctx); } -static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, - struct nh_grp *grp, vrf_id_t vrf_id, - afi_t afi, int type, uint8_t count, +static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh, struct nh_grp *grp, + vrf_id_t vrf_id, afi_t afi, int type, uint16_t count, struct nhg_resilience *resilience) { struct nhg_ctx *ctx = NULL; @@ -1101,11 +1099,15 @@ void zebra_nhg_check_valid(struct nhg_hash_entry *nhe) bool valid = false; /* - * If I have other nhe's depending on me, then this is a + * If I have other nhe's depending on me, or I have nothing + * I am depending on then this is a * singleton nhe so set this nexthops flag as appropriate. */ - if (nhg_connected_tree_count(&nhe->nhg_depends)) + if (nhg_connected_tree_count(&nhe->nhg_depends) || + nhg_connected_tree_count(&nhe->nhg_dependents) == 0) { + UNSET_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_FIB); UNSET_FLAG(nhe->nhg.nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } /* If anthing else in the group is valid, the group is valid */ frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { @@ -1200,7 +1202,7 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx) struct nhg_hash_entry *nhe = NULL; uint32_t id = nhg_ctx_get_id(ctx); - uint8_t count = nhg_ctx_get_count(ctx); + uint16_t count = nhg_ctx_get_count(ctx); vrf_id_t vrf_id = nhg_ctx_get_vrf_id(ctx); int type = nhg_ctx_get_type(ctx); afi_t afi = nhg_ctx_get_afi(ctx); @@ -1352,9 +1354,9 @@ int nhg_ctx_process(struct nhg_ctx *ctx) } /* Kernel-side, you either get a single new nexthop or a array of ID's */ -int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, - uint8_t count, vrf_id_t vrf_id, afi_t afi, int type, - int startup, struct nhg_resilience *nhgr) +int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, uint16_t count, + vrf_id_t vrf_id, afi_t afi, int type, int startup, + struct nhg_resilience *nhgr) { struct nhg_ctx *ctx = NULL; @@ -2922,13 +2924,162 @@ static uint32_t proto_nhg_nexthop_active_update(struct nexthop_group *nhg) } /* + * This function takes the start of two comparable nexthops from two different + * nexthop groups and walks them to see if they can be considered the same + * or not. This is being used to determine if zebra should reuse a nhg + * from the old_re to the new_re, when an interface goes down and the + * new nhg sent down from the upper level protocol would resolve to it + */ +static bool zebra_nhg_nexthop_compare(const struct nexthop *nhop, + const struct nexthop *old_nhop, + const struct route_node *rn) +{ + bool same = true; + + while (nhop && old_nhop) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: %pRN Comparing %pNHvv(%u) to old: %pNHvv(%u)", + __func__, rn, nhop, nhop->flags, old_nhop, + old_nhop->flags); + if (!CHECK_FLAG(old_nhop->flags, NEXTHOP_FLAG_ACTIVE)) { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: %pRN Old is not active going to the next one", + __func__, rn); + old_nhop = old_nhop->next; + continue; + } + + if (nexthop_same(nhop, old_nhop)) { + struct nexthop *new_recursive, *old_recursive; + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s: %pRN New and old are same, continuing search", + __func__, rn); + + new_recursive = nhop->resolved; + old_recursive = old_nhop->resolved; + + while (new_recursive && old_recursive) { + if (!nexthop_same(new_recursive, old_recursive)) { + same = false; + break; + } + + new_recursive = new_recursive->next; + old_recursive = old_recursive->next; + } + + if (new_recursive) + same = false; + else if (old_recursive) { + while (old_recursive) { + if (CHECK_FLAG(old_recursive->flags, + NEXTHOP_FLAG_ACTIVE)) + break; + old_recursive = old_recursive->next; + } + + if (old_recursive) + same = false; + } + + if (!same) + break; + + nhop = nhop->next; + old_nhop = old_nhop->next; + continue; + } else { + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s:%pRN They are not the same, stopping using new nexthop entry", + __func__, rn); + same = false; + break; + } + } + + if (nhop) + same = false; + else if (old_nhop) { + while (old_nhop) { + if (CHECK_FLAG(old_nhop->flags, NEXTHOP_FLAG_ACTIVE)) + break; + old_nhop = old_nhop->next; + } + + if (old_nhop) + same = false; + } + + return same; +} + +static struct nhg_hash_entry *zebra_nhg_rib_compare_old_nhe( + const struct route_node *rn, const struct route_entry *re, + struct nhg_hash_entry *new_nhe, struct nhg_hash_entry *old_nhe) +{ + struct nexthop *nhop, *old_nhop; + bool same = true; + struct vrf *vrf = vrf_lookup_by_id(re->vrf_id); + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) { + char straddr[PREFIX_STRLEN]; + + prefix2str(&rn->p, straddr, sizeof(straddr)); + zlog_debug("%s: %pRN new id: %u old id: %u", __func__, rn, + new_nhe->id, old_nhe->id); + zlog_debug("%s: %pRN NEW", __func__, rn); + for (ALL_NEXTHOPS(new_nhe->nhg, nhop)) + route_entry_dump_nh(re, straddr, vrf, nhop); + + zlog_debug("%s: %pRN OLD", __func__, rn); + for (ALL_NEXTHOPS(old_nhe->nhg, nhop)) + route_entry_dump_nh(re, straddr, vrf, nhop); + } + + nhop = new_nhe->nhg.nexthop; + old_nhop = old_nhe->nhg.nexthop; + + same = zebra_nhg_nexthop_compare(nhop, old_nhop, rn); + + if (same) { + struct nexthop_group *bnhg, *old_bnhg; + + bnhg = zebra_nhg_get_backup_nhg(new_nhe); + old_bnhg = zebra_nhg_get_backup_nhg(old_nhe); + + if (bnhg || old_bnhg) { + if (bnhg && !old_bnhg) + same = false; + else if (!bnhg && old_bnhg) + same = false; + else + same = zebra_nhg_nexthop_compare(bnhg->nexthop, + old_bnhg->nexthop, + rn); + } + } + + if (IS_ZEBRA_DEBUG_NHG_DETAIL) + zlog_debug("%s:%pRN They are %sthe same, using the %s nhg entry", + __func__, rn, same ? "" : "not ", + same ? "old" : "new"); + + if (same) + return old_nhe; + else + return new_nhe; +} + +/* * Iterate over all nexthops of the given RIB entry and refresh their * ACTIVE flag. If any nexthop is found to toggle the ACTIVE flag, * the whole re structure is flagged with ROUTE_ENTRY_CHANGED. * * Return value is the new number of active nexthops. */ -int nexthop_active_update(struct route_node *rn, struct route_entry *re) +int nexthop_active_update(struct route_node *rn, struct route_entry *re, + struct route_entry *old_re) { struct nhg_hash_entry *curr_nhe; uint32_t curr_active = 0, backup_active = 0; @@ -2984,6 +3135,11 @@ backups_done: new_nhe = zebra_nhg_rib_find_nhe(curr_nhe, rt_afi); + if (old_re && old_re->type == re->type && + old_re->instance == re->instance) + new_nhe = zebra_nhg_rib_compare_old_nhe(rn, re, new_nhe, + old_re->nhe); + if (IS_ZEBRA_DEBUG_NHG_DETAIL) zlog_debug( "%s: re %p CHANGED: nhe %p (%pNG) => new_nhe %p (%pNG)", @@ -3022,15 +3178,14 @@ backups_done: * I'm pretty sure we only allow ONE level of group within group currently. * But making this recursive just in case that ever changes. */ -static uint8_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp, uint8_t curr_index, - struct nhg_hash_entry *nhe, - struct nhg_hash_entry *original, - int max_num) +static uint16_t zebra_nhg_nhe2grp_internal(struct nh_grp *grp, uint16_t curr_index, + struct nhg_hash_entry *nhe, + struct nhg_hash_entry *original, int max_num) { struct nhg_connected *rb_node_dep = NULL; struct nhg_hash_entry *depend = NULL; struct nexthop *nexthop; - uint8_t i = curr_index; + uint16_t i = curr_index; frr_each(nhg_connected_tree, &nhe->nhg_depends, rb_node_dep) { bool duplicate = false; @@ -3151,8 +3306,7 @@ done: } /* Convert a nhe into a group array */ -uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, - int max_num) +uint16_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, int max_num) { /* Call into the recursive function */ return zebra_nhg_nhe2grp_internal(grp, 0, nhe, nhe, max_num); @@ -3779,6 +3933,17 @@ void zebra_interface_nhg_reinstall(struct interface *ifp) frr_each_safe (nhg_connected_tree, &rb_node_dep->nhe->nhg_dependents, rb_node_dependent) { + struct nexthop *nhop_dependent = + rb_node_dependent->nhe->nhg.nexthop; + + while (nhop_dependent && + !nexthop_same(nhop_dependent, nh)) + nhop_dependent = nhop_dependent->next; + + if (nhop_dependent) + SET_FLAG(nhop_dependent->flags, + NEXTHOP_FLAG_ACTIVE); + if (IS_ZEBRA_DEBUG_NHG) zlog_debug("%s dependent nhe %pNG Setting Reinstall flag", __func__, diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 712c1057a1..0f90627a0d 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -231,7 +231,7 @@ struct nhg_ctx { int type; /* If its a group array, how many? */ - uint8_t count; + uint16_t count; /* Its either a single nexthop or an array of ID's */ union { @@ -317,10 +317,8 @@ extern int nhg_ctx_process(struct nhg_ctx *ctx); void nhg_ctx_free(struct nhg_ctx **ctx); /* Find via kernel nh creation */ -extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, - struct nh_grp *grp, uint8_t count, - vrf_id_t vrf_id, afi_t afi, int type, - int startup, +extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp, + uint16_t count, vrf_id_t vrf_id, afi_t afi, int type, int startup, struct nhg_resilience *resilience); /* Del via kernel */ extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id); @@ -379,8 +377,7 @@ extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe); extern void zebra_nhg_check_valid(struct nhg_hash_entry *nhe); /* Convert nhe depends to a grp context that can be passed around safely */ -extern uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, - int size); +extern uint16_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, int size); /* Dataplane install/uninstall */ extern void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe, uint8_t type); @@ -404,7 +401,8 @@ extern void zebra_nhg_mark_keep(void); /* Nexthop resolution processing */ struct route_entry; /* Forward ref to avoid circular includes */ -extern int nexthop_active_update(struct route_node *rn, struct route_entry *re); +extern int nexthop_active_update(struct route_node *rn, struct route_entry *re, + struct route_entry *old_re); #ifdef _FRR_ATTRIBUTE_PRINTFRR #pragma FRR printfrr_ext "%pNG" (const struct nhg_hash_entry *) diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index deed3b6ad3..6adc0b1b4a 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -147,7 +147,6 @@ void zebra_pw_update(struct zebra_pw *pw) { if (zebra_pw_check_reachability(pw) < 0) { zebra_pw_uninstall(pw); - zebra_pw_install_failure(pw, PW_NOT_FORWARDING); /* wait for NHT and try again later */ } else { /* @@ -167,12 +166,17 @@ static void zebra_pw_install(struct zebra_pw *pw) hook_call(pw_install, pw); if (dplane_pw_install(pw) == ZEBRA_DPLANE_REQUEST_FAILURE) { + /* + * Realistically this is never going to fail passing + * the pw data down to the dplane. The failure modes + * look like impossible events but we still return + * on them.... but I don't see a real clean way to remove this + * at all. So let's just leave the retry mechanism for + * the moment. + */ zebra_pw_install_failure(pw, PW_NOT_FORWARDING); return; } - - if (pw->status != PW_FORWARDING) - zebra_pw_update_status(pw, PW_FORWARDING); } static void zebra_pw_uninstall(struct zebra_pw *pw) @@ -188,9 +192,30 @@ static void zebra_pw_uninstall(struct zebra_pw *pw) /* ignore any possible error */ hook_call(pw_uninstall, pw); dplane_pw_uninstall(pw); +} + +void zebra_pw_handle_dplane_results(struct zebra_dplane_ctx *ctx) +{ + struct zebra_pw *pw; + struct zebra_vrf *vrf; + enum dplane_op_e op; + + op = dplane_ctx_get_op(ctx); + + vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); + pw = zebra_pw_find(vrf, dplane_ctx_get_ifname(ctx)); + + if (!pw) + return; - if (zebra_pw_enabled(pw)) - zebra_pw_update_status(pw, PW_NOT_FORWARDING); + if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) { + zebra_pw_install_failure(pw, dplane_ctx_get_pw_status(ctx)); + } else { + if (op == DPLANE_OP_PW_INSTALL && pw->status != PW_FORWARDING) + zebra_pw_update_status(pw, PW_FORWARDING); + else if (op == DPLANE_OP_PW_UNINSTALL && zebra_pw_enabled(pw)) + zebra_pw_update_status(pw, PW_NOT_FORWARDING); + } } /* diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h index 431d663f7c..e037a55048 100644 --- a/zebra/zebra_pw.h +++ b/zebra/zebra_pw.h @@ -64,6 +64,7 @@ void zebra_pw_init_vrf(struct zebra_vrf *); void zebra_pw_exit_vrf(struct zebra_vrf *); void zebra_pw_terminate(void); void zebra_pw_vty_init(void); +void zebra_pw_handle_dplane_results(struct zebra_dplane_ctx *ctx); #ifdef __cplusplus } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 402a3104b9..8ebc193fba 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -611,45 +611,6 @@ struct route_entry *rib_match_multicast(afi_t afi, vrf_id_t vrf_id, return re; } -struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p, vrf_id_t vrf_id) -{ - struct route_table *table; - struct route_node *rn; - struct route_entry *match = NULL; - rib_dest_t *dest; - - /* Lookup table. */ - table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, vrf_id); - if (!table) - return 0; - - rn = route_node_lookup(table, (struct prefix *)p); - - /* No route for this prefix. */ - if (!rn) - return NULL; - - /* Unlock node. */ - route_unlock_node(rn); - dest = rib_dest_from_rnode(rn); - - if (dest && dest->selected_fib - && !CHECK_FLAG(dest->selected_fib->status, ROUTE_ENTRY_REMOVED)) - match = dest->selected_fib; - - if (!match) - return NULL; - - if (match->type == ZEBRA_ROUTE_CONNECT || - match->type == ZEBRA_ROUTE_LOCAL) - return match; - - if (CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) - return match; - - return NULL; -} - /* * Is this RIB labeled-unicast? It must be of type BGP and all paths * (nexthops) must have a label. @@ -1313,7 +1274,7 @@ static void rib_process(struct route_node *rn) */ if (CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED)) { proto_re_changed = re; - if (!nexthop_active_update(rn, re)) { + if (!nexthop_active_update(rn, re, old_fib)) { const struct prefix *p; struct rib_table_info *info; @@ -4118,9 +4079,8 @@ void rib_delnode(struct route_node *rn, struct route_entry *re) /* * Helper that debugs a single nexthop within a route-entry */ -static void _route_entry_dump_nh(const struct route_entry *re, - const char *straddr, const struct vrf *re_vrf, - const struct nexthop *nexthop) +void route_entry_dump_nh(const struct route_entry *re, const char *straddr, + const struct vrf *re_vrf, const struct nexthop *nexthop) { char nhname[PREFIX_STRLEN]; char backup_str[50]; @@ -4243,7 +4203,7 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, /* Dump nexthops */ for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) - _route_entry_dump_nh(re, straddr, vrf, nexthop); + route_entry_dump_nh(re, straddr, vrf, nexthop); if (zebra_nhg_get_backup_nhg(re->nhe)) { zlog_debug("%s(%s): backup nexthops:", straddr, @@ -4251,7 +4211,7 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, nhg = zebra_nhg_get_backup_nhg(re->nhe); for (ALL_NEXTHOPS_PTR(nhg, nexthop)) - _route_entry_dump_nh(re, straddr, vrf, nexthop); + route_entry_dump_nh(re, straddr, vrf, nexthop); } zlog_debug("%s(%s): dump complete", straddr, VRF_LOGNAME(vrf)); @@ -4891,29 +4851,6 @@ void rib_close_table(struct route_table *table) } /* - * Handler for async dataplane results after a pseudowire installation - */ -static void handle_pw_result(struct zebra_dplane_ctx *ctx) -{ - struct zebra_pw *pw; - struct zebra_vrf *vrf; - - /* The pseudowire code assumes success - we act on an error - * result for installation attempts here. - */ - if (dplane_ctx_get_op(ctx) != DPLANE_OP_PW_INSTALL) - return; - - if (dplane_ctx_get_status(ctx) != ZEBRA_DPLANE_REQUEST_SUCCESS) { - vrf = zebra_vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); - pw = zebra_pw_find(vrf, dplane_ctx_get_ifname(ctx)); - if (pw) - zebra_pw_install_failure(pw, - dplane_ctx_get_pw_status(ctx)); - } -} - -/* * Handle results from the dataplane system. Dequeue update context * structs, dispatch to appropriate internal handlers. */ @@ -5019,7 +4956,7 @@ static void rib_process_dplane_results(struct event *thread) case DPLANE_OP_PW_INSTALL: case DPLANE_OP_PW_UNINSTALL: - handle_pw_result(ctx); + zebra_pw_handle_dplane_results(ctx); break; case DPLANE_OP_SYS_ROUTE_ADD: diff --git a/zebra/zebra_trace.h b/zebra/zebra_trace.h index 17528c4bf1..6451562466 100644 --- a/zebra/zebra_trace.h +++ b/zebra/zebra_trace.h @@ -70,20 +70,6 @@ TRACEPOINT_EVENT( TRACEPOINT_EVENT( frr_zebra, - netlink_interface_addr, - TP_ARGS( - struct nlmsghdr *, header, - ns_id_t, ns_id, - int, startup), - TP_FIELDS( - ctf_integer_hex(intptr_t, header, header) - ctf_integer(uint32_t, ns_id, ns_id) - ctf_integer(uint32_t, startup, startup) - ) - ) - -TRACEPOINT_EVENT( - frr_zebra, netlink_route_change_read_unicast, TP_ARGS( struct nlmsghdr *, header, |
