Remove the global one-level rtcache variable and associated

complex locking and rework ip_rtaddr() to do its own rtlookup.
Adopt all its callers to this and make ip_output() callable
with NULL rt pointer.

Reviewed by:	sam (mentor)
This commit is contained in:
Andre Oppermann 2003-11-14 21:48:57 +00:00
parent 9365176c26
commit 02c1c7070e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=122708
6 changed files with 103 additions and 242 deletions

View File

@ -134,13 +134,6 @@ in_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
}
}
/*
* If the new route created successfully, and we are forwarding,
* flush any cached routes to avoid using a stale value.
*/
if (ret != NULL && ipforwarding)
ip_forward_cacheinval();
return ret;
}

View File

@ -1160,7 +1160,6 @@ send_pkt(struct ipfw_flow_id *id, u_int32_t seq, u_int32_t ack, int flags)
struct mbuf *m;
struct ip *ip;
struct tcphdr *tcp;
struct route sro; /* fake route */
MGETHDR(m, M_DONTWAIT, MT_HEADER);
if (m == 0)
@ -1226,12 +1225,8 @@ send_pkt(struct ipfw_flow_id *id, u_int32_t seq, u_int32_t ack, int flags)
*/
ip->ip_ttl = ip_defttl;
ip->ip_len = m->m_pkthdr.len;
bzero (&sro, sizeof (sro));
ip_rtaddr(ip->ip_dst, &sro);
m->m_flags |= M_SKIP_FIREWALL;
ip_output(m, NULL, &sro, 0, NULL, NULL);
if (sro.ro_rt)
RTFREE(sro.ro_rt);
ip_output(m, NULL, NULL, 0, NULL, NULL);
}
/*

View File

@ -120,7 +120,7 @@ int icmpprintfs = 0;
#endif
static void icmp_reflect(struct mbuf *);
static void icmp_send(struct mbuf *, struct mbuf *, struct route *);
static void icmp_send(struct mbuf *, struct mbuf *);
static int ip_next_mtu(int, int);
extern struct protosw inetsw[];
@ -615,7 +615,6 @@ icmp_reflect(m)
struct in_addr t;
struct mbuf *opts = 0;
int optlen = (ip->ip_hl << 2) - sizeof(struct ip);
struct route *ro = NULL, rt;
if (!in_canforward(ip->ip_src) &&
((ntohl(ip->ip_src.s_addr) & IN_CLASSA_NET) !=
@ -626,8 +625,6 @@ icmp_reflect(m)
}
t = ip->ip_dst;
ip->ip_dst = ip->ip_src;
ro = &rt;
bzero(ro, sizeof(*ro));
/*
* If the incoming packet was addressed directly to us,
* use dst as the src for the reply. Otherwise (broadcast
@ -648,7 +645,7 @@ icmp_reflect(m)
goto match;
}
}
ia = ip_rtaddr(ip->ip_dst, ro);
ia = ip_rtaddr(ip->ip_dst);
/* We need a route to do anything useful. */
if (ia == NULL) {
m_freem(m);
@ -738,12 +735,10 @@ icmp_reflect(m)
}
m_tag_delete_nonpersistent(m);
m->m_flags &= ~(M_BCAST|M_MCAST);
icmp_send(m, opts, ro);
icmp_send(m, opts);
done:
if (opts)
(void)m_free(opts);
if (ro && ro->ro_rt)
RTFREE(ro->ro_rt);
}
/*
@ -751,10 +746,9 @@ icmp_reflect(m)
* after supplying a checksum.
*/
static void
icmp_send(m, opts, rt)
icmp_send(m, opts)
register struct mbuf *m;
struct mbuf *opts;
struct route *rt;
{
register struct ip *ip = mtod(m, struct ip *);
register int hlen;
@ -777,7 +771,7 @@ icmp_send(m, opts, rt)
buf, inet_ntoa(ip->ip_src));
}
#endif
(void) ip_output(m, opts, rt, 0, NULL, NULL);
(void) ip_output(m, opts, NULL, 0, NULL, NULL);
}
n_time

View File

