Index: route.c =================================================================== RCS file: /cvs/src/sys/net/route.c,v retrieving revision 1.423 diff -u -p -r1.423 route.c --- route.c 10 Nov 2023 20:05:22 -0000 1.423 +++ route.c 11 Nov 2023 15:13:08 -0000 @@ -158,8 +158,8 @@ int rttrash; /* routes not in table bu struct pool rtentry_pool; /* pool for rtentry structures */ struct pool rttimer_pool; /* pool for rttimer structures */ -int rt_setgwroute(struct rtentry *, u_int); -void rt_putgwroute(struct rtentry *); +int rt_setgwroute(struct rtentry *, /* const */ struct sockaddr *, u_int); +void rt_putgwroute(struct rtentry *, struct rtentry *); int rtflushclone1(struct rtentry *, void *, u_int); int rtflushclone(struct rtentry *, unsigned int); int rt_ifa_purge_walker(struct rtentry *, void *, unsigned int); @@ -378,7 +378,8 @@ rtalloc(struct sockaddr *dst, int flags, * the gateway entry ``rt''. */ int -rt_setgwroute(struct rtentry *rt, u_int rtableid) +rt_setgwroute(struct rtentry *rt, /* const */ struct sockaddr *gate, + u_int rtableid) { struct rtentry *prt, *nhrt; unsigned int rdomain = rtable_l2(rtableid); @@ -386,10 +387,8 @@ rt_setgwroute(struct rtentry *rt, u_int NET_ASSERT_LOCKED(); - KASSERT(ISSET(rt->rt_flags, RTF_GATEWAY)); - /* If we cannot find a valid next hop bail. */ - nhrt = rt_match(rt->rt_gateway, NULL, RT_RESOLVE, rdomain); + nhrt = rt_match(gate, NULL, RT_RESOLVE, rdomain); if (nhrt == NULL) return (ENOENT); @@ -422,7 +421,7 @@ rt_setgwroute(struct rtentry *rt, u_int return (EHOSTUNREACH); } - error = rt_clone(&prt, rt->rt_gateway, rdomain); + error = rt_clone(&prt, gate, rdomain); if (error) { rtfree(prt); return (error); @@ -439,10 +438,6 @@ rt_setgwroute(struct rtentry *rt, u_int return (ENETUNREACH); } - /* Next hop is valid so remove possible old cache. */ - rt_putgwroute(rt); - KASSERT(rt->rt_gwroute == NULL); - /* * If the MTU of next hop is 0, this will reset the MTU of the * route to run PMTUD again from scratch. @@ -459,7 +454,8 @@ rt_setgwroute(struct rtentry *rt, u_int nhrt->rt_flags |= RTF_CACHED; nhrt->rt_cachecnt++; - rt->rt_gwroute = nhrt; + /* commit */ + rt_putgwroute(rt, nhrt); return (0); } @@ -468,24 +464,27 @@ rt_setgwroute(struct rtentry *rt, u_int * Invalidate the cached route entry of the gateway entry ``rt''. */ void -rt_putgwroute(struct rtentry *rt) +rt_putgwroute(struct rtentry *rt, struct rtentry *nhrt) { - struct rtentry *nhrt = rt->rt_gwroute; + struct rtentry *onhrt; NET_ASSERT_LOCKED(); - if (!ISSET(rt->rt_flags, RTF_GATEWAY) || nhrt == NULL) + if (!ISSET(rt->rt_flags, RTF_GATEWAY)) return; - KASSERT(ISSET(nhrt->rt_flags, RTF_CACHED)); - KASSERT(nhrt->rt_cachecnt > 0); - - --nhrt->rt_cachecnt; - if (nhrt->rt_cachecnt == 0) - nhrt->rt_flags &= ~RTF_CACHED; + onhrt = rt->rt_gwroute; + rt->rt_gwroute = nhrt; + if (onhrt != NULL) { + 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); - rtfree(rt->rt_gwroute); - rt->rt_gwroute = NULL; + rtfree(onhrt); + } } void @@ -796,7 +795,7 @@ rtrequest_delete(struct rt_addrinfo *inf } /* Release next hop cache before flushing cloned entries. */ - rt_putgwroute(rt); + rt_putgwroute(rt, NULL); /* Clean up any cloned children. */ if (ISSET(rt->rt_flags, RTF_CLONING)) @@ -932,7 +931,7 @@ rtrequest(int req, struct rt_addrinfo *i tableid))) { ifafree(ifa); rtfree(rt->rt_parent); - rt_putgwroute(rt); + rt_putgwroute(rt, NULL); free(rt->rt_gateway, M_RTABLE, ROUNDUP(rt->rt_gateway->sa_len)); free(ndst, M_RTABLE, ndst->sa_len); @@ -965,7 +964,7 @@ rtrequest(int req, struct rt_addrinfo *i if (error != 0) { ifafree(ifa); rtfree(rt->rt_parent); - rt_putgwroute(rt); + rt_putgwroute(rt, NULL); free(rt->rt_gateway, M_RTABLE, ROUNDUP(rt->rt_gateway->sa_len)); free(ndst, M_RTABLE, ndst->sa_len); @@ -991,22 +990,35 @@ int rt_setgate(struct rtentry *rt, struct sockaddr *gate, u_int rtableid) { int glen = ROUNDUP(gate->sa_len); - struct sockaddr *sa; + struct sockaddr *sa, *osa; - if (rt->rt_gateway == NULL || glen != ROUNDUP(rt->rt_gateway->sa_len)) { - sa = malloc(glen, M_RTABLE, M_NOWAIT); - if (sa == NULL) - return (ENOBUFS); - if (rt->rt_gateway != NULL) { - free(rt->rt_gateway, M_RTABLE, - ROUNDUP(rt->rt_gateway->sa_len)); + KASSERT(gate != NULL); + if (rt->rt_gateway == gate) { + /* nop */ + return (0); + }; + + sa = malloc(glen, M_RTABLE, M_NOWAIT | M_ZERO); + if (sa == NULL) + return (ENOBUFS); + memcpy(sa, gate, gate->sa_len); + + KERNEL_LOCK(); /* see [X] in route.h */ + if (ISSET(rt->rt_flags, RTF_GATEWAY)) { + int error = rt_setgwroute(rt, gate, rtableid); + if (error != 0) { + KERNEL_UNLOCK(); + free(sa, M_RTABLE, glen); + return (error); } - rt->rt_gateway = sa; } - memmove(rt->rt_gateway, gate, glen); - if (ISSET(rt->rt_flags, RTF_GATEWAY)) - return (rt_setgwroute(rt, rtableid)); + osa = rt->rt_gateway; + rt->rt_gateway = sa; + KERNEL_UNLOCK(); + + if (osa != NULL) + free(osa, M_RTABLE, ROUNDUP(osa->sa_len)); return (0); }