version 1.66, 2005/05/29 21:22:53 |
version 1.66.2.4, 2007/09/03 14:42:24 |
|
|
* @(#)route.c 8.3 (Berkeley) 1/9/95 |
* @(#)route.c 8.3 (Berkeley) 1/9/95 |
*/ |
*/ |
|
|
|
#include "opt_route.h" |
|
|
#include <sys/cdefs.h> |
#include <sys/cdefs.h> |
__KERNEL_RCSID(0, "$NetBSD$"); |
__KERNEL_RCSID(0, "$NetBSD$"); |
|
|
#include "opt_ns.h" |
|
|
|
#include <sys/param.h> |
#include <sys/param.h> |
|
#include <sys/sysctl.h> |
#include <sys/systm.h> |
#include <sys/systm.h> |
#include <sys/callout.h> |
#include <sys/callout.h> |
#include <sys/proc.h> |
#include <sys/proc.h> |
Line 122 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 123 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <netinet/in.h> |
#include <netinet/in.h> |
#include <netinet/in_var.h> |
#include <netinet/in_var.h> |
|
|
#ifdef NS |
#ifdef RTFLUSH_DEBUG |
#include <netns/ns.h> |
#define rtcache_debug() __predict_false(_rtcache_debug) |
#endif |
#else /* RTFLUSH_DEBUG */ |
|
#define rtcache_debug() 0 |
#define SA(p) ((struct sockaddr *)(p)) |
#endif /* RTFLUSH_DEBUG */ |
|
|
struct route_cb route_cb; |
struct route_cb route_cb; |
struct rtstat rtstat; |
struct rtstat rtstat; |
Line 135 struct radix_node_head *rt_tables[AF_MAX |
|
Line 136 struct radix_node_head *rt_tables[AF_MAX |
|
int rttrash; /* routes not in table but not freed */ |
int rttrash; /* routes not in table but not freed */ |
struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ |
struct sockaddr wildcard; /* zero valued cookie for wildcard searches */ |
|
|
POOL_INIT(rtentry_pool, sizeof(struct rtentry), 0, 0, 0, "rtentpl", NULL); |
POOL_INIT(rtentry_pool, sizeof(struct rtentry), 0, 0, 0, "rtentpl", NULL, |
POOL_INIT(rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl", NULL); |
IPL_SOFTNET); |
|
POOL_INIT(rttimer_pool, sizeof(struct rttimer), 0, 0, 0, "rttmrpl", NULL, |
|
IPL_SOFTNET); |
|
|
struct callout rt_timer_ch; /* callout for rt_timer_timer() */ |
struct callout rt_timer_ch; /* callout for rt_timer_timer() */ |
|
|
|
#ifdef RTFLUSH_DEBUG |
|
static int _rtcache_debug = 0; |
|
#endif /* RTFLUSH_DEBUG */ |
|
|
static int rtdeletemsg(struct rtentry *); |
static int rtdeletemsg(struct rtentry *); |
static int rtflushclone1(struct radix_node *, void *); |
static int rtflushclone1(struct rtentry *, void *); |
static void rtflushclone(struct radix_node_head *, struct rtentry *); |
static void rtflushclone(sa_family_t family, struct rtentry *); |
|
|
|
#ifdef RTFLUSH_DEBUG |
|
SYSCTL_SETUP(sysctl_net_rtcache_setup, "sysctl net.rtcache.debug setup") |
|
{ |
|
const struct sysctlnode *rnode; |
|
|
|
/* XXX do not duplicate */ |
|
if (sysctl_createv(clog, 0, NULL, &rnode, CTLFLAG_PERMANENT, |
|
CTLTYPE_NODE, "net", NULL, NULL, 0, NULL, 0, CTL_NET, CTL_EOL) != 0) |
|
return; |
|
if (sysctl_createv(clog, 0, &rnode, &rnode, CTLFLAG_PERMANENT, |
|
CTLTYPE_NODE, |
|
"rtcache", SYSCTL_DESCR("Route cache related settings"), |
|
NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL) != 0) |
|
return; |
|
if (sysctl_createv(clog, 0, &rnode, &rnode, |
|
CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, |
|
"debug", SYSCTL_DESCR("Debug route caches"), |
|
NULL, 0, &_rtcache_debug, 0, CTL_CREATE, CTL_EOL) != 0) |
|
return; |
|
} |
|
#endif /* RTFLUSH_DEBUG */ |
|
|
|
struct ifaddr * |
|
rt_get_ifa(struct rtentry *rt) |
|
{ |
|
struct ifaddr *ifa; |
|
|
|
if ((ifa = rt->rt_ifa) == NULL) |
|
return ifa; |
|
else if (ifa->ifa_getifa == NULL) |
|
return ifa; |
|
#if 0 |
|
else if (ifa->ifa_seqno != NULL && *ifa->ifa_seqno == rt->rt_ifa_seqno) |
|
return ifa; |
|
#endif |
|
else { |
|
ifa = (*ifa->ifa_getifa)(ifa, rt_getkey(rt)); |
|
rt_replace_ifa(rt, ifa); |
|
return ifa; |
|
} |
|
} |
|
|
|
static void |
|
rt_set_ifa1(struct rtentry *rt, struct ifaddr *ifa) |
|
{ |
|
rt->rt_ifa = ifa; |
|
if (ifa->ifa_seqno != NULL) |
|
rt->rt_ifa_seqno = *ifa->ifa_seqno; |
|
} |
|
|
|
void |
|
rt_replace_ifa(struct rtentry *rt, struct ifaddr *ifa) |
|
{ |
|
IFAREF(ifa); |
|
IFAFREE(rt->rt_ifa); |
|
rt_set_ifa1(rt, ifa); |
|
} |
|
|
|
static void |
|
rt_set_ifa(struct rtentry *rt, struct ifaddr *ifa) |
|
{ |
|
IFAREF(ifa); |
|
rt_set_ifa1(rt, ifa); |
|
} |
|
|
void |
void |
rtable_init(void **table) |
rtable_init(void **table) |
Line 162 route_init(void) |
|
Line 234 route_init(void) |
|
rtable_init((void **)rt_tables); |
rtable_init((void **)rt_tables); |
} |
} |
|
|
|
void |
|
rtflushall(int family) |
|
{ |
|
int s; |
|
struct domain *dom; |
|
struct route *ro; |
|
|
|
if (rtcache_debug()) |
|
printf("%s: enter\n", __func__); |
|
|
|
if ((dom = pffinddomain(family)) == NULL) |
|
return; |
|
|
|
s = splnet(); |
|
while ((ro = LIST_FIRST(&dom->dom_rtcache)) != NULL) { |
|
KASSERT(ro->ro_rt != NULL); |
|
rtcache_clear(ro); |
|
} |
|
splx(s); |
|
} |
|
|
|
void |
|
rtflush(struct route *ro) |
|
{ |
|
int s = splnet(); |
|
KASSERT(ro->ro_rt != NULL); |
|
KASSERT(rtcache_getdst(ro) != NULL); |
|
|
|
RTFREE(ro->ro_rt); |
|
ro->ro_rt = NULL; |
|
|
|
LIST_REMOVE(ro, ro_rtcache_next); |
|
splx(s); |
|
|
|
#if 0 |
|
if (rtcache_debug()) { |
|
printf("%s: flushing %s\n", __func__, |
|
inet_ntoa((satocsin(rtcache_getdst(ro)))->sin_addr)); |
|
} |
|
#endif |
|
} |
|
|
|
void |
|
rtcache(struct route *ro) |
|
{ |
|
int s; |
|
struct domain *dom; |
|
|
|
KASSERT(ro->ro_rt != NULL); |
|
KASSERT(rtcache_getdst(ro) != NULL); |
|
|
|
if ((dom = pffinddomain(rtcache_getdst(ro)->sa_family)) == NULL) |
|
return; |
|
|
|
s = splnet(); |
|
LIST_INSERT_HEAD(&dom->dom_rtcache, ro, ro_rtcache_next); |
|
splx(s); |
|
} |
|
|
/* |
/* |
* Packet routing routines. |
* Packet routing routines. |
*/ |
*/ |
void |
void |
rtalloc(struct route *ro) |
rtalloc(struct route *ro) |
{ |
{ |
if (ro->ro_rt && ro->ro_rt->rt_ifp && (ro->ro_rt->rt_flags & RTF_UP)) |
if (ro->ro_rt != NULL) { |
return; /* XXX */ |
if (ro->ro_rt->rt_ifp != NULL && |
ro->ro_rt = rtalloc1(&ro->ro_dst, 1); |
(ro->ro_rt->rt_flags & RTF_UP) != 0) |
|
return; |
|
rtflush(ro); |
|
} |
|
if (rtcache_getdst(ro) == NULL || |
|
(ro->ro_rt = rtalloc1(rtcache_getdst(ro), 1)) == NULL) |
|
return; |
|
rtcache(ro); |
} |
} |
|
|
struct rtentry * |
struct rtentry * |
Line 179 rtalloc1(const struct sockaddr *dst, int |
|
Line 317 rtalloc1(const struct sockaddr *dst, int |
|
struct radix_node_head *rnh = rt_tables[dst->sa_family]; |
struct radix_node_head *rnh = rt_tables[dst->sa_family]; |
struct rtentry *rt; |
struct rtentry *rt; |
struct radix_node *rn; |
struct radix_node *rn; |
struct rtentry *newrt = 0; |
struct rtentry *newrt = NULL; |
struct rt_addrinfo info; |
struct rt_addrinfo info; |
int s = splsoftnet(), err = 0, msgtype = RTM_MISS; |
int s = splsoftnet(), err = 0, msgtype = RTM_MISS; |
|
|
Line 187 rtalloc1(const struct sockaddr *dst, int |
|
Line 325 rtalloc1(const struct sockaddr *dst, int |
|
((rn->rn_flags & RNF_ROOT) == 0)) { |
((rn->rn_flags & RNF_ROOT) == 0)) { |
newrt = rt = (struct rtentry *)rn; |
newrt = rt = (struct rtentry *)rn; |
if (report && (rt->rt_flags & RTF_CLONING)) { |
if (report && (rt->rt_flags & RTF_CLONING)) { |
err = rtrequest(RTM_RESOLVE, dst, SA(0), |
err = rtrequest(RTM_RESOLVE, dst, NULL, NULL, 0, |
SA(0), 0, &newrt); |
&newrt); |
if (err) { |
if (err) { |
newrt = rt; |
newrt = rt; |
rt->rt_refcnt++; |
rt->rt_refcnt++; |
goto miss; |
goto miss; |
} |
} |
|
KASSERT(newrt != NULL); |
if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { |
if ((rt = newrt) && (rt->rt_flags & RTF_XRESOLVE)) { |
msgtype = RTM_RESOLVE; |
msgtype = RTM_RESOLVE; |
goto miss; |
goto miss; |
} |
} |
/* Inform listeners of the new route */ |
/* Inform listeners of the new route */ |
memset(&info, 0, sizeof(info)); |
memset(&info, 0, sizeof(info)); |
info.rti_info[RTAX_DST] = rt_key(rt); |
info.rti_info[RTAX_DST] = rt_getkey(rt); |
info.rti_info[RTAX_NETMASK] = rt_mask(rt); |
info.rti_info[RTAX_NETMASK] = rt_mask(rt); |
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; |
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; |
if (rt->rt_ifp != NULL) { |
if (rt->rt_ifp != NULL) { |
Line 214 rtalloc1(const struct sockaddr *dst, int |
|
Line 353 rtalloc1(const struct sockaddr *dst, int |
|
} else { |
} else { |
rtstat.rts_unreach++; |
rtstat.rts_unreach++; |
miss: if (report) { |
miss: if (report) { |
memset((caddr_t)&info, 0, sizeof(info)); |
memset((void *)&info, 0, sizeof(info)); |
info.rti_info[RTAX_DST] = dst; |
info.rti_info[RTAX_DST] = dst; |
rt_missmsg(msgtype, &info, 0, err); |
rt_missmsg(msgtype, &info, 0, err); |
} |
} |
} |
} |
splx(s); |
splx(s); |
return (newrt); |
return newrt; |
} |
} |
|
|
void |
void |
Line 228 rtfree(struct rtentry *rt) |
|
Line 367 rtfree(struct rtentry *rt) |
|
{ |
{ |
struct ifaddr *ifa; |
struct ifaddr *ifa; |
|
|
if (rt == 0) |
if (rt == NULL) |
panic("rtfree"); |
panic("rtfree"); |
rt->rt_refcnt--; |
rt->rt_refcnt--; |
if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { |
if (rt->rt_refcnt <= 0 && (rt->rt_flags & RTF_UP) == 0) { |
Line 241 rtfree(struct rtentry *rt) |
|
Line 380 rtfree(struct rtentry *rt) |
|
} |
} |
rt_timer_remove_all(rt, 0); |
rt_timer_remove_all(rt, 0); |
ifa = rt->rt_ifa; |
ifa = rt->rt_ifa; |
|
rt->rt_ifa = NULL; |
IFAFREE(ifa); |
IFAFREE(ifa); |
Free(rt_key(rt)); |
rt->rt_ifp = NULL; |
|
rt_destroy(rt); |
pool_put(&rtentry_pool, rt); |
pool_put(&rtentry_pool, rt); |
} |
} |
} |
} |
Line 263 ifafree(struct ifaddr *ifa) |
|
Line 404 ifafree(struct ifaddr *ifa) |
|
free(ifa, M_IFADDR); |
free(ifa, M_IFADDR); |
} |
} |
|
|
|
static inline int |
|
equal(const struct sockaddr *sa1, const struct sockaddr *sa2) |
|
{ |
|
return sockaddr_cmp(sa1, sa2) == 0; |
|
} |
|
|
/* |
/* |
* Force a routing table entry to the specified |
* Force a routing table entry to the specified |
* destination to go through the given gateway. |
* destination to go through the given gateway. |
Line 278 rtredirect(const struct sockaddr *dst, c |
|
Line 425 rtredirect(const struct sockaddr *dst, c |
|
{ |
{ |
struct rtentry *rt; |
struct rtentry *rt; |
int error = 0; |
int error = 0; |
u_quad_t *stat = 0; |
u_quad_t *stat = NULL; |
struct rt_addrinfo info; |
struct rt_addrinfo info; |
struct ifaddr *ifa; |
struct ifaddr *ifa; |
|
|
/* verify the gateway is directly reachable */ |
/* verify the gateway is directly reachable */ |
if ((ifa = ifa_ifwithnet(gateway)) == 0) { |
if ((ifa = ifa_ifwithnet(gateway)) == NULL) { |
error = ENETUNREACH; |
error = ENETUNREACH; |
goto out; |
goto out; |
} |
} |
Line 294 rtredirect(const struct sockaddr *dst, c |
|
Line 441 rtredirect(const struct sockaddr *dst, c |
|
* we have a routing loop, perhaps as a result of an interface |
* we have a routing loop, perhaps as a result of an interface |
* going down recently. |
* going down recently. |
*/ |
*/ |
#define equal(a1, a2) \ |
|
((a1)->sa_len == (a2)->sa_len && \ |
|
memcmp((a1), (a2), (a1)->sa_len) == 0) |
|
if (!(flags & RTF_DONE) && rt && |
if (!(flags & RTF_DONE) && rt && |
(!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) |
(!equal(src, rt->rt_gateway) || rt->rt_ifa != ifa)) |
error = EINVAL; |
error = EINVAL; |
Line 310 rtredirect(const struct sockaddr *dst, c |
|
Line 454 rtredirect(const struct sockaddr *dst, c |
|
* which use routing redirects generated by smart gateways |
* which use routing redirects generated by smart gateways |
* to dynamically build the routing tables. |
* to dynamically build the routing tables. |
*/ |
*/ |
if ((rt == 0) || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) |
if (rt == NULL || (rt_mask(rt) && rt_mask(rt)->sa_len < 2)) |
goto create; |
goto create; |
/* |
/* |
* Don't listen to the redirect if it's |
* Don't listen to the redirect if it's |
Line 323 rtredirect(const struct sockaddr *dst, c |
|
Line 467 rtredirect(const struct sockaddr *dst, c |
|
* Create new route, rather than smashing route to net. |
* Create new route, rather than smashing route to net. |
*/ |
*/ |
create: |
create: |
if (rt) |
if (rt != NULL) |
rtfree(rt); |
rtfree(rt); |
flags |= RTF_GATEWAY | RTF_DYNAMIC; |
flags |= RTF_GATEWAY | RTF_DYNAMIC; |
info.rti_info[RTAX_DST] = dst; |
info.rti_info[RTAX_DST] = dst; |
Line 344 rtredirect(const struct sockaddr *dst, c |
|
Line 488 rtredirect(const struct sockaddr *dst, c |
|
rt->rt_flags |= RTF_MODIFIED; |
rt->rt_flags |= RTF_MODIFIED; |
flags |= RTF_MODIFIED; |
flags |= RTF_MODIFIED; |
stat = &rtstat.rts_newgateway; |
stat = &rtstat.rts_newgateway; |
rt_setgate(rt, rt_key(rt), gateway); |
rt_setgate(rt, gateway); |
} |
} |
} else |
} else |
error = EHOSTUNREACH; |
error = EHOSTUNREACH; |
done: |
done: |
if (rt) { |
if (rt) { |
if (rtp && !error) |
if (rtp != NULL && !error) |
*rtp = rt; |
*rtp = rt; |
else |
else |
rtfree(rt); |
rtfree(rt); |
|
|
rtstat.rts_badredirect++; |
rtstat.rts_badredirect++; |
else if (stat != NULL) |
else if (stat != NULL) |
(*stat)++; |
(*stat)++; |
memset((caddr_t)&info, 0, sizeof(info)); |
memset(&info, 0, sizeof(info)); |
info.rti_info[RTAX_DST] = dst; |
info.rti_info[RTAX_DST] = dst; |
info.rti_info[RTAX_GATEWAY] = gateway; |
info.rti_info[RTAX_GATEWAY] = gateway; |
info.rti_info[RTAX_NETMASK] = netmask; |
info.rti_info[RTAX_NETMASK] = netmask; |
Line 382 rtdeletemsg(struct rtentry *rt) |
|
Line 526 rtdeletemsg(struct rtentry *rt) |
|
* deleted. That will allow the information being reported to |
* deleted. That will allow the information being reported to |
* be accurate (and consistent with route_output()). |
* be accurate (and consistent with route_output()). |
*/ |
*/ |
memset((caddr_t)&info, 0, sizeof(info)); |
memset(&info, 0, sizeof(info)); |
info.rti_info[RTAX_DST] = rt_key(rt); |
info.rti_info[RTAX_DST] = rt_getkey(rt); |
info.rti_info[RTAX_NETMASK] = rt_mask(rt); |
info.rti_info[RTAX_NETMASK] = rt_mask(rt); |
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; |
info.rti_info[RTAX_GATEWAY] = rt->rt_gateway; |
info.rti_flags = rt->rt_flags; |
info.rti_flags = rt->rt_flags; |
Line 396 rtdeletemsg(struct rtentry *rt) |
|
Line 540 rtdeletemsg(struct rtentry *rt) |
|
rt->rt_refcnt++; |
rt->rt_refcnt++; |
rtfree(rt); |
rtfree(rt); |
} |
} |
return (error); |
return error; |
} |
} |
|
|
static int |
static int |
rtflushclone1(struct radix_node *rn, void *arg) |
rtflushclone1(struct rtentry *rt, void *arg) |
{ |
{ |
struct rtentry *rt, *parent; |
struct rtentry *parent; |
|
|
rt = (struct rtentry *)rn; |
|
parent = (struct rtentry *)arg; |
parent = (struct rtentry *)arg; |
if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent) |
if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent == parent) |
rtdeletemsg(rt); |
rtdeletemsg(rt); |
Line 412 rtflushclone1(struct radix_node *rn, voi |
|
Line 555 rtflushclone1(struct radix_node *rn, voi |
|
} |
} |
|
|
static void |
static void |
rtflushclone(struct radix_node_head *rnh, struct rtentry *parent) |
rtflushclone(sa_family_t family, struct rtentry *parent) |
{ |
{ |
|
|
#ifdef DIAGNOSTIC |
#ifdef DIAGNOSTIC |
if (!parent || (parent->rt_flags & RTF_CLONING) == 0) |
if (!parent || (parent->rt_flags & RTF_CLONING) == 0) |
panic("rtflushclone: called with a non-cloning route"); |
panic("rtflushclone: called with a non-cloning route"); |
if (!rnh->rnh_walktree) |
|
panic("rtflushclone: no rnh_walktree"); |
|
#endif |
#endif |
rnh->rnh_walktree(rnh, rtflushclone1, (void *)parent); |
rt_walktree(family, rtflushclone1, (void *)parent); |
} |
} |
|
|
/* |
/* |
* Routing table ioctl interface. |
* Routing table ioctl interface. |
*/ |
*/ |
int |
int |
rtioctl(u_long req, caddr_t data, struct proc *p) |
rtioctl(u_long req, void *data, struct lwp *l) |
{ |
{ |
return (EOPNOTSUPP); |
return EOPNOTSUPP; |
} |
} |
|
|
struct ifaddr * |
struct ifaddr * |
Line 446 ifa_ifwithroute(int flags, const struct |
|
Line 587 ifa_ifwithroute(int flags, const struct |
|
* as our clue to the interface. Otherwise |
* as our clue to the interface. Otherwise |
* we can use the local address. |
* we can use the local address. |
*/ |
*/ |
ifa = 0; |
ifa = NULL; |
if (flags & RTF_HOST) |
if (flags & RTF_HOST) |
ifa = ifa_ifwithdstaddr(dst); |
ifa = ifa_ifwithdstaddr(dst); |
if (ifa == 0) |
if (ifa == NULL) |
ifa = ifa_ifwithaddr(gateway); |
ifa = ifa_ifwithaddr(gateway); |
} else { |
} else { |
/* |
/* |
Line 459 ifa_ifwithroute(int flags, const struct |
|
Line 600 ifa_ifwithroute(int flags, const struct |
|
*/ |
*/ |
ifa = ifa_ifwithdstaddr(gateway); |
ifa = ifa_ifwithdstaddr(gateway); |
} |
} |
if (ifa == 0) |
if (ifa == NULL) |
ifa = ifa_ifwithnet(gateway); |
ifa = ifa_ifwithnet(gateway); |
if (ifa == 0) { |
if (ifa == NULL) { |
struct rtentry *rt = rtalloc1(dst, 0); |
struct rtentry *rt = rtalloc1(dst, 0); |
if (rt == 0) |
if (rt == NULL) |
return (0); |
return NULL; |
rt->rt_refcnt--; |
rt->rt_refcnt--; |
if ((ifa = rt->rt_ifa) == 0) |
if ((ifa = rt->rt_ifa) == NULL) |
return (0); |
return NULL; |
} |
} |
if (ifa->ifa_addr->sa_family != dst->sa_family) { |
if (ifa->ifa_addr->sa_family != dst->sa_family) { |
struct ifaddr *oifa = ifa; |
struct ifaddr *oifa = ifa; |
Line 475 ifa_ifwithroute(int flags, const struct |
|
Line 616 ifa_ifwithroute(int flags, const struct |
|
if (ifa == 0) |
if (ifa == 0) |
ifa = oifa; |
ifa = oifa; |
} |
} |
return (ifa); |
return ifa; |
} |
} |
|
|
#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) |
#define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) |
Line 494 rtrequest(int req, const struct sockaddr |
|
Line 635 rtrequest(int req, const struct sockaddr |
|
return rtrequest1(req, &info, ret_nrt); |
return rtrequest1(req, &info, ret_nrt); |
} |
} |
|
|
/* |
|
* These (questionable) definitions of apparent local variables apply |
|
* to the next function. XXXXXX!!! |
|
*/ |
|
#define dst info->rti_info[RTAX_DST] |
|
#define gateway info->rti_info[RTAX_GATEWAY] |
|
#define netmask info->rti_info[RTAX_NETMASK] |
|
#define ifaaddr info->rti_info[RTAX_IFA] |
|
#define ifpaddr info->rti_info[RTAX_IFP] |
|
#define flags info->rti_flags |
|
|
|
int |
int |
rt_getifa(struct rt_addrinfo *info) |
rt_getifa(struct rt_addrinfo *info) |
{ |
{ |
struct ifaddr *ifa; |
struct ifaddr *ifa; |
int error = 0; |
const struct sockaddr *dst = info->rti_info[RTAX_DST]; |
|
const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY]; |
|
const struct sockaddr *ifaaddr = info->rti_info[RTAX_IFA]; |
|
const struct sockaddr *ifpaddr = info->rti_info[RTAX_IFP]; |
|
int flags = info->rti_flags; |
|
|
/* |
/* |
* ifp may be specified by sockaddr_dl when protocol address |
* ifp may be specified by sockaddr_dl when protocol address |
Line 533 rt_getifa(struct rt_addrinfo *info) |
|
Line 667 rt_getifa(struct rt_addrinfo *info) |
|
else if (sa != NULL) |
else if (sa != NULL) |
info->rti_ifa = ifa_ifwithroute(flags, sa, sa); |
info->rti_ifa = ifa_ifwithroute(flags, sa, sa); |
} |
} |
if ((ifa = info->rti_ifa) != NULL) { |
if ((ifa = info->rti_ifa) == NULL) |
if (info->rti_ifp == NULL) |
return ENETUNREACH; |
info->rti_ifp = ifa->ifa_ifp; |
if (ifa->ifa_getifa != NULL) |
} else |
info->rti_ifa = ifa = (*ifa->ifa_getifa)(ifa, dst); |
error = ENETUNREACH; |
if (info->rti_ifp == NULL) |
return (error); |
info->rti_ifp = ifa->ifa_ifp; |
|
return 0; |
} |
} |
|
|
int |
int |
Line 550 rtrequest1(int req, struct rt_addrinfo * |
|
Line 685 rtrequest1(int req, struct rt_addrinfo * |
|
struct radix_node *rn; |
struct radix_node *rn; |
struct radix_node_head *rnh; |
struct radix_node_head *rnh; |
struct ifaddr *ifa; |
struct ifaddr *ifa; |
struct sockaddr *ndst; |
struct sockaddr_storage maskeddst; |
struct sockaddr_storage deldst; |
const struct sockaddr *dst = info->rti_info[RTAX_DST]; |
|
const struct sockaddr *gateway = info->rti_info[RTAX_GATEWAY]; |
|
const struct sockaddr *netmask = info->rti_info[RTAX_NETMASK]; |
|
int flags = info->rti_flags; |
#define senderr(x) { error = x ; goto bad; } |
#define senderr(x) { error = x ; goto bad; } |
|
|
if ((rnh = rt_tables[dst->sa_family]) == 0) |
if ((rnh = rt_tables[dst->sa_family]) == NULL) |
senderr(ESRCH); |
senderr(ESRCH); |
if (flags & RTF_HOST) |
if (flags & RTF_HOST) |
netmask = 0; |
netmask = NULL; |
switch (req) { |
switch (req) { |
case RTM_DELETE: |
case RTM_DELETE: |
if (netmask) { |
if (netmask) { |
rt_maskedcopy(dst, (struct sockaddr *)&deldst, netmask); |
rt_maskedcopy(dst, (struct sockaddr *)&maskeddst, |
dst = (struct sockaddr *)&deldst; |
netmask); |
|
dst = (struct sockaddr *)&maskeddst; |
} |
} |
if ((rn = rnh->rnh_lookup(dst, netmask, rnh)) == 0) |
if ((rn = rnh->rnh_lookup(dst, netmask, rnh)) == NULL) |
senderr(ESRCH); |
senderr(ESRCH); |
rt = (struct rtentry *)rn; |
rt = (struct rtentry *)rn; |
if ((rt->rt_flags & RTF_CLONING) != 0) { |
if ((rt->rt_flags & RTF_CLONING) != 0) { |
/* clean up any cloned children */ |
/* clean up any cloned children */ |
rtflushclone(rnh, rt); |
rtflushclone(dst->sa_family, rt); |
} |
} |
if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == 0) |
if ((rn = rnh->rnh_deladdr(dst, netmask, rnh)) == NULL) |
senderr(ESRCH); |
senderr(ESRCH); |
if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) |
if (rn->rn_flags & (RNF_ACTIVE | RNF_ROOT)) |
panic ("rtrequest delete"); |
panic ("rtrequest delete"); |
rt = (struct rtentry *)rn; |
rt = (struct rtentry *)rn; |
if (rt->rt_gwroute) { |
if (rt->rt_gwroute) { |
rt = rt->rt_gwroute; RTFREE(rt); |
RTFREE(rt->rt_gwroute); |
(rt = (struct rtentry *)rn)->rt_gwroute = 0; |
rt->rt_gwroute = NULL; |
} |
} |
if (rt->rt_parent) { |
if (rt->rt_parent) { |
rt->rt_parent->rt_refcnt--; |
rt->rt_parent->rt_refcnt--; |
Line 597 rtrequest1(int req, struct rt_addrinfo * |
|
Line 736 rtrequest1(int req, struct rt_addrinfo * |
|
break; |
break; |
|
|
case RTM_RESOLVE: |
case RTM_RESOLVE: |
if (ret_nrt == 0 || (rt = *ret_nrt) == 0) |
if (ret_nrt == NULL || (rt = *ret_nrt) == NULL) |
senderr(EINVAL); |
senderr(EINVAL); |
if ((rt->rt_flags & RTF_CLONING) == 0) |
if ((rt->rt_flags & RTF_CLONING) == 0) |
senderr(EINVAL); |
senderr(EINVAL); |
Line 605 rtrequest1(int req, struct rt_addrinfo * |
|
Line 744 rtrequest1(int req, struct rt_addrinfo * |
|
flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC); |
flags = rt->rt_flags & ~(RTF_CLONING | RTF_STATIC); |
flags |= RTF_CLONED; |
flags |= RTF_CLONED; |
gateway = rt->rt_gateway; |
gateway = rt->rt_gateway; |
if ((netmask = rt->rt_genmask) == 0) |
flags |= RTF_HOST; |
flags |= RTF_HOST; |
|
goto makeroute; |
goto makeroute; |
|
|
case RTM_ADD: |
case RTM_ADD: |
if (info->rti_ifa == 0 && (error = rt_getifa(info))) |
if (info->rti_ifa == NULL && (error = rt_getifa(info))) |
senderr(error); |
senderr(error); |
ifa = info->rti_ifa; |
ifa = info->rti_ifa; |
makeroute: |
makeroute: |
|
/* Already at splsoftnet() so pool_get/pool_put are safe */ |
rt = pool_get(&rtentry_pool, PR_NOWAIT); |
rt = pool_get(&rtentry_pool, PR_NOWAIT); |
if (rt == 0) |
if (rt == NULL) |
senderr(ENOBUFS); |
senderr(ENOBUFS); |
Bzero(rt, sizeof(*rt)); |
Bzero(rt, sizeof(*rt)); |
rt->rt_flags = RTF_UP | flags; |
rt->rt_flags = RTF_UP | flags; |
LIST_INIT(&rt->rt_timer); |
LIST_INIT(&rt->rt_timer); |
if (rt_setgate(rt, dst, gateway)) { |
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, |
|
(void *)rt->_rt_key); |
|
if (rt_setkey(rt, dst, M_NOWAIT) == NULL || |
|
rt_setgate(rt, gateway) != 0) { |
pool_put(&rtentry_pool, rt); |
pool_put(&rtentry_pool, rt); |
senderr(ENOBUFS); |
senderr(ENOBUFS); |
} |
} |
ndst = rt_key(rt); |
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, __LINE__, |
|
(void *)rt->_rt_key); |
if (netmask) { |
if (netmask) { |
rt_maskedcopy(dst, ndst, netmask); |
rt_maskedcopy(dst, (struct sockaddr *)&maskeddst, |
} else |
netmask); |
Bcopy(dst, ndst, dst->sa_len); |
rt_setkey(rt, (struct sockaddr *)&maskeddst, M_NOWAIT); |
IFAREF(ifa); |
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
rt->rt_ifa = ifa; |
__LINE__, (void *)rt->_rt_key); |
|
} else { |
|
rt_setkey(rt, dst, M_NOWAIT); |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
|
} |
|
rt_set_ifa(rt, ifa); |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
rt->rt_ifp = ifa->ifa_ifp; |
rt->rt_ifp = ifa->ifa_ifp; |
if (req == RTM_RESOLVE) { |
if (req == RTM_RESOLVE) { |
rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ |
rt->rt_rmx = (*ret_nrt)->rt_rmx; /* copy metrics */ |
rt->rt_parent = *ret_nrt; |
rt->rt_parent = *ret_nrt; |
rt->rt_parent->rt_refcnt++; |
rt->rt_parent->rt_refcnt++; |
} |
} |
rn = rnh->rnh_addaddr(ndst, netmask, rnh, rt->rt_nodes); |
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
if (rn == NULL && (crt = rtalloc1(ndst, 0)) != NULL) { |
__LINE__, (void *)rt->_rt_key); |
|
rn = rnh->rnh_addaddr(rt_getkey(rt), netmask, rnh, |
|
rt->rt_nodes); |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
|
if (rn == NULL && (crt = rtalloc1(rt_getkey(rt), 0)) != NULL) { |
/* overwrite cloned route */ |
/* overwrite cloned route */ |
if ((crt->rt_flags & RTF_CLONED) != 0) { |
if ((crt->rt_flags & RTF_CLONED) != 0) { |
rtdeletemsg(crt); |
rtdeletemsg(crt); |
rn = rnh->rnh_addaddr(ndst, |
rn = rnh->rnh_addaddr(rt_getkey(rt), |
netmask, rnh, rt->rt_nodes); |
netmask, rnh, rt->rt_nodes); |
} |
} |
RTFREE(crt); |
RTFREE(crt); |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
} |
} |
if (rn == 0) { |
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
|
if (rn == NULL) { |
IFAFREE(ifa); |
IFAFREE(ifa); |
if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent) |
if ((rt->rt_flags & RTF_CLONED) != 0 && rt->rt_parent) |
rtfree(rt->rt_parent); |
rtfree(rt->rt_parent); |
if (rt->rt_gwroute) |
if (rt->rt_gwroute) |
rtfree(rt->rt_gwroute); |
rtfree(rt->rt_gwroute); |
Free(rt_key(rt)); |
rt_destroy(rt); |
pool_put(&rtentry_pool, rt); |
pool_put(&rtentry_pool, rt); |
senderr(EEXIST); |
senderr(EEXIST); |
} |
} |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
if (ifa->ifa_rtrequest) |
if (ifa->ifa_rtrequest) |
ifa->ifa_rtrequest(req, rt, info); |
ifa->ifa_rtrequest(req, rt, info); |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
if (ret_nrt) { |
if (ret_nrt) { |
*ret_nrt = rt; |
*ret_nrt = rt; |
rt->rt_refcnt++; |
rt->rt_refcnt++; |
} |
} |
if ((rt->rt_flags & RTF_CLONING) != 0) { |
if ((rt->rt_flags & RTF_CLONING) != 0) { |
/* clean up any cloned children */ |
/* clean up any cloned children */ |
rtflushclone(rnh, rt); |
rtflushclone(dst->sa_family, rt); |
|
} |
|
rtflushall(dst->sa_family); |
|
break; |
|
case RTM_GET: |
|
if (netmask != NULL) { |
|
rt_maskedcopy(dst, (struct sockaddr *)&maskeddst, |
|
netmask); |
|
dst = (struct sockaddr *)&maskeddst; |
|
} |
|
rn = rnh->rnh_lookup(dst, netmask, rnh); |
|
if (rn == NULL || (rn->rn_flags & RNF_ROOT) != 0) |
|
senderr(ESRCH); |
|
if (ret_nrt != NULL) { |
|
rt = (struct rtentry *)rn; |
|
*ret_nrt = rt; |
|
rt->rt_refcnt++; |
} |
} |
break; |
break; |
} |
} |
bad: |
bad: |
splx(s); |
splx(s); |
return (error); |
return error; |
} |
} |
|
|
#undef dst |
|
#undef gateway |
|
#undef netmask |
|
#undef ifaaddr |
|
#undef ifpaddr |
|
#undef flags |
|
|
|
int |
int |
rt_setgate( struct rtentry *rt0, const struct sockaddr *dst, |
rt_setgate(struct rtentry *rt, const struct sockaddr *gate) |
const struct sockaddr *gate) |
|
{ |
{ |
char *new, *old; |
KASSERT(rt != rt->rt_gwroute); |
u_int dlen = ROUNDUP(dst->sa_len), glen = ROUNDUP(gate->sa_len); |
|
struct rtentry *rt = rt0; |
KASSERT(rt->_rt_key != NULL); |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
if (rt->rt_gateway == 0 || glen > ROUNDUP(rt->rt_gateway->sa_len)) { |
__LINE__, (void *)rt->_rt_key); |
old = (caddr_t)rt_key(rt); |
|
R_Malloc(new, caddr_t, dlen + glen); |
|
if (new == 0) |
|
return 1; |
|
Bzero(new, dlen + glen); |
|
rt->rt_nodes->rn_key = new; |
|
} else { |
|
new = __UNCONST(rt->rt_nodes->rn_key); /*XXXUNCONST*/ |
|
old = 0; |
|
} |
|
Bcopy(gate, (rt->rt_gateway = (struct sockaddr *)(new + dlen)), glen); |
|
if (old) { |
|
Bcopy(dst, new, dlen); |
|
Free(old); |
|
} |
|
if (rt->rt_gwroute) { |
if (rt->rt_gwroute) { |
rt = rt->rt_gwroute; RTFREE(rt); |
RTFREE(rt->rt_gwroute); |
rt = rt0; rt->rt_gwroute = 0; |
rt->rt_gwroute = NULL; |
} |
} |
|
KASSERT(rt->_rt_key != NULL); |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
|
if (rt->rt_gateway != NULL) |
|
sockaddr_free(rt->rt_gateway); |
|
KASSERT(rt->_rt_key != NULL); |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
|
if ((rt->rt_gateway = sockaddr_dup(gate, M_NOWAIT)) == NULL) |
|
return ENOMEM; |
|
KASSERT(rt->_rt_key != NULL); |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
|
|
if (rt->rt_flags & RTF_GATEWAY) { |
if (rt->rt_flags & RTF_GATEWAY) { |
|
KASSERT(rt->_rt_key != NULL); |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
rt->rt_gwroute = rtalloc1(gate, 1); |
rt->rt_gwroute = rtalloc1(gate, 1); |
/* |
/* |
* If we switched gateways, grab the MTU from the new |
* If we switched gateways, grab the MTU from the new |
Line 718 rt_setgate( struct rtentry *rt0, const s |
|
Line 893 rt_setgate( struct rtentry *rt0, const s |
|
* Note that, if the MTU of gateway is 0, we will reset the |
* Note that, if the MTU of gateway is 0, we will reset the |
* MTU of the route to run PMTUD again from scratch. XXX |
* MTU of the route to run PMTUD again from scratch. XXX |
*/ |
*/ |
|
KASSERT(rt->_rt_key != NULL); |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
if (rt->rt_gwroute |
if (rt->rt_gwroute |
&& !(rt->rt_rmx.rmx_locks & RTV_MTU) |
&& !(rt->rt_rmx.rmx_locks & RTV_MTU) |
&& rt->rt_rmx.rmx_mtu |
&& rt->rt_rmx.rmx_mtu |
Line 725 rt_setgate( struct rtentry *rt0, const s |
|
Line 903 rt_setgate( struct rtentry *rt0, const s |
|
rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu; |
rt->rt_rmx.rmx_mtu = rt->rt_gwroute->rt_rmx.rmx_mtu; |
} |
} |
} |
} |
|
KASSERT(rt->_rt_key != NULL); |
|
RT_DPRINTF("%s l.%d: rt->_rt_key = %p\n", __func__, |
|
__LINE__, (void *)rt->_rt_key); |
return 0; |
return 0; |
} |
} |
|
|
|
|
rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst, |
rt_maskedcopy(const struct sockaddr *src, struct sockaddr *dst, |
const struct sockaddr *netmask) |
const struct sockaddr *netmask) |
{ |
{ |
const u_char *cp1 = (const u_char *)src; |
const char *netmaskp = &netmask->sa_data[0], |
u_char *cp2 = (u_char *)dst; |
*srcp = &src->sa_data[0]; |
const u_char *cp3 = (const u_char *)netmask; |
char *dstp = &dst->sa_data[0]; |
u_char *cplim = cp2 + *cp3; |
const char *maskend = dstp + MIN(netmask->sa_len, src->sa_len); |
u_char *cplim2 = cp2 + *cp1; |
const char *srcend = dstp + src->sa_len; |
|
|
*cp2++ = *cp1++; *cp2++ = *cp1++; /* copies sa_len & sa_family */ |
dst->sa_len = src->sa_len; |
cp3 += 2; |
dst->sa_family = src->sa_family; |
if (cplim > cplim2) |
|
cplim = cplim2; |
while (dstp < maskend) |
while (cp2 < cplim) |
*dstp++ = *srcp++ & *netmaskp++; |
*cp2++ = *cp1++ & *cp3++; |
if (dstp < srcend) |
if (cp2 < cplim2) |
memset(dstp, 0, (size_t)(srcend - dstp)); |
memset(cp2, 0, (unsigned)(cplim2 - cp2)); |
|
} |
} |
|
|
/* |
/* |
Line 757 rtinit(struct ifaddr *ifa, int cmd, int |
|
Line 937 rtinit(struct ifaddr *ifa, int cmd, int |
|
{ |
{ |
struct rtentry *rt; |
struct rtentry *rt; |
struct sockaddr *dst, *odst; |
struct sockaddr *dst, *odst; |
struct sockaddr_storage deldst; |
struct sockaddr_storage maskeddst; |
struct rtentry *nrt = 0; |
struct rtentry *nrt = NULL; |
int error; |
int error; |
struct rt_addrinfo info; |
struct rt_addrinfo info; |
|
|
Line 767 rtinit(struct ifaddr *ifa, int cmd, int |
|
Line 947 rtinit(struct ifaddr *ifa, int cmd, int |
|
if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { |
if ((flags & RTF_HOST) == 0 && ifa->ifa_netmask) { |
/* Delete subnet route for this interface */ |
/* Delete subnet route for this interface */ |
odst = dst; |
odst = dst; |
dst = (struct sockaddr *)&deldst; |
dst = (struct sockaddr *)&maskeddst; |
rt_maskedcopy(odst, dst, ifa->ifa_netmask); |
rt_maskedcopy(odst, dst, ifa->ifa_netmask); |
} |
} |
if ((rt = rtalloc1(dst, 0)) != NULL) { |
if ((rt = rtalloc1(dst, 0)) != NULL) { |
rt->rt_refcnt--; |
rt->rt_refcnt--; |
if (rt->rt_ifa != ifa) |
if (rt->rt_ifa != ifa) |
return (flags & RTF_HOST ? EHOSTUNREACH |
return (flags & RTF_HOST) ? EHOSTUNREACH |
: ENETUNREACH); |
: ENETUNREACH; |
} |
} |
} |
} |
memset(&info, 0, sizeof(info)); |
memset(&info, 0, sizeof(info)); |
Line 804 rtinit(struct ifaddr *ifa, int cmd, int |
|
Line 984 rtinit(struct ifaddr *ifa, int cmd, int |
|
rt->rt_ifa); |
rt->rt_ifa); |
if (rt->rt_ifa->ifa_rtrequest) |
if (rt->rt_ifa->ifa_rtrequest) |
rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, NULL); |
rt->rt_ifa->ifa_rtrequest(RTM_DELETE, rt, NULL); |
IFAFREE(rt->rt_ifa); |
rt_replace_ifa(rt, ifa); |
rt->rt_ifa = ifa; |
|
rt->rt_ifp = ifa->ifa_ifp; |
rt->rt_ifp = ifa->ifa_ifp; |
IFAREF(ifa); |
|
if (ifa->ifa_rtrequest) |
if (ifa->ifa_rtrequest) |
ifa->ifa_rtrequest(RTM_ADD, rt, NULL); |
ifa->ifa_rtrequest(RTM_ADD, rt, NULL); |
} |
} |
rt_newaddrmsg(cmd, ifa, error, nrt); |
rt_newaddrmsg(cmd, ifa, error, nrt); |
} |
} |
return (error); |
return error; |
} |
} |
|
|
/* |
/* |
Line 833 static int rt_init_done = 0; |
|
Line 1011 static int rt_init_done = 0; |
|
(*r->rtt_func)(r->rtt_rt, r); \ |
(*r->rtt_func)(r->rtt_rt, r); \ |
} else { \ |
} else { \ |
rtrequest((int) RTM_DELETE, \ |
rtrequest((int) RTM_DELETE, \ |
(struct sockaddr *)rt_key(r->rtt_rt), \ |
rt_getkey(r->rtt_rt), \ |
0, 0, 0, 0); \ |
0, 0, 0, 0); \ |
} \ |
} \ |
} while (/*CONSTCOND*/0) |
} while (/*CONSTCOND*/0) |
Line 851 rt_timer_init(void) |
|
Line 1029 rt_timer_init(void) |
|
assert(rt_init_done == 0); |
assert(rt_init_done == 0); |
|
|
LIST_INIT(&rttimer_queue_head); |
LIST_INIT(&rttimer_queue_head); |
callout_init(&rt_timer_ch); |
callout_init(&rt_timer_ch, 0); |
callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL); |
callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL); |
rt_init_done = 1; |
rt_init_done = 1; |
} |
} |
Line 866 rt_timer_queue_create(u_int timeout) |
|
Line 1044 rt_timer_queue_create(u_int timeout) |
|
|
|
R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq); |
R_Malloc(rtq, struct rttimer_queue *, sizeof *rtq); |
if (rtq == NULL) |
if (rtq == NULL) |
return (NULL); |
return NULL; |
Bzero(rtq, sizeof *rtq); |
Bzero(rtq, sizeof *rtq); |
|
|
rtq->rtq_timeout = timeout; |
rtq->rtq_timeout = timeout; |
Line 874 rt_timer_queue_create(u_int timeout) |
|
Line 1052 rt_timer_queue_create(u_int timeout) |
|
TAILQ_INIT(&rtq->rtq_head); |
TAILQ_INIT(&rtq->rtq_head); |
LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link); |
LIST_INSERT_HEAD(&rttimer_queue_head, rtq, rtq_link); |
|
|
return (rtq); |
return rtq; |
} |
} |
|
|
void |
void |
Line 894 rt_timer_queue_remove_all(struct rttimer |
|
Line 1072 rt_timer_queue_remove_all(struct rttimer |
|
TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); |
TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); |
if (destroy) |
if (destroy) |
RTTIMER_CALLOUT(r); |
RTTIMER_CALLOUT(r); |
|
/* we are already at splsoftnet */ |
pool_put(&rttimer_pool, r); |
pool_put(&rttimer_pool, r); |
if (rtq->rtq_count > 0) |
if (rtq->rtq_count > 0) |
rtq->rtq_count--; |
rtq->rtq_count--; |
Line 936 rt_timer_remove_all(struct rtentry *rt, |
|
Line 1115 rt_timer_remove_all(struct rtentry *rt, |
|
r->rtt_queue->rtq_count--; |
r->rtt_queue->rtq_count--; |
else |
else |
printf("rt_timer_remove_all: rtq_count reached 0\n"); |
printf("rt_timer_remove_all: rtq_count reached 0\n"); |
|
/* we are already at splsoftnet */ |
pool_put(&rttimer_pool, r); |
pool_put(&rttimer_pool, r); |
} |
} |
} |
} |
Line 946 rt_timer_add(struct rtentry *rt, |
|
Line 1126 rt_timer_add(struct rtentry *rt, |
|
struct rttimer_queue *queue) |
struct rttimer_queue *queue) |
{ |
{ |
struct rttimer *r; |
struct rttimer *r; |
long current_time; |
|
int s; |
int s; |
|
|
s = splclock(); |
|
current_time = mono_time.tv_sec; |
|
splx(s); |
|
|
|
/* |
/* |
* If there's already a timer with this action, destroy it before |
* If there's already a timer with this action, destroy it before |
* we add a new one. |
* we add a new one. |
*/ |
*/ |
for (r = LIST_FIRST(&rt->rt_timer); r != NULL; |
LIST_FOREACH(r, &rt->rt_timer, rtt_link) { |
r = LIST_NEXT(r, rtt_link)) { |
if (r->rtt_func == func) |
if (r->rtt_func == func) { |
break; |
LIST_REMOVE(r, rtt_link); |
} |
TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); |
if (r != NULL) { |
if (r->rtt_queue->rtq_count > 0) |
LIST_REMOVE(r, rtt_link); |
r->rtt_queue->rtq_count--; |
TAILQ_REMOVE(&r->rtt_queue->rtq_head, r, rtt_next); |
else |
if (r->rtt_queue->rtq_count > 0) |
printf("rt_timer_add: rtq_count reached 0\n"); |
r->rtt_queue->rtq_count--; |
pool_put(&rttimer_pool, r); |
else |
break; /* only one per list, so we can quit... */ |
printf("rt_timer_add: rtq_count reached 0\n"); |
} |
} else { |
|
s = splsoftnet(); |
|
r = pool_get(&rttimer_pool, PR_NOWAIT); |
|
splx(s); |
|
if (r == NULL) |
|
return ENOBUFS; |
} |
} |
|
|
r = pool_get(&rttimer_pool, PR_NOWAIT); |
memset(r, 0, sizeof(*r)); |
if (r == NULL) |
|
return (ENOBUFS); |
|
Bzero(r, sizeof(*r)); |
|
|
|
r->rtt_rt = rt; |
r->rtt_rt = rt; |
r->rtt_time = current_time; |
r->rtt_time = time_uptime; |
r->rtt_func = func; |
r->rtt_func = func; |
r->rtt_queue = queue; |
r->rtt_queue = queue; |
LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link); |
LIST_INSERT_HEAD(&rt->rt_timer, r, rtt_link); |
TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next); |
TAILQ_INSERT_TAIL(&queue->rtq_head, r, rtt_next); |
r->rtt_queue->rtq_count++; |
r->rtt_queue->rtq_count++; |
|
|
return (0); |
return 0; |
} |
} |
|
|
/* ARGSUSED */ |
/* ARGSUSED */ |
Line 993 rt_timer_timer(void *arg) |
|
Line 1170 rt_timer_timer(void *arg) |
|
{ |
{ |
struct rttimer_queue *rtq; |
struct rttimer_queue *rtq; |
struct rttimer *r; |
struct rttimer *r; |
long current_time; |
|
int s; |
int s; |
|
|
s = splclock(); |
|
current_time = mono_time.tv_sec; |
|
splx(s); |
|
|
|
s = splsoftnet(); |
s = splsoftnet(); |
for (rtq = LIST_FIRST(&rttimer_queue_head); rtq != NULL; |
LIST_FOREACH(rtq, &rttimer_queue_head, rtq_link) { |
rtq = LIST_NEXT(rtq, rtq_link)) { |
|
while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL && |
while ((r = TAILQ_FIRST(&rtq->rtq_head)) != NULL && |
(r->rtt_time + rtq->rtq_timeout) < current_time) { |
(r->rtt_time + rtq->rtq_timeout) < time_uptime) { |
LIST_REMOVE(r, rtt_link); |
LIST_REMOVE(r, rtt_link); |
TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); |
TAILQ_REMOVE(&rtq->rtq_head, r, rtt_next); |
RTTIMER_CALLOUT(r); |
RTTIMER_CALLOUT(r); |
Line 1019 rt_timer_timer(void *arg) |
|
Line 1190 rt_timer_timer(void *arg) |
|
|
|
callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL); |
callout_reset(&rt_timer_ch, hz, rt_timer_timer, NULL); |
} |
} |
|
|
|
#ifdef RTCACHE_DEBUG |
|
#ifndef RTCACHE_DEBUG_SIZE |
|
#define RTCACHE_DEBUG_SIZE (1024 * 1024) |
|
#endif |
|
static const char *cache_caller[RTCACHE_DEBUG_SIZE]; |
|
static struct route *cache_entry[RTCACHE_DEBUG_SIZE]; |
|
size_t cache_cur; |
|
#endif |
|
|
|
#ifdef RTCACHE_DEBUG |
|
static void |
|
_rtcache_init_debug(const char *caller, struct route *ro, int flag) |
|
#else |
|
static void |
|
_rtcache_init(struct route *ro, int flag) |
|
#endif |
|
{ |
|
#ifdef RTCACHE_DEBUG |
|
size_t i; |
|
for (i = 0; i < cache_cur; ++i) { |
|
if (cache_entry[i] == ro) |
|
panic("Reinit of route %p, initialised from %s", ro, cache_caller[i]); |
|
} |
|
#endif |
|
|
|
if (rtcache_getdst(ro) == NULL) |
|
return; |
|
ro->ro_rt = rtalloc1(rtcache_getdst(ro), flag); |
|
if (ro->ro_rt != NULL) { |
|
#ifdef RTCACHE_DEBUG |
|
if (cache_cur == RTCACHE_DEBUG_SIZE) |
|
panic("Route cache debug overflow"); |
|
cache_caller[cache_cur] = caller; |
|
cache_entry[cache_cur] = ro; |
|
++cache_cur; |
|
#endif |
|
rtcache(ro); |
|
} |
|
} |
|
|
|
#ifdef RTCACHE_DEBUG |
|
void |
|
rtcache_init_debug(const char *caller, struct route *ro) |
|
{ |
|
_rtcache_init_debug(caller, ro, 1); |
|
} |
|
|
|
void |
|
rtcache_init_noclone_debug(const char *caller, struct route *ro) |
|
{ |
|
_rtcache_init_debug(caller, ro, 0); |
|
} |
|
|
|
void |
|
rtcache_update(struct route *ro, int clone) |
|
{ |
|
rtcache_clear(ro); |
|
_rtcache_init_debug(__func__, ro, clone); |
|
} |
|
#else |
|
void |
|
rtcache_init(struct route *ro) |
|
{ |
|
_rtcache_init(ro, 1); |
|
} |
|
|
|
void |
|
rtcache_init_noclone(struct route *ro) |
|
{ |
|
_rtcache_init(ro, 0); |
|
} |
|
|
|
void |
|
rtcache_update(struct route *ro, int clone) |
|
{ |
|
rtcache_clear(ro); |
|
_rtcache_init(ro, clone); |
|
} |
|
#endif |
|
|
|
#ifdef RTCACHE_DEBUG |
|
void |
|
rtcache_copy_debug(const char *caller, struct route *new_ro, const struct route *old_ro) |
|
#else |
|
void |
|
rtcache_copy(struct route *new_ro, const struct route *old_ro) |
|
#endif |
|
{ |
|
/* XXX i doubt this DTRT any longer --dyoung */ |
|
#ifdef RTCACHE_DEBUG |
|
size_t i; |
|
|
|
for (i = 0; i < cache_cur; ++i) { |
|
if (cache_entry[i] == new_ro) |
|
panic("Copy to initalised route %p (before %s)", new_ro, cache_caller[i]); |
|
} |
|
#endif |
|
|
|
if (rtcache_getdst(old_ro) == NULL || |
|
rtcache_setdst(new_ro, rtcache_getdst(old_ro)) != 0) |
|
return; |
|
new_ro->ro_rt = old_ro->ro_rt; |
|
if (new_ro->ro_rt != NULL) { |
|
#ifdef RTCACHE_DEBUG |
|
if (cache_cur == RTCACHE_DEBUG_SIZE) |
|
panic("Route cache debug overflow"); |
|
cache_caller[cache_cur] = caller; |
|
cache_entry[cache_cur] = new_ro; |
|
++cache_cur; |
|
#endif |
|
rtcache(new_ro); |
|
++new_ro->ro_rt->rt_refcnt; |
|
} |
|
} |
|
|
|
void |
|
rtcache_clear(struct route *ro) |
|
{ |
|
#ifdef RTCACHE_DEBUG |
|
size_t j, i = cache_cur; |
|
for (i = j = 0; i < cache_cur; ++i, ++j) { |
|
if (cache_entry[i] == ro) { |
|
if (ro->ro_rt == NULL) |
|
panic("Route cache manipulated (allocated by %s)", cache_caller[i]); |
|
--j; |
|
} else { |
|
cache_caller[j] = cache_caller[i]; |
|
cache_entry[j] = cache_entry[i]; |
|
} |
|
} |
|
if (ro->ro_rt != NULL) { |
|
if (i != j + 1) |
|
panic("Wrong entries after rtcache_free: %zu (expected %zu)", j, i - 1); |
|
--cache_cur; |
|
} |
|
#endif |
|
|
|
if (ro->ro_rt != NULL) |
|
rtflush(ro); |
|
ro->ro_rt = NULL; |
|
} |
|
|
|
struct rtentry * |
|
rtcache_lookup2(struct route *ro, const struct sockaddr *dst, int clone, |
|
int *hitp) |
|
{ |
|
const struct sockaddr *odst; |
|
|
|
odst = rtcache_getdst(ro); |
|
|
|
if (odst == NULL) |
|
; |
|
else if (sockaddr_cmp(odst, dst) != 0) |
|
rtcache_free(ro); |
|
else if (rtcache_down(ro)) |
|
rtcache_clear(ro); |
|
|
|
if (ro->ro_rt == NULL) { |
|
*hitp = 0; |
|
rtcache_setdst(ro, dst); |
|
_rtcache_init(ro, clone); |
|
} else |
|
*hitp = 1; |
|
|
|
return ro->ro_rt; |
|
} |
|
|
|
void |
|
rtcache_free(struct route *ro) |
|
{ |
|
rtcache_clear(ro); |
|
if (ro->ro_sa != NULL) { |
|
sockaddr_free(ro->ro_sa); |
|
ro->ro_sa = NULL; |
|
} |
|
} |
|
|
|
int |
|
rtcache_setdst(struct route *ro, const struct sockaddr *sa) |
|
{ |
|
KASSERT(sa != NULL); |
|
|
|
if (ro->ro_sa != NULL && ro->ro_sa->sa_family == sa->sa_family) { |
|
rtcache_clear(ro); |
|
if (sockaddr_copy(ro->ro_sa, ro->ro_sa->sa_len, sa) != NULL) |
|
return 0; |
|
sockaddr_free(ro->ro_sa); |
|
} else if (ro->ro_sa != NULL) |
|
rtcache_free(ro); /* free ro_sa, wrong family */ |
|
|
|
if ((ro->ro_sa = sockaddr_dup(sa, M_NOWAIT)) == NULL) |
|
return ENOMEM; |
|
return 0; |
|
} |
|
|
|
static int |
|
rt_walktree_visitor(struct radix_node *rn, void *v) |
|
{ |
|
struct rtwalk *rw = (struct rtwalk *)v; |
|
|
|
return (*rw->rw_f)((struct rtentry *)rn, rw->rw_v); |
|
} |
|
|
|
int |
|
rt_walktree(sa_family_t family, int (*f)(struct rtentry *, void *), void *v) |
|
{ |
|
struct radix_node_head *rnh = rt_tables[family]; |
|
struct rtwalk rw; |
|
|
|
if (rnh == NULL) |
|
return 0; |
|
|
|
rw.rw_f = f; |
|
rw.rw_v = v; |
|
|
|
return rn_walktree(rnh, rt_walktree_visitor, &rw); |
|
} |