diff options
61 files changed, 676 insertions, 216 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 1e2698cd92..de77bd5304 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -4312,7 +4312,6 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, * if the peer belongs to us. */ if (bgp_confederation_peers_check(bgp, peer->as)) { - aspath = aspath_dup(attr->aspath); aspath = aspath_add_confed_seq(aspath, peer->local_as); } else { diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 0beef97a04..1e9f9429c5 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -515,11 +515,19 @@ static uint32_t bgp_med_value(struct attr *attr, struct bgp *bgp) void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, char *buf, size_t buf_len) { + struct peer *peer; + + if (pi->sub_type == BGP_ROUTE_IMPORTED && + bgp_get_imported_bpi_ultimate(pi)) + peer = bgp_get_imported_bpi_ultimate(pi)->peer; + else + peer = pi->peer; + if (pi->addpath_rx_id) - snprintf(buf, buf_len, "path %s (addpath rxid %d)", - pi->peer->host, pi->addpath_rx_id); + snprintf(buf, buf_len, "path %s (addpath rxid %d)", peer->host, + pi->addpath_rx_id); else - snprintf(buf, buf_len, "path %s", pi->peer->host); + snprintf(buf, buf_len, "path %s", peer->host); } @@ -581,6 +589,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, bool new_proxy; bool new_origin, exist_origin; struct bgp_path_info *bpi_ultimate; + struct peer *peer_new, *peer_exist; *paths_eq = 0; @@ -1081,9 +1090,21 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } } + if (exist->sub_type == BGP_ROUTE_IMPORTED) { + bpi_ultimate = bgp_get_imported_bpi_ultimate(exist); + peer_exist = bpi_ultimate->peer; + } else + peer_exist = exist->peer; + + if (new->sub_type == BGP_ROUTE_IMPORTED) { + bpi_ultimate = bgp_get_imported_bpi_ultimate(new); + peer_new = bpi_ultimate->peer; + } else + peer_new = new->peer; + /* 7. Peer type check. */ - new_sort = new->peer->sort; - exist_sort = exist->peer->sort; + new_sort = peer_new->sort; + exist_sort = peer_exist->sort; if (new_sort == BGP_PEER_EBGP && (exist_sort == BGP_PEER_IBGP || exist_sort == BGP_PEER_CONFED)) { @@ -1138,8 +1159,8 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, pair (newm, existm) with the cluster list length. Prefer the path with smaller cluster list length. */ if (newm == existm) { - if (peer_sort_lookup(new->peer) == BGP_PEER_IBGP && - peer_sort_lookup(exist->peer) == BGP_PEER_IBGP && + if (peer_sort_lookup(peer_new) == BGP_PEER_IBGP && + peer_sort_lookup(peer_exist) == BGP_PEER_IBGP && (mpath_cfg == NULL || mpath_cfg->same_clusterlen)) { newm = BGP_CLUSTER_LIST_LENGTH(new->attr); existm = BGP_CLUSTER_LIST_LENGTH(exist->attr); @@ -1236,7 +1257,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, zlog_debug( "%s: %s and %s are equal via multipath-relax", pfx_buf, new_buf, exist_buf); - } else if (new->peer->sort == BGP_PEER_IBGP) { + } else if (peer_new->sort == BGP_PEER_IBGP) { if (aspath_cmp(new->attr->aspath, exist->attr->aspath)) { *paths_eq = 1; @@ -1246,7 +1267,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, "%s: %s and %s are equal via matching aspaths", pfx_buf, new_buf, exist_buf); } - } else if (new->peer->as == exist->peer->as) { + } else if (peer_new->as == peer_exist->as) { *paths_eq = 1; if (debug) @@ -1326,11 +1347,11 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) new_id.s_addr = newattr->originator_id.s_addr; else - new_id.s_addr = new->peer->remote_id.s_addr; + new_id.s_addr = peer_new->remote_id.s_addr; if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) exist_id.s_addr = existattr->originator_id.s_addr; else - exist_id.s_addr = exist->peer->remote_id.s_addr; + exist_id.s_addr = peer_exist->remote_id.s_addr; if (ntohl(new_id.s_addr) < ntohl(exist_id.s_addr)) { *reason = bgp_path_selection_router_id; @@ -1397,16 +1418,17 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } /* locally configured routes to advertise do not have su_remote */ - if (new->peer->su_remote == NULL) { + if (peer_new->su_remote == NULL) { *reason = bgp_path_selection_local_configured; return 0; } - if (exist->peer->su_remote == NULL) { + + if (peer_exist->su_remote == NULL) { *reason = bgp_path_selection_local_configured; return 1; } - ret = sockunion_cmp(new->peer->su_remote, exist->peer->su_remote); + ret = sockunion_cmp(peer_new->su_remote, peer_exist->su_remote); if (ret == 1) { *reason = bgp_path_selection_neighbor_ip; @@ -7638,9 +7660,11 @@ void bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, /* If the bgp instance is being deleted or self peer is deleted * then do not create aggregate route */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) - || (bgp->peer_self == NULL)) + if (CHECK_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS) || + (bgp->peer_self == NULL)) { + bgp_aggregate_free(aggregate); return; + } /* Initialize and test routes for MED difference. */ if (aggregate->match_med) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 6ab9c2873d..32ca909fe6 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -281,7 +281,7 @@ static void print_record(const struct pfx_record *record, struct vty *vty, if (!json) { vty_out(vty, "%-40s %3u - %3u ", ip, record->min_len, record->max_len); - vty_out(vty, ASN_FORMAT(asnotation), &record->asn); + vty_out(vty, ASN_FORMAT(asnotation), (as_t *)&record->asn); vty_out(vty, "\n"); } else { json_record = json_object_new_object(); diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index a32cdb1ba4..277492157f 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -317,7 +317,7 @@ static unsigned int updgrp_hash_key_make(const void *p) const struct update_group *updgrp; const struct peer *peer; const struct bgp_filter *filter; - uint32_t flags; + uint64_t flags; uint32_t key; afi_t afi; safi_t safi; @@ -501,8 +501,8 @@ static bool updgrp_hash_cmp(const void *p1, const void *p2) const struct update_group *grp2; const struct peer *pe1; const struct peer *pe2; - uint32_t flags1; - uint32_t flags2; + uint64_t flags1; + uint64_t flags2; const struct bgp_filter *fl1; const struct bgp_filter *fl2; afi_t afi; diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 9eefd2a637..d6eb3ff20b 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -683,11 +683,14 @@ void subgroup_announce_table(struct update_subgroup *subgrp, &attr, NULL)) { /* Check if route can be advertised */ if (advertise) { - if (!bgp_check_withdrawal(bgp, dest)) + if (!bgp_check_withdrawal(bgp, dest)) { + struct attr *adv_attr = + bgp_attr_intern(&attr); + bgp_adj_out_set_subgroup( - dest, subgrp, &attr, + dest, subgrp, adv_attr, ri); - else + } else bgp_adj_out_unset_subgroup( dest, subgrp, 1, bgp_addpath_id_for_peer( diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 8ef18a34d0..a1e9a9a8a9 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -5671,7 +5671,7 @@ DEFPY(neighbor_capability_software_version, } static int peer_af_flag_modify_vty(struct vty *vty, const char *peer_str, - afi_t afi, safi_t safi, uint32_t flag, + afi_t afi, safi_t safi, uint64_t flag, int set) { int ret; @@ -5690,13 +5690,13 @@ static int peer_af_flag_modify_vty(struct vty *vty, const char *peer_str, } static int peer_af_flag_set_vty(struct vty *vty, const char *peer_str, - afi_t afi, safi_t safi, uint32_t flag) + afi_t afi, safi_t safi, uint64_t flag) { return peer_af_flag_modify_vty(vty, peer_str, afi, safi, flag, 1); } static int peer_af_flag_unset_vty(struct vty *vty, const char *peer_str, - afi_t afi, safi_t safi, uint32_t flag) + afi_t afi, safi_t safi, uint64_t flag) { return peer_af_flag_modify_vty(vty, peer_str, afi, safi, flag, 0); } @@ -8893,7 +8893,7 @@ DEFPY(neighbor_path_attribute_discard, { struct peer *peer; int idx = 0; - const char *discard_attrs = NULL; + char *discard_attrs = NULL; peer = peer_and_group_lookup_vty(vty, neighbor); if (!peer) @@ -8905,6 +8905,8 @@ DEFPY(neighbor_path_attribute_discard, bgp_path_attribute_discard_vty(vty, peer, discard_attrs, true); + XFREE(MTYPE_TMP, discard_attrs); + return CMD_SUCCESS; } @@ -8920,7 +8922,7 @@ DEFPY(no_neighbor_path_attribute_discard, { struct peer *peer; int idx = 0; - const char *discard_attrs = NULL; + char *discard_attrs = NULL; peer = peer_and_group_lookup_vty(vty, neighbor); if (!peer) @@ -8932,6 +8934,8 @@ DEFPY(no_neighbor_path_attribute_discard, bgp_path_attribute_discard_vty(vty, peer, discard_attrs, false); + XFREE(MTYPE_TMP, discard_attrs); + return CMD_SUCCESS; } @@ -8946,7 +8950,7 @@ DEFPY(neighbor_path_attribute_treat_as_withdraw, { struct peer *peer; int idx = 0; - const char *withdraw_attrs = NULL; + char *withdraw_attrs = NULL; peer = peer_and_group_lookup_vty(vty, neighbor); if (!peer) @@ -8958,6 +8962,8 @@ DEFPY(neighbor_path_attribute_treat_as_withdraw, bgp_path_attribute_withdraw_vty(vty, peer, withdraw_attrs, true); + XFREE(MTYPE_TMP, withdraw_attrs); + return CMD_SUCCESS; } @@ -8973,7 +8979,7 @@ DEFPY(no_neighbor_path_attribute_treat_as_withdraw, { struct peer *peer; int idx = 0; - const char *withdraw_attrs = NULL; + char *withdraw_attrs = NULL; peer = peer_and_group_lookup_vty(vty, neighbor); if (!peer) @@ -8985,6 +8991,8 @@ DEFPY(no_neighbor_path_attribute_treat_as_withdraw, bgp_path_attribute_withdraw_vty(vty, peer, withdraw_attrs, false); + XFREE(MTYPE_TMP, withdraw_attrs); + return CMD_SUCCESS; } @@ -17154,7 +17162,7 @@ static bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, if (CHECK_FLAG(peer->af_flags_invert[afi][safi], flag)) return !peer_af_flag_check(peer, afi, safi, flag); else - return !!peer_af_flag_check(peer, afi, safi, flag); + return peer_af_flag_check(peer, afi, safi, flag); } return !!CHECK_FLAG(peer->af_flags_override[afi][safi], flag); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 0fd0dafa22..96c6a111ce 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -977,9 +977,10 @@ void peer_flag_inherit(struct peer *peer, uint64_t flag) COND_FLAG(peer->flags, flag, group_val); } -int peer_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint32_t flag) +bool peer_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, + uint64_t flag) { - return CHECK_FLAG(peer->af_flags[afi][safi], flag); + return !!CHECK_FLAG(peer->af_flags[afi][safi], flag); } void peer_af_flag_inherit(struct peer *peer, afi_t afi, safi_t safi, @@ -2725,7 +2726,7 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name) static void peer_group2peer_config_copy(struct peer_group *group, struct peer *peer) { - uint32_t flags_tmp; + uint64_t flags_tmp; struct peer *conf; bool config_node = !!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); @@ -4517,7 +4518,7 @@ static int peer_flag_action_set(const struct peer_flag_action *action_list, return found; } -static void peer_flag_modify_action(struct peer *peer, uint32_t flag) +static void peer_flag_modify_action(struct peer *peer, uint64_t flag) { if (flag == PEER_FLAG_SHUTDOWN) { if (CHECK_FLAG(peer->flags, flag)) { @@ -6312,8 +6313,11 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend, && old_replace_as == replace_as) return 0; peer->change_local_as = as; - if (as_str) + if (as_str) { + if (peer->change_local_as_pretty) + XFREE(MTYPE_BGP, peer->change_local_as_pretty); peer->change_local_as_pretty = XSTRDUP(MTYPE_BGP, as_str); + } (void)peer_sort(peer); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 2a7c7a3143..c0dd8d5ef4 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1441,14 +1441,14 @@ struct peer { #define PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE (1ULL << 19) #define PEER_FLAG_AS_OVERRIDE (1ULL << 20) #define PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE (1ULL << 21) -#define PEER_FLAG_WEIGHT (1ULL << 24) -#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1ULL << 25) -#define PEER_FLAG_SEND_LARGE_COMMUNITY (1ULL << 26) -#define PEER_FLAG_MAX_PREFIX_OUT (1ULL << 27) -#define PEER_FLAG_MAX_PREFIX_FORCE (1ULL << 28) -#define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 29) -#define PEER_FLAG_SOO (1ULL << 30) -#define PEER_FLAG_ACCEPT_OWN (1ULL << 31) +#define PEER_FLAG_WEIGHT (1ULL << 22) +#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1ULL << 23) +#define PEER_FLAG_SEND_LARGE_COMMUNITY (1ULL << 24) +#define PEER_FLAG_MAX_PREFIX_OUT (1ULL << 25) +#define PEER_FLAG_MAX_PREFIX_FORCE (1ULL << 26) +#define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 27) +#define PEER_FLAG_SOO (1ULL << 28) +#define PEER_FLAG_ACCEPT_OWN (1ULL << 63) enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX]; @@ -2247,7 +2247,8 @@ extern int peer_af_flag_set(struct peer *peer, afi_t afi, safi_t safi, uint64_t flag); extern int peer_af_flag_unset(struct peer *peer, afi_t afi, safi_t safi, uint64_t flag); -extern int peer_af_flag_check(struct peer *, afi_t, safi_t, uint32_t); +extern bool peer_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, + uint64_t flag); extern void peer_af_flag_inherit(struct peer *peer, afi_t afi, safi_t safi, uint64_t flag); extern void peer_change_action(struct peer *peer, afi_t afi, safi_t safi, diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 2b114ad127..d68fa67259 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -95,6 +95,9 @@ writing, *isisd* does not support multiple ISIS processes. Configure the maximum size of generated LSPs, in bytes. +.. clicmd:: advertise-passive-only + + Advertise prefixes of passive interfaces only. .. _isis-timer: diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 26ae2024b9..5c7f610881 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -892,6 +892,29 @@ void cli_show_isis_lsp_mtu(struct vty *vty, const struct lyd_node *dnode, } /* + * XPath: /frr-isisd:isis/instance/advertise-passive-only + */ +DEFPY_YANG(advertise_passive_only, advertise_passive_only_cmd, + "[no] advertise-passive-only", + NO_STR "Advertise prefixes of passive interfaces only\n") +{ + nb_cli_enqueue_change(vty, "./advertise-passive-only", NB_OP_MODIFY, + no ? "false" : "true"); + + return nb_cli_apply_changes(vty, NULL); +} + +void cli_show_advertise_passive_only(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + if (!yang_dnode_get_bool(dnode, NULL)) + vty_out(vty, " no"); + + vty_out(vty, " advertise-passive-only\n"); +} + +/* * XPath: /frr-isisd:isis/instance/spf/minimum-interval */ DEFPY_YANG(spf_interval, spf_interval_cmd, @@ -3151,6 +3174,7 @@ void isis_cli_init(void) install_element(ISIS_NODE, &no_lsp_timers_cmd); install_element(ISIS_NODE, &area_lsp_mtu_cmd); install_element(ISIS_NODE, &no_area_lsp_mtu_cmd); + install_element(ISIS_NODE, &advertise_passive_only_cmd); install_element(ISIS_NODE, &spf_interval_cmd); install_element(ISIS_NODE, &no_spf_interval_cmd); diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 8c347ef813..4a332d0aed 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -1171,6 +1171,13 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) continue; } + if (area->advertise_passive_only && !circuit->is_passive) { + lsp_debug( + "ISIS (%s): Circuit is not passive, ignoring.", + area->area_tag); + continue; + } + uint32_t metric = area->oldmetric ? circuit->metric[level - 1] : circuit->te_metric[level - 1]; @@ -1364,6 +1371,10 @@ int lsp_generate(struct isis_area *area, int level) if ((area == NULL) || (area->is_type & level) != level) return ISIS_ERROR; + /* Check if config is still being processed */ + if (thread_is_scheduled(t_isis_cfg)) + return ISIS_OK; + memset(&lspid, 0, ISIS_SYS_ID_LEN + 2); memcpy(&lspid, area->isis->sysid, ISIS_SYS_ID_LEN); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 9b2bebb420..25ea187492 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -168,6 +168,40 @@ static const struct frr_yang_module_info *const isisd_yang_modules[] = { }; /* clang-format on */ + +static void isis_config_finish(struct thread *t) +{ + struct listnode *node, *inode; + struct isis *isis; + struct isis_area *area; + + for (ALL_LIST_ELEMENTS_RO(im->isis, inode, isis)) { + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) + config_end_lsp_generate(area); + } +} + +static void isis_config_start(void) +{ + /* Max wait time for config to load before generating lsp */ +#define ISIS_PRE_CONFIG_MAX_WAIT_SECONDS 600 + THREAD_OFF(t_isis_cfg); + thread_add_timer(im->master, isis_config_finish, NULL, + ISIS_PRE_CONFIG_MAX_WAIT_SECONDS, &t_isis_cfg); +} + +static void isis_config_end(void) +{ + /* If ISIS config processing thread isn't running, then + * we can return and rely it's properly handled. + */ + if (!thread_is_scheduled(t_isis_cfg)) + return; + + THREAD_OFF(t_isis_cfg); + isis_config_finish(t_isis_cfg); +} + #ifdef FABRICD FRR_DAEMON_INFO(fabricd, OPEN_FABRIC, .vty_port = FABRICD_VTY_PORT, @@ -231,6 +265,7 @@ int main(int argc, char **argv, char **envp) /* * initializations */ + cmd_init_config_callbacks(isis_config_start, isis_config_end); isis_error_init(); access_list_init(); access_list_add_hook(isis_filter_update); diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index bcda5bd6aa..5caa61a4d1 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -103,6 +103,13 @@ const struct frr_yang_module_info frr_isisd_info = { }, }, { + .xpath = "/frr-isisd:isis/instance/advertise-passive-only", + .cbs = { + .cli_show = cli_show_advertise_passive_only, + .modify = isis_instance_advertise_passive_only_modify, + }, + }, + { .xpath = "/frr-isisd:isis/instance/lsp/timers", .cbs = { .cli_show = cli_show_isis_lsp_timers, diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index 1a2bd2deb8..c90f6dca37 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -29,6 +29,7 @@ int isis_instance_overload_on_startup_modify(struct nb_cb_modify_args *args); int isis_instance_metric_style_modify(struct nb_cb_modify_args *args); int isis_instance_purge_originator_modify(struct nb_cb_modify_args *args); int isis_instance_lsp_mtu_modify(struct nb_cb_modify_args *args); +int isis_instance_advertise_passive_only_modify(struct nb_cb_modify_args *args); int isis_instance_lsp_refresh_interval_level_1_modify( struct nb_cb_modify_args *args); int isis_instance_lsp_refresh_interval_level_2_modify( @@ -473,6 +474,9 @@ void cli_show_isis_lsp_timers(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void cli_show_isis_lsp_mtu(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +void cli_show_advertise_passive_only(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults); void cli_show_isis_spf_min_interval(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index a7c4e4f369..ea021a4ff5 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -420,6 +420,26 @@ int isis_instance_lsp_mtu_modify(struct nb_cb_modify_args *args) } /* + * XPath: /frr-isisd:isis/instance/advertise-passive-only + */ +int isis_instance_advertise_passive_only_modify(struct nb_cb_modify_args *args) +{ + struct isis_area *area; + bool advertise_passive_only; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + area = nb_running_get_entry(args->dnode, NULL, true); + advertise_passive_only = yang_dnode_get_bool(args->dnode, NULL); + area->advertise_passive_only = advertise_passive_only; + + lsp_regenerate_schedule(area, IS_LEVEL_1 | IS_LEVEL_2, 1); + + return NB_OK; +} + +/* * XPath: /frr-isisd:isis/instance/lsp/timers/level-1/refresh-interval */ int isis_instance_lsp_refresh_interval_level_1_modify( diff --git a/isisd/isisd.c b/isisd/isisd.c index d9f8a262cb..852d7b88e8 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -87,6 +87,9 @@ static struct isis_master isis_master; /* ISIS process wide configuration pointer to export. */ struct isis_master *im; +/* ISIS config processing thread */ +struct thread *t_isis_cfg; + #ifndef FABRICD DEFINE_HOOK(isis_hook_db_overload, (const struct isis_area *area), (area)); #endif /* ifndef FABRICD */ @@ -3234,6 +3237,16 @@ void isis_area_overload_on_startup_set(struct isis_area *area, } } +void config_end_lsp_generate(struct isis_area *area) +{ + if (listcount(area->area_addrs) > 0) { + if (CHECK_FLAG(area->is_type, IS_LEVEL_1)) + lsp_generate(area, IS_LEVEL_1); + if (CHECK_FLAG(area->is_type, IS_LEVEL_2)) + lsp_generate(area, IS_LEVEL_2); + } +} + /* * Returns the path of the file (non-volatile memory) that contains restart * information. diff --git a/isisd/isisd.h b/isisd/isisd.h index 2052e8e3d9..0f1161e574 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -99,6 +99,8 @@ struct isis { extern struct isis_master *im; +extern struct thread *t_isis_cfg; + enum spf_tree_id { SPFTREE_IPV4 = 0, SPFTREE_IPV6, @@ -171,6 +173,8 @@ struct isis_area { bool overload_configured; uint32_t overload_counter; uint32_t overload_on_startup_time; + /* advertise prefixes of passive interfaces only? */ + bool advertise_passive_only; /* L1/L2 router identifier for inter-area traffic */ char attached_bit_send; char attached_bit_rcv_ignore; @@ -314,6 +318,8 @@ char *isis_restart_filepath(void); void isis_restart_write_overload_time(struct isis_area *isis_area, uint32_t overload_time); uint32_t isis_restart_read_overload_time(struct isis_area *isis_area); +void config_end_lsp_generate(struct isis_area *area); + /* YANG paths */ #define ISIS_INSTANCE "/frr-isisd:isis/instance" #define ISIS_SR "/frr-isisd:isis/instance/segment-routing" diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c index 97e4c2ef01..42c3ef0535 100644 --- a/ldpd/adjacency.c +++ b/ldpd/adjacency.c @@ -170,7 +170,7 @@ static void adj_itimer(struct thread *thread) log_debug("%s: lsr-id %pI4", __func__, &adj->lsr_id); if (adj->source.type == HELLO_TARGETED) { - if (!(adj->source.target->flags & F_TNBR_CONFIGURED) && + if (!CHECK_FLAG(adj->source.target->flags, F_TNBR_CONFIGURED) && adj->source.target->pw_count == 0 && adj->source.target->rlfa_count == 0) { /* remove dynamic targeted neighbor */ @@ -245,7 +245,7 @@ tnbr_find(struct ldpd_conf *xconf, int af, union ldpd_addr *addr) struct tnbr * tnbr_check(struct ldpd_conf *xconf, struct tnbr *tnbr) { - if (!(tnbr->flags & (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) && + if (!CHECK_FLAG(tnbr->flags, (F_TNBR_CONFIGURED|F_TNBR_DYNAMIC)) && tnbr->pw_count == 0 && tnbr->rlfa_count == 0) { tnbr_del(xconf, tnbr); return (NULL); diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c index b181e33a5b..906b5c1bf2 100644 --- a/ldpd/ldp_vty_exec.c +++ b/ldpd/ldp_vty_exec.c @@ -408,10 +408,10 @@ show_discovery_detail_msg(struct vty *vty, struct imsg *imsg, rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf); vty_out (vty, "Local:\n"); vty_out (vty, " LSR Id: %pI4:0\n",&rtr_id); - if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED) + if (CHECK_FLAG(ldpd_conf->ipv4.flags, F_LDPD_AF_ENABLED)) vty_out (vty, " Transport Address (IPv4): %s\n", log_addr(AF_INET, &ldpd_conf->ipv4.trans_addr)); - if (ldpd_conf->ipv6.flags & F_LDPD_AF_ENABLED) + if (CHECK_FLAG(ldpd_conf->ipv6.flags, F_LDPD_AF_ENABLED)) vty_out (vty, " Transport Address (IPv6): %s\n", log_addr(AF_INET6, &ldpd_conf->ipv6.trans_addr)); vty_out (vty, "Discovery Sources:\n"); @@ -524,10 +524,10 @@ show_discovery_detail_msg_json(struct imsg *imsg, struct show_params *params, case IMSG_CTL_SHOW_DISCOVERY: rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf); json_object_string_addf(json, "lsrId", "%pI4", &rtr_id); - if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED) + if (CHECK_FLAG(ldpd_conf->ipv4.flags, F_LDPD_AF_ENABLED)) json_object_string_add(json, "transportAddressIPv4", log_addr(AF_INET, &ldpd_conf->ipv4.trans_addr)); - if (ldpd_conf->ipv6.flags & F_LDPD_AF_ENABLED) + if (CHECK_FLAG(ldpd_conf->ipv6.flags, F_LDPD_AF_ENABLED)) json_object_string_add(json, "transportAddressIPv6", log_addr(AF_INET6, &ldpd_conf->ipv6.trans_addr)); json_interfaces = json_object_new_object(); @@ -968,11 +968,11 @@ show_nbr_capabilities(struct vty *vty, struct ctl_nbr *nbr) " - Typed Wildcard (0x050B)\n" " - Unrecognized Notification (0x0603)\n"); vty_out (vty, " Capabilities Received:\n"); - if (nbr->flags & F_NBR_CAP_DYNAMIC) + if (CHECK_FLAG(nbr->flags, F_NBR_CAP_DYNAMIC)) vty_out (vty," - Dynamic Announcement (0x0506)\n"); - if (nbr->flags & F_NBR_CAP_TWCARD) + if (CHECK_FLAG(nbr->flags, F_NBR_CAP_TWCARD)) vty_out (vty, " - Typed Wildcard (0x050B)\n"); - if (nbr->flags & F_NBR_CAP_UNOTIF) + if (CHECK_FLAG(nbr->flags, F_NBR_CAP_UNOTIF)) vty_out (vty," - Unrecognized Notification (0x0603)\n"); } @@ -1037,7 +1037,7 @@ show_nbr_capabilities_json(struct ctl_nbr *nbr, json_object *json_nbr) json_object_object_add(json_nbr, "receivedCapabilities", json_array); /* Dynamic Announcement (0x0506) */ - if (nbr->flags & F_NBR_CAP_DYNAMIC) { + if (CHECK_FLAG(nbr->flags, F_NBR_CAP_DYNAMIC)) { json_cap = json_object_new_object(); json_object_string_add(json_cap, "description", "Dynamic Announcement"); @@ -1046,7 +1046,7 @@ show_nbr_capabilities_json(struct ctl_nbr *nbr, json_object *json_nbr) } /* Typed Wildcard (0x050B) */ - if (nbr->flags & F_NBR_CAP_TWCARD) { + if (CHECK_FLAG(nbr->flags, F_NBR_CAP_TWCARD)) { json_cap = json_object_new_object(); json_object_string_add(json_cap, "description", "Typed Wildcard"); @@ -1055,7 +1055,7 @@ show_nbr_capabilities_json(struct ctl_nbr *nbr, json_object *json_nbr) } /* Unrecognized Notification (0x0603) */ - if (nbr->flags & F_NBR_CAP_UNOTIF) { + if (CHECK_FLAG(nbr->flags, F_NBR_CAP_UNOTIF)) { json_cap = json_object_new_object(); json_object_string_add(json_cap, "description", "Unrecognized Notification"); @@ -52,6 +52,10 @@ static bool asn_str2asn_internal(const char *asstring, as_t *asn, if (!isdigit((unsigned char)*p)) goto end; + /* leading zero is forbidden */ + if (*p == '0' && isdigit((unsigned char)*(p + 1))) + goto end; + temp_val = 0; while (isdigit((unsigned char)*p)) { digit = (*p) - '0'; @@ -65,11 +69,17 @@ static bool asn_str2asn_internal(const char *asstring, as_t *asn, high = (uint32_t)temp_val; if (*p == '.') { /* dot format */ p++; - temp_val = 0; + if (*p == '\0' && partial) { *partial = true; goto end; } + + /* leading zero is forbidden */ + if (*p == '0' && isdigit((unsigned char)*(p + 1))) + goto end; + + temp_val = 0; while (isdigit((unsigned char)*p)) { digit = (*p) - '0'; temp_val *= 10; diff --git a/lib/libfrr.c b/lib/libfrr.c index 0467dc1d7e..d1b7dd133e 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -992,7 +992,7 @@ static void frr_config_read_in(struct thread *t) int ret; context.client = NB_CLIENT_CLI; - ret = nb_candidate_commit(&context, vty_shared_candidate_config, + ret = nb_candidate_commit(context, vty_shared_candidate_config, true, "Read configuration file", NULL, errmsg, sizeof(errmsg)); if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) diff --git a/lib/northbound.c b/lib/northbound.c index b755264be1..6f2c522a29 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -61,7 +61,7 @@ static int nb_callback_configuration(struct nb_context *context, struct nb_config_change *change, char *errmsg, size_t errmsg_len); static struct nb_transaction * -nb_transaction_new(struct nb_context *context, struct nb_config *config, +nb_transaction_new(struct nb_context context, struct nb_config *config, struct nb_config_cbs *changes, const char *comment, char *errmsg, size_t errmsg_len); static void nb_transaction_free(struct nb_transaction *transaction); @@ -835,7 +835,7 @@ int nb_candidate_validate(struct nb_context *context, return ret; } -int nb_candidate_commit_prepare(struct nb_context *context, +int nb_candidate_commit_prepare(struct nb_context context, struct nb_config *candidate, const char *comment, struct nb_transaction **transaction, @@ -860,9 +860,8 @@ int nb_candidate_commit_prepare(struct nb_context *context, return NB_ERR_NO_CHANGES; } - if (nb_candidate_validate_code(context, candidate, &changes, errmsg, - errmsg_len) - != NB_OK) { + if (nb_candidate_validate_code(&context, candidate, &changes, errmsg, + errmsg_len) != NB_OK) { flog_warn(EC_LIB_NB_CANDIDATE_INVALID, "%s: failed to validate candidate configuration", __func__); @@ -913,7 +912,7 @@ void nb_candidate_commit_apply(struct nb_transaction *transaction, nb_transaction_free(transaction); } -int nb_candidate_commit(struct nb_context *context, struct nb_config *candidate, +int nb_candidate_commit(struct nb_context context, struct nb_config *candidate, bool save_transaction, const char *comment, uint32_t *transaction_id, char *errmsg, size_t errmsg_len) @@ -1411,13 +1410,13 @@ static int nb_callback_configuration(struct nb_context *context, } static struct nb_transaction * -nb_transaction_new(struct nb_context *context, struct nb_config *config, +nb_transaction_new(struct nb_context context, struct nb_config *config, struct nb_config_cbs *changes, const char *comment, char *errmsg, size_t errmsg_len) { struct nb_transaction *transaction; - if (nb_running_lock_check(context->client, context->user)) { + if (nb_running_lock_check(context.client, context.user)) { strlcpy(errmsg, "running configuration is locked by another client", errmsg_len); @@ -1469,7 +1468,7 @@ static int nb_transaction_process(enum nb_event event, break; /* Call the appropriate callback. */ - ret = nb_callback_configuration(transaction->context, event, + ret = nb_callback_configuration(&transaction->context, event, change, errmsg, errmsg_len); switch (event) { case NB_EV_PREPARE: @@ -1584,7 +1583,7 @@ static void nb_transaction_apply_finish(struct nb_transaction *transaction, /* Call the 'apply_finish' callbacks, sorted by their priorities. */ RB_FOREACH (cb, nb_config_cbs, &cbs) - nb_callback_apply_finish(transaction->context, cb->nb_node, + nb_callback_apply_finish(&transaction->context, cb->nb_node, cb->dnode, errmsg, errmsg_len); /* Release memory. */ diff --git a/lib/northbound.h b/lib/northbound.h index c132daebdb..152810b3a9 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -622,22 +622,6 @@ struct nb_context { /* Northbound user (can be NULL). */ const void *user; - - /* Client-specific data. */ -#if 0 - union { - struct { - } cli; - struct { - } confd; - struct { - } sysrepo; - struct { - } grpc; - struct { - } pcep; - } client_data; -#endif }; /* Northbound configuration. */ @@ -666,7 +650,7 @@ struct nb_config_change { /* Northbound configuration transaction. */ struct nb_transaction { - struct nb_context *context; + struct nb_context context; char comment[80]; struct nb_config *config; struct nb_config_cbs changes; @@ -927,7 +911,7 @@ extern int nb_candidate_validate(struct nb_context *context, * the candidate configuration. * - NB_ERR for other errors. */ -extern int nb_candidate_commit_prepare(struct nb_context *context, +extern int nb_candidate_commit_prepare(struct nb_context context, struct nb_config *candidate, const char *comment, struct nb_transaction **transaction, @@ -1014,7 +998,7 @@ extern void nb_candidate_commit_apply(struct nb_transaction *transaction, * the candidate configuration. * - NB_ERR for other errors. */ -extern int nb_candidate_commit(struct nb_context *context, +extern int nb_candidate_commit(struct nb_context context, struct nb_config *candidate, bool save_transaction, const char *comment, uint32_t *transaction_id, char *errmsg, diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 0dfa66b37e..fa5884fb78 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -46,7 +46,7 @@ static int nb_cli_classic_commit(struct vty *vty) context.client = NB_CLIENT_CLI; context.user = vty; - ret = nb_candidate_commit(&context, vty->candidate_config, true, NULL, + ret = nb_candidate_commit(context, vty->candidate_config, true, NULL, NULL, errmsg, sizeof(errmsg)); switch (ret) { case NB_OK: @@ -313,7 +313,7 @@ int nb_cli_confirmed_commit_rollback(struct vty *vty) context.client = NB_CLIENT_CLI; context.user = vty; ret = nb_candidate_commit( - &context, vty->confirmed_commit_rollback, true, + context, vty->confirmed_commit_rollback, true, "Rollback to previous configuration - confirmed commit has timed out", &transaction_id, errmsg, sizeof(errmsg)); if (ret == NB_OK) { @@ -394,9 +394,8 @@ static int nb_cli_commit(struct vty *vty, bool force, context.client = NB_CLIENT_CLI; context.user = vty; - ret = nb_candidate_commit(&context, vty->candidate_config, true, - comment, &transaction_id, errmsg, - sizeof(errmsg)); + ret = nb_candidate_commit(context, vty->candidate_config, true, comment, + &transaction_id, errmsg, sizeof(errmsg)); /* Map northbound return code to CLI return code. */ switch (ret) { @@ -1717,7 +1716,7 @@ static int nb_cli_rollback_configuration(struct vty *vty, context.client = NB_CLIENT_CLI; context.user = vty; - ret = nb_candidate_commit(&context, candidate, true, comment, NULL, + ret = nb_candidate_commit(context, candidate, true, comment, NULL, errmsg, sizeof(errmsg)); nb_config_free(candidate); switch (ret) { diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index 81ba313e81..2b57ff2707 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -311,7 +311,7 @@ static void frr_confd_cdb_read_cb_prepare(int fd, int *subp, int reslen) */ transaction = NULL; context.client = NB_CLIENT_CONFD; - ret = nb_candidate_commit_prepare(&context, candidate, NULL, + ret = nb_candidate_commit_prepare(context, candidate, NULL, &transaction, errmsg, sizeof(errmsg)); if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) { enum confd_errcode errcode; diff --git a/lib/northbound_db.c b/lib/northbound_db.c index cefcfbcf1f..74abcde955 100644 --- a/lib/northbound_db.c +++ b/lib/northbound_db.c @@ -73,7 +73,7 @@ int nb_db_transaction_save(const struct nb_transaction *transaction, if (!ss) goto exit; - client_name = nb_client_name(transaction->context->client); + client_name = nb_client_name(transaction->context.client); /* * Always record configurations in the XML format, save the default * values too, as this covers the case where defaults may change. diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp index f5d59d92d6..1459146eab 100644 --- a/lib/northbound_grpc.cpp +++ b/lib/northbound_grpc.cpp @@ -824,7 +824,7 @@ HandleUnaryCommit(UnaryRpcState<frr::CommitRequest, frr::CommitResponse> *tag) case frr::CommitRequest::PREPARE: grpc_debug("`-> Performing PREPARE"); ret = nb_candidate_commit_prepare( - &context, candidate->config, comment.c_str(), + context, candidate->config, comment.c_str(), &candidate->transaction, errmsg, sizeof(errmsg)); break; case frr::CommitRequest::ABORT: @@ -840,7 +840,7 @@ HandleUnaryCommit(UnaryRpcState<frr::CommitRequest, frr::CommitResponse> *tag) break; case frr::CommitRequest::ALL: grpc_debug("`-> Performing ALL"); - ret = nb_candidate_commit(&context, candidate->config, true, + ret = nb_candidate_commit(context, candidate->config, true, comment.c_str(), &transaction_id, errmsg, sizeof(errmsg)); break; diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c index 824d81a51e..096414ff24 100644 --- a/lib/northbound_sysrepo.c +++ b/lib/northbound_sysrepo.c @@ -268,7 +268,7 @@ static int frr_sr_config_change_cb_prepare(sr_session_ctx_t *session, * Validate the configuration changes and allocate all resources * required to apply them. */ - ret = nb_candidate_commit_prepare(&context, candidate, NULL, + ret = nb_candidate_commit_prepare(context, candidate, NULL, &transaction, errmsg, sizeof(errmsg)); if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) flog_warn( @@ -2420,7 +2420,7 @@ static void vty_read_file(struct nb_config *config, FILE *confp) context.client = NB_CLIENT_CLI; context.user = vty; - ret = nb_candidate_commit(&context, vty->candidate_config, true, + ret = nb_candidate_commit(context, vty->candidate_config, true, "Read configuration file", NULL, errmsg, sizeof(errmsg)); if (ret != NB_OK && ret != NB_ERR_NO_CHANGES) diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index 75d8098821..fcece56c6f 100644 --- a/pimd/pim6_mld.c +++ b/pimd/pim6_mld.c @@ -2380,24 +2380,18 @@ static void gm_show_if_one_detail(struct vty *vty, struct interface *ifp) } static void gm_show_if_one(struct vty *vty, struct interface *ifp, - json_object *js_if) + json_object *js_if, struct ttable *tt) { struct pim_interface *pim_ifp = (struct pim_interface *)ifp->info; struct gm_if *gm_ifp = pim_ifp->mld; bool querier; - if (!gm_ifp) { - if (js_if) - json_object_string_add(js_if, "state", "down"); - else - vty_out(vty, "%-16s %5s\n", ifp->name, "down"); - return; - } - querier = IPV6_ADDR_SAME(&gm_ifp->querier, &pim_ifp->ll_lowest); if (js_if) { json_object_string_add(js_if, "name", ifp->name); + json_object_string_addf(js_if, "address", "%pPA", + &pim_ifp->primary_address); json_object_string_add(js_if, "state", "up"); json_object_string_addf(js_if, "version", "%d", gm_ifp->cur_version); @@ -2424,11 +2418,11 @@ static void gm_show_if_one(struct vty *vty, struct interface *ifp, json_object_int_add(js_if, "timerLastMemberQueryIntervalMsec", gm_ifp->cur_query_intv_trig); } else { - vty_out(vty, "%-16s %-5s %d %-25pPA %-5s %11pTH %pTVMs\n", - ifp->name, "up", gm_ifp->cur_version, &gm_ifp->querier, - querier ? "query" : "other", - querier ? gm_ifp->t_query : gm_ifp->t_other_querier, - &gm_ifp->started); + ttable_add_row(tt, "%s|%s|%pPAs|%d|%s|%pPAs|%pTH|%pTVMs", + ifp->name, "up", &pim_ifp->primary_address, + gm_ifp->cur_version, querier ? "local" : "other", + &gm_ifp->querier, gm_ifp->t_query, + &gm_ifp->started); } } @@ -2436,13 +2430,27 @@ static void gm_show_if_vrf(struct vty *vty, struct vrf *vrf, const char *ifname, bool detail, json_object *js) { struct interface *ifp; - json_object *js_vrf; + json_object *js_vrf = NULL; + struct pim_interface *pim_ifp; + struct ttable *tt = NULL; + char *table = NULL; if (js) { js_vrf = json_object_new_object(); json_object_object_add(js, vrf->name, js_vrf); } + if (!js && !detail) { + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row( + tt, + "Interface|State|Address|V|Querier|QuerierIp|Query Timer|Uptime"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + } + FOR_ALL_INTERFACES (vrf, ifp) { json_object *js_if = NULL; @@ -2453,24 +2461,31 @@ static void gm_show_if_vrf(struct vty *vty, struct vrf *vrf, const char *ifname, continue; } - if (!ifp->info) + pim_ifp = ifp->info; + + if (!pim_ifp || !pim_ifp->mld) continue; + if (js) { js_if = json_object_new_object(); json_object_object_add(js_vrf, ifp->name, js_if); } - gm_show_if_one(vty, ifp, js_if); + gm_show_if_one(vty, ifp, js_if, tt); + } + + /* Dump the generated table. */ + if (!js && !detail) { + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + ttable_del(tt); } } static void gm_show_if(struct vty *vty, struct vrf *vrf, const char *ifname, bool detail, json_object *js) { - if (!js && !detail) - vty_out(vty, "%-16s %-5s V %-25s %-18s %s\n", "Interface", - "State", "Querier", "Timer", "Uptime"); - if (vrf) gm_show_if_vrf(vty, vrf, ifname, detail, js); else diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index c7b501ee14..75df09ec35 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -1385,7 +1385,7 @@ void pim_show_upstream(struct pim_instance *pim, struct vty *vty, nbr = pim_neighbor_find( up->rpf.source_nexthop.interface, - up->rpf.rpf_addr); + up->rpf.rpf_addr, false); if (nbr) pim_time_timer_to_hhmmss(join_timer, sizeof(join_timer), diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index 8d19247415..978607d147 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -277,7 +277,7 @@ int pim_hello_recv(struct interface *ifp, pim_addr src_addr, uint8_t *tlv_buf, New neighbor? */ - neigh = pim_neighbor_find(ifp, src_addr); + neigh = pim_neighbor_find(ifp, src_addr, false); if (!neigh) { /* Add as new neighbor */ diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index 0ba7b5a65e..d284912d1d 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1534,8 +1534,10 @@ void pim_if_create_pimreg(struct pim_instance *pim) pim->vrf->name); pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF; - pim_if_new(pim->regiface, false, false, true, - false /*vxlan_term*/); + if (!pim->regiface->info) + pim_if_new(pim->regiface, false, false, true, + false /*vxlan_term*/); + /* * On vrf moves we delete the interface if there * is nothing going on with it. We cannot have diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 02b50c9af2..adf0540f65 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -154,11 +154,15 @@ int pim_mroute_msg_nocache(int fd, struct interface *ifp, const kernmsg *msg) sg.src = msg->msg_im_src; sg.grp = msg->msg_im_dst; - if (!pim_ifp) { + + if (!pim_ifp || !pim_ifp->pim_enable) { if (PIM_DEBUG_MROUTE) zlog_debug( - "%s: PIM not enabled on interface, dropping packet to %pSG", - ifp->name, &sg); + "%s: %s on interface, dropping packet to %pSG", + ifp->name, + !pim_ifp ? "Multicast not enabled" + : "PIM not enabled", + &sg); return 0; } diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index 36e90a9697..fa6f664149 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -157,10 +157,10 @@ static int pim_cmd_interface_delete(struct interface *ifp) * pim_ifp->pim_neighbor_list. */ pim_sock_delete(ifp, "pim unconfigured on interface"); + pim_upstream_nh_if_update(pim_ifp->pim, ifp); if (!pim_ifp->gm_enable) { pim_if_addr_del_all(ifp); - pim_upstream_nh_if_update(pim_ifp->pim, ifp); pim_if_delete(ifp); } diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 9edc3c1af2..0b7ea0ad9d 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -406,7 +406,7 @@ struct pim_neighbor *pim_neighbor_find_by_secondary(struct interface *ifp, } struct pim_neighbor *pim_neighbor_find(struct interface *ifp, - pim_addr source_addr) + pim_addr source_addr, bool secondary) { struct pim_interface *pim_ifp; struct listnode *node; @@ -425,6 +425,13 @@ struct pim_neighbor *pim_neighbor_find(struct interface *ifp, } } + if (secondary) { + struct prefix p; + + pim_addr_to_prefix(&p, source_addr); + return pim_neighbor_find_by_secondary(ifp, &p); + } + return NULL; } diff --git a/pimd/pim_neighbor.h b/pimd/pim_neighbor.h index e00f99fe26..f7375745a1 100644 --- a/pimd/pim_neighbor.h +++ b/pimd/pim_neighbor.h @@ -38,7 +38,7 @@ struct pim_neighbor { void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime); void pim_neighbor_free(struct pim_neighbor *neigh); struct pim_neighbor *pim_neighbor_find(struct interface *ifp, - pim_addr source_addr); + pim_addr source_addr, bool secondary); struct pim_neighbor *pim_neighbor_find_by_secondary(struct interface *ifp, struct prefix *src); struct pim_neighbor *pim_neighbor_find_if(struct interface *ifp); diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index d73f366d43..d164e7ed81 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -307,12 +307,11 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, if (if_is_loopback(ifp) && if_is_loopback(src_ifp)) return true; - nbr = pim_neighbor_find(ifp, znh->nexthop_addr); + nbr = pim_neighbor_find(ifp, znh->nexthop_addr, true); if (!nbr) continue; - return znh->ifindex == src_ifp->ifindex && - (!pim_addr_cmp(znh->nexthop_addr, src_ip)); + return znh->ifindex == src_ifp->ifindex; } return false; } @@ -373,12 +372,13 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, return true; /* MRIB (IGP) may be pointing at a router where PIM is down */ - nbr = pim_neighbor_find(ifp, nhaddr); + + nbr = pim_neighbor_find(ifp, nhaddr, true); + if (!nbr) continue; - return nh->ifindex == src_ifp->ifindex && - (!pim_addr_cmp(nhaddr, src_ip)); + return nh->ifindex == src_ifp->ifindex; } return false; } @@ -561,7 +561,7 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, src)) { nbr = pim_neighbor_find( nexthop->interface, - nexthop->mrib_nexthop_addr); + nexthop->mrib_nexthop_addr, true); if (!nbr && !if_is_loopback(nexthop->interface)) { if (PIM_DEBUG_PIM_NHT) @@ -603,7 +603,7 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, #else pim_addr nhaddr = nh_node->gate.ipv6; #endif - nbrs[i] = pim_neighbor_find(ifps[i], nhaddr); + nbrs[i] = pim_neighbor_find(ifps[i], nhaddr, true); if (nbrs[i] || pim_if_connected_to_source(ifps[i], src)) num_nbrs++; } @@ -954,7 +954,8 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim, pim->vrf->vrf_id); if (ifps[i]) { nbrs[i] = pim_neighbor_find( - ifps[i], nexthop_tab[i].nexthop_addr); + ifps[i], nexthop_tab[i].nexthop_addr, true); + if (nbrs[i] || pim_if_connected_to_source(ifps[i], src)) num_nbrs++; } diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index a7a8b05753..1248db3de4 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -289,7 +289,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, pim_msg_len - PIM_MSG_HEADER_LEN); break; case PIM_MSG_TYPE_JOIN_PRUNE: - neigh = pim_neighbor_find(ifp, sg.src); + neigh = pim_neighbor_find(ifp, sg.src, false); if (!neigh) { if (PIM_DEBUG_PIM_PACKETS) zlog_debug( @@ -304,7 +304,7 @@ int pim_pim_packet(struct interface *ifp, uint8_t *buf, size_t len, pim_msg_len - PIM_MSG_HEADER_LEN); break; case PIM_MSG_TYPE_ASSERT: - neigh = pim_neighbor_find(ifp, sg.src); + neigh = pim_neighbor_find(ifp, sg.src, false); if (!neigh) { if (PIM_DEBUG_PIM_PACKETS) zlog_debug( diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 06765d93df..b17ae3131f 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -116,8 +116,8 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, i++; } else if (neighbor_needed && !pim_if_connected_to_source(ifp, addr)) { - nbr = pim_neighbor_find(ifp, - nexthop_tab[i].nexthop_addr); + nbr = pim_neighbor_find( + ifp, nexthop_tab[i].nexthop_addr, true); if (PIM_DEBUG_PIM_TRACE_DETAIL) zlog_debug("ifp name: %s, pim nbr: %p", ifp->name, nbr); diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index d63d530f93..b0f1158596 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -327,7 +327,7 @@ static void join_timer_stop(struct pim_upstream *up) if (up->rpf.source_nexthop.interface) nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr); + up->rpf.rpf_addr, true); if (nbr) pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr); @@ -341,7 +341,7 @@ void join_timer_start(struct pim_upstream *up) if (up->rpf.source_nexthop.interface) { nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr); + up->rpf.rpf_addr, true); if (PIM_DEBUG_PIM_EVENTS) { zlog_debug( @@ -433,7 +433,8 @@ void pim_upstream_join_suppress(struct pim_upstream *up, pim_addr rpf, else { /* Remove it from jp agg from the nbr for suppression */ nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr); + up->rpf.rpf_addr, true); + if (nbr) { join_timer_remain_msec = pim_time_timer_remain_msec(nbr->jp_timer); @@ -485,7 +486,8 @@ void pim_upstream_join_timer_decrease_to_t_override(const char *debug_label, struct pim_neighbor *nbr; nbr = pim_neighbor_find(up->rpf.source_nexthop.interface, - up->rpf.rpf_addr); + up->rpf.rpf_addr, true); + if (nbr) join_timer_remain_msec = pim_time_timer_remain_msec(nbr->jp_timer); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index e39eca7a2c..29aac7f1c7 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -257,7 +257,8 @@ void pim_zebra_upstream_rpf_changed(struct pim_instance *pim, struct pim_neighbor *nbr; nbr = pim_neighbor_find(old->source_nexthop.interface, - old->rpf_addr); + old->rpf_addr, true); + if (nbr) pim_jp_agg_remove_group(nbr->upstream_jp_agg, up, nbr); diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index 652aaa25d4..dde38c8693 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -639,6 +639,14 @@ static struct test_peer_attr test_peer_attrs[] = { .u.flag = PEER_FLAG_WEIGHT, .handlers[0] = TEST_HANDLER(weight), }, + { + .cmd = "accept-own", + .peer_cmd = "accept-own", + .group_cmd = "accept-own", + .families[0] = {.afi = AFI_IP, .safi = SAFI_MPLS_VPN}, + .families[1] = {.afi = AFI_IP6, .safi = SAFI_MPLS_VPN}, + .u.flag = PEER_FLAG_ACCEPT_OWN, + }, {NULL} }; /* clang-format on */ diff --git a/tests/bgpd/test_peer_attr.py b/tests/bgpd/test_peer_attr.py index 16b441b25d..eb57618434 100644 --- a/tests/bgpd/test_peer_attr.py +++ b/tests/bgpd/test_peer_attr.py @@ -196,3 +196,5 @@ TestFlag.okfail("peer\\ipv4-unicast\\weight") TestFlag.okfail("peer\\ipv4-multicast\\weight") TestFlag.okfail("peer\\ipv6-unicast\\weight") TestFlag.okfail("peer\\ipv6-multicast\\weight") +TestFlag.okfail("peer\\ipv4-vpn\\accept-own") +TestFlag.okfail("peer\\ipv6-vpn\\accept-own") diff --git a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py index 0b6152568d..a820b4b221 100644 --- a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py +++ b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py @@ -83,18 +83,9 @@ def test_bgp_gr_restart_retain_routes(): return topotest.json_cmp(output, expected) def _bgp_check_kernel_retained_routes(): - output = ( - r2.cmd("ip route show 172.16.255.1/32 proto bgp dev r2-eth0") - .replace("\n", "") - .rstrip() - ) - expected = "172.16.255.1 via 192.168.255.1 metric 20" - diff = topotest.get_textdiff( - output, expected, "Actual IP Routing Table", "Expected IP RoutingTable" - ) - if diff: - return False - return True + output = json.loads(r2.cmd("ip -j route show 172.16.255.1/32 proto bgp dev r2-eth0")) + expected = [{"dst":"172.16.255.1","gateway":"192.168.255.1","metric":20}] + return topotest.json_cmp(output, expected) step("Initial BGP converge") test_func = functools.partial(_bgp_converge) @@ -110,7 +101,7 @@ def test_bgp_gr_restart_retain_routes(): assert result is None, "Failed to see BGP retained routes on R2" step("Check if routes (Kernel) are retained at R2") - assert _bgp_check_kernel_retained_routes() == True + assert _bgp_check_kernel_retained_routes() is None, "Failed to retain BGP routes in kernel on R2" if __name__ == "__main__": diff --git a/tests/topotests/bgp_vpnv4_ebgp/r1/bgp_ipv4_routes.json b/tests/topotests/bgp_vpnv4_ebgp/r1/bgp_ipv4_routes.json new file mode 100644 index 0000000000..184ab312b6 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp/r1/bgp_ipv4_routes.json @@ -0,0 +1,49 @@ +{ + "vrfName": "vrf1", + "localAS": 65500, + "routes": + { + "172.31.0.10/32": [ + { + "prefix": "172.31.0.10", + "prefixLen": 32, + "network": "172.31.0.10\/32", + "nhVrfName": "default", + "nexthops": [ + { + "ip": "192.168.0.3", + "afi": "ipv4", + "used": true + } + ] + }, + { + "prefix": "172.31.0.10", + "prefixLen": 32, + "network": "172.31.0.10\/32", + "nhVrfName": "default", + "nexthops": [ + { + "ip": "192.168.0.2", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.31.0.1/32": [ + { + "prefix": "172.31.0.1", + "prefixLen": 32, + "network": "172.31.0.1\/32", + "nexthops": [ + { + "ip": "0.0.0.0", + "afi": "ipv4", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_vpnv4_ebgp/r1/bgpd.conf b/tests/topotests/bgp_vpnv4_ebgp/r1/bgpd.conf index 2eebe5e6dd..0249279c65 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r1/bgpd.conf +++ b/tests/topotests/bgp_vpnv4_ebgp/r1/bgpd.conf @@ -1,16 +1,19 @@ router bgp 65500 - bgp router-id 1.1.1.1 + bgp router-id 192.0.2.1 no bgp ebgp-requires-policy - neighbor 10.125.0.2 remote-as 65501 + neighbor 192.168.0.2 remote-as 65501 + neighbor 192.168.0.3 remote-as 65501 address-family ipv4 unicast - no neighbor 10.125.0.2 activate + no neighbor 192.168.0.3 activate + no neighbor 192.168.0.2 activate exit-address-family address-family ipv4 vpn - neighbor 10.125.0.2 activate + neighbor 192.168.0.2 activate + neighbor 192.168.0.3 activate exit-address-family ! router bgp 65500 vrf vrf1 - bgp router-id 1.1.1.1 + bgp router-id 192.0.2.1 address-family ipv4 unicast redistribute connected label vpn export 101 diff --git a/tests/topotests/bgp_vpnv4_ebgp/r1/ipv4_routes.json b/tests/topotests/bgp_vpnv4_ebgp/r1/ipv4_routes.json index da7d281833..79b020af76 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r1/ipv4_routes.json +++ b/tests/topotests/bgp_vpnv4_ebgp/r1/ipv4_routes.json @@ -1,8 +1,8 @@ { - "10.200.0.0/24": [ + "172.31.0.10/32": [ { - "prefix": "10.200.0.0/24", - "prefixLen": 24, + "prefix": "172.31.0.10/32", + "prefixLen": 32, "protocol": "bgp", "vrfName": "vrf1", "selected": true, @@ -13,7 +13,19 @@ { "flags": 3, "fib": true, - "ip": "10.125.0.2", + "ip": "192.168.0.2", + "afi": "ipv4", + "interfaceName": "r1-eth0", + "vrf": "default", + "active": true, + "labels":[ + 102 + ] + }, + { + "flags": 3, + "fib": true, + "ip": "192.168.0.3", "afi": "ipv4", "interfaceName": "r1-eth0", "vrf": "default", @@ -25,10 +37,10 @@ ] } ], - "10.201.0.0/24": [ + "172.31.0.1/32": [ { - "prefix": "10.201.0.0/24", - "prefixLen": 24, + "prefix": "172.31.0.1/32", + "prefixLen": 32, "protocol": "connected", "vrfName": "vrf1", "selected": true, diff --git a/tests/topotests/bgp_vpnv4_ebgp/r1/zebra.conf b/tests/topotests/bgp_vpnv4_ebgp/r1/zebra.conf index e9ae4e9831..f626e448a7 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r1/zebra.conf +++ b/tests/topotests/bgp_vpnv4_ebgp/r1/zebra.conf @@ -1,7 +1,7 @@ log stdout interface r1-eth1 vrf vrf1 - ip address 10.201.0.1/24 + ip address 172.31.0.1/32 ! interface r1-eth0 - ip address 10.125.0.1/24 + ip address 192.168.0.1/24 ! diff --git a/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_routes.json b/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_routes.json index 19797dd561..1fc3a4b89c 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_routes.json +++ b/tests/topotests/bgp_vpnv4_ebgp/r2/bgp_ipv4_routes.json @@ -3,28 +3,28 @@ "localAS": 65501, "routes": { - "10.201.0.0/24": [ + "172.31.0.1/32": [ { - "prefix": "10.201.0.0", - "prefixLen": 24, - "network": "10.201.0.0\/24", + "prefix": "172.31.0.1", + "prefixLen": 32, + "network": "172.31.0.1\/32", "nhVrfName": "default", "nexthops": [ { - "ip": "10.125.0.1", + "ip": "192.168.0.1", "afi": "ipv4", "used": true } ] } ], - "10.200.0.0/24": [ + "172.31.0.10/32": [ { "valid": true, "bestpath": true, - "prefix": "10.200.0.0", - "prefixLen": 24, - "network": "10.200.0.0\/24", + "prefix": "172.31.0.10", + "prefixLen": 32, + "network": "172.31.0.10\/32", "nexthops": [ { "ip": "0.0.0.0", diff --git a/tests/topotests/bgp_vpnv4_ebgp/r2/bgpd.conf b/tests/topotests/bgp_vpnv4_ebgp/r2/bgpd.conf index e38c99d69c..e873469d79 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r2/bgpd.conf +++ b/tests/topotests/bgp_vpnv4_ebgp/r2/bgpd.conf @@ -1,16 +1,16 @@ router bgp 65501 - bgp router-id 2.2.2.2 + bgp router-id 192.0.2.2 no bgp ebgp-requires-policy - neighbor 10.125.0.1 remote-as 65500 + neighbor 192.168.0.1 remote-as 65500 address-family ipv4 unicast - no neighbor 10.125.0.1 activate + no neighbor 192.168.0.1 activate exit-address-family address-family ipv4 vpn - neighbor 10.125.0.1 activate + neighbor 192.168.0.1 activate exit-address-family ! router bgp 65501 vrf vrf1 - bgp router-id 2.2.2.2 + bgp router-id 192.0.2.2 address-family ipv4 unicast redistribute connected label vpn export 102 diff --git a/tests/topotests/bgp_vpnv4_ebgp/r2/zebra.conf b/tests/topotests/bgp_vpnv4_ebgp/r2/zebra.conf index 6c433aef2b..bbc524065d 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/r2/zebra.conf +++ b/tests/topotests/bgp_vpnv4_ebgp/r2/zebra.conf @@ -1,7 +1,7 @@ log stdout interface r2-eth1 vrf vrf1 - ip address 10.200.0.2/24 + ip address 172.31.0.10/32 ! interface r2-eth0 - ip address 10.125.0.2/24 + ip address 192.168.0.2/24 ! diff --git a/tests/topotests/bgp_vpnv4_ebgp/r3/bgp_ipv4_routes.json b/tests/topotests/bgp_vpnv4_ebgp/r3/bgp_ipv4_routes.json new file mode 100644 index 0000000000..19797dd561 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp/r3/bgp_ipv4_routes.json @@ -0,0 +1,38 @@ +{ + "vrfName": "vrf1", + "localAS": 65501, + "routes": + { + "10.201.0.0/24": [ + { + "prefix": "10.201.0.0", + "prefixLen": 24, + "network": "10.201.0.0\/24", + "nhVrfName": "default", + "nexthops": [ + { + "ip": "10.125.0.1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.200.0.0/24": [ + { + "valid": true, + "bestpath": true, + "prefix": "10.200.0.0", + "prefixLen": 24, + "network": "10.200.0.0\/24", + "nexthops": [ + { + "ip": "0.0.0.0", + "afi": "ipv4", + "used": true + } + ] + } + ] + } +} diff --git a/tests/topotests/bgp_vpnv4_ebgp/r3/bgpd.conf b/tests/topotests/bgp_vpnv4_ebgp/r3/bgpd.conf new file mode 100644 index 0000000000..a327638c69 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp/r3/bgpd.conf @@ -0,0 +1,25 @@ +router bgp 65501 + bgp router-id 192.0.2.3 + no bgp ebgp-requires-policy + neighbor 192.168.0.1 remote-as 65500 + address-family ipv4 unicast + no neighbor 192.168.0.1 activate + exit-address-family + address-family ipv4 vpn + neighbor 192.168.0.1 activate + exit-address-family +! +router bgp 65502 vrf vrf1 + bgp router-id 192.0.2.3 + address-family ipv4 unicast + redistribute connected + label vpn export 102 + rd vpn export 444:3 + rt vpn both 52:100 + export vpn + import vpn + exit-address-family +! +interface r3-eth0 + mpls bgp forwarding +! diff --git a/tests/topotests/bgp_vpnv4_ebgp/r3/zebra.conf b/tests/topotests/bgp_vpnv4_ebgp/r3/zebra.conf new file mode 100644 index 0000000000..4412c04a2b --- /dev/null +++ b/tests/topotests/bgp_vpnv4_ebgp/r3/zebra.conf @@ -0,0 +1,7 @@ +log stdout +interface r3-eth1 vrf vrf1 + ip address 172.31.0.10/32 +! +interface r3-eth0 + ip address 192.168.0.3/24 +! diff --git a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py index 342bad20ab..61e1163c18 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py +++ b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py @@ -40,10 +40,12 @@ def build_topo(tgen): # Create 2 routers. tgen.add_router("r1") tgen.add_router("r2") + tgen.add_router("r3") switch = tgen.add_switch("s1") switch.add_link(tgen.gears["r1"]) switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r3"]) switch = tgen.add_switch("s2") switch.add_link(tgen.gears["r1"]) @@ -51,27 +53,38 @@ def build_topo(tgen): switch = tgen.add_switch("s3") switch.add_link(tgen.gears["r2"]) + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r3"]) + + def _populate_iface(): tgen = get_topogen() cmds_list = [ - 'ip link add vrf1 type vrf table 10', - 'echo 100000 > /proc/sys/net/mpls/platform_labels', - 'ip link set dev vrf1 up', - 'ip link set dev {0}-eth1 master vrf1', - 'echo 1 > /proc/sys/net/mpls/conf/{0}-eth0/input', + "ip link add vrf1 type vrf table 10", + "echo 100000 > /proc/sys/net/mpls/platform_labels", + "ip link set dev vrf1 up", + "ip link set dev {0}-eth1 master vrf1", + "echo 1 > /proc/sys/net/mpls/conf/{0}-eth0/input", ] for cmd in cmds_list: - input = cmd.format('r1', '1', '2') - logger.info('input: ' + cmd) - output = tgen.net['r1'].cmd(cmd.format('r1', '1', '2')) - logger.info('output: ' + output) + input = cmd.format("r1") + logger.info("input: " + cmd) + output = tgen.net["r1"].cmd(cmd.format("r1")) + logger.info("output: " + output) + + for cmd in cmds_list: + input = cmd.format("r2") + logger.info("input: " + cmd) + output = tgen.net["r2"].cmd(cmd.format("r2")) + logger.info("output: " + output) for cmd in cmds_list: - input = cmd.format('r2', '2', '1') - logger.info('input: ' + cmd) - output = tgen.net['r2'].cmd(cmd.format('r2', '2', '1')) - logger.info('output: ' + output) + input = cmd.format("r3") + logger.info("input: " + cmd) + output = tgen.net["r3"].cmd(cmd.format("r3")) + logger.info("output: " + output) + def setup_module(mod): "Sets up the pytest environment" @@ -109,13 +122,13 @@ def test_protocols_convergence(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - router = tgen.gears['r1'] + router = tgen.gears["r1"] logger.info("Dump some context for r1") router.vtysh_cmd("show bgp ipv4 vpn") router.vtysh_cmd("show bgp summary") router.vtysh_cmd("show bgp vrf vrf1 ipv4") router.vtysh_cmd("show running-config") - router = tgen.gears['r2'] + router = tgen.gears["r2"] logger.info("Dump some context for r2") router.vtysh_cmd("show bgp ipv4 vpn") router.vtysh_cmd("show bgp summary") @@ -124,11 +137,11 @@ def test_protocols_convergence(): # Check IPv4 routing tables on r1 logger.info("Checking IPv4 routes for convergence on r1") - router = tgen.gears['r1'] + router = tgen.gears["r1"] json_file = "{}/{}/ipv4_routes.json".format(CWD, router.name) if not os.path.isfile(json_file): logger.info("skipping file {}".format(json_file)) - assert 0, 'ipv4_routes.json file not found' + assert 0, "ipv4_routes.json file not found" return expected = json.loads(open(json_file).read()) @@ -142,12 +155,52 @@ def test_protocols_convergence(): assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg + # Check BGP IPv4 routing tables on r1 + logger.info("Checking BGP IPv4 routes for convergence on r1") + router = tgen.gears["r1"] + json_file = "{}/{}/bgp_ipv4_routes.json".format(CWD, router.name) + if not os.path.isfile(json_file): + assert 0, "bgp_ipv4_routes.json file not found" + + expected = json.loads(open(json_file).read()) + test_func = partial( + topotest.router_json_cmp, + router, + "show bgp vrf vrf1 ipv4 json", + expected, + ) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=2) + assertmsg = '"{}" JSON output mismatches'.format(router.name) + assert result is None, assertmsg + + # Check BGP IPv4 imported entry is not detected as local + # "selectionReason": "Locally configured route" + donna = tgen.gears["r1"].vtysh_cmd( + "show bgp vrf vrf1 ipv4 172.31.0.10/32 json", isjson=True + ) + routes = donna["paths"] + selectionReasonFound = False + for route in routes: + if "bestpath" not in route.keys(): + continue + if "selectionReason" not in route["bestpath"].keys(): + continue + + if "Locally configured route" == route["bestpath"]["selectionReason"]: + assert 0, "imported prefix has wrong reason detected" + + selectionReasonFound = True + + if not selectionReasonFound: + assertmsg = '"{}" imported prefix has wrong reason detected'.format(router.name) + assert False, assertmsg + # Check BGP IPv4 routing tables on r2 not installed logger.info("Checking BGP IPv4 routes for convergence on r2") - router = tgen.gears['r2'] + router = tgen.gears["r2"] json_file = "{}/{}/bgp_ipv4_routes.json".format(CWD, router.name) if not os.path.isfile(json_file): - assert 0, 'bgp_ipv4_routes.json file not found' + assert 0, "bgp_ipv4_routes.json file not found" expected = json.loads(open(json_file).read()) test_func = partial( @@ -159,7 +212,8 @@ def test_protocols_convergence(): _, result = topotest.run_and_expect(test_func, None, count=40, wait=2) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg - + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index 608ef48ff4..baacba613d 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -520,6 +520,67 @@ def test_isis_overload_on_startup_override_timer(): check_lsp_overload_bit("r3", "r3.00-00", "0/0/1") +def test_isis_advertise_passive_only(): + """Check that we only advertise prefixes of passive interfaces when advertise-passive-only is enabled.""" + tgen = get_topogen() + net = get_topogen().net + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Testing isis advertise-passive-only behavior") + expected_prefixes_no_advertise_passive_only = set( + ["10.0.20.0/24", "10.254.0.1/32", "2001:db8:f::1/128", "2001:db8:1:1::/64"] + ) + expected_prefixes_advertise_passive_only = set( + ["10.254.0.1/32", "2001:db8:f::1/128"] + ) + lsp_id = "r1.00-00" + + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ + configure + router isis 1 + no redistribute ipv4 connected level-2 + no redistribute ipv6 connected level-2 + interface lo + ip router isis 1 + ipv6 router isis 1 + isis passive + end + """ + ) + + result = check_advertised_prefixes( + r1, lsp_id, expected_prefixes_no_advertise_passive_only + ) + assert result is True, result + + r1.vtysh_cmd( + """ + configure + router isis 1 + advertise-passive-only + end + """ + ) + + result = check_advertised_prefixes( + r1, lsp_id, expected_prefixes_advertise_passive_only + ) + assert result is True, result + + +@retry(retry_timeout=5) +def check_advertised_prefixes(router, lsp_id, expected_prefixes): + output = router.vtysh_cmd("show isis database detail {}".format(lsp_id)) + prefixes = set(re.findall(r"IP(?:v6)? Reachability: (.*) \(Metric: 10\)", output)) + if prefixes == expected_prefixes: + return True + return str({"expected_prefixes:": expected_prefixes, "prefixes": prefixes}) + + @retry(retry_timeout=200) def _check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected): "Verfiy overload bit in router's LSP" diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 7609c7f899..23b1f2e533 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -2816,7 +2816,7 @@ def get_ospf_database(tgen, topo, dut, input_dict, vrf=None, lsatype=None, rid=N result = True break if ( - _age is not "get" + _age != "get" and lsa["lsaAge"] == show_ospf_json["routerLinkStates"][rtrlsa][ ospf_area diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index fd8a0de4ee..ff3ba5d12b 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -1178,6 +1178,13 @@ module frr-isisd { "RFC6232"; } + leaf advertise-passive-only { + type boolean; + default "false"; + description + "Advertise prefixes of passive interfaces only"; + } + container lsp { description "Configuration of Link-State Packets (LSP) parameters"; diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 900c6520d3..e4ddbd95d7 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -2006,6 +2006,25 @@ static int netlink_neigh_update(int cmd, int ifindex, void *addr, char *lla, if (lla) nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); + if (IS_ZEBRA_DEBUG_KERNEL) { + char ip_str[INET6_ADDRSTRLEN + 8]; + struct interface *ifp = if_lookup_by_index_per_ns( + zebra_ns_lookup(ns_id), ifindex); + if (ifp) { + if (family == AF_INET6) + snprintfrr(ip_str, sizeof(ip_str), "ipv6 %pI6", + (struct in6_addr *)addr); + else + snprintfrr(ip_str, sizeof(ip_str), "ipv4 %pI4", + (in_addr_t *)addr); + zlog_debug( + "%s: %s ifname %s ifindex %u addr %s mac %pEA vrf %s(%u)", + __func__, nl_msg_type_to_str(cmd), ifp->name, + ifindex, ip_str, (struct ethaddr *)lla, + vrf_id_to_name(ifp->vrf->vrf_id), + ifp->vrf->vrf_id); + } + } return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, false); } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 59152df2f1..1ff188c76d 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -121,8 +121,6 @@ static int zserv_encode_nexthop(struct stream *s, struct nexthop *nexthop) stream_putl(s, nexthop->ifindex); break; case NEXTHOP_TYPE_IPV6: - stream_put(s, &nexthop->gate.ipv6, 16); - break; case NEXTHOP_TYPE_IPV6_IFINDEX: stream_put(s, &nexthop->gate.ipv6, 16); stream_putl(s, nexthop->ifindex); |
