diff options
31 files changed, 1137 insertions, 305 deletions
diff --git a/babeld/babeld.c b/babeld/babeld.c index 1d2f60e3ad..4e68f05df4 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -538,7 +538,7 @@ resize_receive_buffer(int size) } static void -babel_distribute_update (struct distribute_ctx *ctx, struct distribute *dist) +babel_distribute_update (struct distribute_ctx *ctx __attribute__((__unused__)), struct distribute *dist) { struct interface *ifp; babel_interface_nfo *babel_ifp; @@ -593,7 +593,7 @@ babel_distribute_update_all (struct prefix_list *notused) } static void -babel_distribute_update_all_wrapper (struct access_list *notused) +babel_distribute_update_all_wrapper (struct access_list *notused __attribute__((__unused__))) { babel_distribute_update_all(NULL); } @@ -872,16 +872,18 @@ babeld_quagga_init(void) /* Stubs to adapt Babel's filtering calls to Quagga's infrastructure. */ int -input_filter(const unsigned char *id, +input_filter(const unsigned char *id __attribute__((__unused__)), const unsigned char *prefix, unsigned short plen, - const unsigned char *neigh, unsigned int ifindex) + const unsigned char *neigh __attribute__((__unused__)), + unsigned int ifindex) { return babel_filter(0, prefix, plen, ifindex); } int -output_filter(const unsigned char *id, const unsigned char *prefix, - unsigned short plen, unsigned int ifindex) +output_filter(const unsigned char *id __attribute__((__unused__)), + const unsigned char *prefix, unsigned short plen, + unsigned int ifindex) { return babel_filter(1, prefix, plen, ifindex); } diff --git a/bfdd/event.c b/bfdd/event.c index e5f43b6cc6..f85b4335be 100644 --- a/bfdd/event.c +++ b/bfdd/event.c @@ -107,6 +107,7 @@ void sbfd_init_xmttimer_update(struct bfd_session *bs, uint64_t jitter) tv_normalize(&tv); event_add_timer_tv(master, sbfd_init_xmt_cb, bs, &tv, &bs->xmttimer_ev); + event_set_tardy_threshold(bs->xmttimer_ev, bs->xmt_TO / 2); } void sbfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter) @@ -123,6 +124,7 @@ void sbfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter) tv_normalize(&tv); event_add_timer_tv(master, sbfd_echo_xmt_cb, bs, &tv, &bs->echo_xmttimer_ev); + event_set_tardy_threshold(bs->echo_xmttimer_ev, bs->echo_xmt_TO / 2); } void bfd_xmttimer_update(struct bfd_session *bs, uint64_t jitter) @@ -140,6 +142,7 @@ void bfd_xmttimer_update(struct bfd_session *bs, uint64_t jitter) tv_normalize(&tv); event_add_timer_tv(master, bfd_xmt_cb, bs, &tv, &bs->xmttimer_ev); + event_set_tardy_threshold(bs->xmttimer_ev, bs->xmt_TO / 2); } void bfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter) @@ -158,6 +161,7 @@ void bfd_echo_xmttimer_update(struct bfd_session *bs, uint64_t jitter) event_add_timer_tv(master, bfd_echo_xmt_cb, bs, &tv, &bs->echo_xmttimer_ev); + event_set_tardy_threshold(bs->echo_xmttimer_ev, bs->echo_xmt_TO / 2); } void bfd_recvtimer_delete(struct bfd_session *bs) diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index e458e5e5ac..b1bff82b05 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -56,6 +56,7 @@ static int bmp_route_update_bgpbmp(struct bmp_targets *bt, afi_t afi, safi_t saf static void bmp_send_all_bgp(struct peer *peer, bool down); static struct bmp_imported_bgp *bmp_imported_bgp_find(struct bmp_targets *bt, char *name); static void bmp_stats_per_instance(struct bgp *bgp, struct bmp_targets *bt); +static void bmp_bgp_peer_vrf(struct bmp_bgp_peer *bbpeer, struct bgp *bgp); DEFINE_MGROUP(BMP, "BMP (BGP Monitoring Protocol)"); @@ -551,9 +552,12 @@ static struct stream *bmp_peerstate(struct peer *peer, bool down) bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid); - if (bbpeer && bbpeer->open_tx) + if (bbpeer && bbpeer->open_tx) { + if (is_locrib) + /* update bgp id each time peer up LOC-RIB message is to be sent */ + bmp_bgp_peer_vrf(bbpeer, peer->bgp); stream_put(s, bbpeer->open_tx, bbpeer->open_tx_len); - else { + } else { stream_put(s, dummy_open, sizeof(dummy_open)); zlog_warn("bmp: missing TX OPEN message for peer %s", peer->host); @@ -2209,6 +2213,8 @@ static void bmp_bgp_peer_vrf(struct bmp_bgp_peer *bbpeer, struct bgp *bgp) struct peer *peer = bgp->peer_self; uint16_t send_holdtime; as_t local_as; + struct stream *s; + size_t open_len; if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) send_holdtime = peer->holdtime; @@ -2221,8 +2227,8 @@ static void bmp_bgp_peer_vrf(struct bmp_bgp_peer *bbpeer, struct bgp *bgp) else local_as = peer->local_as; - struct stream *s = bgp_open_make(peer, send_holdtime, local_as); - size_t open_len = stream_get_endp(s); + s = bgp_open_make(peer, send_holdtime, local_as, &peer->local_id); + open_len = stream_get_endp(s); bbpeer->open_rx_len = open_len; if (bbpeer->open_rx) @@ -2230,6 +2236,10 @@ static void bmp_bgp_peer_vrf(struct bmp_bgp_peer *bbpeer, struct bgp *bgp) bbpeer->open_rx = XMALLOC(MTYPE_BMP_OPEN, open_len); memcpy(bbpeer->open_rx, s->data, open_len); + stream_free(s); + + s = bgp_open_make(peer, send_holdtime, bgp->as, &bgp->router_id); + open_len = stream_get_endp(s); bbpeer->open_tx_len = open_len; if (bbpeer->open_tx) XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx); diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index dc6e0d33c2..8a0c6e10d6 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -766,7 +766,7 @@ static void bgp_evpn_show_routes_mac_ip_es(struct vty *vty, esi_t *esi, if (detail) route_vty_out_detail(vty, bgp, bd, bgp_dest_get_prefix(bd), pi, AFI_L2VPN, SAFI_EVPN, RPKI_NOT_BEING_USED, - json_path, NULL); + json_path, NULL, 0); else route_vty_out(vty, &bd->rn->p, pi, 0, SAFI_EVPN, json_path, false); @@ -893,7 +893,7 @@ static void show_vni_routes(struct bgp *bgp, struct bgpevpn *vpn, if (detail) route_vty_out_detail(vty, bgp, dest, &tmp_p, pi, AFI_L2VPN, SAFI_EVPN, RPKI_NOT_BEING_USED, json_path, - NULL); + NULL, 0); else route_vty_out(vty, &tmp_p, pi, 0, SAFI_EVPN, @@ -2569,7 +2569,7 @@ static void evpn_show_route_vni_multicast(struct vty *vty, struct bgp *bgp, json_path = json_object_new_array(); route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, afi, safi, - RPKI_NOT_BEING_USED, json_path, NULL); + RPKI_NOT_BEING_USED, json_path, NULL, 0); if (json) json_object_array_add(json_paths, json_path); @@ -2697,7 +2697,7 @@ static void evpn_show_route_vni_macip(struct vty *vty, struct bgp *bgp, } route_vty_out_detail(vty, bgp, dest, (struct prefix *)&tmp_p, pi, afi, safi, - RPKI_NOT_BEING_USED, json_path, NULL); + RPKI_NOT_BEING_USED, json_path, NULL, 0); if (json) json_object_array_add(json_paths, json_path); @@ -2807,7 +2807,7 @@ static void evpn_show_route_rd_macip(struct vty *vty, struct bgp *bgp, json_path = json_object_new_array(); route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, afi, safi, - RPKI_NOT_BEING_USED, json_path, NULL); + RPKI_NOT_BEING_USED, json_path, NULL, 0); if (json) json_object_array_add(json_paths, json_path); @@ -2919,7 +2919,7 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp, json_path = json_object_new_array(); route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, afi, - safi, RPKI_NOT_BEING_USED, json_path, NULL); + safi, RPKI_NOT_BEING_USED, json_path, NULL, 0); if (json) json_object_array_add(json_paths, json_path); @@ -3055,7 +3055,7 @@ static void evpn_show_route_rd_all_macip(struct vty *vty, struct bgp *bgp, json_path = json_object_new_array(); route_vty_out_detail(vty, bgp, dest, p, pi, AFI_L2VPN, SAFI_EVPN, - RPKI_NOT_BEING_USED, json_path, NULL); + RPKI_NOT_BEING_USED, json_path, NULL, 0); if (json) json_object_array_add(json_paths, json_path); @@ -3227,7 +3227,8 @@ static void evpn_show_all_routes(struct vty *vty, struct bgp *bgp, int type, route_vty_out_detail(vty, bgp, dest, bgp_dest_get_prefix(dest), pi, AFI_L2VPN, SAFI_EVPN, - RPKI_NOT_BEING_USED, json_path, NULL); + RPKI_NOT_BEING_USED, json_path, NULL, + 0); } else route_vty_out(vty, p, pi, 0, SAFI_EVPN, json_path, false); diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 46e529f03d..6a8df3b68e 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1052,6 +1052,7 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, struct bgp_path_info *bpi_ultimate; struct bgp *bgp_nexthop; struct bgp_table *table; + struct interface *ifp; bool nh_valid; bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi); @@ -1062,6 +1063,15 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn, else bgp_nexthop = bgp_orig; + /* The nexthop is invalid if its VRF does not exist */ + if (bgp_nexthop->vrf_id == VRF_UNKNOWN) + return false; + + /* The nexthop is invalid if its VRF interface is down*/ + ifp = if_get_vrf_loopback(bgp_nexthop->vrf_id); + if (ifp && !if_is_up(ifp)) + return false; + /* * No nexthop tracking for redistributed routes, for * EVPN-imported routes that get leaked, or for routes @@ -1126,8 +1136,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, struct bgp_path_info *bpi; struct bgp_path_info *new; struct bgp_path_info_extra *extra; - struct bgp_path_info *parent = source_bpi; struct bgp_labels bgp_labels = {}; + struct bgp *bgp_nexthop; bool labelssame; uint8_t i; @@ -1159,8 +1169,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, * match parent */ for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { - if (bpi->extra && bpi->extra->vrfleak && - bpi->extra->vrfleak->parent == parent) + if (bpi->extra && bpi->extra->vrfleak && bpi->extra->vrfleak->parent == source_bpi) break; } @@ -1174,6 +1183,16 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, labelssame = bgp_path_info_labels_same(bpi, bgp_labels.label, bgp_labels.num_labels); + bgp_nexthop = bpi->extra->vrfleak->bgp_orig ?: bgp_orig; + if (bgp_nexthop->vrf_id == VRF_UNKNOWN) { + if (debug) { + zlog_debug("%s: ->%s(s_flags: 0x%x b_flags: 0x%x): %pFX: Found route, origin VRF does not exist, not leaking", + __func__, to_bgp->name_pretty, source_bpi->flags, + bpi->flags, p); + } + return NULL; + } + if (CHECK_FLAG(source_bpi->flags, BGP_PATH_REMOVED) && CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { if (debug) { @@ -1185,9 +1204,11 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, return NULL; } - if (attrhash_cmp(bpi->attr, new_attr) && labelssame - && !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) { - + if (attrhash_cmp(bpi->attr, new_attr) && labelssame && + !CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && + leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi, source_bpi, bpi, + bgp_orig, p, + debug) == !!CHECK_FLAG(bpi->flags, BGP_PATH_VALID)) { bgp_attr_unintern(&new_attr); if (debug) zlog_debug( @@ -1274,6 +1295,14 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, return NULL; } + if (bgp_orig->vrf_id == VRF_UNKNOWN) { + if (debug) { + zlog_debug("%s: ->%s(s_flags: 0x%x): %pFX: New route, origin VRF does not exist, not leaking", + __func__, to_bgp->name_pretty, source_bpi->flags, p); + } + return NULL; + } + new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_IMPORTED, 0, to_bgp->peer_self, new_attr, bn); @@ -1297,9 +1326,8 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, if (bgp_labels.num_labels) new->extra->labels = bgp_labels_intern(&bgp_labels); - new->extra->vrfleak->parent = bgp_path_info_lock(parent); - bgp_dest_lock_node( - (struct bgp_dest *)parent->net); + new->extra->vrfleak->parent = bgp_path_info_lock(source_bpi); + bgp_dest_lock_node((struct bgp_dest *)source_bpi->net); new->extra->vrfleak->bgp_orig = bgp_lock(bgp_orig); diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 7e342dba26..5ac7c7176e 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -637,7 +637,8 @@ void bgp_keepalive_send(struct peer *peer) bgp_writes_on(peer->connection); } -struct stream *bgp_open_make(struct peer *peer, uint16_t send_holdtime, as_t local_as) +struct stream *bgp_open_make(struct peer *peer, uint16_t send_holdtime, as_t local_as, + struct in_addr *id) { struct stream *s = stream_new(BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE); bool ext_opt_params = false; @@ -650,7 +651,7 @@ struct stream *bgp_open_make(struct peer *peer, uint16_t send_holdtime, as_t loc stream_putw(s, (local_as <= BGP_AS_MAX) ? (uint16_t)local_as : BGP_AS_TRANS); stream_putw(s, send_holdtime); /* Hold Time */ - stream_put_in_addr(s, &peer->local_id); /* BGP Identifier */ + stream_put_in_addr(s, id); /* BGP Identifier */ /* Set capabilities */ if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) { @@ -705,7 +706,7 @@ void bgp_open_send(struct peer_connection *connection) else local_as = peer->local_as; - s = bgp_open_make(peer, send_holdtime, local_as); + s = bgp_open_make(peer, send_holdtime, local_as, &peer->local_id); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index 866b8f617d..ae81aade70 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -49,7 +49,8 @@ DECLARE_HOOK(bgp_packet_send, /* Packet send and receive function prototypes. */ extern void bgp_keepalive_send(struct peer *peer); -extern struct stream *bgp_open_make(struct peer *peer, uint16_t send_holdtime, as_t local_as); +extern struct stream *bgp_open_make(struct peer *peer, uint16_t send_holdtime, as_t local_as, + struct in_addr *id); extern void bgp_open_send(struct peer_connection *connection); extern void bgp_notify_send(struct peer_connection *connection, uint8_t code, uint8_t sub_code); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index a1a5068a7f..36690d55f4 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10795,7 +10795,7 @@ static void route_vty_out_detail_es_info(struct vty *vty, void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, const struct prefix *p, struct bgp_path_info *path, afi_t afi, safi_t safi, enum rpki_states rpki_curr_state, json_object *json_paths, - struct attr *pattr) + struct attr *pattr, uint16_t show_opts) { char buf[INET6_ADDRSTRLEN]; char vni_buf[30] = {}; @@ -11824,6 +11824,16 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, llgr_remaining); } + /* Display internal data if asked */ + if (CHECK_FLAG(show_opts, BGP_SHOW_OPT_INTERNAL_DATA)) { + if (!json_paths) { + vty_out(vty, " net: %p, path: %p, pathext: %p, attr: %p\n", path->net, + path, path->extra, attr); + vty_out(vty, " flags net: 0x%u, path: 0x%u, attr: 0x%" PRIu64 "\n", + path->net->flags, path->flags, attr->flag); + } + } + /* Output some debug about internal state of the dest flags */ if (json_paths) { if (CHECK_FLAG(bn->flags, BGP_NODE_PROCESS_SCHEDULED)) @@ -12255,7 +12265,8 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t sa route_vty_out_detail(vty, bgp, dest, dest_p, pi, family2afi(dest_p->family), safi, - rpki_curr_state, json_paths, NULL); + rpki_curr_state, json_paths, NULL, + show_flags); } else { route_vty_out(vty, dest_p, pi, display, safi, json_paths, wide); @@ -12773,7 +12784,8 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, static void bgp_show_path_info(const struct prefix_rd *pfx_rd, struct bgp_dest *bgp_node, struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, json_object *json, enum bgp_path_type pathtype, int *display, - enum rpki_states rpki_target_state, struct attr *attr) + enum rpki_states rpki_target_state, struct attr *attr, + uint16_t show_opts) { struct bgp_path_info *pi; int header = 1; @@ -12817,7 +12829,8 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd, struct bgp_dest * && (CHECK_FLAG(pi->flags, BGP_PATH_MULTIPATH) || CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)))) route_vty_out_detail(vty, bgp, bgp_node, bgp_dest_get_prefix(bgp_node), pi, - afi, safi, rpki_curr_state, json_paths, attr); + afi, safi, rpki_curr_state, json_paths, attr, + show_opts); } if (json && json_paths) { @@ -12854,12 +12867,11 @@ const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, } /* Display specified route of BGP table. */ -static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, - struct bgp_table *rib, const char *ip_str, - afi_t afi, safi_t safi, - enum rpki_states rpki_target_state, - struct prefix_rd *prd, int prefix_check, - enum bgp_path_type pathtype, bool use_json) +static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, struct bgp_table *rib, + const char *ip_str, afi_t afi, safi_t safi, + enum rpki_states rpki_target_state, struct prefix_rd *prd, + int prefix_check, enum bgp_path_type pathtype, bool use_json, + uint16_t show_opts) { int ret; int display = 0; @@ -12904,8 +12916,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, continue; } - bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, - json, pathtype, &display, rpki_target_state, NULL); + bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, json, + pathtype, &display, rpki_target_state, NULL, show_opts); bgp_dest_unlock_node(rm); } @@ -12964,8 +12976,8 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, rm = longest_pfx; bgp_dest_lock_node(rm); - bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, - json, pathtype, &display, rpki_target_state, NULL); + bgp_show_path_info((struct prefix_rd *)dest_p, rm, vty, bgp, afi, safi, json, + pathtype, &display, rpki_target_state, NULL, show_opts); bgp_dest_unlock_node(rm); } @@ -12992,7 +13004,7 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, if (!prefix_check || dest_p->prefixlen == match.prefixlen) { bgp_show_path_info(NULL, dest, vty, bgp, afi, safi, json, pathtype, - &display, rpki_target_state, NULL); + &display, rpki_target_state, NULL, show_opts); } bgp_dest_unlock_node(dest); @@ -13012,10 +13024,10 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, } /* Display specified route of Main RIB */ -static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str, - afi_t afi, safi_t safi, struct prefix_rd *prd, - int prefix_check, enum bgp_path_type pathtype, - enum rpki_states rpki_target_state, bool use_json) +static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str, afi_t afi, + safi_t safi, struct prefix_rd *prd, int prefix_check, + enum bgp_path_type pathtype, enum rpki_states rpki_target_state, + bool use_json, uint16_t show_opts) { if (!bgp) { bgp = bgp_get_default(); @@ -13032,9 +13044,9 @@ static int bgp_show_route(struct vty *vty, struct bgp *bgp, const char *ip_str, if (safi == SAFI_LABELED_UNICAST) safi = SAFI_UNICAST; - return bgp_show_route_in_table(vty, bgp, bgp->rib[afi][safi], ip_str, - afi, safi, rpki_target_state, prd, - prefix_check, pathtype, use_json); + return bgp_show_route_in_table(vty, bgp, bgp->rib[afi][safi], ip_str, afi, safi, + rpki_target_state, prd, prefix_check, pathtype, use_json, + show_opts); } static int bgp_show_lcommunity(struct vty *vty, struct bgp *bgp, int argc, @@ -13396,7 +13408,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, |A.B.C.D/M longer-prefixes\ |X:X::X:X/M longer-prefixes\ |"BGP_SELF_ORIG_CMD_STR"\ - |detail-routes$detail_routes\ + |detail-routes$detail_routes [internal$internal]\ ] [json$uj [detail$detail_json] | wide$wide]", SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR BGP_SAFI_WITH_LABEL_HELP_STR @@ -13447,6 +13459,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, "Display route and more specific routes\n" BGP_SELF_ORIG_HELP_STR "Display detailed version of all routes\n" + "Display detailed version of all routes including internal data\n" JSON_STR "Display detailed version of JSON output\n" "Increase table width for longer prefixes\n") @@ -13475,6 +13488,9 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, if (detail_routes) SET_FLAG(show_flags, BGP_SHOW_OPT_ROUTES_DETAIL); + if (internal) + SET_FLAG(show_flags, BGP_SHOW_OPT_INTERNAL_DATA); + /* [<ipv4|ipv6> [all]] */ if (all) { SET_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL); @@ -13763,7 +13779,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, DEFUN (show_ip_bgp_route, show_ip_bgp_route_cmd, - "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> [<bestpath|multipath>] [rpki <valid|invalid|notfound>] [json]", + "show [ip] bgp [<view|vrf> VIEWVRFNAME] ["BGP_AFI_CMD_STR" ["BGP_SAFI_WITH_LABEL_CMD_STR"]]<A.B.C.D|A.B.C.D/M|X:X::X:X|X:X::X:X/M> [internal] [<bestpath|multipath>] [rpki <valid|invalid|notfound>] [json]", SHOW_STR IP_STR BGP_STR @@ -13774,6 +13790,7 @@ DEFUN (show_ip_bgp_route, "IPv4 prefix\n" "Network in the BGP routing table to display\n" "IPv6 prefix\n" + "Display internal data additionally\n" "Display only the bestpath\n" "Display only multipaths\n" "Display only paths that match the specified rpki state\n" @@ -13790,6 +13807,7 @@ DEFUN (show_ip_bgp_route, struct bgp *bgp = NULL; enum bgp_path_type path_type; bool uj = use_json(argc, argv); + uint16_t show_opts = 0; int idx = 0; @@ -13827,6 +13845,10 @@ DEFUN (show_ip_bgp_route, prefix = argv[idx]->arg; + /* Display internal data also */ + if (argv_find(argv, argc, "internal", &idx)) + SET_FLAG(show_opts, BGP_SHOW_OPT_INTERNAL_DATA); + /* [<bestpath|multipath>] */ if (argv_find(argv, argc, "bestpath", &idx)) path_type = BGP_PATH_SHOW_BESTPATH; @@ -13835,8 +13857,8 @@ DEFUN (show_ip_bgp_route, else path_type = BGP_PATH_SHOW_ALL; - return bgp_show_route(vty, bgp, prefix, afi, safi, NULL, prefix_check, - path_type, RPKI_NOT_BEING_USED, uj); + return bgp_show_route(vty, bgp, prefix, afi, safi, NULL, prefix_check, path_type, + RPKI_NOT_BEING_USED, uj, show_opts); } DEFUN (show_ip_bgp_regexp, @@ -14694,9 +14716,8 @@ DEFUN (show_ip_bgp_vpn_all_route_prefix, return CMD_WARNING; } - return bgp_show_route(vty, bgp, network, AFI_IP, SAFI_MPLS_VPN, NULL, 0, - BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, - use_json(argc, argv)); + return bgp_show_route(vty, bgp, network, AFI_IP, SAFI_MPLS_VPN, NULL, 0, BGP_PATH_SHOW_ALL, + RPKI_NOT_BEING_USED, use_json(argc, argv), 0); } #endif /* KEEP_OLD_VPN_COMMANDS */ @@ -14728,9 +14749,8 @@ DEFUN (show_bgp_l2vpn_evpn_route_prefix, vty_out(vty, "Unable to figure out Network\n"); return CMD_WARNING; } - return bgp_show_route(vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL, - prefix_check, BGP_PATH_SHOW_ALL, - RPKI_NOT_BEING_USED, use_json(argc, argv)); + return bgp_show_route(vty, NULL, network, AFI_L2VPN, SAFI_EVPN, NULL, prefix_check, + BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, use_json(argc, argv), 0); } static void show_adj_route_header(struct vty *vty, struct peer *peer, @@ -14886,8 +14906,9 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (use_json) json_net = json_object_new_object(); - bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi, safi, json_net, - BGP_PATH_SHOW_ALL, &display, RPKI_NOT_BEING_USED, NULL); + bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi, safi, + json_net, BGP_PATH_SHOW_ALL, &display, + RPKI_NOT_BEING_USED, NULL, show_flags); if (use_json) json_object_object_addf(json_ar, json_net, "%pFX", rn_p); @@ -15023,7 +15044,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, pass_in = dest; bgp_show_path_info(NULL, pass_in, vty, bgp, afi, safi, json_net, BGP_PATH_SHOW_ALL, &display, - RPKI_NOT_BEING_USED, NULL); + RPKI_NOT_BEING_USED, NULL, show_flags); if (use_json) json_object_object_addf( json_ar, json_net, @@ -15075,7 +15096,7 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, bgp_show_path_info(NULL, dest, vty, bgp, afi, safi, json_net, BGP_PATH_SHOW_ALL, &display, RPKI_NOT_BEING_USED, - adj->attr); + adj->attr, show_flags); if (use_json) json_object_object_addf(json_ar, json_net, "%pFX", rn_p); @@ -15121,9 +15142,10 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, if (use_json) json_net = json_object_new_object(); - bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, afi, - safi, json_net, BGP_PATH_SHOW_BESTPATH, - &display, RPKI_NOT_BEING_USED, NULL); + bgp_show_path_info(NULL /* prefix_rd */, dest, vty, bgp, + afi, safi, json_net, + BGP_PATH_SHOW_BESTPATH, &display, + RPKI_NOT_BEING_USED, NULL, show_flags); if (use_json) json_object_object_addf( json_ar, json_net, @@ -15767,10 +15789,9 @@ DEFUN (show_bgp_afi_vpn_rd_route, } if (!strcmp(argv[5]->arg, "all")) - return bgp_show_route(vty, NULL, argv[6]->arg, afi, - SAFI_MPLS_VPN, NULL, 0, BGP_PATH_SHOW_ALL, - RPKI_NOT_BEING_USED, - use_json(argc, argv)); + return bgp_show_route(vty, NULL, argv[6]->arg, afi, SAFI_MPLS_VPN, NULL, 0, + BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, use_json(argc, argv), + 0); ret = str2prefix_rd(argv[5]->arg, &prd); if (!ret) { @@ -15778,9 +15799,8 @@ DEFUN (show_bgp_afi_vpn_rd_route, return CMD_WARNING; } - return bgp_show_route(vty, NULL, argv[6]->arg, afi, SAFI_MPLS_VPN, &prd, - 0, BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, - use_json(argc, argv)); + return bgp_show_route(vty, NULL, argv[6]->arg, afi, SAFI_MPLS_VPN, &prd, 0, + BGP_PATH_SHOW_ALL, RPKI_NOT_BEING_USED, use_json(argc, argv), 0); } static struct bgp_distance *bgp_distance_new(void) diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index c4cbbee0c7..1f854cad19 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -752,6 +752,7 @@ DECLARE_HOOK(bgp_route_update, #define BGP_SHOW_OPT_JSON_DETAIL (1 << 7) #define BGP_SHOW_OPT_TERSE (1 << 8) #define BGP_SHOW_OPT_ROUTES_DETAIL (1 << 9) +#define BGP_SHOW_OPT_INTERNAL_DATA (1 << 10) /* Prototypes. */ extern void bgp_rib_remove(struct bgp_dest *dest, struct bgp_path_info *pi, @@ -969,7 +970,7 @@ extern void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, const struct prefix *p, struct bgp_path_info *path, afi_t afi, safi_t safi, enum rpki_states, json_object *json_paths, - struct attr *attr); + struct attr *attr, uint16_t show_opts); extern int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_table *table, struct prefix_rd *prd, enum bgp_show_type type, void *output_arg, diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 1669aabc60..84ff88be16 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2349,6 +2349,13 @@ void bgp_zebra_instance_register(struct bgp *bgp) bgp_zebra_advertise_all_vni(bgp, 1); bgp_nht_register_nexthops(bgp); + + /* + * Request SRv6 locator information from Zebra, if SRv6 is enabled + * and a locator is configured for this BGP instance. + */ + if (bgp->srv6_enabled && bgp->srv6_locator_name[0] != '\0' && !bgp->srv6_locator) + bgp_zebra_srv6_manager_get_locator(bgp->srv6_locator_name); } /* Deregister this instance with Zebra. Invoked upon the instance diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 1034e49bae..2672f38291 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -3418,17 +3418,6 @@ static struct bgp *bgp_create(as_t *as, const char *name, } bgp = XCALLOC(MTYPE_BGP, sizeof(struct bgp)); - bgp->as = *as; - if (as_pretty) - bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_pretty); - else - bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, asn_asn2asplain(*as)); - - if (asnotation != ASNOTATION_UNDEFINED) { - bgp->asnotation = asnotation; - SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION); - } else - asn_str2asn_notation(bgp->as_pretty, NULL, &bgp->asnotation); if (BGP_DEBUG(zebra, ZEBRA)) { if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) @@ -3472,6 +3461,18 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp->peer = list_new(); peer_init: + bgp->as = *as; + if (as_pretty) + bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_pretty); + else + bgp->as_pretty = XSTRDUP(MTYPE_BGP_NAME, asn_asn2asplain(*as)); + + if (asnotation != ASNOTATION_UNDEFINED) { + bgp->asnotation = asnotation; + SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION); + } else + asn_str2asn_notation(bgp->as_pretty, NULL, &bgp->asnotation); + bgp->peer->cmp = (int (*)(void *, void *))peer_cmp; bgp->peerhash = hash_create(peer_hash_key_make, peer_hash_same, "BGP Peer Hash"); diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 42f7ca84dd..a1dd799392 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -4647,7 +4647,7 @@ incoming/outgoing directions. If ``json`` option is specified, output is displayed in JSON format. -.. clicmd:: show [ip] bgp [afi] [safi] [all] detail-routes +.. clicmd:: show [ip] bgp [afi] [safi] [all] detail-routes [internal] Display the detailed version of all routes. The same format as using ``show [ip] bgp [afi] [safi] PREFIX``, but for the whole BGP table. @@ -4655,6 +4655,9 @@ incoming/outgoing directions. If ``all`` option is specified, ``ip`` keyword is ignored and, routes displayed for all AFIs and SAFIs. + ``internal`` option is used to display internal data additionally. JSON + output is not supported with this option. + If ``afi`` is specified, with ``all`` option, routes will be displayed for each SAFI in the selected AFI. diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c index 3024bb57ea..5f95fe48a4 100644 --- a/isisd/isis_nb.c +++ b/isisd/isis_nb.c @@ -561,12 +561,6 @@ const struct frr_yang_module_info frr_isisd_info = { } }, { - .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker/type", - .cbs = { - .modify = isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify, - } - }, - { .xpath = "/frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list", .cbs = { .cli_show = cli_show_isis_frr_remote_lfa_plist, @@ -598,12 +592,6 @@ const struct frr_yang_module_info frr_isisd_info = { } }, { - .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker/type", - .cbs = { - .modify = isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify, - } - }, - { .xpath = "/frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list", .cbs = { .cli_show = cli_show_isis_frr_remote_lfa_plist, diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index fb391534e2..6bd3b39bc7 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -1763,26 +1763,6 @@ int isis_instance_fast_reroute_level_1_lfa_tiebreaker_destroy( } /* - * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/lfa/tiebreaker/type - */ -int isis_instance_fast_reroute_level_1_lfa_tiebreaker_type_modify( - struct nb_cb_modify_args *args) -{ - struct lfa_tiebreaker *tie_b; - struct isis_area *area; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - tie_b = nb_running_get_entry(args->dnode, NULL, true); - area = tie_b->area; - tie_b->type = yang_dnode_get_enum(args->dnode, NULL); - lsp_regenerate_schedule(area, area->is_type, 0); - - return NB_OK; -} - -/* * XPath: /frr-isisd:isis/instance/fast-reroute/level-1/remote-lfa/prefix-list */ int isis_instance_fast_reroute_level_1_remote_lfa_prefix_list_modify( @@ -1912,26 +1892,6 @@ int isis_instance_fast_reroute_level_2_lfa_tiebreaker_destroy( } /* - * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/lfa/tiebreaker/type - */ -int isis_instance_fast_reroute_level_2_lfa_tiebreaker_type_modify( - struct nb_cb_modify_args *args) -{ - struct lfa_tiebreaker *tie_b; - struct isis_area *area; - - if (args->event != NB_EV_APPLY) - return NB_OK; - - tie_b = nb_running_get_entry(args->dnode, NULL, true); - area = tie_b->area; - tie_b->type = yang_dnode_get_enum(args->dnode, NULL); - lsp_regenerate_schedule(area, area->is_type, 0); - - return NB_OK; -} - -/* * XPath: /frr-isisd:isis/instance/fast-reroute/level-2/remote-lfa/prefix-list */ int isis_instance_fast_reroute_level_2_remote_lfa_prefix_list_modify( diff --git a/lib/event.c b/lib/event.c index 6081ba4727..8c09debf91 100644 --- a/lib/event.c +++ b/lib/event.c @@ -571,6 +571,11 @@ struct event_loop *event_master_create(const char *name) rv->spin = true; rv->handle_signals = true; + /* tardy event warnings */ + monotime(&rv->last_tardy_warning); + rv->last_tardy_warning.tv_sec -= (TARDY_WARNING_INTERVAL + TIMER_SECOND_MICRO - 1) / + TIMER_SECOND_MICRO; + /* Set pthread owner, should be updated by actual owner */ rv->owner = pthread_self(); rv->cancel_req = list_new(); @@ -770,13 +775,13 @@ static struct event *thread_get(struct event_loop *m, uint8_t type, thread->master = m; thread->arg = arg; thread->yield = EVENT_YIELD_TIME_SLOT; /* default */ + thread->tardy_threshold = 0; /* thread->ref is zeroed either by XCALLOC above or by memset before * being put on the "unuse" list by thread_add_unuse(). * Setting it here again makes coverity complain about a missing * lock :( */ /* thread->ref = NULL; */ - thread->ignore_timer_late = false; /* * So if the passed in funcname is not what we have @@ -1023,6 +1028,8 @@ static void _event_add_timer_timeval(const struct xref_eventsched *xref, return; thread = thread_get(m, EVENT_TIMER, func, arg, xref); + /* default lateness warning: 4s */ + thread->tardy_threshold = TARDY_DEFAULT_THRESHOLD; frr_with_mutex (&thread->mtx) { thread->u.sands = t; @@ -1685,34 +1692,12 @@ static void thread_process_io(struct event_loop *m, unsigned int num) static unsigned int thread_process_timers(struct event_loop *m, struct timeval *timenow) { - struct timeval prev = *timenow; - bool displayed = false; struct event *thread; unsigned int ready = 0; while ((thread = event_timer_list_first(&m->timer))) { if (timercmp(timenow, &thread->u.sands, <)) break; - prev = thread->u.sands; - prev.tv_sec += 4; - /* - * If the timer would have popped 4 seconds in the - * past then we are in a situation where we are - * really getting behind on handling of events. - * Let's log it and do the right thing with it. - */ - if (timercmp(timenow, &prev, >)) { - atomic_fetch_add_explicit( - &thread->hist->total_starv_warn, 1, - memory_order_seq_cst); - if (!displayed && !thread->ignore_timer_late) { - flog_warn( - EC_LIB_STARVE_THREAD, - "Thread Starvation: %pTHD was scheduled to pop greater than 4s ago", - thread); - displayed = true; - } - } event_timer_list_pop(&m->timer); thread->type = EVENT_READY; @@ -1946,6 +1931,29 @@ void event_getrusage(RUSAGE_T *r) #endif } +static void event_tardy_warn(struct event *thread, unsigned long since_us) +{ + char buf[64]; + struct fbuf fb = { .buf = buf, .pos = buf, .len = sizeof(buf) }; + double loadavg[3]; + int rv; + + rv = getloadavg(loadavg, array_size(loadavg)); + if (rv < 0) + bprintfrr(&fb, "not available"); + else { + for (int i = 0; i < rv; i++) { + bprintfrr(&fb, "%.2f", loadavg[i]); + if (i < rv - 1) + bputs(&fb, ", "); + } + } + + flog_warn(EC_LIB_STARVE_THREAD, + "CPU starvation: %pTHD getting executed %lums late, warning threshold %lums. System load: %pFB", + thread, (since_us + 999) / 1000, (thread->tardy_threshold + 999) / 1000, &fb); +} + /* * Call a thread. * @@ -1962,6 +1970,33 @@ void event_call(struct event *thread) RUSAGE_T before, after; bool suppress_warnings = EVENT_ARG(thread); + if (thread->tardy_threshold) { + int64_t timer_late_us = monotime_since(&thread->u.sands, NULL); + + /* Timers have a tardiness warning defaulting to 4s. + * It can be customized with event_set_tardy_threshold() + * (bfdd does that since the protocol has really short timers) + * + * If we are more than that threshold late, print a warning + * since we're running behind in calling timers (probably due + * to high system load.) + */ + if (timer_late_us > (int64_t)thread->tardy_threshold) { + int64_t since_last_warning; + struct timeval *tw; + + atomic_fetch_add_explicit(&thread->hist->total_starv_warn, 1, + memory_order_seq_cst); + + tw = &thread->master->last_tardy_warning; + since_last_warning = monotime_since(tw, NULL); + if (since_last_warning > TARDY_WARNING_INTERVAL) { + event_tardy_warn(thread, timer_late_us); + monotime(tw); + } + } + } + /* if the thread being called is the CLI, it may change cputime_enabled * ("service cputime-stats" command), which can result in nonsensical * and very confusing warnings @@ -2145,9 +2180,9 @@ static ssize_t printfrr_thread_dbg(struct fbuf *buf, struct printfrr_eargs *ea, char info[16] = ""; if (!thread) - return bputs(buf, "{(thread *)NULL}"); + return bputs(buf, "{(event *)NULL}"); - rv += bprintfrr(buf, "{(thread *)%p arg=%p", thread, thread->arg); + rv += bprintfrr(buf, "{(event *)%p arg=%p", thread, thread->arg); if (thread->type < array_size(types) && types[thread->type]) rv += bprintfrr(buf, " %-6s", types[thread->type]); diff --git a/lib/frr_pthread.c b/lib/frr_pthread.c index 3a4bc712fc..0b4d7c77ae 100644 --- a/lib/frr_pthread.c +++ b/lib/frr_pthread.c @@ -20,6 +20,7 @@ #include "zlog.h" #include "libfrr.h" #include "libfrr_trace.h" +#include "sigevent.h" DEFINE_MTYPE_STATIC(LIB, FRR_PTHREAD, "FRR POSIX Thread"); DEFINE_MTYPE_STATIC(LIB, PTHREAD_PRIM, "POSIX sync primitives"); @@ -185,10 +186,9 @@ int frr_pthread_run(struct frr_pthread *fpt, const pthread_attr_t *attr) assert(frr_is_after_fork || !"trying to start thread before fork()"); - /* Ensure we never handle signals on a background thread by blocking - * everything here (new thread inherits signal mask) - */ - sigfillset(&blocksigs); + sigemptyset(&blocksigs); + frr_sigset_add_mainonly(&blocksigs); + /* new thread inherits mask */ pthread_sigmask(SIG_BLOCK, &blocksigs, &oldsigs); frrtrace(1, frr_libfrr, frr_pthread_run, fpt->name); diff --git a/lib/frrcu.c b/lib/frrcu.c index b85c525c58..1e7ed99eff 100644 --- a/lib/frrcu.c +++ b/lib/frrcu.c @@ -42,6 +42,7 @@ #include "frrcu.h" #include "seqlock.h" #include "atomlist.h" +#include "sigevent.h" DEFINE_MTYPE_STATIC(LIB, RCU_THREAD, "RCU thread"); DEFINE_MTYPE_STATIC(LIB, RCU_NEXT, "RCU sequence barrier"); @@ -346,7 +347,19 @@ static void rcu_start(void) */ sigset_t oldsigs, blocksigs; - sigfillset(&blocksigs); + /* technically, the RCU thread is very poorly suited to run even just a + * crashlog handler, since zlog_sigsafe() could deadlock on transiently + * invalid (due to RCU) logging data structures + * + * but given that when we try to write a crashlog, we're already in + * b0rked territory anyway - give the crashlog handler a chance. + * + * (also cf. the SIGALRM usage in writing crashlogs to avoid hung + * processes on any kind of deadlock in crash handlers) + */ + sigemptyset(&blocksigs); + frr_sigset_add_mainonly(&blocksigs); + /* new thread inherits mask */ pthread_sigmask(SIG_BLOCK, &blocksigs, &oldsigs); rcu_active = true; diff --git a/lib/frrevent.h b/lib/frrevent.h index c35b39a147..61baf7919c 100644 --- a/lib/frrevent.h +++ b/lib/frrevent.h @@ -95,6 +95,7 @@ struct event_loop { bool ready_run_loop; RUSAGE_T last_getrusage; + struct timeval last_tardy_warning; }; /* Event types. */ @@ -126,11 +127,17 @@ struct event { struct timeval real; struct cpu_event_history *hist; /* cache pointer to cpu_history */ unsigned long yield; /* yield time in microseconds */ + /* lateness warning threshold, usec. 0 if it's not a timer. */ + unsigned long tardy_threshold; const struct xref_eventsched *xref; /* origin location */ pthread_mutex_t mtx; /* mutex for thread.c functions */ - bool ignore_timer_late; }; +/* rate limit late timer warnings */ +#define TARDY_WARNING_INTERVAL 10 * TIMER_SECOND_MICRO +/* default threshold for late timer warning */ +#define TARDY_DEFAULT_THRESHOLD 4 * TIMER_SECOND_MICRO + #ifdef _FRR_ATTRIBUTE_PRINTFRR #pragma FRR printfrr_ext "%pTH"(struct event *) #endif @@ -305,9 +312,17 @@ static inline bool event_is_scheduled(struct event *thread) /* Debug signal mask */ void debug_signals(const sigset_t *sigs); +/* getting called more than given microseconds late will print a warning. + * Default if not called: 4s. Don't call this on non-timers. + */ +static inline void event_set_tardy_threshold(struct event *event, unsigned long thres) +{ + event->tardy_threshold = thres; +} + static inline void event_ignore_late_timer(struct event *event) { - event->ignore_timer_late = true; + event->tardy_threshold = 0; } #ifdef __cplusplus diff --git a/lib/sigevent.h b/lib/sigevent.h index 0b07f594c1..2c51ba3767 100644 --- a/lib/sigevent.h +++ b/lib/sigevent.h @@ -45,6 +45,33 @@ bool frr_sigevent_check(sigset_t *setp); /* check whether there are signals to handle, process any found */ extern int frr_sigevent_process(void); +/* Ensure we don't handle "application-type" signals on a secondary thread by + * blocking these signals when creating threads + * + * NB: SIGSEGV, SIGABRT, etc. must be allowed on all threads or we get no + * crashlogs. Since signals vary a little bit between platforms, below is a + * list of known things to go to the main thread. Any unknown signals should + * stay thread-local. + */ +static inline void frr_sigset_add_mainonly(sigset_t *blocksigs) +{ + /* signals we actively handle */ + sigaddset(blocksigs, SIGHUP); + sigaddset(blocksigs, SIGINT); + sigaddset(blocksigs, SIGTERM); + sigaddset(blocksigs, SIGUSR1); + + /* signals we don't actively use but that semantically belong */ + sigaddset(blocksigs, SIGUSR2); + sigaddset(blocksigs, SIGQUIT); + sigaddset(blocksigs, SIGCHLD); + sigaddset(blocksigs, SIGPIPE); + sigaddset(blocksigs, SIGTSTP); + sigaddset(blocksigs, SIGTTIN); + sigaddset(blocksigs, SIGTTOU); + sigaddset(blocksigs, SIGWINCH); +} + #ifdef __cplusplus } #endif diff --git a/lib/zlog_5424.c b/lib/zlog_5424.c index 4c60d4b405..6265ce3b1f 100644 --- a/lib/zlog_5424.c +++ b/lib/zlog_5424.c @@ -782,7 +782,7 @@ static void zlog_5424_cycle(struct zlog_cfg_5424 *zcf, int fd) } old = zcf->active ? &zcf->active->zt : NULL; - old = zlog_target_replace(old, &zlt->zt); + old = zlog_target_replace(old, zlt ? &zlt->zt : NULL); zcf->active = zlt; /* oldt->fd == fd happens for zlog_5424_apply_meta() */ @@ -1076,9 +1076,17 @@ bool zlog_5424_apply_dst(struct zlog_cfg_5424 *zcf) bool zlog_5424_apply_meta(struct zlog_cfg_5424 *zcf) { + int fd; + frr_with_mutex (&zcf->cfg_mtx) { if (zcf->active) - zlog_5424_cycle(zcf, zcf->active->fd); + fd = zcf->active->fd; + else if (zcf->prio_min != ZLOG_DISABLED) + fd = zlog_5424_open(zcf, -1); + else + fd = -1; + if (fd >= 0) + zlog_5424_cycle(zcf, fd); } return true; diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c index be909c862a..564e04deba 100644 --- a/nhrpd/netlink_arp.c +++ b/nhrpd/netlink_arp.c @@ -184,7 +184,7 @@ int nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS) : (cmd == ZEBRA_NEIGH_ADDED) ? "new-neigh" : "del-neigh", &addr, ifp->name, &lladdr, ndm_state, c->used, c->cur.type); - if (cmd == ZEBRA_NEIGH_GET) { + if (cmd == ZEBRA_NEIGH_GET && ndm_state != ZEBRA_NEIGH_STATE_INCOMPLETE) { if (c->cur.type >= NHRP_CACHE_CACHED) { nhrp_cache_set_used(c, 1); debugf(NHRP_DEBUG_KERNEL, diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py index 1d7aa97473..c454c9c4a4 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py @@ -78,6 +78,13 @@ def setup_module(mod): "tcpdump -nni r1-eth0 -s 0 -w {} &".format(pcap_file), stdout=None ) + tgen.net["r2"].cmd( + """ +ip link add vrf1 type vrf table 10 +ip link set vrf1 up +""" + ) + for _, (rname, router) in enumerate(tgen.routers().items(), 1): logger.info("Loading router %s" % rname) router.load_frr_config( diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf index d3ababde3a..e3f8b242a1 100644 --- a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/frr.conf @@ -1,3 +1,7 @@ +vrf DONNA + ip route 172.16.3.0/24 10.0.0.254 +exit-vrf +! int dummy0 ip address 10.0.4.1/24 no shut @@ -28,6 +32,9 @@ ip router-id 10.0.4.1 ! router bgp 99 no bgp ebgp-requires-policy + ! 10.0.4.254 peer session will not be established + ! it is there just to activate the ipv4 vpn table + neighbor 10.0.4.254 remote-as external address-family ipv4 unicast redistribute connected rd vpn export 10.0.4.1:1 @@ -36,11 +43,14 @@ router bgp 99 export vpn import vpn ! + address-family ipv4 vpn + neighbor 10.0.4.254 activate ! router bgp 99 vrf DONNA no bgp ebgp-requires-policy address-family ipv4 unicast redistribute connected + network 172.16.3.0/24 label vpn export 101 rd vpn export 10.0.4.1:1 rt vpn export 10.0.4.1:101 diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json new file mode 100644 index 0000000000..c7ff2f4f80 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_add_zita.json @@ -0,0 +1,155 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.101.0/24": [ + { + "valid": null, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "ZITA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json new file mode 100644 index 0000000000..1797d78582 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_del_donna_prefix.json @@ -0,0 +1,103 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": null, + "172.16.101.0/24": null + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json new file mode 100644 index 0000000000..4b0eaaa052 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_eva_down.json @@ -0,0 +1,120 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": null, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": null, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.101.0/24": null + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json new file mode 100644 index 0000000000..de18bc8463 --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_init.json @@ -0,0 +1,120 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.101.0/24": null + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json new file mode 100644 index 0000000000..0c249e241e --- /dev/null +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/r1/show_bgp_ipv4_vpn_zita_up.json @@ -0,0 +1,137 @@ +{ + "routerId": "10.0.4.1", + "localAS": 99, + "routes": { + "routeDistinguishers": { + "10.0.4.1:1": { + "10.0.0.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.1.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.2.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "EVA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "10.0.4.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "incomplete", + "announceNexthopSelf": true, + "nhVrfName": "default", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.3.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "DONNA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ], + "172.16.101.0/24": [ + { + "valid": true, + "pathFrom": "external", + "path": "", + "origin": "IGP", + "announceNexthopSelf": true, + "nhVrfName": "ZITA", + "nexthops": [ + { + "ip": "0.0.0.0", + "hostname": "r1", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + } + } +} + diff --git a/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py b/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py index a44f07b560..67e53cb0cc 100644 --- a/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py +++ b/tests/topotests/bgp_vpnv4_route_leak_basic/test_bgp_vpnv4_route_leak_basic.py @@ -13,6 +13,7 @@ Test basic VPNv4 route leaking """ +import json import os import sys from functools import partial @@ -60,6 +61,22 @@ def teardown_module(mod): tgen.stop_topology() +def test_bgp_convergence(): + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + + def test_vrf_route_leak_donna(): logger.info("Ensure that routes are leaked back and forth") tgen = get_topogen() @@ -119,20 +136,20 @@ def test_vrf_route_leak_donna(): ], }, ], - "172.16.101.0/24": [ + "172.16.3.0/24": [ { - "protocol": "bgp", - "selected": None, + "protocol": "static", + "selected": True, "nexthops": [ { - "fib": None, - "interfaceName": "unknown", - "vrf": "Unknown", - "active": None, - }, + "fib": True, + "interfaceName": "dummy1", + "active": True, + } ], }, ], + "172.16.101.0/24": None, } test_func = partial( @@ -191,20 +208,21 @@ def test_vrf_route_leak_eva(): "protocol": "connected", } ], - "172.16.101.0/24": [ + "172.16.3.0/24": [ { "protocol": "bgp", - "selected": None, + "selected": True, "nexthops": [ { - "fib": None, - "interfaceName": "unknown", - "vrf": "Unknown", - "active": None, - }, + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + } ], }, ], + "172.16.101.0/24": None, } test_func = partial( @@ -258,6 +276,20 @@ def test_vrf_route_leak_default(): "protocol": "connected", } ], + "172.16.3.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + } + ], + }, + ], } test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect) @@ -298,34 +330,8 @@ interface EVA # Test DONNA VRF. expect = { - "10.0.1.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "EVA", - "vrf": "EVA", - "active": None, - }, - ], - }, - ], - "10.0.3.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "EVA", - "vrf": "EVA", - "active": None, - }, - ], - }, - ], + "10.0.1.0/24": None, + "10.0.3.0/24": None, } test_func = partial( @@ -349,6 +355,14 @@ interface EVA result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_eva_down.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + def test_vrf_route_leak_donna_after_eva_up(): logger.info("Ensure that route states change after EVA interface goes up") @@ -404,6 +418,14 @@ interface EVA result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + def test_vrf_route_leak_donna_add_vrf_zita(): logger.info("Add VRF ZITA and ensure that the route from VRF ZITA is updated") @@ -417,20 +439,7 @@ def test_vrf_route_leak_donna_add_vrf_zita(): # Test DONNA VRF. expect = { - "172.16.101.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "ZITA", - "vrf": "ZITA", - "active": None, - }, - ], - }, - ], + "172.16.101.0/24": None, } test_func = partial( @@ -439,6 +448,14 @@ def test_vrf_route_leak_donna_add_vrf_zita(): result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_add_zita.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + def test_vrf_route_leak_donna_set_zita_up(): logger.info("Set VRF ZITA up and ensure that the route from VRF ZITA is updated") @@ -480,6 +497,14 @@ interface ZITA result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_zita_up.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + def test_vrf_route_leak_donna_delete_vrf_zita(): logger.info("Delete VRF ZITA and ensure that the route from VRF ZITA is deleted") @@ -502,6 +527,101 @@ def test_vrf_route_leak_donna_delete_vrf_zita(): result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result, "BGP VRF DONNA check failed:\n{}".format(diff) + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + + +def test_vrf_route_leak_default_delete_prefix(): + logger.info( + "Remove BGP static prefix 172.16.3.0/24 from VRF DONNA and ensure that the route is deleted on default" + ) + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +router bgp 99 vrf DONNA + address-family ipv4 unicast + no network 172.16.3.0/24 +""" + ) + + # Test default VRF. + expect = { + "172.16.3.0/24": None, + } + + test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP VRF default check failed:\n{}".format(diff) + + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_del_donna_prefix.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + + +def test_vrf_route_leak_default_prefix_back(): + logger.info( + "Set back BGP static prefix 172.16.3.0/24 to VRF DONNA and ensure that the route is set on default" + ) + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + """ +configure +router bgp 99 vrf DONNA + address-family ipv4 unicast + network 172.16.3.0/24 +""" + ) + + # Test default VRF. + expect = { + "172.16.3.0/24": [ + { + "protocol": "bgp", + "selected": True, + "nexthops": [ + { + "fib": True, + "interfaceName": "DONNA", + "vrf": "DONNA", + "active": True, + } + ], + }, + ], + } + + test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP VRF default check failed:\n{}".format(diff) + + # check BGP IPv4 VPN table + json_file = "{}/{}/show_bgp_ipv4_vpn_init.json".format(CWD, r1.name) + expect = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, r1, "show bgp ipv4 vpn json", expect) + result, diff = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result, "BGP IPv4 VPN table check failed:\n{}".format(diff) + def test_memory_leak(): "Run the memory leak test and report results." diff --git a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py index 6d4b436bcc..3bc36862bf 100644 --- a/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py +++ b/tests/topotests/bgp_vrf_route_leak_basic/test_bgp-vrf-route-leak-basic.py @@ -123,20 +123,7 @@ def test_vrf_route_leak_donna(): ], }, ], - "172.16.101.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "unknown", - "vrf": "Unknown", - "active": None, - }, - ], - }, - ], + "172.16.101.0/24": None, } test_func = partial( @@ -195,20 +182,7 @@ def test_vrf_route_leak_eva(): "protocol": "connected", } ], - "172.16.101.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "unknown", - "vrf": "Unknown", - "active": None, - }, - ], - }, - ], + "172.16.101.0/24": None, } test_func = partial( @@ -302,34 +276,8 @@ interface EVA # Test DONNA VRF. expect = { - "10.0.1.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "EVA", - "vrf": "EVA", - "active": None, - }, - ], - }, - ], - "10.0.3.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "EVA", - "vrf": "EVA", - "active": None, - }, - ], - }, - ], + "10.0.1.0/24": None, + "10.0.3.0/24": None, } test_func = partial( @@ -421,20 +369,7 @@ def test_vrf_route_leak_donna_add_vrf_zita(): # Test DONNA VRF. expect = { - "172.16.101.0/24": [ - { - "protocol": "bgp", - "selected": None, - "nexthops": [ - { - "fib": None, - "interfaceName": "ZITA", - "vrf": "ZITA", - "active": None, - }, - ], - }, - ], + "172.16.101.0/24": None, } test_func = partial( diff --git a/zebra/fpm_listener.c b/zebra/fpm_listener.c index ed0842a3b1..140cfa77cf 100644 --- a/zebra/fpm_listener.c +++ b/zebra/fpm_listener.c @@ -189,7 +189,7 @@ read_fpm_msg(char *buf, size_t buf_len) fprintf(stderr, "Read %lu bytes but expected to read %lu bytes instead\n", bytes_read, need_len); - return NULL; + continue; } if (reading_full_msg) |
