mirror of
				https://github.com/vyos/vyos-build.git
				synced 2025-10-01 20:28:40 +02:00 
			
		
		
		
	An old patch breaks connected routes in a situation when more than one IP address is presented on an interface and it switches state from down to up: ``` ip link set eth0 down ip a add 192.0.2.50/24 dev eth0 ip a add 192.0.2.51/24 dev eth0 ip link set eth0 up ``` A new version includes more backports from frr upstream, which work well regardless of an interface state.
		
			
				
	
	
		
			177 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 18b1c3c06eb69c8d10666c40f55be4926f888042 Mon Sep 17 00:00:00 2001
 | 
						|
From: zsdc <taras@vyos.io>
 | 
						|
Date: Wed, 24 May 2023 20:43:27 +0300
 | 
						|
Subject: [PATCH] zebra: Fixes for connected routes
 | 
						|
 | 
						|
This is a cumulative backport of:
 | 
						|
92980561382fc04380414a6e2f6ca6746c2fe5e9
 | 
						|
7fb9825cf7e762add68f5108df4eddda1247f198
 | 
						|
e3d901f8638dec32eac4c2690912138963ae5a05
 | 
						|
---
 | 
						|
 lib/if.h          |  3 ++
 | 
						|
 zebra/connected.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++-
 | 
						|
 2 files changed, 75 insertions(+), 1 deletion(-)
 | 
						|
 | 
						|
diff --git a/lib/if.h b/lib/if.h
 | 
						|
index a2a40d095..0c73ab63a 100644
 | 
						|
--- a/lib/if.h
 | 
						|
+++ b/lib/if.h
 | 
						|
@@ -393,6 +393,7 @@ struct connected {
 | 
						|
 #define ZEBRA_IFC_REAL         (1 << 0)
 | 
						|
 #define ZEBRA_IFC_CONFIGURED   (1 << 1)
 | 
						|
 #define ZEBRA_IFC_QUEUED       (1 << 2)
 | 
						|
+#define ZEBRA_IFC_DOWN         (1 << 3)
 | 
						|
 	/*
 | 
						|
 	   The ZEBRA_IFC_REAL flag should be set if and only if this address
 | 
						|
 	   exists in the kernel and is actually usable. (A case where it exists
 | 
						|
@@ -406,6 +407,8 @@ struct connected {
 | 
						|
 	   in the kernel. It may and should be set although the address might
 | 
						|
 	   not be
 | 
						|
 	   usable yet. (compare with ZEBRA_IFC_REAL)
 | 
						|
+	   The ZEBRA_IFC_DOWN flag is used to record that an address is
 | 
						|
+	   present, but down/unavailable.
 | 
						|
 	 */
 | 
						|
 
 | 
						|
 	/* Flags for connected address. */
 | 
						|
diff --git a/zebra/connected.c b/zebra/connected.c
 | 
						|
index 8c4ba163b..fd3fefdd2 100644
 | 
						|
--- a/zebra/connected.c
 | 
						|
+++ b/zebra/connected.c
 | 
						|
@@ -207,6 +207,9 @@ void connected_up(struct interface *ifp, struct connected *ifc)
 | 
						|
 	};
 | 
						|
 	struct zebra_vrf *zvrf;
 | 
						|
 	uint32_t metric;
 | 
						|
+	uint32_t count = 0;
 | 
						|
+	struct listnode *cnode;
 | 
						|
+	struct connected *c;
 | 
						|
 
 | 
						|
 	zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
 | 
						|
 	if (!zvrf) {
 | 
						|
@@ -219,6 +222,9 @@ void connected_up(struct interface *ifp, struct connected *ifc)
 | 
						|
 	if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
 | 
						|
 		return;
 | 
						|
 
 | 
						|
+	/* Ensure 'down' flag is cleared */
 | 
						|
+	UNSET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
 | 
						|
+
 | 
						|
 	PREFIX_COPY(&p, CONNECTED_PREFIX(ifc));
 | 
						|
 
 | 
						|
 	/* Apply mask to the network. */
 | 
						|
@@ -251,6 +257,29 @@ void connected_up(struct interface *ifp, struct connected *ifc)
 | 
						|
 
 | 
						|
 	metric = (ifc->metric < (uint32_t)METRIC_MAX) ?
 | 
						|
 				ifc->metric : ifp->metric;
 | 
						|
+
 | 
						|
+	/*
 | 
						|
+	 * It's possible to add the same network and mask
 | 
						|
+	 * to an interface over and over.  This would
 | 
						|
+	 * result in an equivalent number of connected
 | 
						|
+	 * routes.  Just add one connected route in
 | 
						|
+	 * for all the addresses on an interface that
 | 
						|
+	 * resolve to the same network and mask
 | 
						|
+	 */
 | 
						|
+	for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
 | 
						|
+		struct prefix cp;
 | 
						|
+
 | 
						|
+		PREFIX_COPY(&cp, CONNECTED_PREFIX(c));
 | 
						|
+		apply_mask(&cp);
 | 
						|
+
 | 
						|
+		if (prefix_same(&cp, &p) &&
 | 
						|
+		    !CHECK_FLAG(c->conf, ZEBRA_IFC_DOWN))
 | 
						|
+			count++;
 | 
						|
+
 | 
						|
+		if (count >= 2)
 | 
						|
+			return;
 | 
						|
+	}
 | 
						|
