From 5f6c0ba6d2aa63f41a37f595a1531527cde76340 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Fri, 6 May 2022 20:03:55 +0200 Subject: [PATCH] bgpd: resend routes deleted by kernel after interface addresses deletion When the last IPv4 address of an interface is deleted, Linux removes all routes includes BGP ones using this interface without any Netlink advertisement. bgpd keeps them in RIB as valid (e.g. installed in FIB). The previous patch invalidates the associated nexthop groups in zebra but bgpd is not notified of the event. > 2022/05/09 17:37:52.925 ZEBRA: [TQKA8-0276P] Not Notifying Owner: connected about prefix 29.0.0.0/24(40) 3 vrf: 7 Look for the bgp_path_info that are unsynchronized with the kernel and flag them for refresh in their attributes. A VPN route leaking update is calles and the refresh flag triggers a route refresh to zebra and then a kernel FIB installation. Signed-off-by: Louis Scalbert --- bgpd/bgp_attr.h | 1 + bgpd/bgp_mplsvpn.c | 1 + bgpd/bgp_zebra.c | 49 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 4eb742422d..f8beb5fba9 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -175,6 +175,7 @@ struct attr { #define BGP_ATTR_NH_VALID 0x01 #define BGP_ATTR_NH_IF_OPERSTATE 0x02 #define BGP_ATTR_NH_MP_PREFER_GLOBAL 0x04 /* MP Nexthop preference */ +#define BGP_ATTR_NH_REFRESH 0x08 /* Path origin attribute */ uint8_t origin; diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 41a00ab60b..0dce714fbd 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -1280,6 +1280,7 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn, if (debug) zlog_debug("%s: ->%s: %pBD Found route, changed attr", __func__, to_bgp->name_pretty, bn); + UNSET_FLAG(bpi->attr->nh_flag, BGP_ATTR_NH_REFRESH); return bpi; } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 82fdce3b44..952b8fcc56 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -408,10 +408,16 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) { struct listnode *node, *nnode; + struct bgp_path_info *pi; + struct bgp_table *table; + struct bgp_dest *dest; struct connected *ifc; struct peer *peer; - struct bgp *bgp; + struct bgp *bgp, *from_bgp, *bgp_default; + struct listnode *next; struct prefix *addr; + afi_t afi; + safi_t safi; bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -439,9 +445,6 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) * we do not want the peering to bounce. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - afi_t afi; - safi_t safi; - if (addr->family == AF_INET) continue; @@ -457,6 +460,44 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) } } + bgp_default = bgp_get_default(); + afi = family2afi(addr->family); + safi = SAFI_UNICAST; + + /* When the last IPv4 address was deleted, Linux removes all routes + * using the interface so that bgpd needs to re-send them. + */ + if (bgp_default && afi == AFI_IP) { + for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, from_bgp)) { + table = from_bgp->rib[afi][safi]; + if (!table) + continue; + + 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) { + if (pi->type == ZEBRA_ROUTE_BGP && + pi->attr && + pi->attr->nh_ifindex == + ifc->ifp->ifindex) { + SET_FLAG(pi->attr->nh_flag, + BGP_ATTR_NH_REFRESH); + } + } + } + + if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) + continue; + + vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi, + bgp_default, from_bgp); + + vpn_leak_postchange(BGP_VPN_POLICY_DIR_FROMVPN, afi, + bgp_default, from_bgp); + } + } + connected_free(&ifc); return 0; -- 2.39.5