Index | Thread | Search

From:
Alexander Bluhm <bluhm@openbsd.org>
Subject:
route cache and mpath
To:
tech@openbsd.org
Date:
Tue, 26 Mar 2024 20:25:37 +0100

Download raw body.

Thread
  • Alexander Bluhm:

    route cache and mpath

Hi,

I would like to recommit the route_mpath() diff that was backed out
before 7.5 release.  An additional rtisvalid() check has caused
problems when the interface link was not up.  I just removed that
and now the diff should not change behavior.

Combine route_cache() and rtalloc_mpath() in new route_mpath().

Fill and check the cache and call rtalloc_mpath() together.  Then
the caller of route_mpath() does not have to care about the uint32_t
*src pointer and just pass struct in_addr.  All the conversions are
done inside the functions.

ok?

bluhm

Index: net/route.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/route.c,v
diff -u -p -r1.435 route.c
--- net/route.c	29 Feb 2024 12:01:59 -0000	1.435
+++ net/route.c	26 Mar 2024 19:17:12 -0000
@@ -239,6 +239,24 @@ route_cache(struct route *ro, const stru
 	return (ESRCH);
 }
 
+/*
+ * Check cache for route, else allocate a new one, potentially using multipath
+ * to select the peer.  Update cache and return valid route or NULL.
+ */
+struct rtentry *
+route_mpath(struct route *ro, const struct in_addr *dst,
+    const struct in_addr *src, u_int rtableid)
+{
+	if (route_cache(ro, dst, src, rtableid)) {
+		uint32_t *s = NULL;
+
+		if (ro->ro_srcin.s_addr != INADDR_ANY)
+			s = &ro->ro_srcin.s_addr;
+		ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, s, ro->ro_tableid);
+	}
+	return (ro->ro_rt);
+}
+
 #ifdef INET6
 int
 route6_cache(struct route *ro, const struct in6_addr *dst,
@@ -276,6 +294,20 @@ route6_cache(struct route *ro, const str
 		ro->ro_srcin6 = *src;
 
 	return (ESRCH);
+}
+
+struct rtentry *
+route6_mpath(struct route *ro, const struct in6_addr *dst,
+    const struct in6_addr *src, u_int rtableid)
+{
+	if (route6_cache(ro, dst, src, rtableid)) {
+		uint32_t *s = NULL;
+
+		if (!IN6_IS_ADDR_UNSPECIFIED(&ro->ro_srcin6))
+			s = &ro->ro_srcin6.s6_addr32[0];
+		ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, s, ro->ro_tableid);
+	}
+	return (ro->ro_rt);
 }
 #endif
 
Index: net/route.h
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/net/route.h,v
diff -u -p -r1.209 route.h
--- net/route.h	29 Feb 2024 12:01:59 -0000	1.209
+++ net/route.h	26 Mar 2024 19:17:12 -0000
@@ -465,7 +465,11 @@ struct bfd_config;
 void	 route_init(void);
 int	 route_cache(struct route *, const struct in_addr *,
 	    const struct in_addr *, u_int);
+struct rtentry *route_mpath(struct route *, const struct in_addr *,
+	    const struct in_addr *, u_int);
 int	 route6_cache(struct route *, const struct in6_addr *,
+	    const struct in6_addr *, u_int);
+struct rtentry *route6_mpath(struct route *, const struct in6_addr *,
 	    const struct in6_addr *, u_int);
 void	 rtm_ifchg(struct ifnet *);
 void	 rtm_ifannounce(struct ifnet *, int);
Index: netinet/in_pcb.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet/in_pcb.c,v
diff -u -p -r1.298 in_pcb.c
--- netinet/in_pcb.c	22 Mar 2024 21:48:38 -0000	1.298
+++ netinet/in_pcb.c	26 Mar 2024 19:17:12 -0000
@@ -904,23 +904,15 @@ in_pcblookup_local_lock(struct inpcbtabl
 struct rtentry *
 in_pcbrtentry(struct inpcb *inp)
 {
-	struct route *ro;
-
 #ifdef INET6
 	if (ISSET(inp->inp_flags, INP_IPV6))
 		return in6_pcbrtentry(inp);
 #endif
 
-	ro = &inp->inp_route;
-
 	if (inp->inp_faddr.s_addr == INADDR_ANY)
 		return (NULL);
-	if (route_cache(ro, &inp->inp_faddr, &inp->inp_laddr,
-	    inp->inp_rtableid)) {
-		ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa,
-		    &inp->inp_laddr.s_addr, ro->ro_tableid);
-	}
-	return (ro->ro_rt);
+	return (route_mpath(&inp->inp_route, &inp->inp_faddr, &inp->inp_laddr,
+	    inp->inp_rtableid));
 }
 
 /*
@@ -934,7 +926,7 @@ in_pcbselsrc(struct in_addr *insrc, stru
     struct inpcb *inp)
 {
 	struct ip_moptions *mopts = inp->inp_moptions;
-	struct route *ro = &inp->inp_route;
+	struct rtentry *rt;
 	const struct in_addr *laddr = &inp->inp_laddr;
 	u_int rtableid = inp->inp_rtableid;
 	struct sockaddr	*ip4_source = NULL;
@@ -979,17 +971,14 @@ in_pcbselsrc(struct in_addr *insrc, stru
 	 * If route is known or can be allocated now,
 	 * our src addr is taken from the i/f, else punt.
 	 */
