diff options
author | Henning Brauer <henning@cvs.openbsd.org> | 2006-06-15 16:33:03 +0000 |
---|---|---|
committer | Henning Brauer <henning@cvs.openbsd.org> | 2006-06-15 16:33:03 +0000 |
commit | 76df8e5b0f5b64f80edc3988c2c84757ae779f94 (patch) | |
tree | f9b21052eb8f07402acee94ef038c38ba36707e6 /sys/net | |
parent | 686c8cda73261a63e3f930ab893ed44830d5e938 (diff) |
put the multiple routing tables support back in, fixed.
problem before: with this, we are no longer using the address family as
array index directly, since only 3 of 31 address fanilies actually attach
a table, but we're using an address family to array index translation (just
another array). there, 0 meant "does not attach a table", thus rt_gettable
has to return a null pointer. unfortunately we were using array index 0 for
whatever af attaches first, and since the list is backwards,, that used to
be ipsec - execpt on ipsec-less ramdisks, where it was inet6, and since
route show blindly iterates over all address families, and all those
without a table pointed to index 0, we got 28 or 29 copies of the v6 table.
i had that right initally, and then i borked it later... re-spotted by
claudio.
ok norby hshoexer claudio
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/route.c | 96 | ||||
-rw-r--r-- | sys/net/route.h | 7 |
2 files changed, 80 insertions, 23 deletions
diff --git a/sys/net/route.c b/sys/net/route.c index 9b05ced60ce..c9ac3840b5a 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -1,4 +1,4 @@ -/* $OpenBSD: route.c,v 1.77 2006/06/06 15:36:07 deraadt Exp $ */ +/* $OpenBSD: route.c,v 1.78 2006/06/15 16:33:02 henning Exp $ */ /* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */ /* @@ -130,9 +130,12 @@ struct ifaddr *encap_findgwifa(struct sockaddr *); #define SA(p) ((struct sockaddr *)(p)) -struct route_cb route_cb; -struct rtstat rtstat; -struct radix_node_head *rt_tables[AF_MAX+1]; +struct route_cb route_cb; +struct rtstat rtstat; +struct radix_node_head ***rt_tables; +u_int8_t af2rtafidx[AF_MAX+1]; +u_int8_t rtafidx_max; +u_int rtbl_id_max = 0; int rttrash; /* routes not in table but not freed */ struct sockaddr wildcard; /* zero cookie for wildcard searches */ @@ -140,6 +143,8 @@ struct sockaddr wildcard; /* zero cookie for wildcard searches */ struct pool rtentry_pool; /* pool for rtentry structures */ struct pool rttimer_pool; /* pool for rttimer structures */ +int rtable_init(struct radix_node_head ***); +int rtable_add(u_int); int okaytoclone(u_int, int); int rtdeletemsg(struct rtentry *); int rtflushclone1(struct radix_node *, void *); @@ -165,23 +170,74 @@ encap_findgwifa(struct sockaddr *gw) } #endif -void -rtable_init(void **table) +int +rtable_init(struct radix_node_head ***table) { - struct domain *dom; + void **p; + struct domain *dom; + + if ((p = malloc(sizeof(void *) * (rtafidx_max + 1), M_RTABLE, + M_NOWAIT)) == NULL) + return (-1); + bzero(p, sizeof(void *) * (rtafidx_max + 1)); + + /* 2nd pass: attach */ for (dom = domains; dom != NULL; dom = dom->dom_next) if (dom->dom_rtattach) - dom->dom_rtattach(&table[dom->dom_family], + dom->dom_rtattach(&p[af2rtafidx[dom->dom_family]], dom->dom_rtoffset); + + *table = (struct radix_node_head **)p; + return (0); } void route_init() { + struct domain *dom; + pool_init(&rtentry_pool, sizeof(struct rtentry), 0, 0, 0, "rtentpl", NULL); rn_init(); /* initialize all zeroes, all ones, mask table */ - rtable_init((void **)rt_tables); + + bzero(af2rtafidx, sizeof(af2rtafidx)); + rtafidx_max = 1; /* must have NULL at index 0, so start at 1 */ + + /* find out how many tables to allocate */ + for (dom = domains; dom != NULL; dom = dom->dom_next) + if (dom->dom_rtattach) + af2rtafidx[dom->dom_family] = rtafidx_max++; + + if (rtable_add(0) == -1) + panic("route_init rtable_add"); +} + +int +rtable_add(u_int id) /* must be called at splsoftnet */ +{ + void *p; + + if (id > RT_TABLEID_MAX) + return (-1); + + if (id == 0 || id > rtbl_id_max) { + size_t newlen = sizeof(void *) * (id+1); + + if ((p = malloc(newlen, M_RTABLE, M_NOWAIT)) == NULL) + return (-1); + bzero(p, newlen); + if (id > 0) { + bcopy(rt_tables, p, sizeof(void *) * (rtbl_id_max+1)); + free(rt_tables, M_RTABLE); + } + rt_tables = p; + rtbl_id_max = id; + } + + if (rt_tables[id] != NULL) /* already exists */ + return (-1); + + return (rtable_init(&rt_tables[id])); } void @@ -205,13 +261,14 @@ okaytoclone(u_int flags, int howstrict) struct rtentry * rtalloc2(struct sockaddr *dst, int report, int howstrict) { - struct radix_node_head *rnh = rt_tables[dst->sa_family]; + struct radix_node_head *rnh; struct rtentry *rt; struct radix_node *rn; struct rtentry *newrt = 0; struct rt_addrinfo info; int s = splnet(), err = 0, msgtype = RTM_MISS; + rnh = rt_gettable(dst->sa_family, 0); if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && ((rn->rn_flags & RNF_ROOT) == 0)) { newrt = rt = (struct rtentry *)rn; @@ -257,13 +314,14 @@ rtalloc(struct route *ro) struct rtentry * rtalloc1(struct sockaddr *dst, int report) { - struct radix_node_head *rnh = rt_tables[dst->sa_family]; + struct radix_node_head *rnh; struct rtentry *rt; struct radix_node *rn; struct rtentry *newrt = 0; struct rt_addrinfo info; int s = splsoftnet(), err = 0, msgtype = RTM_MISS; + rnh = rt_gettable(dst->sa_family, 0); if (rnh && (rn = rnh->rnh_matchaddr((caddr_t)dst, rnh)) && ((rn->rn_flags & RNF_ROOT) == 0)) { newrt = rt = (struct rtentry *)rn; @@ -657,7 +715,7 @@ rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt) struct sockaddr_rtlabel *sa_rl; #define senderr(x) { error = x ; goto bad; } - if ((rnh = rt_tables[info->rti_info[RTAX_DST]->sa_family]) == 0) + if ((rnh = rt_gettable(info->rti_info[RTAX_DST]->sa_family, 0)) == NULL) senderr(EAFNOSUPPORT); if (info->rti_flags & RTF_HOST) info->rti_info[RTAX_NETMASK] = NULL; @@ -1127,10 +1185,9 @@ rt_timer_add(struct rtentry *rt, void (*func)(struct rtentry *, } struct radix_node_head * -rt_gettable(sa_family_t af, int id) +rt_gettable(sa_family_t af, u_int id) { - /* ignore id for now */ - return (rt_tables[af]); + return (rt_tables[id][af2rtafidx[af]]); } struct radix_node * @@ -1143,6 +1200,7 @@ rt_lookup(struct sockaddr *dst, struct sockaddr *mask, int tableid) return (rnh->rnh_lookup(dst, mask, rnh)); } + /* ARGSUSED */ void rt_timer_timer(void *arg) @@ -1259,13 +1317,11 @@ rt_if_remove(struct ifnet *ifp) int i; struct radix_node_head *rnh; - for (i = 1; i <= AF_MAX; i++) { - rnh = rt_tables[i]; - if (rnh) + for (i = 1; i <= AF_MAX; i++) + if ((rnh = rt_gettable(i, 0)) != NULL) while ((*rnh->rnh_walktree)(rnh, rt_if_remove_rtdelete, ifp) == EAGAIN) - ; - } + ; /* nothing */ } /* diff --git a/sys/net/route.h b/sys/net/route.h index 9db16dbf54a..6534ddf1057 100644 --- a/sys/net/route.h +++ b/sys/net/route.h @@ -1,4 +1,4 @@ -/* $OpenBSD: route.h,v 1.42 2006/06/06 15:36:07 deraadt Exp $ */ +/* $OpenBSD: route.h,v 1.43 2006/06/15 16:33:02 henning Exp $ */ /* $NetBSD: route.h,v 1.9 1996/02/13 22:00:49 christos Exp $ */ /* @@ -304,6 +304,8 @@ void rtlabel_unref(u_int16_t); #define ONNET_CLONING 1 #define NO_CLONING 2 +#define RT_TABLEID_MAX 255 + extern struct route_cb route_cb; extern struct rtstat rtstat; extern const struct sockaddr_rtin rt_defmask4; @@ -334,7 +336,6 @@ void rt_timer_queue_destroy(struct rttimer_queue *, int); void rt_timer_remove_all(struct rtentry *); unsigned long rt_timer_count(struct rttimer_queue *); void rt_timer_timer(void *); -void rtable_init(void **); void rtalloc(struct route *); struct rtentry * rtalloc1(struct sockaddr *, int); @@ -354,7 +355,7 @@ int rtrequest(int, struct sockaddr *, int rtrequest1(int, struct rt_addrinfo *, struct rtentry **); void rt_if_remove(struct ifnet *); -struct radix_node_head *rt_gettable(sa_family_t, int); +struct radix_node_head *rt_gettable(sa_family_t, u_int); struct radix_node *rt_lookup(struct sockaddr *, struct sockaddr *, int); #endif /* _KERNEL */ #endif /* _NET_ROUTE_H_ */ |