+
 | 
						|
 	rib_add(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
 | 
						|
 		0, 0, &p, NULL, &nh, 0, zvrf->table_id, metric, 0, 0, 0);
 | 
						|
 
 | 
						|
@@ -290,6 +319,8 @@ void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr,
 | 
						|
 	/* If we get a notification from the kernel,
 | 
						|
 	 * we can safely assume the address is known to the kernel */
 | 
						|
 	SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
 | 
						|
+	if (!if_is_operative(ifp))
 | 
						|
+		SET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
 | 
						|
 
 | 
						|
 	/* Allocate new connected address. */
 | 
						|
 	p = prefix_ipv4_new();
 | 
						|
@@ -350,12 +381,15 @@ void connected_down(struct interface *ifp, struct connected *ifc)
 | 
						|
 		.vrf_id = ifp->vrf_id,
 | 
						|
 	};
 | 
						|
 	struct zebra_vrf *zvrf;
 | 
						|
+	uint32_t count = 0;
 | 
						|
+	struct listnode *cnode;
 | 
						|
+	struct connected *c;
 | 
						|
 
 | 
						|
 	zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
 | 
						|
 	if (!zvrf) {
 | 
						|
 		flog_err(
 | 
						|
 			EC_ZEBRA_VRF_NOT_FOUND,
 | 
						|
-			"%s: Received Up for interface but no associated zvrf: %d",
 | 
						|
+			"%s: Received Down for interface but no associated zvrf: %d",
 | 
						|
 			__func__, ifp->vrf_id);
 | 
						|
 		return;
 | 
						|
 	}
 | 
						|
@@ -363,6 +397,17 @@ void connected_down(struct interface *ifp, struct connected *ifc)
 | 
						|
 	if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
 | 
						|
 		return;
 | 
						|
 
 | 
						|
+	/* Skip if we've already done this; this can happen if we have a
 | 
						|
+	 * config change that takes an interface down, then we receive kernel
 | 
						|
+	 * notifications about the downed interface and its addresses.
 | 
						|
+	 */
 | 
						|
+	if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_DOWN)) {
 | 
						|
+		if (IS_ZEBRA_DEBUG_RIB)
 | 
						|
+			zlog_debug("%s: ifc %p, %pFX already DOWN",
 | 
						|
+				   __func__, ifc, ifc->address);
 | 
						|
+		return;
 | 
						|
+	}
 | 
						|
+
 | 
						|
 	PREFIX_COPY(&p, CONNECTED_PREFIX(ifc));
 | 
						|
 
 | 
						|
 	/* Apply mask to the network. */
 | 
						|
@@ -388,6 +433,30 @@ void connected_down(struct interface *ifp, struct connected *ifc)
 | 
						|
 		break;
 | 
						|
 	}
 | 
						|
 
 | 
						|
+	/* Mark the address as 'down' */
 | 
						|
+	SET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
 | 
						|
+
 | 
						|
+	/*
 | 
						|
+	 * It's possible to have X number of addresses
 | 
						|
+	 * on a interface that all resolve to the same
 | 
						|
+	 * network and mask.  Find them and just
 | 
						|
+	 * allow the deletion when are removing the last
 | 
						|
+	 * one.
 | 
						|
+	 */
 | 
						|
+	for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) {
 | 
						|
+		struct prefix cp;
 | 
						|
+
 | 
						|
+		PREFIX_COPY(&cp, CONNECTED_PREFIX(c));
 | 
						|
+		apply_mask(&cp);
 | 
						|
+
 | 
						|
+		if (prefix_same(&p, &cp) &&
 | 
						|
+		    !CHECK_FLAG(c->conf, ZEBRA_IFC_DOWN))
 | 
						|
+			count++;
 | 
						|
+
 | 
						|
+		if (count >= 1)
 | 
						|
+			return;
 | 
						|
+	}
 | 
						|
+
 | 
						|
 	/*
 | 
						|
 	 * Same logic as for connected_up(): push the changes into the
 | 
						|
 	 * head.
 | 
						|
@@ -481,6 +550,8 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr,
 | 
						|
 	/* If we get a notification from the kernel,
 | 
						|
 	 * we can safely assume the address is known to the kernel */
 | 
						|
 	SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
 | 
						|
+	if (!if_is_operative(ifp))
 | 
						|
+		SET_FLAG(ifc->conf, ZEBRA_IFC_DOWN);
 | 
						|
 
 | 
						|
 	/* Allocate new connected address. */
 | 
						|
 	p = prefix_ipv6_new();
 | 
						|
-- 
 | 
						|
2.34.1
 | 
						|
 |