]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: resend routes deleted by kernel after interface addresses deletion
authorLouis Scalbert <louis.scalbert@6wind.com>
Fri, 6 May 2022 18:03:55 +0000 (20:03 +0200)
committerLouis Scalbert <louis.scalbert@6wind.com>
Fri, 16 Dec 2022 14:07:49 +0000 (15:07 +0100)
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 <louis.scalbert@6wind.com>
bgpd/bgp_attr.h
bgpd/bgp_mplsvpn.c
bgpd/bgp_zebra.c

index 4eb742422d09d2b91eefcf9f4e3f9ae1a5dfe06c..f8beb5fba99d1a9ccaa339ca468d93e2298f98f6 100644 (file)
@@ -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;
index 41a00ab60b0ee270086e4a55641719f37744c699..0dce714fbdfc4a440647f80762cb972b138546a0 100644 (file)
@@ -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;
        }
index 82fdce3b44e648b1545bd7707a923679f6538b0b..952b8fcc56cea73012dbfc88ac8002c55b7a20ec 100644 (file)
@@ -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;