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@
-/* $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 $ */
/*
}
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;
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;
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);
}
-/* $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 $ */
/*
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 */
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 *);
-/* $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 $ */
/*
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);
}
* 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);
}
-/* $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 $ */
/*
{ 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 },
};
}
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,
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 &&
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),
-/* $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 $ */
/*
* 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) ||
-/* $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.
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);
}
-/* $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 $ */
/*
* 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);
}
/*
* 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);
-/* $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 $ */
/*
#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);
-/* $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 $ */
/*
{ 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 },
#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)
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),
-/* $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 $ */
/*
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) &&