Index: sys/net/if_gre.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/net/if_gre.c,v diff -u -p -u -p -r1.179 if_gre.c --- sys/net/if_gre.c 4 Dec 2024 18:20:46 -0000 1.179 +++ sys/net/if_gre.c 12 Feb 2025 18:39:52 -0000 @@ -1633,7 +1633,7 @@ mgre_output(struct ifnet *ifp, struct mb { struct mgre_softc *sc = ifp->if_softc; struct sockaddr *gate; - struct rtentry *rt; + struct rtentry *rt = NULL; struct m_tag *mtag; int error = 0; sa_family_t af; @@ -1730,7 +1730,8 @@ mgre_output(struct ifnet *ifp, struct mb m = gre_l3_encap_dst(&sc->sc_tunnel, addr, m, dest->sa_family); if (m == NULL) { ifp->if_oerrors++; - return (ENOBUFS); + error = ENOBUFS; + goto out; } m->m_pkthdr.ph_family = dest->sa_family; @@ -1738,10 +1739,13 @@ mgre_output(struct ifnet *ifp, struct mb error = if_enqueue(ifp, m); if (error) ifp->if_oerrors++; +out: + rtfree(rt); return (error); drop: m_freem(m); + rtfree(rt); return (error); } Index: sys/net/route.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/net/route.c,v diff -u -p -u -p -r1.438 route.c --- sys/net/route.c 3 Jan 2025 21:27:40 -0000 1.438 +++ sys/net/route.c 12 Feb 2025 18:39:52 -0000 @@ -104,6 +104,7 @@ #include #include #include +#include #include #include #include @@ -324,10 +325,14 @@ rtisvalid(struct rtentry *rt) return (0); if (ISSET(rt->rt_flags, RTF_GATEWAY)) { - KASSERT(rt->rt_gwroute != NULL); - KASSERT(!ISSET(rt->rt_gwroute->rt_flags, RTF_GATEWAY)); - if (!ISSET(rt->rt_gwroute->rt_flags, RTF_UP)) - return (0); + int up; + + smr_read_enter(); + rt = SMR_PTR_GET(&rt->rt_gwroute); + KASSERT(!ISSET(rt->rt_flags, RTF_GATEWAY)); + up = ISSET(rt->rt_flags, RTF_UP) ? 1 : 0; + smr_read_leave(); + return (up); } return (1); @@ -572,8 +577,10 @@ rt_setgwroute(struct rtentry *rt, const * of a cached entry is greater than the bigger lifetime of the * gateway entries it is pointed by. */ + rw_enter_write(&nhrt->rt_lock); nhrt->rt_flags |= RTF_CACHED; nhrt->rt_cachecnt++; + rw_exit_write(&nhrt->rt_lock); /* commit */ rt_putgwroute(rt, nhrt); @@ -594,18 +601,20 @@ rt_putgwroute(struct rtentry *rt, struct if (!ISSET(rt->rt_flags, RTF_GATEWAY)) return; - /* this is protected as per [X] in route.h */ - onhrt = rt->rt_gwroute; - rt->rt_gwroute = nhrt; + rw_enter_write(&rt->rt_lock); + onhrt = SMR_PTR_GET_LOCKED(&rt->rt_gwroute); + SMR_PTR_SET_LOCKED(&rt->rt_gwroute, nhrt); + rw_exit_write(&rt->rt_lock); if (onhrt != NULL) { + smr_barrier(); + rw_enter_write(&onhrt->rt_lock); KASSERT(onhrt->rt_cachecnt > 0); KASSERT(ISSET(onhrt->rt_flags, RTF_CACHED)); - --onhrt->rt_cachecnt; if (onhrt->rt_cachecnt == 0) CLR(onhrt->rt_flags, RTF_CACHED); - + rw_exit_write(&onhrt->rt_lock); rtfree(onhrt); } } @@ -1157,16 +1166,20 @@ rt_setgate(struct rtentry *rt, const str /* * Return the route entry containing the next hop link-layer - * address corresponding to ``rt''. + * address corresponding to ``rt''. The caller has to free. */ struct rtentry * rt_getll(struct rtentry *rt) { if (ISSET(rt->rt_flags, RTF_GATEWAY)) { - KASSERT(rt->rt_gwroute != NULL); - return (rt->rt_gwroute); + smr_read_enter(); + rt = SMR_PTR_GET(&rt->rt_gwroute); + rtref(rt); + smr_read_leave(); + return (rt); } + rtref(rt); return (rt); } Index: sys/net/route.h =================================================================== RCS file: /mount/openbsd/cvs/src/sys/net/route.h,v diff -u -p -u -p -r1.211 route.h --- sys/net/route.h 3 Jan 2025 21:27:40 -0000 1.211 +++ sys/net/route.h 12 Feb 2025 18:39:52 -0000 @@ -41,6 +41,7 @@ * N net lock * X exclusive net lock, or shared net lock + kernel lock * R art (rtable) lock + * r per route entry lock * L arp/nd6/etc lock for updates, net lock for reads * T rttimer_mtx route timer lists */ @@ -114,6 +115,7 @@ struct rttimer; */ struct rtentry { + struct rwlock rt_lock; struct sockaddr *rt_dest; /* [I] destination */ SRPL_ENTRY(rtentry) rt_next; /* [R] next mpath entry to our dst */ struct sockaddr *rt_gateway; /* [X] gateway address */ @@ -121,8 +123,8 @@ struct rtentry { caddr_t rt_llinfo; /* [L] pointer to link level info or an MPLS structure */ union { - struct rtentry *_nh; /* [X] rtentry for rt_gateway */ - unsigned int _ref; /* [X] # gateway rtentry refs */ + struct rtentry *_nh; /* [r] rtentry for rt_gateway */ + unsigned int _ref; /* [r] # gateway rtentry refs */ } RT_gw; #define rt_gwroute RT_gw._nh #define rt_cachecnt RT_gw._ref Index: sys/net/rtsock.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/net/rtsock.c,v diff -u -p -u -p -r1.379 rtsock.c --- sys/net/rtsock.c 30 Jan 2025 14:40:50 -0000 1.379 +++ sys/net/rtsock.c 12 Feb 2025 18:39:52 -0000 @@ -1343,9 +1343,11 @@ route_cleargateway(struct rtentry *rt, v { struct rtentry *nhrt = arg; + rw_enter_read(&rt->rt_lock); if (ISSET(rt->rt_flags, RTF_GATEWAY) && rt->rt_gwroute == nhrt && !ISSET(rt->rt_locks, RTV_MTU)) atomic_store_int(&rt->rt_mtu, 0); + rw_exit_read(&rt->rt_lock); return (0); } Index: sys/netinet/if_ether.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/netinet/if_ether.c,v diff -u -p -u -p -r1.268 if_ether.c --- sys/netinet/if_ether.c 1 Jan 2025 13:44:22 -0000 1.268 +++ sys/netinet/if_ether.c 12 Feb 2025 18:39:52 -0000 @@ -337,7 +337,7 @@ arpresolve(struct ifnet *ifp, struct rte struct arpcom *ac = (struct arpcom *)ifp; struct llinfo_arp *la; struct sockaddr_dl *sdl; - struct rtentry *rt = NULL; + struct rtentry *rt; char addr[INET_ADDRSTRLEN]; time_t uptime; int refresh = 0, reject = 0; @@ -357,6 +357,7 @@ arpresolve(struct ifnet *ifp, struct rte if (ISSET(rt->rt_flags, RTF_REJECT) && (rt->rt_expire == 0 || rt->rt_expire > uptime)) { m_freem(m); + rtfree(rt); return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); } @@ -404,6 +405,7 @@ arpresolve(struct ifnet *ifp, struct rte &satosin(dst)->sin_addr.s_addr, ac->ac_enaddr); } + rtfree(rt); return (0); } @@ -472,10 +474,12 @@ arpresolve(struct ifnet *ifp, struct rte if (refresh) arprequest(ifp, &satosin(rt->rt_ifa->ifa_addr)->sin_addr.s_addr, &satosin(dst)->sin_addr.s_addr, ac->ac_enaddr); + rtfree(rt); return (EAGAIN); bad: m_freem(m); + rtfree(rt); return (EINVAL); } Index: sys/netinet6/nd6.c =================================================================== RCS file: /mount/openbsd/cvs/src/sys/netinet6/nd6.c,v diff -u -p -u -p -r1.284 nd6.c --- sys/netinet6/nd6.c 31 Jan 2025 11:44:47 -0000 1.284 +++ sys/netinet6/nd6.c 12 Feb 2025 18:39:52 -0000 @@ -1288,6 +1288,7 @@ nd6_resolve(struct ifnet *ifp, struct rt if (ISSET(rt->rt_flags, RTF_REJECT) && (rt->rt_expire == 0 || rt->rt_expire > uptime)) { m_freem(m); + rtfree(rt); return (rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); } @@ -1357,6 +1358,7 @@ nd6_resolve(struct ifnet *ifp, struct rt } bcopy(LLADDR(sdl), desten, sdl->sdl_alen); + rtfree(rt); return (0); } @@ -1394,10 +1396,12 @@ nd6_resolve(struct ifnet *ifp, struct rt if (solicit) nd6_ns_output(ifp, NULL, &satosin6(dst)->sin6_addr, &saddr6, 0); + rtfree(rt); return (EAGAIN); bad: m_freem(m); + rtfree(rt); return (EINVAL); }