@ -212,52 +212,6 @@ int fw_one_pass = 1;
/* Dummynet hooks */
ip_dn_io_t *ip_dn_io_ptr;
/*
* One deep route cache for ip forwarding. This is done
* very inefficiently. We don't care as it's about to be
* replaced by something better.
*/
static struct rtcache {
struct route rc_ro; /* most recently used route */
struct mtx rc_mtx; /* update lock for cache */
} ip_fwdcache;
#define RTCACHE_LOCK() mtx_lock(&ip_fwdcache.rc_mtx)
#define RTCACHE_UNLOCK() mtx_unlock(&ip_fwdcache.rc_mtx)
#define RTCACHE_LOCK_INIT() \
mtx_init(&ip_fwdcache.rc_mtx, "route cache", NULL, MTX_DEF)
#define RTCACHE_LOCK_ASSERT() mtx_assert(&ip_fwdcache.rc_mtx, MA_OWNED)
/*
* Get a copy of the current route cache contents.
*/
#define RTCACHE_GET(_ro) do { \
struct rtentry *rt; \
RTCACHE_LOCK(); \
*(_ro) = ip_fwdcache.rc_ro; \
if ((rt = (_ro)->ro_rt) != NULL) { \
RT_LOCK(rt); \
RT_ADDREF(rt); \
RT_UNLOCK(rt); \
} \
RTCACHE_UNLOCK(); \
} while (0)
/*
* Update the cache contents.
*/
#define RTCACHE_UPDATE(_ro) do { \
struct rtentry *rt; \
RTCACHE_LOCK(); \
rt = ip_fwdcache.rc_ro.ro_rt; \
if ((_ro)->ro_rt != rt) { \
ip_fwdcache.rc_ro = *(_ro); \
if (rt) \
RTFREE(rt); \
} \
RTCACHE_UNLOCK(); \
} while (0)
/*
* XXX this is ugly -- the following two global variables are
* used to store packet state while it travels through the stack.
@ -282,7 +236,7 @@ static struct ip_srcrt {
static void save_rte(u_char *, struct in_addr);
static int ip_dooptions(struct mbuf *m, int,
struct sockaddr_in *next_hop);
static void ip_forward(struct mbuf *m, struct route *, int srcrt,
static void ip_forward(struct mbuf *m, int srcrt,
struct sockaddr_in *next_hop);
static void ip_freef(struct ipqhead *, struct ipq *);
static struct mbuf *ip_reass(struct mbuf *, struct ipqhead *,
@ -323,9 +277,6 @@ ip_init()
for (i = 0; i < IPREASS_NHASH; i++)
TAILQ_INIT(&ipq[i]);
bzero(&ip_fwdcache, sizeof(ip_fwdcache));
RTCACHE_LOCK_INIT();
maxnipq = nmbclusters / 32;
maxfragsperpacket = 16;
@ -337,22 +288,6 @@ ip_init()
netisr_register(NETISR_IP, ip_input, &ipintrq, NETISR_MPSAFE);
}
/*
* Invalidate any cached route used for forwarding.
*/
void
ip_forward_cacheinval(void)
{
struct rtentry *rt;
RTCACHE_LOCK();
rt = ip_fwdcache.rc_ro.ro_rt;
ip_fwdcache.rc_ro.ro_rt = 0;
if (rt != NULL)
RTFREE(rt);
RTCACHE_UNLOCK();
}
/*
* Ip input routine. Checksum and byte swap header. If fragmented
* try to reassemble. Process options. Pass to next level.
@ -370,8 +305,7 @@ ip_input(struct mbuf *m)
struct in_addr pkt_dst;
u_int32_t divert_info = 0; /* packet divert/tee info */
struct ip_fw_args args;
struct route cro; /* copy of cached route */
int srcrt = 0; /* forward by ``src routing'' */
int dchg = 0; /* dest changed after fw */
#ifdef PFIL_HOOKS
struct in_addr odst; /* original dst address */
#endif
@ -566,7 +500,7 @@ ip_input(struct mbuf *m)
if (m == NULL) /* consumed by filter */
return;
ip = mtod(m, struct ip *);
srcrt = (odst.s_addr != ip->ip_dst.s_addr);
dchg = (odst.s_addr != ip->ip_dst.s_addr);
#endif /* PFIL_HOOKS */
if (fw_enable && IPFW_LOADED) {
@ -802,8 +736,7 @@ ip_input(struct mbuf *m)
goto bad;
}
#endif /* FAST_IPSEC */
RTCACHE_GET(&cro);
ip_forward(m, &cro, srcrt, args.next_hop);
ip_forward(m, dchg, args.next_hop);
}
return;
@ -1419,14 +1352,6 @@ ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
struct in_addr *sin, dst;
n_time ntime;
struct sockaddr_in ipaddr = { sizeof(ipaddr), AF_INET };
struct route cro; /* copy of cached route */
/*
* Grab a copy of the route cache in case we need
* to update to reflect source routing or the like.
* Could optimize this to do it later...
*/
RTCACHE_GET(&cro);
dst = ip->ip_dst;
cp = (u_char *)(ip + 1);
@ -1546,7 +1471,7 @@ ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0)
ia = (INA)ifa_ifwithnet((SA)&ipaddr);
} else
ia = ip_rtaddr(ipaddr.sin_addr, &cro);
ia = ip_rtaddr(ipaddr.sin_addr);
if (ia == 0) {
type = ICMP_UNREACH;
code = ICMP_UNREACH_SRCFAIL;
@ -1588,7 +1513,7 @@ ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
* use the incoming interface (should be same).
*/
if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 &&
(ia = ip_rtaddr(ipaddr.sin_addr, &cro)) == 0) {
(ia = ip_rtaddr(ipaddr.sin_addr)) == 0) {
type = ICMP_UNREACH;
code = ICMP_UNREACH_HOST;
goto bad;
@ -1668,7 +1593,7 @@ ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
}
}
if (forward && ipforwarding) {
ip_forward(m, &cro, 1, next_hop);
ip_forward(m, 1, next_hop);
return (1);
}
return (0);
@ -1683,30 +1608,26 @@ ip_dooptions(struct mbuf *m, int pass, struct sockaddr_in *next_hop)
* return internet address info of interface to be used to get there.
*/
struct in_ifaddr *
ip_rtaddr(dst, rt)
ip_rtaddr(dst)
struct in_addr dst;
struct route *rt;
{
register struct sockaddr_in *sin;
struct sockaddr_in *sin;
struct in_ifaddr *ifa;
struct route ro;
sin = (struct sockaddr_in *)&rt->ro_dst;
bzero(&ro, sizeof(ro));
sin = (struct sockaddr_in *)&ro.ro_dst;
sin->sin_family = AF_INET;
sin->sin_len = sizeof(*sin);
sin->sin_addr = dst;
rtalloc_ign(&ro, (RTF_PRCLONING | RTF_CLONING));
if (rt->ro_rt == 0 ||
!(rt->ro_rt->rt_flags & RTF_UP) ||
dst.s_addr != sin->sin_addr.s_addr) {
if (rt->ro_rt) {
RTFREE(rt->ro_rt);
rt->ro_rt = 0;
}
sin->sin_family = AF_INET;
sin->sin_len = sizeof(*sin);
sin->sin_addr = dst;
rtalloc_ign(rt, RTF_PRCLONING);
}
if (rt->ro_rt == 0)
if (ro.ro_rt == 0)
return ((struct in_ifaddr *)0);
return (ifatoia(rt->ro_rt->rt_ifa));
ifa = ifatoia(ro.ro_rt->rt_ifa);
RTFREE(ro.ro_rt);
return ifa;
}
/*
@ -1853,11 +1774,10 @@ u_char inetctlerrmap[PRC_NCMDS] = {
* via a source route.
*/
static void
ip_forward(struct mbuf *m, struct route *ro,
int srcrt, struct sockaddr_in *next_hop)
ip_forward(struct mbuf *m, int srcrt, struct sockaddr_in *next_hop)
{
struct ip *ip = mtod(m, struct ip *);
struct rtentry *rt;
struct in_ifaddr *ia;
int error, type = 0, code = 0;
struct mbuf *mcopy;
n_long dest;
@ -1867,7 +1787,6 @@ ip_forward(struct mbuf *m, struct route *ro,
struct ifnet dummyifp;
#endif
dest = 0;
/*
* Cache the destination address of the packet; this may be
* changed by use of 'ipfw fwd'.
@ -1892,18 +1811,17 @@ ip_forward(struct mbuf *m, struct route *ro,
#endif
if (ip->ip_ttl <= IPTTLDEC) {
icmp_error(m, ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS,
dest, 0);
0, 0);
return;
}
#ifdef IPSTEALTH
}
#endif
if (ip_rtaddr(pkt_dst, ro) == 0) {
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, dest, 0);
if ((ia = ip_rtaddr(pkt_dst)) == 0) {
icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_HOST, 0, 0);
return;
} else
rt = ro->ro_rt;
}
/*
* Save the IP header and at most 8 bytes of the payload,
@ -1954,27 +1872,44 @@ ip_forward(struct mbuf *m, struct route *ro,
* Also, don't send redirect if forwarding using a default route
* or a route modified by a redirect.
*/
if (rt->rt_ifp == m->m_pkthdr.rcvif &&
(rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
ipsendredirects && !srcrt && !next_hop) {
#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa))
u_long src = ntohl(ip->ip_src.s_addr);
dest = 0;
if (ipsendredirects && ia->ia_ifp == m->m_pkthdr.rcvif) {
struct sockaddr_in *sin;
struct route ro;
struct rtentry *rt;
if (RTA(rt) &&
(src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
if (rt->rt_flags & RTF_GATEWAY)
dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
else
dest = pkt_dst.s_addr;
/* Router requirements says to only send host redirects */
type = ICMP_REDIRECT;
code = ICMP_REDIRECT_HOST;
bzero(&ro, sizeof(ro));
sin = (struct sockaddr_in *)&ro.ro_dst;
sin->sin_family = AF_INET;
sin->sin_len = sizeof(*sin);
sin->sin_addr = pkt_dst;
rtalloc_ign(&ro, (RTF_PRCLONING | RTF_CLONING));
rt = ro.ro_rt;
if (rt && (rt->rt_flags & (RTF_DYNAMIC|RTF_MODIFIED)) == 0 &&
satosin(rt_key(rt))->sin_addr.s_addr != 0 &&
ipsendredirects && !srcrt && !next_hop) {
#define RTA(rt) ((struct in_ifaddr *)(rt->rt_ifa))
u_long src = ntohl(ip->ip_src.s_addr);
if (RTA(rt) &&
(src & RTA(rt)->ia_subnetmask) == RTA(rt)->ia_subnet) {
if (rt->rt_flags & RTF_GATEWAY)
dest = satosin(rt->rt_gateway)->sin_addr.s_addr;
else
dest = pkt_dst.s_addr;
/* Router requirements says to only send host redirects */
type = ICMP_REDIRECT;
code = ICMP_REDIRECT_HOST;
#ifdef DIAGNOSTIC
if (ipprintfs)
printf("redirect (%d) to %lx\n", code, (u_long)dest);
if (ipprintfs)
printf("redirect (%d) to %lx\n", code, (u_long)dest);
#endif
}
}
if (rt)
RTFREE(rt);
}
{
@ -1989,13 +1924,8 @@ ip_forward(struct mbuf *m, struct route *ro,
tag.mh_next = m;
m = (struct mbuf *)&tag;
}
error = ip_output(m, (struct mbuf *)0, ro, IP_FORWARDING, 0, NULL);
error = ip_output(m, (struct mbuf *)0, NULL, IP_FORWARDING, 0, NULL);
}
/*
* Update the ip forwarding cache with the route we used.
* We may want to do this more selectively; not sure.
*/
RTCACHE_UPDATE(ro);
if (error)
ipstat.ips_cantforward++;
else {
@ -2030,77 +1960,31 @@ ip_forward(struct mbuf *m, struct route *ro,
case EMSGSIZE:
type = ICMP_UNREACH;
code = ICMP_UNREACH_NEEDFRAG;
#ifdef IPSEC
#if defined(IPSEC) || defined(FAST_IPSEC)
/*
* If the packet is routed over IPsec tunnel, tell the
* originator the tunnel MTU.
* tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
* XXX quickhack!!!
*/
if (ro->ro_rt) {
{
struct secpolicy *sp = NULL;
int ipsecerror;
int ipsechdr;
struct route *ro;
#ifdef IPSEC
sp = ipsec4_getpolicybyaddr(mcopy,
IPSEC_DIR_OUTBOUND,
IP_FORWARDING,
&ipsecerror);
if (sp == NULL)
destifp = ro->ro_rt->rt_ifp;
else {
/* count IPsec header size */
ipsechdr = ipsec4_hdrsiz(mcopy,
IPSEC_DIR_OUTBOUND,
NULL);
/*
* find the correct route for outer IPv4
* header, compute tunnel MTU.
*
* XXX BUG ALERT
* The "dummyifp" code relies upon the fact
* that icmp_error() touches only ifp->if_mtu.
*/
/*XXX*/
destifp = NULL;
if (sp->req != NULL
&& sp->req->sav != NULL
&& sp->req->sav->sah != NULL) {
struct route *saro;
saro = &sp->req->sav->sah->sa_route;
if (saro->ro_rt && saro->ro_rt->rt_ifp) {
dummyifp.if_mtu =
saro->ro_rt->rt_ifp->if_mtu;
dummyifp.if_mtu -= ipsechdr;
destifp = &dummyifp;
}
}
key_freesp(sp);
}
}
#elif FAST_IPSEC
/*
* If the packet is routed over IPsec tunnel, tell the
* originator the tunnel MTU.
* tunnel MTU = if MTU - sizeof(IP) - ESP/AH hdrsiz
* XXX quickhack!!!
*/
if (ro->ro_rt) {
struct secpolicy *sp = NULL;
int ipsecerror;
int ipsechdr;
IP_FORWARDING,
&ipsecerror);
#else /* FAST_IPSEC */
sp = ipsec_getpolicybyaddr(mcopy,
IPSEC_DIR_OUTBOUND,
IP_FORWARDING,
&ipsecerror);
if (sp == NULL)
destifp = ro->ro_rt->rt_ifp;
else {
IP_FORWARDING,
&ipsecerror);
#endif
if (sp != NULL) {
/* count IPsec header size */
ipsechdr = ipsec4_hdrsiz(mcopy,
IPSEC_DIR_OUTBOUND,
@ -2119,23 +2003,28 @@ ip_forward(struct mbuf *m, struct route *ro,
if (sp->req != NULL
&& sp->req->sav != NULL
&& sp->req->sav->sah != NULL) {
struct route *saro;
saro = &sp->req->sav->sah->sa_route;
if (saro->ro_rt && saro->ro_rt->rt_ifp) {
ro = &sp->req->sav->sah->sa_route;
if (ro->ro_rt && ro->ro_rt->rt_ifp) {
dummyifp.if_mtu =
saro->ro_rt->rt_ifp->if_mtu;
ro->ro_rt->rt_ifp->if_mtu;
dummyifp.if_mtu -= ipsechdr;
destifp = &dummyifp;
}
}
#ifdef IPSEC
key_freesp(sp);
#else /* FAST_IPSEC */
KEY_FREESP(&sp);
}
#endif
ipstat.ips_cantfrag++;
break;
} else
#endif /*IPSEC || FAST_IPSEC*/
destifp = ia->ia_ifp;
#if defined(IPSEC) || defined(FAST_IPSEC)
}
#else /* !IPSEC && !FAST_IPSEC */
if (ro->ro_rt)
destifp = ro->ro_rt->rt_ifp;
#endif /*IPSEC*/
#endif /*IPSEC || FAST_IPSEC*/
ipstat.ips_cantfrag++;
break;

View File

@ -142,13 +142,12 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
struct in_ifaddr *ia = NULL;
int isbroadcast, sw_csum;
struct in_addr pkt_dst;
#ifdef IPSEC
struct route iproute;
#ifdef IPSEC
struct socket *so;
struct secpolicy *sp = NULL;
#endif
#ifdef FAST_IPSEC
struct route iproute;
struct m_tag *mtag;
struct secpolicy *sp = NULL;
struct tdb_ident *tdbi;
@ -202,10 +201,12 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
#endif /*IPSEC*/
M_ASSERTPKTHDR(m);
#ifndef FAST_IPSEC
KASSERT(ro != NULL, ("ip_output: no route, proto %d",
mtod(m, struct ip *)->ip_p));
#endif
if (ro == NULL) {
ro = &iproute;
bzero(ro, sizeof (*ro));
}
if (inp != NULL)
INP_LOCK_ASSERT(inp);
@ -256,12 +257,6 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
hlen = ip->ip_hl << 2;
}
#ifdef FAST_IPSEC
if (ro == NULL) {
ro = &iproute;
bzero(ro, sizeof (*ro));
}
#endif /* FAST_IPSEC */
dst = (struct sockaddr_in *)&ro->ro_dst;
/*
* If there is a cached route,
@ -1089,11 +1084,11 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
ipstat.ips_fragmented++;
done:
#ifdef IPSEC
if (ro == &iproute && ro->ro_rt) {
RTFREE(ro->ro_rt);
ro->ro_rt = NULL;
}
#ifdef IPSEC
if (sp != NULL) {
KEYDEBUG(KEYDEBUG_IPSEC_STAMP,
printf("DP ip_output call free SP:%p\n", sp));
@ -1101,10 +1096,6 @@ ip_output(struct mbuf *m0, struct mbuf *opt, struct route *ro,
}
#endif
#ifdef FAST_IPSEC
if (ro == &iproute && ro->ro_rt) {
RTFREE(ro->ro_rt);
ro->ro_rt = NULL;
}
if (sp != NULL)
KEY_FREESP(&sp);
#endif

View File

@ -162,7 +162,6 @@ int ip_ctloutput(struct socket *, struct sockopt *sopt);
void ip_drain(void);
int ip_fragment(struct ip *ip, struct mbuf **m_frag, int mtu,
u_long if_hwassist_flags, int sw_csum);
void ip_forward_cacheinval(void);
void ip_freemoptions(struct ip_moptions *);
void ip_init(void);
extern int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,
@ -171,7 +170,7 @@ int ip_output(struct mbuf *,
struct mbuf *, struct route *, int, struct ip_moptions *,
struct inpcb *);
struct in_ifaddr *
ip_rtaddr(struct in_addr, struct route *);
ip_rtaddr(struct in_addr);
void ip_savecontrol(struct inpcb *, struct mbuf **, struct ip *,
struct mbuf *);
void ip_slowtimo(void);