Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F131703001
D4306.id12399.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D4306.id12399.diff
View Options
Index: sys/net/radix.h
===================================================================
--- sys/net/radix.h
+++ sys/net/radix.h
@@ -101,11 +101,18 @@
#define rm_mask rm_rmu.rmu_mask
#define rm_leaf rm_rmu.rmu_leaf /* extra field would make 32 bytes */
+/*
+ * Keep a generation count of routing table, incremented on route addition,
+ * so we can invalidate caches. This is accessed without a lock, as precision
+ * is not required.
+ */
+typedef volatile u_int rt_gen_t; /* tree generation (for adds) */
+
typedef int walktree_f_t(struct radix_node *, void *);
struct radix_node_head {
struct radix_node *rnh_treetop;
- u_int rnh_gen; /* generation counter */
+ rt_gen_t rnh_gen; /* generation counter */
int rnh_multipath; /* multipath capable ? */
struct radix_node *(*rnh_addaddr) /* add based on sockaddr */
(void *v, void *mask,
Index: sys/net/route.h
===================================================================
--- sys/net/route.h
+++ sys/net/route.h
@@ -415,6 +415,27 @@
struct radix_node_head *rt_tables_get_rnh(int, int);
+/*
+ * Keep a generation count of routing table, incremented on route addition,
+ * so we can invalidate caches. This is accessed without a lock, as precision
+ * is not required.
+ */
+#define RT_GEN(fibnum, af) rt_tables_get_rnh(fibnum, af)->rnh_gen
+
+/*
+ * Validate a cached route based on a supplied cookie. If there is an
+ * out-of-date cache, simply free it. Update the generation number
+ * for the new allocation
+ */
+#define RT_VALIDATE(ro, cookiep, fibnum) do { \
+ rt_gen_t cookie = RT_GEN(fibnum, (ro)->ro_dst.sa_family); \
+ if (*(cookiep) != cookie && (ro)->ro_rt != NULL) { \
+ RTFREE((ro)->ro_rt); \
+ (ro)->ro_rt = NULL; \
+ *(cookiep) = cookie; \
+ } \
+} while (0)
+
struct ifmultiaddr;
void rt_ieee80211msg(struct ifnet *, int, void *, size_t);
Index: sys/net/route.c
===================================================================
--- sys/net/route.c
+++ sys/net/route.c
@@ -1702,6 +1702,7 @@
*ret_nrt = rt;
RT_ADDREF(rt);
}
+ rnh->rnh_gen++; /* Routing table updated */
RT_UNLOCK(rt);
break;
case RTM_CHANGE:
Index: sys/netinet/in_pcb.h
===================================================================
--- sys/netinet/in_pcb.h
+++ sys/netinet/in_pcb.h
@@ -42,6 +42,7 @@
#include <sys/_lock.h>
#include <sys/_mutex.h>
#include <sys/_rwlock.h>
+#include <net/route.h>
#ifdef _KERNEL
#include <sys/lock.h>
@@ -238,8 +239,14 @@
#define inp_zero_size offsetof(struct inpcb, inp_gencnt)
inp_gen_t inp_gencnt; /* (c) generation count */
struct llentry *inp_lle; /* cached L2 information */
- struct rtentry *inp_rt; /* cached L3 information */
struct rwlock inp_lock;
+ rt_gen_t inp_rt_cookie; /* generation for route entry */
+ union { /* cached L3 information */
+ struct route inpu_route;
+ struct route_in6 inpu_route6;
+ } inp_rtu;
+#define inp_route inp_rtu.inpu_route
+#define inp_route6 inp_rtu.inpu_route6
};
#define inp_fport inp_inc.inc_fport
#define inp_lport inp_inc.inc_lport
@@ -722,6 +729,7 @@
int in_pcbrele(struct inpcb *);
int in_pcbrele_rlocked(struct inpcb *);
int in_pcbrele_wlocked(struct inpcb *);
+void in_losing(struct inpcb *);
void in_pcbsetsolabel(struct socket *so);
int in_getpeeraddr(struct socket *so, struct sockaddr **nam);
int in_getsockaddr(struct socket *so, struct sockaddr **nam);
Index: sys/netinet/in_pcb.c
===================================================================
--- sys/netinet/in_pcb.c
+++ sys/netinet/in_pcb.c
@@ -1298,6 +1298,11 @@
if (inp->inp_moptions != NULL)
inp_freemoptions(inp->inp_moptions);
#endif
+ if (inp->inp_route.ro_rt) {
+ RTFREE(inp->inp_route.ro_rt);
+ inp->inp_route.ro_rt = (struct rtentry *)NULL;
+ }
+
inp->inp_vflag = 0;
inp->inp_flags2 |= INP_FREED;
crfree(inp->inp_cred);
@@ -2225,6 +2230,23 @@
}
/*
+ * Check for alternatives when higher level complains
+ * about service problems. For now, invalidate cached
+ * routing information. If the route was created dynamically
+ * (by a redirect), time to try a default gateway again.
+ */
+void
+in_losing(struct inpcb *inp)
+{
+
+ if (inp->inp_route.ro_rt) {
+ RTFREE(inp->inp_route.ro_rt);
+ inp->inp_route.ro_rt = (struct rtentry *)NULL;
+ }
+ return;
+}
+
+/*
* A set label operation has occurred at the socket layer, propagate the
* label change into the in_pcb for the socket.
*/
Index: sys/netinet/ip_output.c
===================================================================
--- sys/netinet/ip_output.c
+++ sys/netinet/ip_output.c
@@ -282,17 +282,36 @@
gw = dst = (struct sockaddr_in *)&ro->ro_dst;
fibnum = (inp != NULL) ? inp->inp_inc.inc_fibnum : M_GETFIB(m);
rte = ro->ro_rt;
- /*
- * The address family should also be checked in case of sharing
- * the cache with IPv6.
- */
- if (rte == NULL || dst->sin_family != AF_INET) {
+ if (rte == NULL) {
bzero(dst, sizeof(*dst));
dst->sin_family = AF_INET;
dst->sin_len = sizeof(*dst);
dst->sin_addr = ip->ip_dst;
}
again:
+ /*
+ * Validate route against routing table additions;
+ * a better/more specific route might have been added.
+ */
+ if (inp)
+ RT_VALIDATE(ro, &inp->inp_rt_cookie, fibnum);
+ /*
+ * 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.
+ * The address family should also be checked in case of sharing the
+ * cache with IPv6.
+ * Also check whether routing cache needs invalidation.
+ */
+ rte = ro->ro_rt;
+ if (rte && ((rte->rt_flags & RTF_UP) == 0 ||
+ rte->rt_ifp == NULL ||
+ !RT_LINK_IS_UP(rte->rt_ifp) ||
+ dst->sin_family != AF_INET ||
+ dst->sin_addr.s_addr != ip->ip_dst.s_addr)) {
+ RTFREE(rte);
+ rte = ro->ro_rt = (struct rtentry *)NULL;
+ }
ia = NULL;
have_ia_ref = 0;
/*
Index: sys/netinet/tcp_output.c
===================================================================
--- sys/netinet/tcp_output.c
+++ sys/netinet/tcp_output.c
@@ -1378,9 +1378,6 @@
#endif
#ifdef INET
{
- struct route ro;
-
- bzero(&ro, sizeof(ro));
ip->ip_len = htons(m->m_pkthdr.len);
#ifdef INET6
if (tp->t_inpcb->inp_vflag & INP_IPV6PROTO)
@@ -1411,13 +1408,12 @@
tcp_pcap_add(th, m, &(tp->t_outpkts));
#endif
- error = ip_output(m, tp->t_inpcb->inp_options, &ro,
+ error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), 0,
tp->t_inpcb);
- if (error == EMSGSIZE && ro.ro_rt != NULL)
- mtu = ro.ro_rt->rt_mtu;
- RO_RTFREE(&ro);
+ if (error == EMSGSIZE && tp->t_inpcb->inp_route.ro_rt != NULL)
+ mtu = tp->t_inpcb->inp_route.ro_rt->rt_mtu;
}
#endif /* INET */
Index: sys/netinet/tcp_subr.c
===================================================================
--- sys/netinet/tcp_subr.c
+++ sys/netinet/tcp_subr.c
@@ -1552,6 +1552,10 @@
if (tp->t_state == TCPS_ESTABLISHED &&
(error == EHOSTUNREACH || error == ENETUNREACH ||
error == EHOSTDOWN)) {
+ if (inp->inp_route.ro_rt) {
+ RTFREE(inp->inp_route.ro_rt);
+ inp->inp_route.ro_rt = (struct rtentry *)NULL;
+ }
return (inp);
} else if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 &&
tp->t_softerror) {
@@ -1845,11 +1849,11 @@
else if (V_icmp_may_rst && (cmd == PRC_UNREACH_ADMIN_PROHIB ||
cmd == PRC_UNREACH_PORT || cmd == PRC_TIMXCEED_INTRANS) && ip)
notify = tcp_drop_syn_sent;
- /*
- * Redirects don't need to be handled up here.
- */
- else if (PRC_IS_REDIRECT(cmd))
+ else if (PRC_IS_REDIRECT(cmd)) {
+ /* signal EHOSTDOWN, as it flushes the cached route */
+ in_pcbnotifyall(&tcbinfo, faddr, EHOSTDOWN, notify);
return;
+ }
/*
* Hostdead is ugly because it goes linearly through all PCBs.
* XXX: We never get this from ICMP, otherwise it makes an
Index: sys/netinet/tcp_timer.c
===================================================================
--- sys/netinet/tcp_timer.c
+++ sys/netinet/tcp_timer.c
@@ -777,7 +777,9 @@
#ifdef INET6
if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0)
in6_losing(tp->t_inpcb);
+ else
#endif
+ in_losing(tp->t_inpcb);
tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
tp->t_srtt = 0;
}
Index: sys/netinet/udp_usrreq.c
===================================================================
--- sys/netinet/udp_usrreq.c
+++ sys/netinet/udp_usrreq.c
@@ -740,6 +740,11 @@
* or a write lock, but a read lock is sufficient.
*/
INP_LOCK_ASSERT(inp);
+ if ((errno == EHOSTUNREACH || errno == ENETUNREACH ||
+ errno == EHOSTDOWN) && inp->inp_route.ro_rt) {
+ RTFREE(inp->inp_route.ro_rt);
+ inp->inp_route.ro_rt = (struct rtentry *)NULL;
+ }
inp->inp_socket->so_error = errno;
sorwakeup(inp->inp_socket);
@@ -761,11 +766,11 @@
if (sa->sa_family != AF_INET || faddr.s_addr == INADDR_ANY)
return;
- /*
- * Redirects don't need to be handled up here.
- */
- if (PRC_IS_REDIRECT(cmd))
+ if (PRC_IS_REDIRECT(cmd)) {
+ /* signal EHOSTDOWN, as it flushes the cached route */
+ in_pcbnotifyall(&udbinfo, faddr, EHOSTDOWN, udp_notify);
return;
+ }
/*
* Hostdead is ugly because it goes linearly through all PCBs.
@@ -1514,7 +1519,7 @@
else if (unlock_udbinfo == UH_RLOCKED)
INP_HASH_RUNLOCK(pcbinfo);
UDP_PROBE(send, NULL, inp, &ui->ui_i, inp, &ui->ui_u);
- error = ip_output(m, inp->inp_options, NULL, ipflags,
+ error = ip_output(m, inp->inp_options, &inp->inp_route, ipflags,
inp->inp_moptions, inp);
if (unlock_udbinfo == UH_WLOCKED)
INP_WUNLOCK(inp);
Index: sys/netinet6/in6_pcb.c
===================================================================
--- sys/netinet6/in6_pcb.c
+++ sys/netinet6/in6_pcb.c
@@ -827,9 +827,10 @@
in6_losing(struct inpcb *in6p)
{
- /*
- * We don't store route pointers in the routing table anymore
- */
+ if (in6p->inp_route6.ro_rt) {
+ RTFREE(in6p->inp_route6.ro_rt);
+ in6p->inp_route6.ro_rt = (struct rtentry *)NULL;
+ }
return;
}
@@ -840,9 +841,11 @@
struct inpcb *
in6_rtchange(struct inpcb *inp, int errno)
{
- /*
- * We don't store route pointers in the routing table anymore
- */
+
+ if (inp->inp_route6.ro_rt) {
+ RTFREE(inp->inp_route6.ro_rt);
+ inp->inp_route6.ro_rt = (struct rtentry *)NULL;
+ }
return inp;
}
Index: sys/netinet6/ip6_output.c
===================================================================
--- sys/netinet6/ip6_output.c
+++ sys/netinet6/ip6_output.c
@@ -546,7 +546,18 @@
/* adjust pointer */
ip6 = mtod(m, struct ip6_hdr *);
- if (ro->ro_rt && fwd_tag == NULL) {
+ /*
+ * Validate route against routing table additions;
+ * a better/more specific route might have been added.
+ * Make sure address family is set in route.
+ */
+ if (inp) {
+ ro->ro_dst.sin6_family = AF_INET6;
+ RT_VALIDATE((struct route *)ro, &inp->inp_rt_cookie, fibnum);
+ }
+ if (ro->ro_rt && fwd_tag == NULL && (ro->ro_rt->rt_flags & RTF_UP) &&
+ ro->ro_dst.sin6_family == AF_INET6 &&
+ IN6_ARE_ADDR_EQUAL(&ro->ro_dst.sin6_addr, &ip6->ip6_dst)) {
rt = ro->ro_rt;
ifp = ro->ro_rt->rt_ifp;
} else {
@@ -939,7 +950,8 @@
m->m_pkthdr.len);
ifa_free(&ia6->ia_ifa);
}
- error = nd6_output_ifp(ifp, origifp, m, dst, NULL);
+ error = nd6_output_ifp(ifp, origifp, m, dst,
+ (struct route *)ro);
goto done;
}
@@ -1038,7 +1050,8 @@
counter_u64_add(ia->ia_ifa.ifa_obytes,
m->m_pkthdr.len);
}
- error = nd6_output_ifp(ifp, origifp, m, dst, NULL);
+ error = nd6_output_ifp(ifp, origifp, m, dst,
+ (struct route *)ro);
} else
m_freem(m);
}
Index: sys/netinet6/udp6_usrreq.c
===================================================================
--- sys/netinet6/udp6_usrreq.c
+++ sys/netinet6/udp6_usrreq.c
@@ -876,8 +876,8 @@
UDP_PROBE(send, NULL, inp, ip6, inp, udp6);
UDPSTAT_INC(udps_opackets);
- error = ip6_output(m, optp, NULL, flags, inp->in6p_moptions,
- NULL, inp);
+ error = ip6_output(m, optp, &inp->inp_route6, flags,
+ inp->in6p_moptions, NULL, inp);
break;
case AF_INET:
error = EAFNOSUPPORT;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Oct 11, 11:49 AM (18 h, 1 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23575743
Default Alt Text
D4306.id12399.diff (11 KB)
Attached To
Mode
D4306: Re-add route caching for TCP
Attached
Detach File
Event Timeline
Log In to Comment