aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet6/ip6_forward.c
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2009-02-01 21:11:08 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2009-02-01 21:11:08 +0000
commit09f8c3ff36e002db86a2d26011e87b446b94b827 (patch)
treea5470a3738df362d49e1bb6da8886ec0f93e4d7c /sys/netinet6/ip6_forward.c
parent23c608c8f6456998ecd0ac7b8fd5fab8e8177f46 (diff)
downloadsrc-09f8c3ff36e002db86a2d26011e87b446b94b827.tar.gz
src-09f8c3ff36e002db86a2d26011e87b446b94b827.zip
Remove the single global unlocked route cache ip6_forward_rt
from the inet6 stack along with statistics and make sure we properly free the rt in all cases. While the current situation is not better performance wise it prevents panics seen more often these days. After more inet6 and ipsec cleanup we should be able to improve the situation again passing the rt to ip6_forward directly. Leave the ip6_forward_rt entry in struct vinet6 but mark it for removal. PR: kern/128247, kern/131038 MFC after: 25 days Committed from: Bugathon #6 Tested by: Denis Ahrens <denis@h3q.com> (different initial version)
Notes
Notes: svn path=/head/; revision=187989
Diffstat (limited to 'sys/netinet6/ip6_forward.c')
-rw-r--r--sys/netinet6/ip6_forward.c107
1 files changed, 38 insertions, 69 deletions
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index 0ce591f37e60..ca5101f0d910 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -77,10 +77,6 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip6protosw.h>
-#ifdef VIMAGE_GLOBALS
-struct route_in6 ip6_forward_rt;
-#endif
-
/*
* Forward a packet. If some error occurs return the sender
* an icmp packet. Note we can't always generate a meaningful
@@ -100,6 +96,7 @@ ip6_forward(struct mbuf *m, int srcrt)
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *);
struct sockaddr_in6 *dst = NULL;
struct rtentry *rt = NULL;
+ struct route_in6 rin6;
int error, type = 0, code = 0;
struct mbuf *mcopy = NULL;
struct ifnet *origifp; /* maybe unnecessary */
@@ -112,8 +109,6 @@ ip6_forward(struct mbuf *m, int srcrt)
#endif
char ip6bufs[INET6_ADDRSTRLEN], ip6bufd[INET6_ADDRSTRLEN];
- /* GIANT_REQUIRED; */ /* XXX bz: ip6_forward_rt */
-
#ifdef IPSEC
/*
* Check AH/ESP integrity.
@@ -355,56 +350,27 @@ ip6_forward(struct mbuf *m, int srcrt)
skip_ipsec:
#endif
- dst = (struct sockaddr_in6 *)&V_ip6_forward_rt.ro_dst;
- if (!srcrt) {
- /* ip6_forward_rt.ro_dst.sin6_addr is equal to ip6->ip6_dst */
- if (V_ip6_forward_rt.ro_rt == 0 ||
- (V_ip6_forward_rt.ro_rt->rt_flags & RTF_UP) == 0) {
- if (V_ip6_forward_rt.ro_rt) {
- RTFREE(V_ip6_forward_rt.ro_rt);
- V_ip6_forward_rt.ro_rt = 0;
- }
-
- /* this probably fails but give it a try again */
- rtalloc((struct route *)&V_ip6_forward_rt);
- }
-
- if (V_ip6_forward_rt.ro_rt == 0) {
- V_ip6stat.ip6s_noroute++;
- in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
- if (mcopy) {
- icmp6_error(mcopy, ICMP6_DST_UNREACH,
- ICMP6_DST_UNREACH_NOROUTE, 0);
- }
- m_freem(m);
- return;
- }
- } else if ((rt = V_ip6_forward_rt.ro_rt) == 0 ||
- !IN6_ARE_ADDR_EQUAL(&ip6->ip6_dst, &dst->sin6_addr)) {
- if (V_ip6_forward_rt.ro_rt) {
- RTFREE(V_ip6_forward_rt.ro_rt);
- V_ip6_forward_rt.ro_rt = 0;
- }
- bzero(dst, sizeof(*dst));
- dst->sin6_len = sizeof(struct sockaddr_in6);
- dst->sin6_family = AF_INET6;
- dst->sin6_addr = ip6->ip6_dst;
-
- rtalloc((struct route *)&V_ip6_forward_rt);
- if (V_ip6_forward_rt.ro_rt == 0) {
- V_ip6stat.ip6s_noroute++;
- in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
- if (mcopy) {
- icmp6_error(mcopy, ICMP6_DST_UNREACH,
- ICMP6_DST_UNREACH_NOROUTE, 0);
- }
- m_freem(m);
- return;
+ bzero(&rin6, sizeof(struct route_in6));
+ dst = (struct sockaddr_in6 *)&rin6.ro_dst;
+ dst->sin6_len = sizeof(struct sockaddr_in6);
+ dst->sin6_family = AF_INET6;
+ dst->sin6_addr = ip6->ip6_dst;
+
+ rin6.ro_rt = rtalloc1((struct sockaddr *)dst, 0, 0);
+ if (rin6.ro_rt != NULL)
+ RT_UNLOCK(rin6.ro_rt);
+ else {
+ V_ip6stat.ip6s_noroute++;
+ in6_ifstat_inc(m->m_pkthdr.rcvif, ifs6_in_noroute);
+ if (mcopy) {
+ icmp6_error(mcopy, ICMP6_DST_UNREACH,
+ ICMP6_DST_UNREACH_NOROUTE, 0);
}
+ goto bad;
}
- rt = V_ip6_forward_rt.ro_rt;
+ rt = rin6.ro_rt;
#ifdef IPSEC
- skip_routing:;
+skip_routing:
#endif
/*
@@ -421,14 +387,12 @@ skip_ipsec:
/* XXX: this should not happen */
V_ip6stat.ip6s_cantforward++;
V_ip6stat.ip6s_badscope++;
- m_freem(m);
- return;
+ goto bad;
}
if (in6_setscope(&src_in6, m->m_pkthdr.rcvif, &inzone)) {
V_ip6stat.ip6s_cantforward++;
V_ip6stat.ip6s_badscope++;
- m_freem(m);
- return;
+ goto bad;
}
if (inzone != outzone
#ifdef IPSEC
@@ -452,8 +416,7 @@ skip_ipsec:
if (mcopy)
icmp6_error(mcopy, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_BEYONDSCOPE, 0);
- m_freem(m);
- return;
+ goto bad;
}
/*
@@ -469,8 +432,7 @@ skip_ipsec:
inzone != outzone) {
V_ip6stat.ip6s_cantforward++;
V_ip6stat.ip6s_badscope++;
- m_freem(m);
- return;
+ goto bad;
}
if (m->m_pkthdr.len > IN6_LINKMTU(rt->rt_ifp)) {
@@ -510,8 +472,7 @@ skip_ipsec:
#endif /* IPSEC */
icmp6_error(mcopy, ICMP6_PACKET_TOO_BIG, 0, mtu);
}
- m_freem(m);
- return;
+ goto bad;
}
if (rt->rt_flags & RTF_GATEWAY)
@@ -544,8 +505,7 @@ skip_ipsec:
*/
icmp6_error(mcopy, ICMP6_DST_UNREACH,
ICMP6_DST_UNREACH_ADDR, 0);
- m_freem(m);
- return;
+ goto bad;
}
type = ND_REDIRECT;
}
@@ -624,12 +584,12 @@ pass:
senderr:
if (mcopy == NULL)
- return;
+ goto out;
switch (error) {
case 0:
if (type == ND_REDIRECT) {
icmp6_redirect_output(mcopy, rt);
- return;
+ goto out;
}
goto freecopy;
@@ -651,9 +611,18 @@ senderr:
break;
}
icmp6_error(mcopy, type, code, 0);
- return;
+ goto out;
freecopy:
m_freem(mcopy);
- return;
+ goto out;
+bad:
+ m_freem(m);
+out:
+ if (rt != NULL
+#ifdef IPSEC
+ && !ipsecrt
+#endif
+ )
+ RTFREE(rt);
}