From caa7f414ec6e1ce31591b7ba9152b8bdb34ac389 Mon Sep 17 00:00:00 2001 From: bluhm Date: Thu, 22 Feb 2024 14:25:58 +0000 Subject: [PATCH] Make the route cache aware of multipath routing. Pass source address to route_cache() and store it in struct route. Cached multipath routes are only valid if source address matches. If sysctl multipath changes, increase route generation number. OK claudio@ --- sys/net/route.c | 44 +++++++++++++++++++++++++------------- sys/net/route.h | 23 +++++++++++--------- sys/netinet/in_pcb.c | 7 +++--- sys/netinet/ip_input.c | 16 ++++++++++---- sys/netinet/ip_output.c | 4 ++-- sys/netinet6/in6_pcb.c | 5 +++-- sys/netinet6/in6_src.c | 8 +++---- sys/netinet6/ip6_forward.c | 5 +++-- sys/netinet6/ip6_input.c | 14 +++++++++--- sys/netinet6/ip6_output.c | 4 ++-- 10 files changed, 83 insertions(+), 47 deletions(-) diff --git a/sys/net/route.c b/sys/net/route.c index f9915cdf7c1..9188b6c4cfc 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -1,4 +1,4 @@ -/* $OpenBSD: route.c,v 1.432 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: route.c,v 1.433 2024/02/22 14:25:58 bluhm Exp $ */ /* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */ /* @@ -202,7 +202,8 @@ route_init(void) } int -route_cache(struct route *ro, struct in_addr addr, u_int rtableid) +route_cache(struct route *ro, const struct in_addr *dst, + const struct in_addr *src, u_int rtableid) { u_long gen; @@ -213,28 +214,35 @@ route_cache(struct route *ro, struct in_addr addr, u_int rtableid) ro->ro_generation == gen && ro->ro_tableid == rtableid && ro->ro_dstsa.sa_family == AF_INET && - ro->ro_dstsin.sin_addr.s_addr == addr.s_addr) { - ipstat_inc(ips_rtcachehit); - return (0); + ro->ro_dstsin.sin_addr.s_addr == dst->s_addr) { + if (src == NULL || !ipmultipath || + !ISSET(ro->ro_rt->rt_flags, RTF_MPATH) || + (ro->ro_srcin.s_addr != INADDR_ANY && + ro->ro_srcin.s_addr == src->s_addr)) { + ipstat_inc(ips_rtcachehit); + return (0); + } } ipstat_inc(ips_rtcachemiss); rtfree(ro->ro_rt); - ro->ro_rt = NULL; + memset(ro, 0, sizeof(*ro)); ro->ro_generation = gen; ro->ro_tableid = rtableid; - memset(&ro->ro_dst, 0, sizeof(ro->ro_dst)); ro->ro_dstsin.sin_family = AF_INET; ro->ro_dstsin.sin_len = sizeof(struct sockaddr_in); - ro->ro_dstsin.sin_addr = addr; + ro->ro_dstsin.sin_addr = *dst; + if (src != NULL) + ro->ro_srcin = *src; return (ESRCH); } #ifdef INET6 int -route6_cache(struct route *ro, const struct in6_addr *addr, u_int rtableid) +route6_cache(struct route *ro, const struct in6_addr *dst, + const struct in6_addr *src, u_int rtableid) { u_long gen; @@ -245,21 +253,27 @@ route6_cache(struct route *ro, const struct in6_addr *addr, u_int rtableid) ro->ro_generation == gen && ro->ro_tableid == rtableid && ro->ro_dstsa.sa_family == AF_INET6 && - IN6_ARE_ADDR_EQUAL(&ro->ro_dstsin6.sin6_addr, addr)) { - ip6stat_inc(ip6s_rtcachehit); - return (0); + IN6_ARE_ADDR_EQUAL(&ro->ro_dstsin6.sin6_addr, dst)) { + if (src == NULL || !ip6_multipath || + !ISSET(ro->ro_rt->rt_flags, RTF_MPATH) || + (!IN6_IS_ADDR_UNSPECIFIED(&ro->ro_srcin6) && + IN6_ARE_ADDR_EQUAL(&ro->ro_srcin6, src))) { + ip6stat_inc(ip6s_rtcachehit); + return (0); + } } ip6stat_inc(ip6s_rtcachemiss); rtfree(ro->ro_rt); - ro->ro_rt = NULL; + memset(ro, 0, sizeof(*ro)); ro->ro_generation = gen; ro->ro_tableid = rtableid; - memset(&ro->ro_dst, 0, sizeof(ro->ro_dst)); ro->ro_dstsin6.sin6_family = AF_INET6; ro->ro_dstsin6.sin6_len = sizeof(struct sockaddr_in6); - ro->ro_dstsin6.sin6_addr = *addr; + ro->ro_dstsin6.sin6_addr = *dst; + if (src != NULL) + ro->ro_srcin6 = *src; return (ESRCH); } diff --git a/sys/net/route.h b/sys/net/route.h index 7833f7ca9a8..fe652bd0925 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -1,4 +1,4 @@ -/* $OpenBSD: route.h,v 1.206 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: route.h,v 1.207 2024/02/22 14:25:58 bluhm Exp $ */ /* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */ /* @@ -393,13 +393,14 @@ struct route { u_long ro_generation; u_long ro_tableid; /* u_long because of alignment */ union { - struct sockaddr rod_sa; - struct sockaddr_in rod_sin; - struct sockaddr_in6 rod_sin6; - } ro_dst; -#define ro_dstsa ro_dst.rod_sa -#define ro_dstsin ro_dst.rod_sin -#define ro_dstsin6 ro_dst.rod_sin6 + struct sockaddr ro_dstsa; + struct sockaddr_in ro_dstsin; + struct sockaddr_in6 ro_dstsin6; + }; + union { + struct in_addr ro_srcin; + struct in6_addr ro_srcin6; + }; }; #endif /* __BSD_VISIBLE */ @@ -462,8 +463,10 @@ struct if_ieee80211_data; struct bfd_config; void route_init(void); -int route_cache(struct route *, struct in_addr, u_int); -int route6_cache(struct route *, const struct in6_addr *, u_int); +int route_cache(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); void rtm_ifchg(struct ifnet *); void rtm_ifannounce(struct ifnet *, int); void rtm_bfd(struct bfd_config *); diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index 87241c03e7a..cc08e62925f 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in_pcb.c,v 1.293 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: in_pcb.c,v 1.294 2024/02/22 14:25:58 bluhm Exp $ */ /* $NetBSD: in_pcb.c,v 1.25 1996/02/13 23:41:53 christos Exp $ */ /* @@ -919,7 +919,8 @@ in_pcbrtentry(struct inpcb *inp) if (inp->inp_faddr.s_addr == INADDR_ANY) return (NULL); - if (route_cache(ro, inp->inp_faddr, inp->inp_rtableid)) { + 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); } @@ -982,7 +983,7 @@ in_pcbselsrc(struct in_addr *insrc, struct sockaddr_in *sin, * 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, rtableid)) { + 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); } diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 60c6e6a422b..d8709c94cf7 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_input.c,v 1.389 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: ip_input.c,v 1.390 2024/02/22 14:25:58 bluhm Exp $ */ /* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */ /* @@ -118,7 +118,6 @@ const struct sysctl_bounded_args ipctl_vars[] = { { IPCTL_IPPORT_HILASTAUTO, &ipport_hilastauto, 0, 65535 }, { IPCTL_IPPORT_MAXQUEUE, &ip_maxqueue, 0, 10000 }, { IPCTL_MFORWARDING, &ipmforwarding, 0, 1 }, - { IPCTL_MULTIPATH, &ipmultipath, 0, 1 }, { IPCTL_ARPTIMEOUT, &arpt_keep, 0, INT_MAX }, { IPCTL_ARPDOWN, &arpt_down, 0, INT_MAX }, }; @@ -1491,7 +1490,7 @@ ip_forward(struct mbuf *m, struct ifnet *ifp, struct rtentry *rt, int srcrt) } ro.ro_rt = NULL; - route_cache(&ro, ip->ip_dst, m->m_pkthdr.ph_rtableid); + route_cache(&ro, &ip->ip_dst, &ip->ip_src, m->m_pkthdr.ph_rtableid); if (!rtisvalid(rt)) { rtfree(rt); rt = rtalloc_mpath(&ro.ro_dstsa, &ip->ip_src.s_addr, @@ -1633,10 +1632,10 @@ int ip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen) { - int error; #ifdef MROUTING extern struct mrtstat mrtstat; #endif + int oldval, error; /* Almost all sysctl names at this level are terminal. */ if (namelen != 1 && name[0] != IPCTL_IFQUEUE && @@ -1721,6 +1720,15 @@ ip_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, case IPCTL_MRTVIF: return (EOPNOTSUPP); #endif + case IPCTL_MULTIPATH: + NET_LOCK(); + oldval = ipmultipath; + error = sysctl_int_bounded(oldp, oldlenp, newp, newlen, + &ipmultipath, 0, 1); + if (oldval != ipmultipath) + atomic_inc_long(&rtgeneration); + NET_UNLOCK(); + return (error); default: NET_LOCK(); error = sysctl_bounded_arr(ipctl_vars, nitems(ipctl_vars), diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index 561b690c765..0a606960376 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_output.c,v 1.395 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: ip_output.c,v 1.396 2024/02/22 14:25:58 bluhm Exp $ */ /* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */ /* @@ -166,7 +166,7 @@ reroute: * If there is a cached route, check that it is to the same * destination and is still up. If not, free it and try again. */ - route_cache(ro, ip->ip_dst, m->m_pkthdr.ph_rtableid); + route_cache(ro, &ip->ip_dst, &ip->ip_src, m->m_pkthdr.ph_rtableid); dst = &ro->ro_dstsin; if ((IN_MULTICAST(ip->ip_dst.s_addr) || diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c index d622c5dcc43..cea4415c17d 100644 --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_pcb.c,v 1.138 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: in6_pcb.c,v 1.139 2024/02/22 14:25:58 bluhm Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -565,7 +565,8 @@ in6_pcbrtentry(struct inpcb *inp) if (IN6_IS_ADDR_UNSPECIFIED(&inp->inp_faddr6)) return (NULL); - if (route6_cache(ro, &inp->inp_faddr6, inp->inp_rtableid)) { + 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); } diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index 470ad67ebbc..ac35960a0f7 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -1,4 +1,4 @@ -/* $OpenBSD: in6_src.c,v 1.94 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: in6_src.c,v 1.95 2024/02/22 14:25:58 bluhm Exp $ */ /* $KAME: in6_src.c,v 1.36 2001/02/06 04:08:17 itojun Exp $ */ /* @@ -179,8 +179,8 @@ in6_pcbselsrc(const struct in6_addr **in6src, struct sockaddr_in6 *dstsock, * 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, rtableid)) { - ro->ro_rt = rtalloc(&ro->ro_dstsa, RT_RESOLVE, ro->ro_tableid); + if (route6_cache(ro, dst, NULL, rtableid)) { + ro->ro_rt = rtalloc_mpath(&ro->ro_dstsa, NULL, ro->ro_tableid); } /* @@ -304,7 +304,7 @@ in6_selectroute(const struct in6_addr *dst, struct ip6_pktopts *opts, * a new one. */ if (ro) { - if (route6_cache(ro, dst, rtableid)) { + 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); diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index cdb2fb417d1..65a51d52dac 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_forward.c,v 1.114 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: ip6_forward.c,v 1.115 2024/02/22 14:25:58 bluhm Exp $ */ /* $KAME: ip6_forward.c,v 1.75 2001/06/29 12:42:13 jinmei Exp $ */ /* @@ -166,7 +166,8 @@ reroute: #endif /* IPSEC */ ro.ro_rt = NULL; - route6_cache(&ro, &ip6->ip6_dst, m->m_pkthdr.ph_rtableid); + route6_cache(&ro, &ip6->ip6_dst, &ip6->ip6_src, + m->m_pkthdr.ph_rtableid); dst = &ro.ro_dstsa; if (!rtisvalid(rt)) { rtfree(rt); diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 21bd2848c31..5d78407442b 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_input.c,v 1.257 2023/12/03 20:36:24 bluhm Exp $ */ +/* $OpenBSD: ip6_input.c,v 1.258 2024/02/22 14:25:58 bluhm Exp $ */ /* $KAME: ip6_input.c,v 1.188 2001/03/29 05:34:31 itojun Exp $ */ /* @@ -1451,7 +1451,6 @@ const struct sysctl_bounded_args ipv6ctl_vars[] = { { IPV6CTL_USE_DEPRECATED, &ip6_use_deprecated, 0, 1 }, { IPV6CTL_MAXFRAGS, &ip6_maxfrags, 0, 1000 }, { IPV6CTL_MFORWARDING, &ip6_mforwarding, 0, 1 }, - { IPV6CTL_MULTIPATH, &ip6_multipath, 0, 1 }, { IPV6CTL_MCAST_PMTU, &ip6_mcast_pmtu, 0, 1 }, { IPV6CTL_NEIGHBORGCTHRESH, &ip6_neighborgcthresh, -1, 5 * 2048 }, { IPV6CTL_MAXDYNROUTES, &ip6_maxdynroutes, -1, 5 * 4096 }, @@ -1499,7 +1498,7 @@ ip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, #ifdef MROUTING extern struct mrt6stat mrt6stat; #endif - int error; + int oldval, error; /* Almost all sysctl names at this level are terminal. */ if (namelen != 1 && name[0] != IPV6CTL_IFQUEUE) @@ -1551,6 +1550,15 @@ ip6_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, oldp, oldlenp, newp, newlen, &ip6intrq)); case IPV6CTL_SOIIKEY: return (ip6_sysctl_soiikey(oldp, oldlenp, newp, newlen)); + case IPV6CTL_MULTIPATH: + NET_LOCK(); + oldval = ip6_multipath; + error = sysctl_int_bounded(oldp, oldlenp, newp, newlen, + &ip6_multipath, 0, 1); + if (oldval != ip6_multipath) + atomic_inc_long(&rtgeneration); + NET_UNLOCK(); + return (error); default: NET_LOCK(); error = sysctl_bounded_arr(ipv6ctl_vars, nitems(ipv6ctl_vars), diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index adb5f30554d..e277d49599f 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip6_output.c,v 1.286 2024/02/13 12:22:09 bluhm Exp $ */ +/* $OpenBSD: ip6_output.c,v 1.287 2024/02/22 14:25:58 bluhm Exp $ */ /* $KAME: ip6_output.c,v 1.172 2001/03/25 09:55:56 itojun Exp $ */ /* @@ -480,7 +480,7 @@ reroute: goto bad; } } else { - route6_cache(ro, &ip6->ip6_dst, m->m_pkthdr.ph_rtableid); + route6_cache(ro, &ip6->ip6_dst, NULL, m->m_pkthdr.ph_rtableid); } if (rt && (rt->rt_flags & RTF_GATEWAY) && -- 2.20.1