-	if (route_cache(ro, &sin->sin_addr, NULL, rtableid)) {
-		/* No route yet, so try to acquire one */
-		ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, NULL, ro->ro_tableid);
-	}
+	rt = route_mpath(&inp->inp_route, &sin->sin_addr, NULL, rtableid);
 
 	/*
 	 * If we found a route, use the address
 	 * corresponding to the outgoing interface.
 	 */
-	if (ro->ro_rt != NULL)
-		ia = ifatoia(ro->ro_rt->rt_ifa);
+	if (rt != NULL)
+		ia = ifatoia(rt->rt_ifa);
 
 	/*
 	 * Use preferred source address if :
@@ -997,8 +986,8 @@ in_pcbselsrc(struct in_addr *insrc, stru
 	 * - preferred source address is set
 	 * - output interface is UP
 	 */
-	if (ro->ro_rt && !(ro->ro_rt->rt_flags & RTF_LLINFO) &&
-	    !(ro->ro_rt->rt_flags & RTF_HOST)) {
+	if (rt != NULL && !(rt->rt_flags & RTF_LLINFO) &&
+	    !(rt->rt_flags & RTF_HOST)) {
 		ip4_source = rtable_getsource(rtableid, AF_INET);
 		if (ip4_source != NULL) {
 			struct ifaddr *ifa;
Index: netinet6/in6_pcb.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/in6_pcb.c,v
diff -u -p -r1.142 in6_pcb.c
--- netinet6/in6_pcb.c	22 Mar 2024 18:05:01 -0000	1.142
+++ netinet6/in6_pcb.c	26 Mar 2024 19:17:12 -0000
@@ -561,16 +561,10 @@ in6_pcbnotify(struct inpcbtable *table, 
 struct rtentry *
 in6_pcbrtentry(struct inpcb *inp)
 {
-	struct route *ro = &inp->inp_route;
-
 	if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6))
 		return (NULL);
-	if (route6_cache(ro, &inp->inp_faddr6, &inp->inp_laddr6,
-	    inp->inp_rtableid)) {
-		ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa,
-		    &inp->inp_laddr6.s6_addr32[0], ro->ro_tableid);
-	}
-	return (ro->ro_rt);
+	return (route6_mpath(&inp->inp_route, &inp->inp_faddr6,
+	    &inp->inp_laddr6, inp->inp_rtableid));
 }
 
 struct inpcb *
Index: netinet6/in6_src.c
===================================================================
RCS file: /data/mirror/openbsd/cvs/src/sys/netinet6/in6_src.c,v
diff -u -p -r1.97 in6_src.c
--- netinet6/in6_src.c	29 Feb 2024 12:01:59 -0000	1.97
+++ netinet6/in6_src.c	26 Mar 2024 19:17:12 -0000
@@ -95,7 +95,7 @@ in6_pcbselsrc(const struct in6_addr **in
     struct inpcb *inp, struct ip6_pktopts *opts)
 {
 	struct ip6_moptions *mopts = inp->inp_moptions6;
-	struct route *ro = &inp->inp_route;
+	struct rtentry *rt;
 	const struct in6_addr *laddr = &inp->inp_laddr6;
 	u_int rtableid = inp->inp_rtableid;
 	struct ifnet *ifp = NULL;
@@ -118,7 +118,8 @@ in6_pcbselsrc(const struct in6_addr **in
 		struct sockaddr_in6 sa6;
 
 		/* get the outgoing interface */
-		error = in6_selectif(dst, opts, mopts, ro, &ifp, rtableid);
+		error = in6_selectif(dst, opts, mopts, &inp->inp_route, &ifp,
+		    rtableid);
 		if (error)
 			return (error);
 
@@ -179,9 +180,7 @@ in6_pcbselsrc(const struct in6_addr **in
 	 * If route is known or can be allocated now,
 	 * our src addr is taken from the i/f, else punt.
 	 */
-	if (route6_cache(ro, dst, NULL, rtableid)) {
-		ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, NULL, ro->ro_tableid);
-	}
+	rt = route6_mpath(&inp->inp_route, dst, NULL, rtableid);
 
 	/*
 	 * in_pcbconnect() checks out IFF_LOOPBACK to skip using
@@ -190,14 +189,14 @@ in6_pcbselsrc(const struct in6_addr **in
 	 * so doesn't check out IFF_LOOPBACK.
 	 */
 
-	if (ro->ro_rt) {
-		ifp = if_get(ro->ro_rt->rt_ifidx);
+	if (rt != NULL) {
+		ifp = if_get(rt->rt_ifidx);
 		if (ifp != NULL) {
 			ia6 = in6_ifawithscope(ifp, dst, rtableid);
 			if_put(ifp);
 		}
 		if (ia6 == NULL) /* xxx scope error ?*/
-			ia6 = ifatoia6(ro->ro_rt->rt_ifa);
+			ia6 = ifatoia6(rt->rt_ifa);
 	}
 
 	/*
@@ -206,8 +205,8 @@ in6_pcbselsrc(const struct in6_addr **in
 	 * - preferred source address is set
 	 * - output interface is UP
 	 */
-	if (ro->ro_rt && !(ro->ro_rt->rt_flags & RTF_LLINFO) &&
-	    !(ro->ro_rt->rt_flags & RTF_HOST)) {
+	if (rt != NULL && !(rt->rt_flags & RTF_LLINFO) &&
+	    !(rt->rt_flags & RTF_HOST)) {
 		ip6_source = rtable_getsource(rtableid, AF_INET6);
 		if (ip6_source != NULL) {
 			struct ifaddr *ifa;
@@ -304,11 +303,9 @@ in6_selectroute(const struct in6_addr *d
 	 * a new one.
 	 */
 	if (ro) {
-		if (route6_cache(ro, dst, NULL, rtableid)) {
-			/* No route yet, so try to acquire one */
-			ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, NULL,
-			    ro->ro_tableid);
-		}
+		struct rtentry *rt;
+
+		rt = route6_mpath(ro, dst, NULL, rtableid);
 
 		/*
 		 * Check if the outgoing interface conflicts with
@@ -319,15 +316,13 @@ in6_selectroute(const struct in6_addr *d
 		 */
 		if (opts && opts->ip6po_pktinfo &&
 		    opts->ip6po_pktinfo->ipi6_ifindex) {
-			if (ro->ro_rt != NULL &&
-			    !ISSET(ro->ro_rt->rt_flags, RTF_LOCAL) &&
-			    ro->ro_rt->rt_ifidx !=
-			    opts->ip6po_pktinfo->ipi6_ifindex) {
+			if (rt != NULL && !ISSET(rt->rt_flags, RTF_LOCAL) &&
+			    rt->rt_ifidx != opts->ip6po_pktinfo->ipi6_ifindex) {
 			    	return (NULL);
 			}
 		}
 
-		return (ro->ro_rt);
+		return (rt);
 	}
 
 	return (NULL);
@@ -338,7 +333,7 @@ in6_selectif(const struct in6_addr *dst,
     struct ip6_moptions *mopts, struct route *ro, struct ifnet **retifp,
     u_int rtableid)
 {
-	struct rtentry *rt = NULL;
+	struct rtentry *rt;
 	struct in6_pktinfo *pi = NULL;
 
 	/* If the caller specify the outgoing interface explicitly, use it. */
@@ -377,11 +372,10 @@ in6_selectif(const struct in6_addr *dst,
 	 * Although this may not be very harmful, it should still be confusing.
 	 * We thus reject the case here.
 	 */
-	if (rt && (rt->rt_flags & (RTF_REJECT | RTF_BLACKHOLE)))
+	if (ISSET(rt->rt_flags, RTF_REJECT | RTF_BLACKHOLE))
 		return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
 
-	if (rt != NULL)
-		*retifp = if_get(rt->rt_ifidx);
+	*retifp = if_get(rt->rt_ifidx);
 
 	return (0);
 }