diff options
author | Daniel Baumann <daniel@debian.org> | 2024-12-24 08:33:45 +0100 |
---|---|---|
committer | Daniel Baumann <daniel@debian.org> | 2024-12-24 08:33:45 +0100 |
commit | 97216bc8112f1169e29e8450a0d406b1868a283e (patch) | |
tree | 697ed0dabc4e825248a98b855cc15bf021a08a71 /bgpd | |
parent | Releasing debian version 10.2-2. (diff) | |
download | frr-97216bc8112f1169e29e8450a0d406b1868a283e.tar.xz frr-97216bc8112f1169e29e8450a0d406b1868a283e.zip |
Merging upstream version 10.2.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to 'bgpd')
-rw-r--r-- | bgpd/bgp_bmp.c | 5 | ||||
-rw-r--r-- | bgpd/bgp_evpn.c | 44 | ||||
-rw-r--r-- | bgpd/bgp_evpn.h | 1 | ||||
-rw-r--r-- | bgpd/bgp_flowspec_vty.c | 2 | ||||
-rw-r--r-- | bgpd/bgp_fsm.c | 106 | ||||
-rw-r--r-- | bgpd/bgp_mplsvpn.c | 6 | ||||
-rw-r--r-- | bgpd/bgp_route.c | 102 | ||||
-rw-r--r-- | bgpd/bgp_rpki.c | 170 | ||||
-rw-r--r-- | bgpd/bgp_vty.c | 61 | ||||
-rw-r--r-- | bgpd/bgp_zebra.c | 7 | ||||
-rw-r--r-- | bgpd/bgpd.c | 22 | ||||
-rw-r--r-- | bgpd/bgpd.h | 1 |
12 files changed, 270 insertions, 257 deletions
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 7b67d4b8..9605c3a8 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -2434,8 +2434,11 @@ DEFPY(bmp_connect, } ba = bmp_active_get(bt, hostname, port); - if (srcif) + if (srcif) { + if (ba->ifsrc) + XFREE(MTYPE_TMP, ba->ifsrc); ba->ifsrc = XSTRDUP(MTYPE_TMP, srcif); + } if (min_retry_str) ba->minretry = min_retry; if (max_retry_str) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 0a8ce615..13483190 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -5112,6 +5112,33 @@ static void evpn_mpattr_encode_type5(struct stream *s, const struct prefix *p, } /* + * In cases such as 'no advertise-all-vni' and L2 VNI DELETE, we need to + * pop all the VPN routes present in the bgp_zebra_announce FIFO yet to + * be processed regardless of VNI is configured or not. + * + * NOTE: NO need to pop the VPN routes in two cases + * 1) In free_vni_entry + * - Called by bgp_free()->bgp_evpn_cleanup(). + * - Since bgp_delete is called before bgp_free and we pop all the dest + * pertaining to bgp under delete. + * 2) evpn_delete_vni() when user configures "no vni" since the withdraw + * of all routes happen in normal cycle. + */ +void bgp_zebra_evpn_pop_items_from_announce_fifo(struct bgpevpn *vpn) +{ + struct bgp_dest *dest = NULL; + struct bgp_dest *dest_next = NULL; + + for (dest = zebra_announce_first(&bm->zebra_announce_head); dest; dest = dest_next) { + dest_next = zebra_announce_next(&bm->zebra_announce_head, dest); + if (dest->za_vpn == vpn) { + zebra_announce_del(&bm->zebra_announce_head, dest); + bgp_path_info_unlock(dest->za_bgp_pi); + bgp_dest_unlock_node(dest); + } + } +} +/* * Cleanup specific VNI upon EVPN (advertise-all-vni) being disabled. */ static void cleanup_vni_on_disable(struct hash_bucket *bucket, struct bgp *bgp) @@ -5123,6 +5150,8 @@ static void cleanup_vni_on_disable(struct hash_bucket *bucket, struct bgp *bgp) /* Clear "live" flag and see if hash needs to be freed. */ UNSET_FLAG(vpn->flags, VNI_FLAG_LIVE); + /* Pop items from bgp_zebra_announce FIFO for any VPN routes pending*/ + bgp_zebra_evpn_pop_items_from_announce_fifo(vpn); if (!is_vni_configured(vpn)) bgp_evpn_free(bgp, vpn); } @@ -6354,19 +6383,6 @@ struct bgpevpn *bgp_evpn_new(struct bgp *bgp, vni_t vni, */ void bgp_evpn_free(struct bgp *bgp, struct bgpevpn *vpn) { - struct bgp_dest *dest = NULL; - struct bgp_dest *dest_next = NULL; - - for (dest = zebra_announce_first(&bm->zebra_announce_head); dest; - dest = dest_next) { - dest_next = zebra_announce_next(&bm->zebra_announce_head, dest); - if (dest->za_vpn == vpn) { - zebra_announce_del(&bm->zebra_announce_head, dest); - bgp_path_info_unlock(dest->za_bgp_pi); - bgp_dest_unlock_node(dest); - } - } - bgp_evpn_remote_ip_hash_destroy(vpn); bgp_evpn_vni_es_cleanup(vpn); bgpevpn_unlink_from_l3vni(vpn); @@ -7047,6 +7063,8 @@ int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni) /* Clear "live" flag and see if hash needs to be freed. */ UNSET_FLAG(vpn->flags, VNI_FLAG_LIVE); + /* Pop items from bgp_zebra_announce FIFO for any VPN routes pending*/ + bgp_zebra_evpn_pop_items_from_announce_fifo(vpn); if (!is_vni_configured(vpn)) bgp_evpn_free(bgp, vpn); diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index 10eff1dc..1a333a5a 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -199,4 +199,5 @@ bool bgp_evpn_skip_vrf_import_of_local_es(struct bgp *bgp_vrf, const struct pref struct bgp_path_info *pi, int install); int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf, const struct prefix_evpn *evp, struct bgp_path_info *parent_pi); +extern void bgp_zebra_evpn_pop_items_from_announce_fifo(struct bgpevpn *vpn); #endif /* _QUAGGA_BGP_EVPN_H */ diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index d4ccca84..3d2dda4e 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -441,7 +441,7 @@ int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, } if (total_count && !use_json) vty_out(vty, - "\nDisplayed %ld flowspec entries\n", + "\nDisplayed %ld flowspec entries\n", total_count); return CMD_SUCCESS; } diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 94fca23e..ac33e8a6 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -661,7 +661,7 @@ static void bgp_llgr_stale_timer_expire(struct event *thread) static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) { struct bgp_dest *dest; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; struct bgp_table *table; struct attr attr; @@ -676,8 +676,8 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) for (rm = bgp_table_top(table); rm; rm = bgp_route_next(rm)) - for (pi = bgp_dest_get_bgp_path_info(rm); pi; - pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(rm); + (pi != NULL) && (next = pi->next, 1); pi = next) { if (pi->peer != peer) continue; @@ -708,8 +708,8 @@ static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) } else { for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest; dest = bgp_route_next(dest)) - for (pi = bgp_dest_get_bgp_path_info(dest); pi; - pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); + (pi != NULL) && (next = pi->next, 1); pi = next) { if (pi->peer != peer) continue; @@ -2724,33 +2724,55 @@ static void bgp_gr_update_mode_of_all_peers(struct bgp *bgp, struct listnode *node = {0}; struct listnode *nnode = {0}; enum peer_mode peer_old_state = PEER_INVALID; - - /* TODO: Need to handle peer-groups. */ + struct peer_group *group; + struct peer *member; for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - peer_old_state = bgp_peer_gr_mode_get(peer); - if (peer_old_state != PEER_GLOBAL_INHERIT) - continue; + if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer_old_state = bgp_peer_gr_mode_get(peer); + if (peer_old_state != PEER_GLOBAL_INHERIT) + continue; - bgp_peer_inherit_global_gr_mode(peer, global_new_state); - bgp_peer_gr_flags_update(peer); + bgp_peer_inherit_global_gr_mode(peer, global_new_state); + bgp_peer_gr_flags_update(peer); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%pBP: Inherited Global GR mode, GR flags 0x%x peer flags 0x%" PRIx64 - "...resetting session", - peer, peer->peer_gr_new_status_flag, - peer->flags); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%pBP: Inherited Global GR mode, GR flags 0x%x peer flags 0x%" PRIx64 + "...resetting session", + peer, peer->peer_gr_new_status_flag, peer->flags); - peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; - /* Reset session to match with behavior for other peer - * configs that require the session to be re-setup. - */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) - bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_CONFIG_CHANGE); - else - bgp_session_reset_safe(peer, &nnode); + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + bgp_session_reset_safe(peer, &nnode); + } else { + group = peer->group; + for (ALL_LIST_ELEMENTS(group->peer, node, nnode, member)) { + peer_old_state = bgp_peer_gr_mode_get(member); + if (peer_old_state != PEER_GLOBAL_INHERIT) + continue; + + bgp_peer_inherit_global_gr_mode(member, global_new_state); + bgp_peer_gr_flags_update(member); + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%pBP: Inherited Global GR mode, GR flags 0x%x peer flags 0x%" PRIx64 + "...resetting session", + member, member->peer_gr_new_status_flag, + member->flags); + + member->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) + bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + bgp_session_reset(member); + } + } } } @@ -2936,6 +2958,9 @@ unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_state, { enum global_mode global_gr_mode; bool session_reset = true; + struct peer_group *group; + struct peer *member; + struct listnode *node, *nnode; if (old_state == new_state) return BGP_GR_NO_OPERATION; @@ -2970,16 +2995,27 @@ unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_state, bgp_peer_move_to_gr_mode(peer, new_state); if (session_reset) { - peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; - /* Reset session to match with behavior for other peer - * configs that require the session to be re-setup. - */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) - bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_CONFIG_CHANGE); - else - bgp_session_reset(peer); + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + bgp_session_reset(peer); + } else { + group = peer->group; + for (ALL_LIST_ELEMENTS(group->peer, node, nnode, member)) { + member->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + bgp_peer_move_to_gr_mode(member, new_state); + + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) + bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + bgp_session_reset(member); + } + } } return BGP_GR_SUCCESS; diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index df45cf23..5eca5e3e 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -2158,6 +2158,8 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ struct interface *ifp = NULL; char rd_buf[RD_ADDRSTRLEN]; struct aspath *new_aspath; + int32_t aspath_loop_count = 0; + struct peer *peer = path_vpn->peer; int debug = BGP_DEBUG(vpn, VPN_LEAK_TO_VRF); @@ -2218,7 +2220,9 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */ bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL); /* Check if leaked route has our asn. If so, don't import it. */ - if (aspath_loop_check(path_vpn->attr->aspath, to_bgp->as)) { + if (CHECK_FLAG(peer->af_flags[afi][SAFI_MPLS_VPN], PEER_FLAG_ALLOWAS_IN)) + aspath_loop_count = peer->allowas_in[afi][SAFI_MPLS_VPN]; + if (aspath_loop_check(path_vpn->attr->aspath, to_bgp->as) > aspath_loop_count) { for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) { if (bpi->extra && bpi->extra->vrfleak && diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 619252b0..0124b12c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2960,7 +2960,10 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, old_select = NULL; pi = bgp_dest_get_bgp_path_info(dest); - while (pi && CHECK_FLAG(pi->flags, BGP_PATH_UNSORTED)) { + while (pi && (CHECK_FLAG(pi->flags, BGP_PATH_UNSORTED) || + (pi->peer != bgp->peer_self && + !CHECK_FLAG(pi->peer->sflags, PEER_STATUS_NSF_WAIT) && + !peer_established(pi->peer->connection)))) { struct bgp_path_info *next = pi->next; if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) @@ -3054,6 +3057,30 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, continue; } + if (first->peer && first->peer != bgp->peer_self && + !CHECK_FLAG(first->peer->sflags, PEER_STATUS_NSF_WAIT) && + !peer_established(first->peer->connection)) { + if (debug) + zlog_debug("%s: %pBD(%s) pi %p from %s is not in established state", + __func__, dest, bgp->name_pretty, first, + first->peer->host); + + /* + * Peer is not in established state we cannot sort this + * item yet. Let's wait, so hold this one to the side + */ + if (unsorted_holddown) { + first->next = unsorted_holddown; + unsorted_holddown->prev = first; + unsorted_holddown = first; + } else + unsorted_holddown = first; + + UNSET_FLAG(first->flags, BGP_PATH_UNSORTED); + + continue; + } + bgp_path_info_unset_flag(dest, first, BGP_PATH_DMED_CHECK); worse = NULL; @@ -4406,7 +4433,7 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, uint8_t type, uint8_t stype, struct attr *attr, struct bgp_dest *dest) { - bool ret = false; + bool nh_invalid = false; bool is_bgp_static_route = (type == ZEBRA_ROUTE_BGP && stype == BGP_ROUTE_STATIC) ? true : false; @@ -4428,13 +4455,15 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, (safi != SAFI_UNICAST && safi != SAFI_MULTICAST && safi != SAFI_EVPN)) return false; - /* If NEXT_HOP is present, validate it. */ - if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { - if (attr->nexthop.s_addr == INADDR_ANY || - !ipv4_unicast_valid(&attr->nexthop) || - bgp_nexthop_self(bgp, afi, type, stype, attr, dest)) - return true; - } + /* If NEXT_HOP is present, validate it: + * The route can have both nexthop + mp_nexthop encoded as multiple NLRIs, + * and we MUST check if at least one of them is valid. + * E.g.: IPv6 prefix can be with nexthop: 0.0.0.0, and mp_nexthop: fc00::1. + */ + if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP))) + nh_invalid = (attr->nexthop.s_addr == INADDR_ANY || + !ipv4_unicast_valid(&attr->nexthop) || + bgp_nexthop_self(bgp, afi, type, stype, attr, dest)); /* If MP_NEXTHOP is present, validate it. */ /* Note: For IPv6 nexthops, we only validate the global (1st) nexthop; @@ -4449,39 +4478,31 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, switch (attr->mp_nexthop_len) { case BGP_ATTR_NHLEN_IPV4: case BGP_ATTR_NHLEN_VPNV4: - ret = (attr->mp_nexthop_global_in.s_addr == - INADDR_ANY || - !ipv4_unicast_valid( - &attr->mp_nexthop_global_in) || - bgp_nexthop_self(bgp, afi, type, stype, attr, - dest)); + nh_invalid = (attr->mp_nexthop_global_in.s_addr == INADDR_ANY || + !ipv4_unicast_valid(&attr->mp_nexthop_global_in) || + bgp_nexthop_self(bgp, afi, type, stype, attr, dest)); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL: case BGP_ATTR_NHLEN_VPNV6_GLOBAL: - ret = (IN6_IS_ADDR_UNSPECIFIED( - &attr->mp_nexthop_global) - || IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global) - || IN6_IS_ADDR_MULTICAST( - &attr->mp_nexthop_global) - || bgp_nexthop_self(bgp, afi, type, stype, attr, - dest)); + nh_invalid = (IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global) || + IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global) || + IN6_IS_ADDR_MULTICAST(&attr->mp_nexthop_global) || + bgp_nexthop_self(bgp, afi, type, stype, attr, dest)); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: - ret = (IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global) - || IN6_IS_ADDR_MULTICAST( - &attr->mp_nexthop_global) - || bgp_nexthop_self(bgp, afi, type, stype, attr, - dest)); + nh_invalid = (IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global) || + IN6_IS_ADDR_MULTICAST(&attr->mp_nexthop_global) || + bgp_nexthop_self(bgp, afi, type, stype, attr, dest)); break; default: - ret = true; + nh_invalid = true; break; } } - return ret; + return nh_invalid; } static void bgp_attr_add_no_export_community(struct attr *attr) @@ -7411,7 +7432,7 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi, { struct bgp_table *table; struct bgp_dest *dest; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; /* Do not install the aggregate route if BGP is in the * process of termination. @@ -7422,7 +7443,8 @@ static void bgp_purge_af_static_redist_routes(struct bgp *bgp, afi_t afi, table = bgp->rib[afi][safi]; for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (next = pi->next, 1); + pi = next) { if (pi->peer == bgp->peer_self && ((pi->type == ZEBRA_ROUTE_BGP && pi->sub_type == BGP_ROUTE_STATIC) @@ -7922,7 +7944,7 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, struct bgp_table *table = bgp->rib[afi][safi]; const struct prefix *dest_p; struct bgp_dest *dest, *top; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; /* We've found a different MED we must revert any suppressed routes. */ top = bgp_node_get(table, p); @@ -7932,7 +7954,8 @@ void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, if (dest_p->prefixlen <= p->prefixlen) continue; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (next = pi->next, 1); + pi = next) { if (BGP_PATH_HOLDDOWN(pi)) continue; if (pi->sub_type == BGP_ROUTE_AGGREGATE) @@ -8007,7 +8030,7 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, struct community *community = NULL; struct ecommunity *ecommunity = NULL; struct lcommunity *lcommunity = NULL; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; uint8_t atomic_aggregate = 0; /* If the bgp instance is being deleted or self peer is deleted @@ -8057,7 +8080,8 @@ bool bgp_aggregate_route(struct bgp *bgp, const struct prefix *p, afi_t afi, if (!bgp_check_advertise(bgp, dest, safi)) continue; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (next = pi->next, 1); + pi = next) { if (BGP_PATH_HOLDDOWN(pi)) continue; @@ -8215,7 +8239,7 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, struct bgp_table *table; struct bgp_dest *top; struct bgp_dest *dest; - struct bgp_path_info *pi; + struct bgp_path_info *pi, *next; table = bgp->rib[afi][safi]; @@ -8228,7 +8252,8 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, if (dest_p->prefixlen <= p->prefixlen) continue; - for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + for (pi = bgp_dest_get_bgp_path_info(dest); (pi != NULL) && (next = pi->next, 1); + pi = next) { if (BGP_PATH_HOLDDOWN(pi)) continue; @@ -12321,8 +12346,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, } else { if (incremental_print) { vty_out(vty, "\"prefix\": \"%pFX\",\n", p); - vty_out(vty, "\"version\": \"%" PRIu64 "\",", - dest->version); + vty_out(vty, "\"version\": %" PRIu64 ",", dest->version); } else { json_object_string_addf(json, "prefix", "%pFX", p); diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 347c5d02..04a709b3 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -155,7 +155,6 @@ static enum route_map_cmd_result_t route_match(void *rule, void *object); static void *route_match_compile(const char *arg); static void revalidate_bgp_node(struct bgp_dest *dest, afi_t afi, safi_t safi); -static void revalidate_all_routes(struct rpki_vrf *rpki_vrf); static bool rpki_debug_conf, rpki_debug_term; @@ -586,48 +585,10 @@ static void rpki_revalidate_prefix(struct event *thread) XFREE(MTYPE_BGP_RPKI_REVALIDATE, rrp); } -static void bgpd_sync_callback(struct event *thread) +static void revalidate_single_prefix(struct vrf *vrf, struct prefix prefix, afi_t afi) { struct bgp *bgp; struct listnode *node; - struct prefix prefix; - struct pfx_record rec; - struct rpki_vrf *rpki_vrf = EVENT_ARG(thread); - struct vrf *vrf = NULL; - - event_add_read(bm->master, bgpd_sync_callback, rpki_vrf, - rpki_vrf->rpki_sync_socket_bgpd, NULL); - - if (atomic_load_explicit(&rpki_vrf->rtr_update_overflow, - memory_order_seq_cst)) { - while (read(rpki_vrf->rpki_sync_socket_bgpd, &rec, - sizeof(struct pfx_record)) != -1) - ; - - atomic_store_explicit(&rpki_vrf->rtr_update_overflow, 0, - memory_order_seq_cst); - revalidate_all_routes(rpki_vrf); - return; - } - - int retval = read(rpki_vrf->rpki_sync_socket_bgpd, &rec, - sizeof(struct pfx_record)); - if (retval != sizeof(struct pfx_record)) { - RPKI_DEBUG("Could not read from rpki_sync_socket_bgpd"); - return; - } - pfx_record_to_prefix(&rec, &prefix); - - afi_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6; - - if (rpki_vrf->vrfname) { - vrf = vrf_lookup_by_name(rpki_vrf->vrfname); - if (!vrf) { - zlog_err("%s(): vrf for rpki %s not found", __func__, - rpki_vrf->vrfname); - return; - } - } for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { safi_t safi; @@ -655,101 +616,76 @@ static void bgpd_sync_callback(struct event *thread) } } -static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi, - safi_t safi) +static void bgpd_sync_callback(struct event *thread) { - struct bgp_adj_in *ain; - mpls_label_t *label; - uint8_t num_labels; - - for (ain = bgp_dest->adj_in; ain; ain = ain->next) { - struct bgp_path_info *path = - bgp_dest_get_bgp_path_info(bgp_dest); - - num_labels = BGP_PATH_INFO_NUM_LABELS(path); - label = num_labels ? path->extra->labels->label : NULL; - - (void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest), - ain->addpath_rx_id, ain->attr, afi, safi, - ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, label, - num_labels, 1, NULL); - } -} - -/* - * The act of a soft reconfig in revalidation is really expensive - * coupled with the fact that the download of a full rpki state - * from a rpki server can be expensive, let's break up the revalidation - * to a point in time in the future to allow other bgp events - * to take place too. - */ -struct rpki_revalidate_peer { + struct prefix prefix; + struct pfx_record rec; + struct rpki_vrf *rpki_vrf = EVENT_ARG(thread); + struct vrf *vrf = NULL; afi_t afi; - safi_t safi; - struct peer *peer; -}; + int retval; -static void bgp_rpki_revalidate_peer(struct event *thread) -{ - struct rpki_revalidate_peer *rvp = EVENT_ARG(thread); - - /* - * Here's the expensive bit of gnomish deviousness - */ - bgp_soft_reconfig_in(rvp->peer, rvp->afi, rvp->safi); - - XFREE(MTYPE_BGP_RPKI_REVALIDATE, rvp); -} - -static void revalidate_all_routes(struct rpki_vrf *rpki_vrf) -{ - struct bgp *bgp; - struct listnode *node; - struct vrf *vrf = NULL; + event_add_read(bm->master, bgpd_sync_callback, rpki_vrf, rpki_vrf->rpki_sync_socket_bgpd, + NULL); if (rpki_vrf->vrfname) { vrf = vrf_lookup_by_name(rpki_vrf->vrfname); if (!vrf) { - zlog_err("%s(): vrf for rpki %s not found", __func__, - rpki_vrf->vrfname); + zlog_err("%s(): vrf for rpki %s not found", __func__, rpki_vrf->vrfname); return; } } - for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) { - struct peer *peer; - struct listnode *peer_listnode; + if (atomic_load_explicit(&rpki_vrf->rtr_update_overflow, memory_order_seq_cst)) { + ssize_t size = 0; - if (!vrf && bgp->vrf_id != VRF_DEFAULT) - continue; - if (vrf && bgp->vrf_id != vrf->vrf_id) - continue; + retval = read(rpki_vrf->rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record)); + while (retval != -1) { + if (retval != sizeof(struct pfx_record)) + break; - for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) { - afi_t afi; - safi_t safi; + size += retval; + pfx_record_to_prefix(&rec, &prefix); + afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6; + revalidate_single_prefix(vrf, prefix, afi); - FOREACH_AFI_SAFI (afi, safi) { - struct rpki_revalidate_peer *rvp; + retval = read(rpki_vrf->rpki_sync_socket_bgpd, &rec, + sizeof(struct pfx_record)); + } - if (!bgp->rib[afi][safi]) - continue; + RPKI_DEBUG("Socket overflow detected (%zu), revalidating affected prefixes", size); - if (!peer_established(peer->connection)) - continue; + atomic_store_explicit(&rpki_vrf->rtr_update_overflow, 0, memory_order_seq_cst); + return; + } - rvp = XCALLOC(MTYPE_BGP_RPKI_REVALIDATE, - sizeof(*rvp)); - rvp->peer = peer; - rvp->afi = afi; - rvp->safi = safi; + retval = read(rpki_vrf->rpki_sync_socket_bgpd, &rec, sizeof(struct pfx_record)); + if (retval != sizeof(struct pfx_record)) { + RPKI_DEBUG("Could not read from rpki_sync_socket_bgpd"); + return; + } + pfx_record_to_prefix(&rec, &prefix); - event_add_event( - bm->master, bgp_rpki_revalidate_peer, - rvp, 0, - &peer->t_revalidate_all[afi][safi]); - } - } + afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6; + + revalidate_single_prefix(vrf, prefix, afi); +} + +static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi, safi_t safi) +{ + struct bgp_adj_in *ain; + mpls_label_t *label; + uint8_t num_labels; + + for (ain = bgp_dest->adj_in; ain; ain = ain->next) { + struct bgp_path_info *path = bgp_dest_get_bgp_path_info(bgp_dest); + + num_labels = BGP_PATH_INFO_NUM_LABELS(path); + label = num_labels ? path->extra->labels->label : NULL; + + (void)bgp_update(ain->peer, bgp_dest_get_prefix(bgp_dest), ain->addpath_rx_id, + ain->attr, afi, safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, NULL, + label, num_labels, 1, NULL); } } diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 68ced14d..0f963175 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -3517,11 +3517,6 @@ DEFUN (bgp_neighbor_graceful_restart_set, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - vty_out(vty, - "Per peer-group graceful-restart configuration is not yet supported\n"); - return CMD_WARNING_CONFIG_FAILED; - } result = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD); if (result == BGP_GR_SUCCESS) { @@ -3552,11 +3547,6 @@ DEFUN (no_bgp_neighbor_graceful_restart, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - vty_out(vty, - "Per peer-group graceful-restart configuration is not yet supported\n"); - return CMD_WARNING_CONFIG_FAILED; - } result = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3586,11 +3576,6 @@ DEFUN (bgp_neighbor_graceful_restart_helper_set, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - vty_out(vty, - "Per peer-group graceful-restart configuration is not yet supported\n"); - return CMD_WARNING_CONFIG_FAILED; - } ret = bgp_neighbor_graceful_restart(peer, PEER_HELPER_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3621,11 +3606,6 @@ DEFUN (no_bgp_neighbor_graceful_restart_helper, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - vty_out(vty, - "Per peer-group graceful-restart configuration is not yet supported\n"); - return CMD_WARNING_CONFIG_FAILED; - } ret = bgp_neighbor_graceful_restart(peer, NO_PEER_HELPER_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3655,11 +3635,6 @@ DEFUN (bgp_neighbor_graceful_restart_disable_set, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - vty_out(vty, - "Per peer-group graceful-restart configuration is not yet supported\n"); - return CMD_WARNING_CONFIG_FAILED; - } ret = bgp_neighbor_graceful_restart(peer, PEER_DISABLE_CMD); if (ret == BGP_GR_SUCCESS) { @@ -3691,11 +3666,6 @@ DEFUN (no_bgp_neighbor_graceful_restart_disable, peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg); if (!peer) return CMD_WARNING_CONFIG_FAILED; - if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - vty_out(vty, - "Per peer-group graceful-restart configuration is not yet supported\n"); - return CMD_WARNING_CONFIG_FAILED; - } ret = bgp_neighbor_graceful_restart(peer, NO_PEER_DISABLE_CMD); if (ret == BGP_GR_SUCCESS) { @@ -5273,7 +5243,7 @@ DEFUN (neighbor_peer_group, DEFUN (no_neighbor, no_neighbor_cmd, - "no neighbor <WORD|<A.B.C.D|X:X::X:X> [remote-as <(1-4294967295)|internal|external|auto>]>", + "no neighbor <WORD|<A.B.C.D|X:X::X:X> [remote-as <ASNUM|internal|external|auto>]>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 @@ -5352,7 +5322,7 @@ DEFUN (no_neighbor, DEFUN (no_neighbor_interface_config, no_neighbor_interface_config_cmd, - "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <(1-4294967295)|internal|external|auto>]", + "no neighbor WORD interface [v6only] [peer-group PGNAME] [remote-as <ASNUM|internal|external|auto>]", NO_STR NEIGHBOR_STR "Interface name\n" @@ -9846,6 +9816,8 @@ DEFPY (af_rd_vpn_export, bgp_get_default(), bgp); if (yes) { + if (bgp->vpn_policy[afi].tovpn_rd_pretty) + XFREE(MTYPE_BGP_NAME, bgp->vpn_policy[afi].tovpn_rd_pretty); bgp->vpn_policy[afi].tovpn_rd_pretty = XSTRDUP(MTYPE_BGP_NAME, rd_str); bgp->vpn_policy[afi].tovpn_rd = prd; @@ -14935,22 +14907,31 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) || CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) { if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV) && - CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) + CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) { json_object_string_add( json_cap, "gracefulRestart", "advertisedAndReceived"); - else if (CHECK_FLAG(p->cap, - PEER_CAP_RESTART_ADV)) + } else if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) { + json_object_string_add(json_cap, "gracefulRestart", + "advertised"); +#if CONFDATE > 20250525 +CPP_NOTICE("Remove `gracefulRestartCapability` JSON field") +#endif json_object_string_add( json_cap, "gracefulRestartCapability", "advertised"); - else if (CHECK_FLAG(p->cap, - PEER_CAP_RESTART_RCV)) + } else if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) { + json_object_string_add(json_cap, "gracefulRestart", + "received"); +#if CONFDATE > 20250525 +CPP_NOTICE("Remove `gracefulRestartCapability` JSON field") +#endif json_object_string_add( json_cap, "gracefulRestartCapability", "received"); + } if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) { int restart_af_count = 0; @@ -18831,7 +18812,11 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, /* enforce-first-as */ if (CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS)) { - if (!peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) + /* The `no` form is printed because by default this enforcing + * is enabled, thus we need to print it inverted. + * See peer_new(). + */ + if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) vty_out(vty, " no neighbor %s enforce-first-as\n", addr); } else { if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 9053df31..64994715 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1187,9 +1187,10 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp, ifindex = pi->peer->nexthop.ifp->ifindex; if (!ifindex) { - if (pi->peer->conf_if) - ifindex = pi->peer->ifp->ifindex; - else if (pi->peer->ifname) + if (pi->peer->conf_if) { + if (pi->peer->ifp) + ifindex = pi->peer->ifp->ifindex; + } else if (pi->peer->ifname) ifindex = ifname2ifindex( pi->peer->ifname, pi->peer->bgp->vrf_id); diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 58183818..80e70219 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -462,6 +462,10 @@ void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set) if (bgp->inst_type == BGP_INSTANCE_TYPE_VIEW) return; + /* Do nothing if already in a desired state */ + if (set == !!CHECK_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_FIB_PENDING)) + return; + if (set) { SET_FLAG(bgp->flags, BGP_FLAG_SUPPRESS_FIB_PENDING); /* Send msg to zebra for the first instance of bgp enabled @@ -1251,8 +1255,6 @@ static void peer_free(struct peer *peer) bgp_reads_off(peer->connection); bgp_writes_off(peer->connection); event_cancel_event_ready(bm->master, peer->connection); - FOREACH_AFI_SAFI (afi, safi) - EVENT_OFF(peer->t_revalidate_all[afi][safi]); assert(!peer->connection->t_write); assert(!peer->connection->t_read); @@ -1592,8 +1594,13 @@ struct peer *peer_new(struct bgp *bgp) SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); - if (CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS)) - peer_flag_set(peer, PEER_FLAG_ENFORCE_FIRST_AS); + /* By default this is enabled, thus we need to mark it as + * inverted in order to display correctly in the configuration. + */ + if (CHECK_FLAG(bgp->flags, BGP_FLAG_ENFORCE_FIRST_AS)) { + SET_FLAG(peer->flags_invert, PEER_FLAG_ENFORCE_FIRST_AS); + SET_FLAG(peer->flags, PEER_FLAG_ENFORCE_FIRST_AS); + } if (CHECK_FLAG(bgp->flags, BGP_FLAG_SOFT_VERSION_CAPABILITY)) peer_flag_set(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION); @@ -2191,8 +2198,7 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, /* When this peer is a member of peer-group. */ if (peer->group) { /* peer-group already has AS number/internal/external */ - if (peer->group->conf->as - || peer->group->conf->as_type) { + if (peer->group->conf->as || peer->group->conf->as_type != AS_UNSPECIFIED) { /* Return peer group's AS number. */ *as = peer->group->conf->as; return BGP_ERR_PEER_GROUP_MEMBER; @@ -2720,8 +2726,6 @@ int peer_delete(struct peer *peer) bgp_reads_off(peer->connection); bgp_writes_off(peer->connection); event_cancel_event_ready(bm->master, peer->connection); - FOREACH_AFI_SAFI (afi, safi) - EVENT_OFF(peer->t_revalidate_all[afi][safi]); assert(!CHECK_FLAG(peer->connection->thread_flags, PEER_THREAD_WRITES_ON)); assert(!CHECK_FLAG(peer->connection->thread_flags, @@ -2902,6 +2906,7 @@ struct peer_group *peer_group_get(struct bgp *bgp, const char *name) group->conf->host = XSTRDUP(MTYPE_BGP_PEER_HOST, name); group->conf->group = group; group->conf->as = 0; + group->conf->as_type = AS_UNSPECIFIED; group->conf->ttl = BGP_DEFAULT_TTL; group->conf->gtsm_hops = BGP_GTSM_HOPS_DISABLED; group->conf->v_routeadv = BGP_DEFAULT_EBGP_ROUTEADV; @@ -3023,6 +3028,7 @@ static void peer_group2peer_config_copy(struct peer_group *group, PEER_ATTR_INHERIT(peer, group, local_role); /* Update GR flags for the peer. */ + PEER_ATTR_INHERIT(peer, group, peer_gr_new_status_flag); bgp_peer_gr_flags_update(peer); /* Apply BFD settings from group to peer if it exists. */ diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 8aeb0eb4..f9c4e7e9 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1646,7 +1646,6 @@ struct peer { /* Threads. */ struct event *t_llgr_stale[AFI_MAX][SAFI_MAX]; - struct event *t_revalidate_all[AFI_MAX][SAFI_MAX]; struct event *t_refresh_stalepath; /* Thread flags. */ |