Don't call rtcache_check() from the fast-forward code, which runs

at IPL_NET, because rtcache_check() may read the forwarding table.
Elsewhere, the kernel only blocks interrupts at priority IPL_SOFTNET
and below while it modifies the forwarding table, so rtcache_check()
could be reading the table in an inconsistent state.  Use
rtcache_done(), instead.

XXX netinet/ip_flow.c and netinet6/ip6_flow.c are virtually identical.
XXX They should share code.
This commit is contained in:
dyoung 2007-08-20 19:42:34 +00:00
parent 1ee8b50f43
commit bd98464c6f
2 changed files with 16 additions and 20 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip_flow.c,v 1.47 2007/05/02 22:39:04 dyoung Exp $ */
/* $NetBSD: ip_flow.c,v 1.48 2007/08/20 19:42:34 dyoung Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@ -37,7 +37,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ip_flow.c,v 1.47 2007/05/02 22:39:04 dyoung Exp $");
__KERNEL_RCSID(0, "$NetBSD: ip_flow.c,v 1.48 2007/08/20 19:42:34 dyoung Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -220,9 +220,8 @@ ipflow_fastforward(struct mbuf *m)
/*
* Route and interface still up?
*/
rtcache_check(&ipf->ipf_ro);
rt = ipf->ipf_ro.ro_rt;
if (rt == NULL || (rt->rt_ifp->if_flags & IFF_UP) == 0)
if (rtcache_down(&ipf->ipf_ro) || (rt = ipf->ipf_ro.ro_rt) == NULL ||
(rt->rt_ifp->if_flags & IFF_UP) == 0)
return 0;
/*
@ -293,8 +292,7 @@ ipflow_fastforward(struct mbuf *m)
static void
ipflow_addstats(struct ipflow *ipf)
{
rtcache_check(&ipf->ipf_ro);
if (ipf->ipf_ro.ro_rt != NULL)
if (!rtcache_down(&ipf->ipf_ro) && ipf->ipf_ro.ro_rt != NULL)
ipf->ipf_ro.ro_rt->rt_use += ipf->ipf_uses;
ipstat.ips_cantforward += ipf->ipf_errors + ipf->ipf_dropped;
ipstat.ips_total += ipf->ipf_uses;
@ -335,8 +333,8 @@ ipflow_reap(int just_one)
* If this no longer points to a valid route
* reclaim it.
*/
rtcache_check(&ipf->ipf_ro);
if (ipf->ipf_ro.ro_rt == NULL)
if (rtcache_down(&ipf->ipf_ro) ||
ipf->ipf_ro.ro_rt == NULL)
goto done;
/*
* choose the one that's been least recently
@ -377,9 +375,8 @@ ipflow_slowtimo(void)
for (ipf = LIST_FIRST(&ipflowlist); ipf != NULL; ipf = next_ipf) {
next_ipf = LIST_NEXT(ipf, ipf_list);
rtcache_check(&ipf->ipf_ro);
if (PRT_SLOW_ISEXPIRED(ipf->ipf_timer) ||
ipf->ipf_ro.ro_rt == NULL) {
rtcache_down(&ipf->ipf_ro) || ipf->ipf_ro.ro_rt == NULL) {
ipflow_free(ipf);
} else {
ipf->ipf_last_uses = ipf->ipf_uses;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ip6_flow.c,v 1.8 2007/05/02 22:39:04 dyoung Exp $ */
/* $NetBSD: ip6_flow.c,v 1.9 2007/08/20 19:42:34 dyoung Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
@ -268,9 +268,9 @@ ip6flow_fastforward(struct mbuf *m)
/*
* Route and interface still up?
*/
rtcache_check(&ip6f->ip6f_ro);
rt = ip6f->ip6f_ro.ro_rt;
if (rt == NULL || (rt->rt_ifp->if_flags & IFF_UP) == 0) {
if (rtcache_down(&ip6f->ip6f_ro) ||
(rt = ip6f->ip6f_ro.ro_rt) == NULL ||
(rt->rt_ifp->if_flags & IFF_UP) == 0) {
/* Route or interface is down */
return 0;
}
@ -314,8 +314,7 @@ ip6flow_fastforward(struct mbuf *m)
static void
ip6flow_addstats(struct ip6flow *ip6f)
{
rtcache_check(&ip6f->ip6f_ro);
if (ip6f->ip6f_ro.ro_rt != NULL)
if (!rtcache_down(&ip6f->ip6f_ro) && ip6f->ip6f_ro.ro_rt != NULL)
ip6f->ip6f_ro.ro_rt->rt_use += ip6f->ip6f_uses;
ip6stat.ip6s_fastforwardflows = ip6flow_inuse;
ip6stat.ip6s_cantforward += ip6f->ip6f_dropped;
@ -364,8 +363,8 @@ ip6flow_reap(int just_one)
* If this no longer points to a valid route -
* reclaim it.
*/
rtcache_check(&ip6f->ip6f_ro);
if (ip6f->ip6f_ro.ro_rt == NULL)
if (rtcache_down(&ip6f->ip6f_ro) ||
ip6f->ip6f_ro.ro_rt == NULL)
goto done;
/*
* choose the one that's been least recently
@ -408,8 +407,8 @@ ip6flow_slowtimo(void)
for (ip6f = LIST_FIRST(&ip6flowlist); ip6f != NULL; ip6f = next_ip6f) {
next_ip6f = LIST_NEXT(ip6f, ip6f_list);
rtcache_check(&ip6f->ip6f_ro);
if (PRT_SLOW_ISEXPIRED(ip6f->ip6f_timer) ||
rtcache_down(&ip6f->ip6f_ro) ||
ip6f->ip6f_ro.ro_rt == NULL) {
ip6flow_free(ip6f);
} else {