-/* $OpenBSD: route.c,v 1.426 2023/11/13 17:18:27 bluhm Exp $ */
+/* $OpenBSD: route.c,v 1.427 2024/01/31 14:56:42 bluhm Exp $ */
/* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */
/*
/*
* Locks used to protect struct members:
+ * a atomic operations
* I immutable after creation
* L rtlabel_mtx
* T rttimer_mtx
extern unsigned int rtmap_limit;
-struct cpumem * rtcounters;
-int rttrash; /* routes not in table but not freed */
+struct cpumem *rtcounters;
+int rttrash; /* [a] routes not in table but not freed */
+u_long rtgeneration; /* [a] generation number, routes changed */
struct pool rtentry_pool; /* pool for rtentry structures */
struct pool rttimer_pool; /* pool for rttimer structures */
#endif
}
+void
+route_cache(struct route *ro, struct in_addr addr, u_int rtableid)
+{
+ u_long gen;
+
+ gen = atomic_load_long(&rtgeneration);
+ membar_consumer();
+
+ if (rtisvalid(ro->ro_rt) &&
+ ro->ro_generation == gen &&
+ ro->ro_tableid == rtableid &&
+ ro->ro_dst.sa_family == AF_INET &&
+ satosin(&ro->ro_dst)->sin_addr.s_addr == addr.s_addr) {
+ return;
+ }
+
+ rtfree(ro->ro_rt);
+ ro->ro_rt = NULL;
+ ro->ro_generation = gen;
+ ro->ro_tableid = rtableid;
+
+ memset(&ro->ro_dst, 0, sizeof(ro->ro_dst));
+ satosin(&ro->ro_dst)->sin_family = AF_INET;
+ satosin(&ro->ro_dst)->sin_len = sizeof(struct sockaddr_in);
+ satosin(&ro->ro_dst)->sin_addr = addr;
+}
+
/*
* Returns 1 if the (cached) ``rt'' entry is still valid, 0 otherwise.
*/
else
rtfree(rt);
+ membar_producer();
+ atomic_inc_long(&rtgeneration);
+
return (0);
}
*ret_nrt = rt;
else
rtfree(rt);
+
+ membar_producer();
+ atomic_inc_long(&rtgeneration);
+
break;
}
}
if_group_routechange(rt_key(rt), rt_plen2mask(rt, &sa_mask));
+ membar_producer();
+ atomic_inc_long(&rtgeneration);
+
return (error);
}
-/* $OpenBSD: route.h,v 1.203 2023/11/12 17:51:40 bluhm Exp $ */
+/* $OpenBSD: route.h,v 1.204 2024/01/31 14:56:42 bluhm Exp $ */
/* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */
/*
*/
struct route {
struct rtentry *ro_rt;
+ u_long ro_generation;
u_long ro_tableid; /* u_long because of alignment */
struct sockaddr ro_dst;
};
#define RT_RESOLVE 1
extern struct rtstat rtstat;
+extern u_long rtgeneration;
struct mbuf;
struct socket;
struct ifnet;
+struct in_addr;
struct sockaddr_in6;
struct if_ieee80211_data;
struct bfd_config;
void route_init(void);
+void route_cache(struct route *, struct in_addr, u_int);
void rtm_ifchg(struct ifnet *);
void rtm_ifannounce(struct ifnet *, int);
void rtm_bfd(struct bfd_config *);
-/* $OpenBSD: ip_input.c,v 1.387 2023/09/16 09:33:27 mpi Exp $ */
+/* $OpenBSD: ip_input.c,v 1.388 2024/01/31 14:56:42 bluhm Exp $ */
/* $NetBSD: ip_input.c,v 1.30 1996/03/16 23:53:58 christos Exp $ */
/*
{
struct mbuf mfake, *mcopy = NULL;
struct ip *ip = mtod(m, struct ip *);
- struct sockaddr_in *sin;
struct route ro;
int error = 0, type = 0, code = 0, destmtu = 0, fake = 0, len;
u_int32_t dest;
goto freecopy;
}
- memset(&ro, 0, sizeof(ro));
- sin = satosin(&ro.ro_dst);
- sin->sin_family = AF_INET;
- sin->sin_len = sizeof(*sin);
- sin->sin_addr = ip->ip_dst;
-
+ ro.ro_rt = NULL;
+ route_cache(&ro, ip->ip_dst, m->m_pkthdr.ph_rtableid);
if (!rtisvalid(rt)) {
rtfree(rt);
- rt = rtalloc_mpath(sintosa(sin), &ip->ip_src.s_addr,
+ rt = rtalloc_mpath(&ro.ro_dst, &ip->ip_src.s_addr,
m->m_pkthdr.ph_rtableid);
if (rt == NULL) {
ipstat_inc(ips_noroute);
return;
}
}
+ ro.ro_rt = rt;
/*
* Save at most 68 bytes of the packet in case
}
}
- ro.ro_rt = rt;
- ro.ro_tableid = m->m_pkthdr.ph_rtableid;
error = ip_output(m, NULL, &ro,
(IP_FORWARDING | (ip_directedbcast ? IP_ALLOWBROADCAST : 0)),
NULL, NULL, 0);
-/* $OpenBSD: ip_output.c,v 1.393 2024/01/18 11:03:16 claudio Exp $ */
+/* $OpenBSD: ip_output.c,v 1.394 2024/01/31 14:56:43 bluhm Exp $ */
/* $NetBSD: ip_output.c,v 1.28 1996/02/13 23:43:07 christos Exp $ */
/*
*/
if (ro == NULL) {
ro = &iproute;
- memset(ro, 0, sizeof(*ro));
+ ro->ro_rt = NULL;
}
- dst = satosin(&ro->ro_dst);
-
/*
* 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.
*/
- if (!rtisvalid(ro->ro_rt) ||
- dst->sin_addr.s_addr != ip->ip_dst.s_addr ||
- ro->ro_tableid != m->m_pkthdr.ph_rtableid) {
- rtfree(ro->ro_rt);
- ro->ro_rt = NULL;
- }
-
- if (ro->ro_rt == NULL) {
- dst->sin_family = AF_INET;
- dst->sin_len = sizeof(*dst);
- dst->sin_addr = ip->ip_dst;
- ro->ro_tableid = m->m_pkthdr.ph_rtableid;
- }
+ route_cache(ro, ip->ip_dst, m->m_pkthdr.ph_rtableid);
+ dst = satosin(&ro->ro_dst);
if ((IN_MULTICAST(ip->ip_dst.s_addr) ||
(ip->ip_dst.s_addr == INADDR_BROADCAST)) &&
-/* $OpenBSD: in6.h,v 1.112 2024/01/27 21:13:46 bluhm Exp $ */
+/* $OpenBSD: in6.h,v 1.113 2024/01/31 14:56:43 bluhm Exp $ */
/* $KAME: in6.h,v 1.83 2001/03/29 02:55:07 jinmei Exp $ */
/*
#if __BSD_VISIBLE
/*
- * IPv6 route structure
+ * IPv6 route structure, keep fields in sync with struct route
*/
struct route_in6 {
struct rtentry *ro_rt;
+ u_long ro_generation;
u_long ro_tableid; /* padded to long for alignment */
struct sockaddr_in6 ro_dst;
};