diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2009-11-03 10:59:05 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2009-11-03 10:59:05 +0000 |
commit | aa799beefd4c8fce27ceb0fd6ed143fb40859be2 (patch) | |
tree | 6e6ca07fa0c49af532b084c80a89d926a9a3bd0f /sys/net/route.c | |
parent | e5888cd56b381838e11260d5af85260b96ce1f4e (diff) |
rtables are stacked on rdomains (it is possible to have multiple routing
tables on top of a rdomain) but until now our code was a crazy mix so that
it was impossible to correctly use rtables in that case. Additionally pf(4)
only knows about rtables and not about rdomains. This is especially bad when
tracking (possibly conflicting) states in various domains.
This diff fixes all or most of these issues. It adds a lookup function to
get the rdomain id based on a rtable id. Makes pf understand rdomains and
allows pf to move packets between rdomains (it is similar to NAT).
Because pf states now track the rdomain id as well it is necessary to modify
the pfsync wire format. So old and new systems will not sync up.
A lot of help by dlg@, tested by sthen@, jsg@ and probably more
OK dlg@, mpf@, deraadt@
Diffstat (limited to 'sys/net/route.c')
-rw-r--r-- | sys/net/route.c | 57 |
1 files changed, 41 insertions, 16 deletions
diff --git a/sys/net/route.c b/sys/net/route.c index d8f9a01b17b..9a798e2fbf3 100644 --- a/sys/net/route.c +++ b/sys/net/route.c @@ -1,4 +1,4 @@ -/* $OpenBSD: route.c,v 1.113 2009/10/26 17:14:24 mk Exp $ */ +/* $OpenBSD: route.c,v 1.114 2009/11/03 10:59:04 claudio Exp $ */ /* $NetBSD: route.c,v 1.14 1996/02/13 22:00:46 christos Exp $ */ /* @@ -140,6 +140,7 @@ struct radix_node_head ***rt_tables; u_int8_t af2rtafidx[AF_MAX+1]; u_int8_t rtafidx_max; u_int rtbl_id_max = 0; +u_int *rt_tab2dom; /* rt table to domain lookup table */ int rttrash; /* routes not in table but not freed */ @@ -218,30 +219,54 @@ route_init() int rtable_add(u_int id) /* must be called at splsoftnet */ { - void *p; + void *p, *q; if (id > RT_TABLEID_MAX) return (-1); if (id == 0 || id > rtbl_id_max) { size_t newlen = sizeof(void *) * (id+1); + size_t newlen2 = sizeof(u_int) * (id+1); if ((p = malloc(newlen, M_RTABLE, M_NOWAIT|M_ZERO)) == NULL) return (-1); + if ((q = malloc(newlen2, M_RTABLE, M_NOWAIT|M_ZERO)) == NULL) { + free(p, M_RTABLE); + return (-1); + } if (rt_tables) { bcopy(rt_tables, p, sizeof(void *) * (rtbl_id_max+1)); + bcopy(rt_tab2dom, q, sizeof(u_int) * (rtbl_id_max+1)); free(rt_tables, M_RTABLE); } rt_tables = p; + rt_tab2dom = q; rtbl_id_max = id; } if (rt_tables[id] != NULL) /* already exists */ return (-1); + rt_tab2dom[id] = 0; /* use main table/domain by default */ return (rtable_init(&rt_tables[id])); } +u_int +rtable_l2(u_int id) +{ + if (id > rtbl_id_max) + return (0); + return (rt_tab2dom[id]); +} + +void +rtable_l2set(u_int id, u_int parent) +{ + if (!rtable_exists(id) || !rtable_exists(parent)) + return; + rt_tab2dom[id] = parent; +} + int rtable_exists(u_int id) /* verify table with that ID exists */ { @@ -616,7 +641,7 @@ rtioctl(u_long req, caddr_t data, struct proc *p) struct ifaddr * ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway, - u_int rdomain) + u_int rtableid) { struct ifaddr *ifa; @@ -641,21 +666,21 @@ ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway, */ ifa = NULL; if (flags & RTF_HOST) - ifa = ifa_ifwithdstaddr(dst, rdomain); + ifa = ifa_ifwithdstaddr(dst, rtableid); if (ifa == NULL) - ifa = ifa_ifwithaddr(gateway, rdomain); + ifa = ifa_ifwithaddr(gateway, rtableid); } else { /* * If we are adding a route to a remote net * or host, the gateway may still be on the * other end of a pt to pt link. */ - ifa = ifa_ifwithdstaddr(gateway, rdomain); + ifa = ifa_ifwithdstaddr(gateway, rtableid); } if (ifa == NULL) - ifa = ifa_ifwithnet(gateway, rdomain); + ifa = ifa_ifwithnet(gateway, rtableid); if (ifa == NULL) { - struct rtentry *rt = rtalloc1(gateway, 0, rdomain); + struct rtentry *rt = rtalloc1(gateway, 0, rtable_l2(rtableid)); if (rt == NULL) return (NULL); rt->rt_refcnt--; @@ -678,7 +703,7 @@ ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway, #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) int -rt_getifa(struct rt_addrinfo *info, u_int rdom) +rt_getifa(struct rt_addrinfo *info, u_int rtid) { struct ifaddr *ifa; int error = 0; @@ -690,11 +715,11 @@ rt_getifa(struct rt_addrinfo *info, u_int rdom) if (info->rti_ifp == NULL && info->rti_info[RTAX_IFP] != NULL && info->rti_info[RTAX_IFP]->sa_family == AF_LINK && (ifa = ifa_ifwithnet((struct sockaddr *)info->rti_info[RTAX_IFP], - rdom)) != NULL) + rtid)) != NULL) info->rti_ifp = ifa->ifa_ifp; if (info->rti_ifa == NULL && info->rti_info[RTAX_IFA] != NULL) - info->rti_ifa = ifa_ifwithaddr(info->rti_info[RTAX_IFA], rdom); + info->rti_ifa = ifa_ifwithaddr(info->rti_info[RTAX_IFA], rtid); if (info->rti_ifa == NULL) { struct sockaddr *sa; @@ -710,10 +735,10 @@ rt_getifa(struct rt_addrinfo *info, u_int rdom) info->rti_ifa = ifa_ifwithroute(info->rti_flags, info->rti_info[RTAX_DST], info->rti_info[RTAX_GATEWAY], - rdom); + rtid); else if (sa != NULL) info->rti_ifa = ifa_ifwithroute(info->rti_flags, - sa, sa, rdom); + sa, sa, rtid); } if ((ifa = info->rti_ifa) != NULL) { if (info->rti_ifp == NULL) @@ -823,8 +848,7 @@ rtrequest1(int req, struct rt_addrinfo *info, u_int8_t prio, goto makeroute; case RTM_ADD: - if (info->rti_ifa == 0 && (error = rt_getifa(info, - /* XXX wrong because only rdomains allowed */ tableid))) + if (info->rti_ifa == 0 && (error = rt_getifa(info, tableid))) senderr(error); ifa = info->rti_ifa; makeroute: @@ -1009,7 +1033,8 @@ rt_setgate(struct rtentry *rt0, struct sockaddr *dst, struct sockaddr *gate, rt->rt_gwroute = NULL; } if (rt->rt_flags & RTF_GATEWAY) { - rt->rt_gwroute = rtalloc1(gate, 1, tableid); + /* XXX is this actually valid to cross tables here? */ + rt->rt_gwroute = rtalloc1(gate, 1, rtable_l2(tableid)); /* * If we switched gateways, grab the MTU from the new * gateway route if the current MTU is 0 or greater |