summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--contrib/netcat/netcat.c13
-rw-r--r--contrib/pf/pfctl/parse.y32
-rwxr-xr-xetc/rc.d/routing26
-rw-r--r--share/man/man4/faith.44
-rw-r--r--sys/contrib/pf/net/pf.c79
-rw-r--r--sys/contrib/pf/net/pf_ioctl.c4
-rw-r--r--sys/contrib/pf/net/pf_lb.c7
-rw-r--r--sys/contrib/pf/net/pf_norm.c12
-rw-r--r--sys/contrib/pf/net/pfvar.h18
-rw-r--r--sys/fs/nfsclient/nfs_clport.c6
-rw-r--r--sys/fs/nfsclient/nfs_clvfsops.c4
-rw-r--r--sys/kern/uipc_socket.c2
-rw-r--r--sys/net/flowtable.c4
-rw-r--r--sys/net/if_faith.c2
-rw-r--r--sys/net/route.c183
-rw-r--r--sys/net/route.h3
-rw-r--r--sys/netinet/in.c2
-rw-r--r--sys/netinet/ipfw/ip_fw2.c12
-rw-r--r--sys/netinet/sctp_os_bsd.h6
-rw-r--r--sys/netinet/tcp_subr.c2
-rw-r--r--sys/netinet6/icmp6.c18
-rw-r--r--sys/netinet6/in6.c549
-rw-r--r--sys/netinet6/in6_gif.c7
-rw-r--r--sys/netinet6/in6_ifattach.c24
-rw-r--r--sys/netinet6/in6_mcast.c9
-rw-r--r--sys/netinet6/in6_rmx.c124
-rw-r--r--sys/netinet6/in6_src.c74
-rw-r--r--sys/netinet6/in6_var.h11
-rw-r--r--sys/netinet6/ip6_forward.c2
-rw-r--r--sys/netinet6/ip6_input.c2
-rw-r--r--sys/netinet6/ip6_output.c26
-rw-r--r--sys/netinet6/ip6_var.h3
-rw-r--r--sys/netinet6/nd6.c5
-rw-r--r--sys/netinet6/nd6_nbr.c45
-rw-r--r--sys/netinet6/nd6_rtr.c188
-rw-r--r--sys/netinet6/raw_ip6.c12
-rw-r--r--sys/netipsec/ipsec_output.c2
-rw-r--r--sys/nfs/bootp_subr.c7
-rw-r--r--sys/nfsclient/nfs_vfsops.c4
-rw-r--r--usr.bin/netstat/route.c29
40 files changed, 947 insertions, 615 deletions
diff --git a/contrib/netcat/netcat.c b/contrib/netcat/netcat.c
index 9b9017d..bee0fa6 100644
--- a/contrib/netcat/netcat.c
+++ b/contrib/netcat/netcat.c
@@ -605,8 +605,10 @@ remote_connect(const char *host, const char *port, struct addrinfo hints)
#endif
if (rtableid) {
- if (setfib(rtableid) == -1)
- err(1, "setfib");
+ if (setsockopt(s, SOL_SOCKET, SO_SETFIB, &rtableid,
+ sizeof(rtableid)) == -1)
+ err(1, "setsockopt(.., SO_SETFIB, %u, ..)",
+ rtableid);
}
/* Bind to a local port or source address if specified. */
@@ -678,8 +680,11 @@ local_listen(char *host, char *port, struct addrinfo hints)
continue;
if (rtableid) {
- if (setfib(rtableid) == -1)
- err(1, "setfib");
+ ret = setsockopt(s, SOL_SOCKET, SO_SETFIB, &rtableid,
+ sizeof(rtableid));
+ if (ret == -1)
+ err(1, "setsockopt(.., SO_SETFIB, %u, ..)",
+ rtableid);
}
ret = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &x, sizeof(x));
diff --git a/contrib/pf/pfctl/parse.y b/contrib/pf/pfctl/parse.y
index 440692e..f798cac 100644
--- a/contrib/pf/pfctl/parse.y
+++ b/contrib/pf/pfctl/parse.y
@@ -33,6 +33,9 @@ __FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#endif
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -335,6 +338,7 @@ int expand_skip_interface(struct node_if *);
int check_rulestate(int);
int getservice(char *);
int rule_label(struct pf_rule *, char *);
+int rt_tableid_max(void);
void mv_rules(struct pf_ruleset *, struct pf_ruleset *);
void decide_address_family(struct node_host *, sa_family_t *);
@@ -1174,7 +1178,7 @@ scrub_opt : NODF {
scrub_opts.randomid = 1;
}
| RTABLE NUMBER {
- if ($2 < 0 /* || $2 > RT_TABLEID_MAX */) {
+ if ($2 < 0 || $2 > rt_tableid_max()) {
yyerror("invalid rtable id");
YYERROR;
}
@@ -1322,7 +1326,7 @@ antispoof_opt : label {
antispoof_opts.label = $1;
}
| RTABLE NUMBER {
- if ($2 < 0 /* || $2 > RT_TABLEID_MAX */ ) {
+ if ($2 < 0 || $2 > rt_tableid_max()) {
yyerror("invalid rtable id");
YYERROR;
}
@@ -2361,7 +2365,7 @@ filter_opt : USER uids {
filter_opts.prob = 1;
}
| RTABLE NUMBER {
- if ($2 < 0 /* || $2 > RT_TABLEID_MAX */ ) {
+ if ($2 < 0 || $2 > rt_tableid_max()) {
yyerror("invalid rtable id");
YYERROR;
}
@@ -4190,7 +4194,7 @@ tagged : /* empty */ { $$.neg = 0; $$.name = NULL; }
rtable : /* empty */ { $$ = -1; }
| RTABLE NUMBER {
- if ($2 < 0 /* || $2 > RT_TABLEID_MAX */ ) {
+ if ($2 < 0 || $2 > rt_tableid_max()) {
yyerror("invalid rtable id");
YYERROR;
}
@@ -6051,3 +6055,23 @@ pfctl_load_anchors(int dev, struct pfctl *pf, struct pfr_buffer *trans)
return (0);
}
+
+int
+rt_tableid_max(void)
+{
+#ifdef __FreeBSD__
+ int fibs;
+ size_t l = sizeof(fibs);
+
+ if (sysctlbyname("net.fibs", &fibs, &l, NULL, 0) == -1)
+ fibs = 16; /* XXX RT_MAXFIBS, at least limit it some. */
+ /*
+ * As the OpenBSD code only compares > and not >= we need to adjust
+ * here given we only accept values of 0..n and want to avoid #ifdefs
+ * in the grammer.
+ */
+ return (fibs - 1);
+#else
+ return (RT_TABLEID_MAX);
+#endif
+}
diff --git a/etc/rc.d/routing b/etc/rc.d/routing
index ec90e8d..5903acc 100755
--- a/etc/rc.d/routing
+++ b/etc/rc.d/routing
@@ -139,12 +139,22 @@ static_inet()
static_inet6()
{
- local _action i
+ local _action i fibs
_action=$1
+ # get the number of FIBs supported.
+ fibs=`sysctl -n net.fibs`
+ : ${fibs:=1}
+
# disallow "internal" addresses to appear on the wire
- route ${_action} -inet6 ::ffff:0.0.0.0 -prefixlen 96 ::1 -reject
- route ${_action} -inet6 ::0.0.0.0 -prefixlen 96 ::1 -reject
+ i=0
+ while test ${i} -lt ${fibs}; do
+ setfib -F ${i} route ${_action} \
+ -inet6 ::ffff:0.0.0.0 -prefixlen 96 ::1 -reject
+ setfib -F ${i} route ${_action} \
+ -inet6 ::0.0.0.0 -prefixlen 96 ::1 -reject
+ i=$((i + 1))
+ done
case ${ipv6_defaultrouter} in
[Nn][Oo] | '')
@@ -216,8 +226,14 @@ static_inet6()
# for the host case, you will allow to omit the identifiers.
# Under this configuration, the packets will go to the default
# interface.
- route ${_action} -inet6 fe80:: -prefixlen 10 ::1 -reject
- route ${_action} -inet6 ff02:: -prefixlen 16 ::1 -reject
+ i=0
+ while test ${i} -lt ${fibs}; do
+ setfib -F ${i} route ${_action} \
+ -inet6 fe80:: -prefixlen 10 ::1 -reject
+ setfib -F ${i} route ${_action} \
+ -inet6 ff02:: -prefixlen 16 ::1 -reject
+ i=$((i + 1))
+ done
case ${ipv6_default_interface} in
'')
diff --git a/share/man/man4/faith.4 b/share/man/man4/faith.4
index b98ba39..f0a2df6 100644
--- a/share/man/man4/faith.4
+++ b/share/man/man4/faith.4
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 10, 1999
+.Dd January 23, 2012
.Dt FAITH 4
.Os
.Sh NAME
@@ -58,7 +58,7 @@ variable in
.Xr rc.conf 5 .
.Pp
Special action will be taken when IPv6 TCP traffic is seen on a router,
-and the routing table suggests to route it to the
+and the default routing table suggests to route it to the
.Nm
interface.
In this case, the packet will be accepted by the router,
diff --git a/sys/contrib/pf/net/pf.c b/sys/contrib/pf/net/pf.c
index 5c9641b..7058b7d 100644
--- a/sys/contrib/pf/net/pf.c
+++ b/sys/contrib/pf/net/pf.c
@@ -320,7 +320,7 @@ u_int8_t pf_get_wscale(struct mbuf *, int, u_int16_t,
u_int16_t pf_get_mss(struct mbuf *, int, u_int16_t,
sa_family_t);
u_int16_t pf_calc_mss(struct pf_addr *, sa_family_t,
- u_int16_t);
+ int, u_int16_t);
void pf_set_rt_ifp(struct pf_state *,
struct pf_addr *);
int pf_check_proto_cksum(struct mbuf *, int, int,
@@ -3137,7 +3137,7 @@ pf_get_mss(struct mbuf *m, int off, u_int16_t th_off, sa_family_t af)
}
u_int16_t
-pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
+pf_calc_mss(struct pf_addr *addr, sa_family_t af, int rtableid, u_int16_t offer)
{
#ifdef INET
struct sockaddr_in *dst;
@@ -3166,11 +3166,7 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
dst->sin_len = sizeof(*dst);
dst->sin_addr = addr->v4;
#ifdef __FreeBSD__
-#ifdef RTF_PRCLONING
- rtalloc_ign(&ro, (RTF_CLONING | RTF_PRCLONING));
-#else /* !RTF_PRCLONING */
- in_rtalloc_ign(&ro, 0, 0);
-#endif
+ in_rtalloc_ign(&ro, 0, rtableid);
#else /* ! __FreeBSD__ */
rtalloc_noclone(&ro, NO_CLONING);
#endif
@@ -3186,12 +3182,7 @@ pf_calc_mss(struct pf_addr *addr, sa_family_t af, u_int16_t offer)
dst6->sin6_len = sizeof(*dst6);
dst6->sin6_addr = addr->v6;
#ifdef __FreeBSD__
-#ifdef RTF_PRCLONING
- rtalloc_ign((struct route *)&ro6,
- (RTF_CLONING | RTF_PRCLONING));
-#else /* !RTF_PRCLONING */
- rtalloc_ign((struct route *)&ro6, 0);
-#endif
+ in6_rtalloc_ign(&ro6, 0, rtableid);
#else /* ! __FreeBSD__ */
rtalloc_noclone((struct route *)&ro6, NO_CLONING);
#endif
@@ -3532,14 +3523,14 @@ pf_test_rule(struct pf_rule **rm, struct pf_state **sm, int direction,
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
else if (PF_MISMATCHAW(&r->src.addr, saddr, af,
- r->src.neg, kif))
+ r->src.neg, kif, M_GETFIB(m)))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
/* tcp/udp only. port_op always 0 in other cases */
else if (r->src.port_op && !pf_match_port(r->src.port_op,
r->src.port[0], r->src.port[1], sport))
r = r->skip[PF_SKIP_SRC_PORT].ptr;
else if (PF_MISMATCHAW(&r->dst.addr, daddr, af,
- r->dst.neg, NULL))
+ r->dst.neg, NULL, M_GETFIB(m)))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
/* tcp/udp only. port_op always 0 in other cases */
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
@@ -3988,9 +3979,10 @@ pf_create_state(struct pf_rule *r, struct pf_rule *nr, struct pf_rule *a,
}
s->src.seqhi = htonl(arc4random());
/* Find mss option */
+ int rtid = M_GETFIB(m);
mss = pf_get_mss(m, off, th->th_off, pd->af);
- mss = pf_calc_mss(pd->src, pd->af, mss);
- mss = pf_calc_mss(pd->dst, pd->af, mss);
+ mss = pf_calc_mss(pd->src, pd->af, rtid, mss);
+ mss = pf_calc_mss(pd->dst, pd->af, rtid, mss);
s->src.mss = mss;
#ifdef __FreeBSD__
pf_send_tcp(NULL, r, pd->af, pd->dst, pd->src, th->th_dport,
@@ -4072,10 +4064,10 @@ pf_test_fragment(struct pf_rule **rm, int direction, struct pfi_kif *kif,
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
- r->src.neg, kif))
+ r->src.neg, kif, M_GETFIB(m)))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
- r->dst.neg, NULL))
+ r->dst.neg, NULL, M_GETFIB(m)))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->tos && !(r->tos == pd->tos))
r = TAILQ_NEXT(r, entries);
@@ -5677,7 +5669,8 @@ pf_pull_hdr(struct mbuf *m, int off, void *p, int len,
}
int
-pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif)
+pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif,
+ int rtableid)
{
#ifdef __FreeBSD__
#ifdef RADIX_MPATH
@@ -5751,13 +5744,21 @@ pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *kif)
goto out;
#ifdef __FreeBSD__
-/* XXX MRT not always INET */ /* stick with table 0 though */
+ switch (af) {
+#ifdef INET6
+ case AF_INET6:
+ in6_rtalloc_ign(&ro, 0, rtableid);
+ break;
+#endif
#ifdef INET
- if (af == AF_INET)
- in_rtalloc_ign((struct route *)&ro, 0, 0);
- else
+ case AF_INET:
+ in_rtalloc_ign((struct route *)&ro, 0, rtableid);
+ break;
#endif
- rtalloc_ign((struct route *)&ro, 0);
+ default:
+ rtalloc_ign((struct route *)&ro, 0); /* No/default FIB. */
+ break;
+ }
#else /* ! __FreeBSD__ */
rtalloc_noclone((struct route *)&ro, NO_CLONING);
#endif
@@ -5803,7 +5804,8 @@ out:
}
int
-pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
+pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw,
+ int rtableid)
{
struct sockaddr_in *dst;
#ifdef INET6
@@ -5835,16 +5837,21 @@ pf_rtlabel_match(struct pf_addr *addr, sa_family_t af, struct pf_addr_wrap *aw)
}
#ifdef __FreeBSD__
-# ifdef RTF_PRCLONING
- rtalloc_ign((struct route *)&ro, (RTF_CLONING|RTF_PRCLONING));
-# else /* !RTF_PRCLONING */
+ switch (af) {
+#ifdef INET6
+ case AF_INET6:
+ in6_rtalloc_ign(&ro, 0, rtableid);
+ break;
+#endif
#ifdef INET
- if (af == AF_INET)
- in_rtalloc_ign((struct route *)&ro, 0, 0);
- else
+ case AF_INET:
+ in_rtalloc_ign((struct route *)&ro, 0, rtableid);
+ break;
#endif
+ default:
rtalloc_ign((struct route *)&ro, 0);
-# endif
+ break;
+ }
#else /* ! __FreeBSD__ */
rtalloc_noclone((struct route *)&ro, NO_CLONING);
#endif
@@ -5927,7 +5934,7 @@ pf_route(struct mbuf **m, struct pf_rule *r, int dir, struct ifnet *oifp,
if (r->rt == PF_FASTROUTE) {
#ifdef __FreeBSD__
- in_rtalloc(ro, 0);
+ in_rtalloc_ign(ro, 0, M_GETFIB(m0));
#else
rtalloc(ro);
#endif
@@ -6893,7 +6900,7 @@ done:
("pf: dropping packet with ip options\n"));
}
- if ((s && s->tag) || r->rtableid)
+ if ((s && s->tag) || r->rtableid >= 0)
#ifdef __FreeBSD__
pf_tag_packet(m, s ? s->tag : 0, r->rtableid, pd.pf_mtag);
#else
@@ -7437,7 +7444,7 @@ done:
("pf: dropping packet with dangerous v6 headers\n"));
}
- if ((s && s->tag) || r->rtableid)
+ if ((s && s->tag) || r->rtableid >= 0)
#ifdef __FreeBSD__
pf_tag_packet(m, s ? s->tag : 0, r->rtableid, pd.pf_mtag);
#else
diff --git a/sys/contrib/pf/net/pf_ioctl.c b/sys/contrib/pf/net/pf_ioctl.c
index e78c8ff..468f3d7 100644
--- a/sys/contrib/pf/net/pf_ioctl.c
+++ b/sys/contrib/pf/net/pf_ioctl.c
@@ -1754,7 +1754,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
}
#ifdef __FreeBSD__ /* ROUTING */
- if (rule->rtableid > 0 && rule->rtableid > rt_numfibs)
+ if (rule->rtableid > 0 && rule->rtableid >= rt_numfibs)
#else
if (rule->rtableid > 0 && !rtable_exists(rule->rtableid))
#endif
@@ -2035,7 +2035,7 @@ pfioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct proc *p)
if (newrule->rtableid > 0 &&
#ifdef __FreeBSD__ /* ROUTING */
- newrule->rtableid > rt_numfibs)
+ newrule->rtableid >= rt_numfibs)
#else
!rtable_exists(newrule->rtableid))
#endif
diff --git a/sys/contrib/pf/net/pf_lb.c b/sys/contrib/pf/net/pf_lb.c
index f4c9a00..4adc6f0 100644
--- a/sys/contrib/pf/net/pf_lb.c
+++ b/sys/contrib/pf/net/pf_lb.c
@@ -261,7 +261,7 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
else if (PF_MISMATCHAW(&src->addr, saddr, pd->af,
- src->neg, kif))
+ src->neg, kif, M_GETFIB(m)))
r = r->skip[src == &r->src ? PF_SKIP_SRC_ADDR :
PF_SKIP_DST_ADDR].ptr;
else if (src->port_op && !pf_match_port(src->port_op,
@@ -269,10 +269,11 @@ pf_match_translation(struct pf_pdesc *pd, struct mbuf *m, int off,
r = r->skip[src == &r->src ? PF_SKIP_SRC_PORT :
PF_SKIP_DST_PORT].ptr;
else if (dst != NULL &&
- PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL))
+ PF_MISMATCHAW(&dst->addr, daddr, pd->af, dst->neg, NULL,
+ M_GETFIB(m)))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (xdst != NULL && PF_MISMATCHAW(xdst, daddr, pd->af,
- 0, NULL))
+ 0, NULL, M_GETFIB(m)))
r = TAILQ_NEXT(r, entries);
else if (dst != NULL && dst->port_op &&
!pf_match_port(dst->port_op, dst->port[0],
diff --git a/sys/contrib/pf/net/pf_norm.c b/sys/contrib/pf/net/pf_norm.c
index 6c04eee..2b20c85 100644
--- a/sys/contrib/pf/net/pf_norm.c
+++ b/sys/contrib/pf/net/pf_norm.c
@@ -1163,11 +1163,11 @@ pf_normalize_ip(struct mbuf **m0, int dir, struct pfi_kif *kif, u_short *reason,
r = r->skip[PF_SKIP_PROTO].ptr;
else if (PF_MISMATCHAW(&r->src.addr,
(struct pf_addr *)&h->ip_src.s_addr, AF_INET,
- r->src.neg, kif))
+ r->src.neg, kif, M_GETFIB(m)))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (PF_MISMATCHAW(&r->dst.addr,
(struct pf_addr *)&h->ip_dst.s_addr, AF_INET,
- r->dst.neg, NULL))
+ r->dst.neg, NULL, M_GETFIB(m)))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
#ifdef __FreeBSD__
else if (r->match_tag && !pf_match_tag(m, r, &tag, pd->pf_mtag))
@@ -1428,11 +1428,11 @@ pf_normalize_ip6(struct mbuf **m0, int dir, struct pfi_kif *kif,
#endif
else if (PF_MISMATCHAW(&r->src.addr,
(struct pf_addr *)&h->ip6_src, AF_INET6,
- r->src.neg, kif))
+ r->src.neg, kif, M_GETFIB(m)))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (PF_MISMATCHAW(&r->dst.addr,
(struct pf_addr *)&h->ip6_dst, AF_INET6,
- r->dst.neg, NULL))
+ r->dst.neg, NULL, M_GETFIB(m)))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else
break;
@@ -1593,13 +1593,13 @@ pf_normalize_tcp(int dir, struct pfi_kif *kif, struct mbuf *m, int ipoff,
else if (r->proto && r->proto != pd->proto)
r = r->skip[PF_SKIP_PROTO].ptr;
else if (PF_MISMATCHAW(&r->src.addr, pd->src, af,
- r->src.neg, kif))
+ r->src.neg, kif, M_GETFIB(m)))
r = r->skip[PF_SKIP_SRC_ADDR].ptr;
else if (r->src.port_op && !pf_match_port(r->src.port_op,
r->src.port[0], r->src.port[1], th->th_sport))
r = r->skip[PF_SKIP_SRC_PORT].ptr;
else if (PF_MISMATCHAW(&r->dst.addr, pd->dst, af,
- r->dst.neg, NULL))
+ r->dst.neg, NULL, M_GETFIB(m)))
r = r->skip[PF_SKIP_DST_ADDR].ptr;
else if (r->dst.port_op && !pf_match_port(r->dst.port_op,
r->dst.port[0], r->dst.port[1], th->th_dport))
diff --git a/sys/contrib/pf/net/pfvar.h b/sys/contrib/pf/net/pfvar.h
index fe4c0ce..85fef1d 100644
--- a/sys/contrib/pf/net/pfvar.h
+++ b/sys/contrib/pf/net/pfvar.h
@@ -402,14 +402,18 @@ extern struct mtx pf_task_mtx;
#endif /* PF_INET6_ONLY */
#endif /* PF_INET_INET6 */
-#define PF_MISMATCHAW(aw, x, af, neg, ifp) \
+/*
+ * XXX callers not FIB-aware in our version of pf yet.
+ * OpenBSD fixed it later it seems, 2010/05/07 13:33:16 claudio.
+ */
+#define PF_MISMATCHAW(aw, x, af, neg, ifp, rtid) \
( \
(((aw)->type == PF_ADDR_NOROUTE && \
- pf_routable((x), (af), NULL)) || \
+ pf_routable((x), (af), NULL, (rtid))) || \
(((aw)->type == PF_ADDR_URPFFAILED && (ifp) != NULL && \
- pf_routable((x), (af), (ifp))) || \
+ pf_routable((x), (af), (ifp), (rtid))) || \
((aw)->type == PF_ADDR_RTLABEL && \
- !pf_rtlabel_match((x), (af), (aw))) || \
+ !pf_rtlabel_match((x), (af), (aw), (rtid))) || \
((aw)->type == PF_ADDR_TABLE && \
!pfr_match_addr((aw)->p.tbl, (x), (af))) || \
((aw)->type == PF_ADDR_DYNIFTL && \
@@ -1977,8 +1981,10 @@ int pf_normalize_tcp_stateful(struct mbuf *, int, struct pf_pdesc *,
u_int32_t
pf_state_expires(const struct pf_state *);
void pf_purge_expired_fragments(void);
-int pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *);
-int pf_rtlabel_match(struct pf_addr *, sa_family_t, struct pf_addr_wrap *);
+int pf_routable(struct pf_addr *addr, sa_family_t af, struct pfi_kif *,
+ int);
+int pf_rtlabel_match(struct pf_addr *, sa_family_t, struct pf_addr_wrap *,
+ int);
#ifdef __FreeBSD__
int pf_socket_lookup(int, struct pf_pdesc *, struct inpcb *);
#else
diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c
index 53bf8b3..c8c5bf5 100644
--- a/sys/fs/nfsclient/nfs_clport.c
+++ b/sys/fs/nfsclient/nfs_clport.c
@@ -976,7 +976,8 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
sad.sin_len = sizeof (struct sockaddr_in);
sad.sin_addr.s_addr = sin->sin_addr.s_addr;
CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
- rt = rtalloc1((struct sockaddr *)&sad, 0, 0UL);
+ rt = rtalloc1_fib((struct sockaddr *)&sad, 0, 0UL,
+ curthread->td_proc->p_fibnum);
if (rt != NULL) {
if (rt->rt_ifp != NULL &&
rt->rt_ifa != NULL &&
@@ -1001,7 +1002,8 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
sad6.sin6_len = sizeof (struct sockaddr_in6);
sad6.sin6_addr = sin6->sin6_addr;
CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
- rt = rtalloc1((struct sockaddr *)&sad6, 0, 0UL);
+ rt = rtalloc1_fib((struct sockaddr *)&sad6, 0, 0UL,
+ curthread->td_proc->p_fibnum);
if (rt != NULL) {
if (rt->rt_ifp != NULL &&
rt->rt_ifa != NULL &&
diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c
index ce128af..04d8e67 100644
--- a/sys/fs/nfsclient/nfs_clvfsops.c
+++ b/sys/fs/nfsclient/nfs_clvfsops.c
@@ -459,10 +459,10 @@ nfs_mountroot(struct mount *mp)
sin.sin_len = sizeof(sin);
/* XXX MRT use table 0 for this sort of thing */
CURVNET_SET(TD_TO_VNET(td));
- error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
+ error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin,
(struct sockaddr *)&nd->mygateway,
(struct sockaddr *)&mask,
- RTF_UP | RTF_GATEWAY, NULL);
+ RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB);
CURVNET_RESTORE();
if (error)
panic("nfs_mountroot: RTM_ADD: %d", error);
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 63a1ef6..91309de 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -392,6 +392,7 @@ socreate(int dom, struct socket **aso, int type, int proto,
so->so_type = type;
so->so_cred = crhold(cred);
if ((prp->pr_domain->dom_family == PF_INET) ||
+ (prp->pr_domain->dom_family == PF_INET6) ||
(prp->pr_domain->dom_family == PF_ROUTE))
so->so_fibnum = td->td_proc->p_fibnum;
else
@@ -2504,6 +2505,7 @@ sosetopt(struct socket *so, struct sockopt *sopt)
}
if (so->so_proto != NULL &&
((so->so_proto->pr_domain->dom_family == PF_INET) ||
+ (so->so_proto->pr_domain->dom_family == PF_INET6) ||
(so->so_proto->pr_domain->dom_family == PF_ROUTE))) {
so->so_fibnum = optval;
/* Note: ignore error */
diff --git a/sys/net/flowtable.c b/sys/net/flowtable.c
index fac0f59..8501b18 100644
--- a/sys/net/flowtable.c
+++ b/sys/net/flowtable.c
@@ -374,7 +374,7 @@ SYSCTL_VNET_PROC(_net_inet_flowtable, OID_AUTO, stats, CTLTYPE_STRING|CTLFLAG_RD
#ifndef RADIX_MPATH
static void
-in_rtalloc_ign_wrapper(struct route *ro, uint32_t hash, u_int fibnum)
+rtalloc_ign_wrapper(struct route *ro, uint32_t hash, u_int fibnum)
{
rtalloc_ign_fib(ro, 0, fibnum);
@@ -1315,7 +1315,7 @@ flowtable_alloc(char *name, int nentry, int flags)
#ifdef RADIX_MPATH
ft->ft_rtalloc = rtalloc_mpath_fib;
#else
- ft->ft_rtalloc = in_rtalloc_ign_wrapper;
+ ft->ft_rtalloc = rtalloc_ign_wrapper;
#endif
if (flags & FL_PCPU) {
ft->ft_lock = flowtable_pcpu_lock;
diff --git a/sys/net/if_faith.c b/sys/net/if_faith.c
index ca80883..db4c1d9 100644
--- a/sys/net/if_faith.c
+++ b/sys/net/if_faith.c
@@ -338,7 +338,7 @@ faithprefix(in6)
sin6.sin6_family = AF_INET6;
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_addr = *in6;
- rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
+ rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, RT_DEFAULT_FIB);
if (rt && rt->rt_ifp && rt->rt_ifp->if_type == IFT_FAITH &&
(rt->rt_ifp->if_flags & IFF_UP) != 0)
ret = 1;
diff --git a/sys/net/route.c b/sys/net/route.c
index 296914b..c48a4ac 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -35,6 +35,7 @@
***********************************************************************/
#include "opt_inet.h"
+#include "opt_inet6.h"
#include "opt_route.h"
#include "opt_mrouting.h"
#include "opt_mpath.h"
@@ -72,7 +73,11 @@ SYSCTL_UINT(_net, OID_AUTO, fibs, CTLFLAG_RD, &rt_numfibs, 0, "");
/*
* Allow the boot code to allow LESS than RT_MAXFIBS to be used.
* We can't do more because storage is statically allocated for now.
- * (for compatibility reasons.. this will change).
+ * (for compatibility reasons.. this will change. When this changes, code should
+ * be refactored to protocol independent parts and protocol dependent parts,
+ * probably hanging of domain(9) specific storage to not need the full
+ * fib * af RNH allocation etc. but allow tuning the number of tables per
+ * address family).
*/
TUNABLE_INT("net.fibs", &rt_numfibs);
@@ -82,6 +87,9 @@ TUNABLE_INT("net.fibs", &rt_numfibs);
* changes for the FIB of the caller when adding a new set of addresses
* to an interface. XXX this is a shotgun aproach to a problem that needs
* a more fine grained solution.. that will come.
+ * XXX also has the problems getting the FIB from curthread which will not
+ * always work given the fib can be overridden and prefixes can be added
+ * from the network stack context.
*/
u_int rt_add_addr_allfibs = 1;
SYSCTL_UINT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RW,
@@ -196,27 +204,23 @@ vnet_route_init(const void *unused __unused)
V_rtzone = uma_zcreate("rtentry", sizeof(struct rtentry), NULL, NULL,
NULL, NULL, UMA_ALIGN_PTR, 0);
for (dom = domains; dom; dom = dom->dom_next) {
- if (dom->dom_rtattach) {
- for (table = 0; table < rt_numfibs; table++) {
- if ( (fam = dom->dom_family) == AF_INET ||
- table == 0) {
- /* for now only AF_INET has > 1 table */
- /* XXX MRT
- * rtattach will be also called
- * from vfs_export.c but the
- * offset will be 0
- * (only for AF_INET and AF_INET6
- * which don't need it anyhow)
- */
- rnh = rt_tables_get_rnh_ptr(table, fam);
- if (rnh == NULL)
- panic("%s: rnh NULL", __func__);
- dom->dom_rtattach((void **)rnh,
- dom->dom_rtoffset);
- } else {
- break;
- }
- }
+ if (dom->dom_rtattach == NULL)
+ continue;
+
+ for (table = 0; table < rt_numfibs; table++) {
+ fam = dom->dom_family;
+ if (table != 0 && fam != AF_INET6 && fam != AF_INET)
+ break;
+
+ /*
+ * XXX MRT rtattach will be also called from
+ * vfs_export.c but the offset will be 0 (only for
+ * AF_INET and AF_INET6 which don't need it anyhow).
+ */
+ rnh = rt_tables_get_rnh_ptr(table, fam);
+ if (rnh == NULL)
+ panic("%s: rnh NULL", __func__);
+ dom->dom_rtattach((void **)rnh, dom->dom_rtoffset);
}
}
}
@@ -233,20 +237,19 @@ vnet_route_uninit(const void *unused __unused)
struct radix_node_head **rnh;
for (dom = domains; dom; dom = dom->dom_next) {
- if (dom->dom_rtdetach) {
- for (table = 0; table < rt_numfibs; table++) {
- if ( (fam = dom->dom_family) == AF_INET ||
- table == 0) {
- /* For now only AF_INET has > 1 tbl. */
- rnh = rt_tables_get_rnh_ptr(table, fam);
- if (rnh == NULL)
- panic("%s: rnh NULL", __func__);
- dom->dom_rtdetach((void **)rnh,
- dom->dom_rtoffset);
- } else {
- break;
- }
- }
+ if (dom->dom_rtdetach == NULL)
+ continue;
+
+ for (table = 0; table < rt_numfibs; table++) {
+ fam = dom->dom_family;
+
+ if (table != 0 && fam != AF_INET6 && fam != AF_INET)
+ break;
+
+ rnh = rt_tables_get_rnh_ptr(table, fam);
+ if (rnh == NULL)
+ panic("%s: rnh NULL", __func__);
+ dom->dom_rtdetach((void **)rnh, dom->dom_rtoffset);
}
}
}
@@ -274,7 +277,8 @@ sys_setfib(struct thread *td, struct setfib_args *uap)
void
rtalloc(struct route *ro)
{
- rtalloc_ign_fib(ro, 0UL, 0);
+
+ rtalloc_ign_fib(ro, 0UL, RT_DEFAULT_FIB);
}
void
@@ -294,7 +298,7 @@ rtalloc_ign(struct route *ro, u_long ignore)
RTFREE(rt);
ro->ro_rt = NULL;
}
- ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, ignore, 0);
+ ro->ro_rt = rtalloc1_fib(&ro->ro_dst, 1, ignore, RT_DEFAULT_FIB);
if (ro->ro_rt)
RT_UNLOCK(ro->ro_rt);
}
@@ -324,7 +328,8 @@ rtalloc_ign_fib(struct route *ro, u_long ignore, u_int fibnum)
struct rtentry *
rtalloc1(struct sockaddr *dst, int report, u_long ignflags)
{
- return (rtalloc1_fib(dst, report, ignflags, 0));
+
+ return (rtalloc1_fib(dst, report, ignflags, RT_DEFAULT_FIB));
}
struct rtentry *
@@ -339,8 +344,15 @@ rtalloc1_fib(struct sockaddr *dst, int report, u_long ignflags,
int needlock;
KASSERT((fibnum < rt_numfibs), ("rtalloc1_fib: bad fibnum"));
- if (dst->sa_family != AF_INET) /* Only INET supports > 1 fib now */
- fibnum = 0;
+ switch (dst->sa_family) {
+ case AF_INET6:
+ case AF_INET:
+ /* We support multiple FIBs. */
+ break;
+ default:
+ fibnum = RT_DEFAULT_FIB;
+ break;
+ }
rnh = rt_tables_get_rnh(fibnum, dst->sa_family);
newrt = NULL;
if (rnh == NULL)
@@ -486,7 +498,8 @@ rtredirect(struct sockaddr *dst,
int flags,
struct sockaddr *src)
{
- rtredirect_fib(dst, gateway, netmask, flags, src, 0);
+
+ rtredirect_fib(dst, gateway, netmask, flags, src, RT_DEFAULT_FIB);
}
void
@@ -617,7 +630,8 @@ out:
int
rtioctl(u_long req, caddr_t data)
{
- return (rtioctl_fib(req, data, 0));
+
+ return (rtioctl_fib(req, data, RT_DEFAULT_FIB));
}
/*
@@ -647,7 +661,8 @@ rtioctl_fib(u_long req, caddr_t data, u_int fibnum)
struct ifaddr *
ifa_ifwithroute(int flags, struct sockaddr *dst, struct sockaddr *gateway)
{
- return (ifa_ifwithroute_fib(flags, dst, gateway, 0));
+
+ return (ifa_ifwithroute_fib(flags, dst, gateway, RT_DEFAULT_FIB));
}
struct ifaddr *
@@ -732,7 +747,9 @@ rtrequest(int req,
int flags,
struct rtentry **ret_nrt)
{
- return (rtrequest_fib(req, dst, gateway, netmask, flags, ret_nrt, 0));
+
+ return (rtrequest_fib(req, dst, gateway, netmask, flags, ret_nrt,
+ RT_DEFAULT_FIB));
}
int
@@ -771,7 +788,8 @@ rtrequest_fib(int req,
int
rt_getifa(struct rt_addrinfo *info)
{
- return (rt_getifa_fib(info, 0));
+
+ return (rt_getifa_fib(info, RT_DEFAULT_FIB));
}
/*
@@ -1029,8 +1047,16 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
#define senderr(x) { error = x ; goto bad; }
KASSERT((fibnum < rt_numfibs), ("rtrequest1_fib: bad fibnum"));
- if (dst->sa_family != AF_INET) /* Only INET supports > 1 fib now */
- fibnum = 0;
+ switch (dst->sa_family) {
+ case AF_INET6:
+ case AF_INET:
+ /* We support multiple FIBs. */
+ break;
+ default:
+ fibnum = RT_DEFAULT_FIB;
+ break;
+ }
+
/*
* Find the correct routing tree to use for this Address Family
*/
@@ -1135,8 +1161,7 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
rt->rt_flags = RTF_UP | flags;
rt->rt_fibnum = fibnum;
/*
- * Add the gateway. Possibly re-malloc-ing the storage for it
- *
+ * Add the gateway. Possibly re-malloc-ing the storage for it.
*/
RT_LOCK(rt);
if ((error = rt_setgate(rt, dst, gateway)) != 0) {
@@ -1182,12 +1207,15 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
#ifdef FLOWTABLE
rt0 = NULL;
- /* XXX
- * "flow-table" only support IPv4 at the moment.
- * XXX-BZ as of r205066 it would support IPv6.
- */
+ /* "flow-table" only supports IPv6 and IPv4 at the moment. */
+ switch (dst->sa_family) {
+#ifdef INET6
+ case AF_INET6:
+#endif
#ifdef INET
- if (dst->sa_family == AF_INET) {
+ case AF_INET:
+#endif
+#if defined(INET6) || defined(INET)
rn = rnh->rnh_matchaddr(dst, rnh);
if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) {
struct sockaddr *mask;
@@ -1226,9 +1254,9 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
}
}
}
+#endif/* INET6 || INET */
}
-#endif
-#endif
+#endif /* FLOWTABLE */
/* XXX mtu manipulation will be done in rnh_addaddr -- itojun */
rn = rnh->rnh_addaddr(ndst, netmask, rnh, rt->rt_nodes);
@@ -1249,9 +1277,18 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
}
#ifdef FLOWTABLE
else if (rt0 != NULL) {
+ switch (dst->sa_family) {
+#ifdef INET6
+ case AF_INET6:
+ flowtable_route_flush(V_ip6_ft, rt0);
+ break;
+#endif
#ifdef INET
- flowtable_route_flush(V_ip_ft, rt0);
+ case AF_INET:
+ flowtable_route_flush(V_ip_ft, rt0);
+ break;
#endif
+ }
RTFREE(rt0);
}
#endif
@@ -1383,8 +1420,17 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum)
dst = ifa->ifa_addr;
netmask = ifa->ifa_netmask;
}
- if ( dst->sa_family != AF_INET)
- fibnum = 0;
+ if (dst->sa_len == 0)
+ return(EINVAL);
+ switch (dst->sa_family) {
+ case AF_INET6:
+ case AF_INET:
+ /* We support multiple FIBs. */
+ break;
+ default:
+ fibnum = RT_DEFAULT_FIB;
+ break;
+ }
if (fibnum == -1) {
if (rt_add_addr_allfibs == 0 && cmd == (int)RTM_ADD) {
startfib = endfib = curthread->td_proc->p_fibnum;
@@ -1397,8 +1443,6 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum)
startfib = fibnum;
endfib = fibnum;
}
- if (dst->sa_len == 0)
- return(EINVAL);
/*
* If it's a delete, check that if it exists,
@@ -1422,9 +1466,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum)
* Now go through all the requested tables (fibs) and do the
* requested action. Realistically, this will either be fib 0
* for protocols that don't do multiple tables or all the
- * tables for those that do. XXX For this version only AF_INET.
- * When that changes code should be refactored to protocol
- * independent parts and protocol dependent parts.
+ * tables for those that do.
*/
for ( fibnum = startfib; fibnum <= endfib; fibnum++) {
if (cmd == RTM_DELETE) {
@@ -1564,12 +1606,14 @@ rtinit1(struct ifaddr *ifa, int cmd, int flags, int fibnum)
return (error);
}
+#ifndef BURN_BRIDGES
/* special one for inet internal use. may not use. */
int
rtinit_fib(struct ifaddr *ifa, int cmd, int flags)
{
return (rtinit1(ifa, cmd, flags, -1));
}
+#endif
/*
* Set up a routing table entry, normally
@@ -1579,7 +1623,7 @@ int
rtinit(struct ifaddr *ifa, int cmd, int flags)
{
struct sockaddr *dst;
- int fib = 0;
+ int fib = RT_DEFAULT_FIB;
if (flags & RTF_HOST) {
dst = ifa->ifa_dstaddr;
@@ -1587,7 +1631,12 @@ rtinit(struct ifaddr *ifa, int cmd, int flags)
dst = ifa->ifa_addr;
}
- if (dst->sa_family == AF_INET)
+ switch (dst->sa_family) {
+ case AF_INET6:
+ case AF_INET:
+ /* We do support multiple FIBs. */
fib = -1;
+ break;
+ }
return (rtinit1(ifa, cmd, flags, fib));
}
diff --git a/sys/net/route.h b/sys/net/route.h
index 7e045b7..a400deb 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -111,6 +111,7 @@ struct rt_metrics {
#endif
#endif
+#define RT_DEFAULT_FIB 0 /* Explicitly mark fib=0 restricted cases */
extern u_int rt_numfibs; /* number fo usable routing tables */
/*
* XXX kernel function pointer `rt_output' is visible to applications.
@@ -405,8 +406,10 @@ void rtredirect(struct sockaddr *, struct sockaddr *,
int rtrequest(int, struct sockaddr *,
struct sockaddr *, struct sockaddr *, int, struct rtentry **);
+#ifndef BURN_BRIDGES
/* defaults to "all" FIBs */
int rtinit_fib(struct ifaddr *, int, int);
+#endif
/* XXX MRT NEW VERSIONS THAT USE FIBs
* For now the protocol indepedent versions are the same as the AF_INET ones
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index ee9259c..58cd062 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -879,7 +879,7 @@ in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
bzero(&ia_ro, sizeof(ia_ro));
*((struct sockaddr_in *)(&ia_ro.ro_dst)) = ia->ia_addr;
- rtalloc_ign_fib(&ia_ro, 0, 0);
+ rtalloc_ign_fib(&ia_ro, 0, RT_DEFAULT_FIB);
if ((ia_ro.ro_rt != NULL) && (ia_ro.ro_rt->rt_ifp != NULL) &&
(ia_ro.ro_rt->rt_ifp == V_loif)) {
RT_LOCK(ia_ro.ro_rt);
diff --git a/sys/netinet/ipfw/ip_fw2.c b/sys/netinet/ipfw/ip_fw2.c
index 82ffb98..cbb4ed7 100644
--- a/sys/netinet/ipfw/ip_fw2.c
+++ b/sys/netinet/ipfw/ip_fw2.c
@@ -496,7 +496,7 @@ search_ip6_addr_net (struct in6_addr * ip6_addr)
}
static int
-verify_path6(struct in6_addr *src, struct ifnet *ifp)
+verify_path6(struct in6_addr *src, struct ifnet *ifp, u_int fib)
{
struct route_in6 ro;
struct sockaddr_in6 *dst;
@@ -507,9 +507,8 @@ verify_path6(struct in6_addr *src, struct ifnet *ifp)
dst->sin6_family = AF_INET6;
dst->sin6_len = sizeof(*dst);
dst->sin6_addr = *src;
- /* XXX MRT 0 for ipv6 at this time */
- rtalloc_ign((struct route *)&ro, 0);
+ in6_rtalloc_ign(&ro, 0, fib);
if (ro.ro_rt == NULL)
return 0;
@@ -1715,7 +1714,7 @@ do { \
#ifdef INET6
is_ipv6 ?
verify_path6(&(args->f_id.src_ip6),
- m->m_pkthdr.rcvif) :
+ m->m_pkthdr.rcvif, args->f_id.fib) :
#endif
verify_path(src_ip, m->m_pkthdr.rcvif,
args->f_id.fib)));
@@ -1727,7 +1726,7 @@ do { \
#ifdef INET6
is_ipv6 ?
verify_path6(&(args->f_id.src_ip6),
- NULL) :
+ NULL, args->f_id.fib) :
#endif
verify_path(src_ip, NULL, args->f_id.fib)));
break;
@@ -1745,7 +1744,8 @@ do { \
#ifdef INET6
is_ipv6 ? verify_path6(
&(args->f_id.src_ip6),
- m->m_pkthdr.rcvif) :
+ m->m_pkthdr.rcvif,
+ args->f_id.fib) :
#endif
verify_path(src_ip,
m->m_pkthdr.rcvif,
diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h
index 4e0dcab..215b93d 100644
--- a/sys/netinet/sctp_os_bsd.h
+++ b/sys/netinet/sctp_os_bsd.h
@@ -424,6 +424,12 @@ typedef struct callout sctp_os_timer_t;
typedef struct route sctp_route_t;
typedef struct rtentry sctp_rtentry_t;
+/*
+ * XXX multi-FIB support was backed out in r179783 and it seems clear that the
+ * VRF support as currently in FreeBSD is not ready to support multi-FIB.
+ * It might be best to implement multi-FIB support for both v4 and v6 indepedent
+ * of VRFs and leave those to a real MPLS stack.
+ */
#define SCTP_RTALLOC(ro, vrf_id) rtalloc_ign((struct route *)ro, 0UL)
/* Future zero copy wakeup/send function */
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index 46b4022..1270f1a 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -1750,7 +1750,7 @@ tcp_maxmtu6(struct in_conninfo *inc, int *flags)
sro6.ro_dst.sin6_family = AF_INET6;
sro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
sro6.ro_dst.sin6_addr = inc->inc6_faddr;
- rtalloc_ign((struct route *)&sro6, 0);
+ in6_rtalloc_ign(&sro6, 0, inc->inc_fibnum);
}
if (sro6.ro_rt != NULL) {
ifp = sro6.ro_rt->rt_ifp;
diff --git a/sys/netinet6/icmp6.c b/sys/netinet6/icmp6.c
index 7d7467a..967d01a 100644
--- a/sys/netinet6/icmp6.c
+++ b/sys/netinet6/icmp6.c
@@ -360,7 +360,7 @@ icmp6_error(struct mbuf *m, int type, int code, int param)
m_adj(m, ICMPV6_PLD_MAXLEN - m->m_pkthdr.len);
preplen = sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr);
- M_PREPEND(m, preplen, M_DONTWAIT);
+ M_PREPEND(m, preplen, M_DONTWAIT); /* FIB is also copied over. */
if (m && m->m_len < preplen)
m = m_pullup(m, preplen);
if (m == NULL) {
@@ -584,7 +584,7 @@ icmp6_input(struct mbuf **mp, int *offp, int proto)
MGETHDR(n, M_DONTWAIT, n0->m_type);
n0len = n0->m_pkthdr.len; /* save for use below */
if (n)
- M_MOVE_PKTHDR(n, n0);
+ M_MOVE_PKTHDR(n, n0); /* FIB copied. */
if (n && maxlen >= MHLEN) {
MCLGET(n, M_DONTWAIT);
if ((n->m_flags & M_EXT) == 0) {
@@ -1502,7 +1502,7 @@ ni6_input(struct mbuf *m, int off)
m_freem(m);
return (NULL);
}
- M_MOVE_PKTHDR(n, m); /* just for recvif */
+ M_MOVE_PKTHDR(n, m); /* just for recvif and FIB */
if (replylen > MHLEN) {
if (replylen > MCLBYTES) {
/*
@@ -2414,7 +2414,7 @@ icmp6_redirect_input(struct mbuf *m, int off)
sin6.sin6_family = AF_INET6;
sin6.sin6_len = sizeof(struct sockaddr_in6);
bcopy(&reddst6, &sin6.sin6_addr, sizeof(reddst6));
- rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
+ rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL, RT_DEFAULT_FIB);
if (rt) {
if (rt->rt_gateway == NULL ||
rt->rt_gateway->sa_family != AF_INET6) {
@@ -2501,6 +2501,7 @@ icmp6_redirect_input(struct mbuf *m, int off)
struct sockaddr_in6 sdst;
struct sockaddr_in6 sgw;
struct sockaddr_in6 ssrc;
+ u_int fibnum;
bzero(&sdst, sizeof(sdst));
bzero(&sgw, sizeof(sgw));
@@ -2511,9 +2512,11 @@ icmp6_redirect_input(struct mbuf *m, int off)
bcopy(&redtgt6, &sgw.sin6_addr, sizeof(struct in6_addr));
bcopy(&reddst6, &sdst.sin6_addr, sizeof(struct in6_addr));
bcopy(&src6, &ssrc.sin6_addr, sizeof(struct in6_addr));
- rtredirect((struct sockaddr *)&sdst, (struct sockaddr *)&sgw,
- (struct sockaddr *)NULL, RTF_GATEWAY | RTF_HOST,
- (struct sockaddr *)&ssrc);
+ for (fibnum = 0; fibnum < rt_numfibs; fibnum++)
+ in6_rtredirect((struct sockaddr *)&sdst,
+ (struct sockaddr *)&sgw, (struct sockaddr *)NULL,
+ RTF_GATEWAY | RTF_HOST, (struct sockaddr *)&ssrc,
+ fibnum);
}
/* finally update cached route in each socket via pfctlinput */
{
@@ -2598,6 +2601,7 @@ icmp6_redirect_output(struct mbuf *m0, struct rtentry *rt)
MCLGET(m, M_DONTWAIT);
if (!m)
goto fail;
+ M_SETFIB(m, rt->rt_fibnum);
m->m_pkthdr.rcvif = NULL;
m->m_len = 0;
maxlen = M_TRAILINGSPACE(m);
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index cf5eb35..0b22a1c 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -180,6 +180,7 @@ in6_ifaddloop(struct ifaddr *ifa)
rt_mask(&rt) = (struct sockaddr *)&mask;
rt_key(&rt) = (struct sockaddr *)&addr;
rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC;
+ /* Announce arrival of local address to all FIBs. */
rt_newaddrmsg(RTM_ADD, ifa, 0, &rt);
}
@@ -214,6 +215,7 @@ in6_ifremloop(struct ifaddr *ifa)
rt_mask(&rt0) = (struct sockaddr *)&mask;
rt_key(&rt0) = (struct sockaddr *)&addr;
rt0.rt_flags = RTF_HOST | RTF_STATIC;
+ /* Announce removal of local address to all FIBs. */
rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0);
}
@@ -282,6 +284,11 @@ in6_control(struct socket *so, u_long cmd, caddr_t data,
switch (cmd) {
case SIOCGETSGCNT_IN6:
case SIOCGETMIFCNT_IN6:
+ /*
+ * XXX mrt_ioctl has a 3rd, unused, FIB argument in route.c.
+ * We cannot see how that would be needed, so do not adjust the
+ * KPI blindly; more likely should clean up the IPv4 variant.
+ */
return (mrt6_ioctl ? mrt6_ioctl(cmd, data) : EOPNOTSUPP);
}
@@ -820,6 +827,170 @@ out:
return (error);
}
+
+/*
+ * Join necessary multicast groups. Factored out from in6_update_ifa().
+ * This entire work should only be done once, for the default FIB.
+ */
+static int
+in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra,
+ struct in6_ifaddr *ia, int flags, struct in6_multi **in6m_sol)
+{
+ char ip6buf[INET6_ADDRSTRLEN];
+ struct sockaddr_in6 mltaddr, mltmask;
+ struct in6_addr llsol;
+ struct in6_multi_mship *imm;
+ struct rtentry *rt;
+ int delay, error;
+
+ KASSERT(in6m_sol != NULL, ("%s: in6m_sol is NULL", __func__));
+
+ /* Join solicited multicast addr for new host id. */
+ bzero(&llsol, sizeof(struct in6_addr));
+ llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
+ llsol.s6_addr32[1] = 0;
+ llsol.s6_addr32[2] = htonl(1);
+ llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
+ llsol.s6_addr8[12] = 0xff;
+ if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
+ /* XXX: should not happen */
+ log(LOG_ERR, "%s: in6_setscope failed\n", __func__);
+ goto cleanup;
+ }
+ delay = 0;
+ if ((flags & IN6_IFAUPDATE_DADDELAY)) {
+ /*
+ * We need a random delay for DAD on the address being
+ * configured. It also means delaying transmission of the
+ * corresponding MLD report to avoid report collision.
+ * [RFC 4861, Section 6.3.7]
+ */
+ delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
+ }
+ imm = in6_joingroup(ifp, &llsol, &error, delay);
+ if (imm == NULL) {
+ nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+ "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &llsol),
+ if_name(ifp), error));
+ goto cleanup;
+ }
+ LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+ *in6m_sol = imm->i6mm_maddr;
+
+ bzero(&mltmask, sizeof(mltmask));
+ mltmask.sin6_len = sizeof(struct sockaddr_in6);
+ mltmask.sin6_family = AF_INET6;
+ mltmask.sin6_addr = in6mask32;
+#define MLTMASK_LEN 4 /* mltmask's masklen (=32bit=4octet) */
+
+ /*
+ * Join link-local all-nodes address.
+ */
+ bzero(&mltaddr, sizeof(mltaddr));
+ mltaddr.sin6_len = sizeof(struct sockaddr_in6);
+ mltaddr.sin6_family = AF_INET6;
+ mltaddr.sin6_addr = in6addr_linklocal_allnodes;
+ if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
+ goto cleanup; /* XXX: should not fail */
+
+ /*
+ * XXX: do we really need this automatic routes? We should probably
+ * reconsider this stuff. Most applications actually do not need the
+ * routes, since they usually specify the outgoing interface.
+ */
+ rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
+ if (rt != NULL) {
+ /* XXX: only works in !SCOPEDROUTING case. */
+ if (memcmp(&mltaddr.sin6_addr,
+ &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
+ MLTMASK_LEN)) {
+ RTFREE_LOCKED(rt);
+ rt = NULL;
+ }
+ }
+ if (rt == NULL) {
+ error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
+ (struct sockaddr *)&ia->ia_addr,
+ (struct sockaddr *)&mltmask, RTF_UP,
+ (struct rtentry **)0, RT_DEFAULT_FIB);
+ if (error)
+ goto cleanup;
+ } else
+ RTFREE_LOCKED(rt);
+
+ imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
+ if (imm == NULL) {
+ nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+ "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
+ &mltaddr.sin6_addr), if_name(ifp), error));
+ goto cleanup;
+ }
+ LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+
+ /*
+ * Join node information group address.
+ */
+ delay = 0;
+ if ((flags & IN6_IFAUPDATE_DADDELAY)) {
+ /*
+ * The spec does not say anything about delay for this group,
+ * but the same logic should apply.
+ */
+ delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz);
+ }
+ if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
+ /* XXX jinmei */
+ imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay);
+ if (imm == NULL)
+ nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+ "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
+ &mltaddr.sin6_addr), if_name(ifp), error));
+ /* XXX not very fatal, go on... */
+ else
+ LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+ }
+
+ /*
+ * Join interface-local all-nodes address.
+ * (ff01::1%ifN, and ff01::%ifN/32)
+ */
+ mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
+ if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
+ goto cleanup; /* XXX: should not fail */
+ /* XXX: again, do we really need the route? */
+ rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
+ if (rt != NULL) {
+ if (memcmp(&mltaddr.sin6_addr,
+ &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
+ MLTMASK_LEN)) {
+ RTFREE_LOCKED(rt);
+ rt = NULL;
+ }
+ }
+ if (rt == NULL) {
+ error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
+ (struct sockaddr *)&ia->ia_addr,
+ (struct sockaddr *)&mltmask, RTF_UP,
+ (struct rtentry **)0, RT_DEFAULT_FIB);
+ if (error)
+ goto cleanup;
+ } else
+ RTFREE_LOCKED(rt);
+
+ imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
+ if (imm == NULL) {
+ nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s "
+ "(errno=%d)\n", __func__, ip6_sprintf(ip6buf,
+ &mltaddr.sin6_addr), if_name(ifp), error));
+ goto cleanup;
+ }
+ LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
+#undef MLTMASK_LEN
+
+cleanup:
+ return (error);
+}
+
/*
* Update parameters of an IPv6 interface address.
* If necessary, a new entry is created and linked into address chains.
@@ -833,9 +1004,7 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
int error = 0, hostIsNew = 0, plen = -1;
struct sockaddr_in6 dst6;
struct in6_addrlifetime *lt;
- struct in6_multi_mship *imm;
struct in6_multi *in6m_sol;
- struct rtentry *rt;
int delay;
char ip6buf[INET6_ADDRSTRLEN];
@@ -1083,178 +1252,17 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
* not just go to unlink.
*/
- /* Join necessary multicast groups */
+ /* Join necessary multicast groups. */
in6m_sol = NULL;
if ((ifp->if_flags & IFF_MULTICAST) != 0) {
- struct sockaddr_in6 mltaddr, mltmask;
- struct in6_addr llsol;
-
- /* join solicited multicast addr for new host id */
- bzero(&llsol, sizeof(struct in6_addr));
- llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL;
- llsol.s6_addr32[1] = 0;
- llsol.s6_addr32[2] = htonl(1);
- llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3];
- llsol.s6_addr8[12] = 0xff;
- if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) {
- /* XXX: should not happen */
- log(LOG_ERR, "in6_update_ifa: "
- "in6_setscope failed\n");
- goto cleanup;
- }
- delay = 0;
- if ((flags & IN6_IFAUPDATE_DADDELAY)) {
- /*
- * We need a random delay for DAD on the address
- * being configured. It also means delaying
- * transmission of the corresponding MLD report to
- * avoid report collision.
- * [RFC 4861, Section 6.3.7]
- */
- delay = arc4random() %
- (MAX_RTR_SOLICITATION_DELAY * hz);
- }
- imm = in6_joingroup(ifp, &llsol, &error, delay);
- if (imm == NULL) {
- nd6log((LOG_WARNING,
- "in6_update_ifa: addmulti failed for "
- "%s on %s (errno=%d)\n",
- ip6_sprintf(ip6buf, &llsol), if_name(ifp),
- error));
+ error = in6_update_ifa_join_mc(ifp, ifra, ia, flags, &in6m_sol);
+ if (error)
goto cleanup;
- }
- LIST_INSERT_HEAD(&ia->ia6_memberships,
- imm, i6mm_chain);
- in6m_sol = imm->i6mm_maddr;
-
- bzero(&mltmask, sizeof(mltmask));
- mltmask.sin6_len = sizeof(struct sockaddr_in6);
- mltmask.sin6_family = AF_INET6;
- mltmask.sin6_addr = in6mask32;
-#define MLTMASK_LEN 4 /* mltmask's masklen (=32bit=4octet) */
-
- /*
- * join link-local all-nodes address
- */
- bzero(&mltaddr, sizeof(mltaddr));
- mltaddr.sin6_len = sizeof(struct sockaddr_in6);
- mltaddr.sin6_family = AF_INET6;
- mltaddr.sin6_addr = in6addr_linklocal_allnodes;
- if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) !=
- 0)
- goto cleanup; /* XXX: should not fail */
-
- /*
- * XXX: do we really need this automatic routes?
- * We should probably reconsider this stuff. Most applications
- * actually do not need the routes, since they usually specify
- * the outgoing interface.
- */
- rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
- if (rt) {
- /* XXX: only works in !SCOPEDROUTING case. */
- if (memcmp(&mltaddr.sin6_addr,
- &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
- MLTMASK_LEN)) {
- RTFREE_LOCKED(rt);
- rt = NULL;
- }
- }
- if (!rt) {
- error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&mltmask, RTF_UP,
- (struct rtentry **)0);
- if (error)
- goto cleanup;
- } else {
- RTFREE_LOCKED(rt);
- }
-
- imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
- if (!imm) {
- nd6log((LOG_WARNING,
- "in6_update_ifa: addmulti failed for "
- "%s on %s (errno=%d)\n",
- ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
- if_name(ifp), error));
- goto cleanup;
- }
- LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
-
- /*
- * join node information group address
- */
- delay = 0;
- if ((flags & IN6_IFAUPDATE_DADDELAY)) {
- /*
- * The spec doesn't say anything about delay for this
- * group, but the same logic should apply.
- */
- delay = arc4random() %
- (MAX_RTR_SOLICITATION_DELAY * hz);
- }
- if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) {
- imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error,
- delay); /* XXX jinmei */
- if (!imm) {
- nd6log((LOG_WARNING, "in6_update_ifa: "
- "addmulti failed for %s on %s "
- "(errno=%d)\n",
- ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
- if_name(ifp), error));
- /* XXX not very fatal, go on... */
- } else {
- LIST_INSERT_HEAD(&ia->ia6_memberships,
- imm, i6mm_chain);
- }
- }
-
- /*
- * join interface-local all-nodes address.
- * (ff01::1%ifN, and ff01::%ifN/32)
- */
- mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
- if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL))
- != 0)
- goto cleanup; /* XXX: should not fail */
- /* XXX: again, do we really need the route? */
- rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
- if (rt) {
- if (memcmp(&mltaddr.sin6_addr,
- &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr,
- MLTMASK_LEN)) {
- RTFREE_LOCKED(rt);
- rt = NULL;
- }
- }
- if (!rt) {
- error = rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&mltmask, RTF_UP,
- (struct rtentry **)0);
- if (error)
- goto cleanup;
- } else
- RTFREE_LOCKED(rt);
-
- imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0);
- if (!imm) {
- nd6log((LOG_WARNING, "in6_update_ifa: "
- "addmulti failed for %s on %s "
- "(errno=%d)\n",
- ip6_sprintf(ip6buf, &mltaddr.sin6_addr),
- if_name(ifp), error));
- goto cleanup;
- }
- LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain);
-#undef MLTMASK_LEN
}
/*
* Perform DAD, if needed.
- * XXX It may be of use, if we can administratively
- * disable DAD.
+ * XXX It may be of use, if we can administratively disable DAD.
*/
if (in6if_do_dad(ifp) && ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) &&
(ia->ia6_flags & IN6_IFF_TENTATIVE))
@@ -1312,58 +1320,20 @@ in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra,
return error;
}
-void
-in6_purgeaddr(struct ifaddr *ifa)
+/*
+ * Leave multicast groups. Factored out from in6_purgeaddr().
+ * This entire work should only be done once, for the default FIB.
+ */
+static int
+in6_purgeaddr_mc(struct ifnet *ifp, struct in6_ifaddr *ia, struct ifaddr *ifa0)
{
- struct ifnet *ifp = ifa->ifa_ifp;
- struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
- struct in6_multi_mship *imm;
struct sockaddr_in6 mltaddr, mltmask;
- int plen, error;
+ struct in6_multi_mship *imm;
struct rtentry *rt;
- struct ifaddr *ifa0;
-
- if (ifa->ifa_carp)
- (*carp_detach_p)(ifa);
-
- /*
- * find another IPv6 address as the gateway for the
- * link-local and node-local all-nodes multicast
- * address routes
- */
- IF_ADDR_RLOCK(ifp);
- TAILQ_FOREACH(ifa0, &ifp->if_addrhead, ifa_link) {
- if ((ifa0->ifa_addr->sa_family != AF_INET6) ||
- memcmp(&satosin6(ifa0->ifa_addr)->sin6_addr,
- &ia->ia_addr.sin6_addr,
- sizeof(struct in6_addr)) == 0)
- continue;
- else
- break;
- }
- if (ifa0 != NULL)
- ifa_ref(ifa0);
- IF_ADDR_RUNLOCK(ifp);
-
- /*
- * Remove the loopback route to the interface address.
- * The check for the current setting of "nd6_useloopback"
- * is not needed.
- */
- if (ia->ia_flags & IFA_RTSELF) {
- error = ifa_del_loopback_route((struct ifaddr *)ia,
- (struct sockaddr *)&ia->ia_addr);
- if (error == 0)
- ia->ia_flags &= ~IFA_RTSELF;
- }
-
- /* stop DAD processing */
- nd6_dad_stop(ifa);
-
- in6_ifremloop(ifa);
+ int error;
/*
- * leave from multicast groups we have joined for the interface
+ * Leave from multicast groups we have joined for the interface.
*/
while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) {
LIST_REMOVE(imm, i6mm_chain);
@@ -1371,7 +1341,7 @@ in6_purgeaddr(struct ifaddr *ifa)
}
/*
- * remove the link-local all-nodes address
+ * Remove the link-local all-nodes address.
*/
bzero(&mltmask, sizeof(mltmask));
mltmask.sin6_len = sizeof(struct sockaddr_in6);
@@ -1384,31 +1354,33 @@ in6_purgeaddr(struct ifaddr *ifa)
mltaddr.sin6_addr = in6addr_linklocal_allnodes;
if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
- goto cleanup;
+ return (error);
- rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
+ rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
if (rt != NULL && rt->rt_gateway != NULL &&
(memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
&ia->ia_addr.sin6_addr,
sizeof(ia->ia_addr.sin6_addr)) == 0)) {
/*
- * if no more IPv6 address exists on this interface
- * then remove the multicast address route
+ * If no more IPv6 address exists on this interface then
+ * remove the multicast address route.
*/
if (ifa0 == NULL) {
memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr,
sizeof(mltaddr.sin6_addr));
RTFREE_LOCKED(rt);
- error = rtrequest(RTM_DELETE, (struct sockaddr *)&mltaddr,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&mltmask, RTF_UP,
- (struct rtentry **)0);
+ error = in6_rtrequest(RTM_DELETE,
+ (struct sockaddr *)&mltaddr,
+ (struct sockaddr *)&ia->ia_addr,
+ (struct sockaddr *)&mltmask, RTF_UP,
+ (struct rtentry **)0, RT_DEFAULT_FIB);
if (error)
- log(LOG_INFO, "in6_purgeaddr: link-local all-nodes"
- "multicast address deletion error\n");
+ log(LOG_INFO, "%s: link-local all-nodes "
+ "multicast address deletion error\n",
+ __func__);
} else {
/*
- * replace the gateway of the route
+ * Replace the gateway of the route.
*/
struct sockaddr_in6 sa;
@@ -1427,38 +1399,38 @@ in6_purgeaddr(struct ifaddr *ifa)
}
/*
- * remove the node-local all-nodes address
+ * Remove the node-local all-nodes address.
*/
mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
- if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) !=
- 0)
- goto cleanup;
+ if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0)
+ return (error);
- rt = rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL);
+ rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB);
if (rt != NULL && rt->rt_gateway != NULL &&
(memcmp(&satosin6(rt->rt_gateway)->sin6_addr,
&ia->ia_addr.sin6_addr,
sizeof(ia->ia_addr.sin6_addr)) == 0)) {
/*
- * if no more IPv6 address exists on this interface
- * then remove the multicast address route
+ * If no more IPv6 address exists on this interface then
+ * remove the multicast address route.
*/
if (ifa0 == NULL) {
memcpy(&mltaddr.sin6_addr, &satosin6(rt_key(rt))->sin6_addr,
sizeof(mltaddr.sin6_addr));
RTFREE_LOCKED(rt);
- error = rtrequest(RTM_DELETE, (struct sockaddr *)&mltaddr,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&mltmask, RTF_UP,
- (struct rtentry **)0);
-
+ error = in6_rtrequest(RTM_DELETE,
+ (struct sockaddr *)&mltaddr,
+ (struct sockaddr *)&ia->ia_addr,
+ (struct sockaddr *)&mltmask, RTF_UP,
+ (struct rtentry **)0, RT_DEFAULT_FIB);
if (error)
- log(LOG_INFO, "in6_purgeaddr: node-local all-nodes"
- "multicast address deletion error\n");
+ log(LOG_INFO, "%s: node-local all-nodes"
+ "multicast address deletion error\n",
+ __func__);
} else {
/*
- * replace the gateway of the route
+ * Replace the gateway of the route.
*/
struct sockaddr_in6 sa;
@@ -1476,31 +1448,70 @@ in6_purgeaddr(struct ifaddr *ifa)
RTFREE_LOCKED(rt);
}
-cleanup:
+ return (0);
+}
+
+void
+in6_purgeaddr(struct ifaddr *ifa)
+{
+ struct ifnet *ifp = ifa->ifa_ifp;
+ struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa;
+ int plen, error;
+ struct ifaddr *ifa0;
+
+ if (ifa->ifa_carp)
+ (*carp_detach_p)(ifa);
+
+ /*
+ * find another IPv6 address as the gateway for the
+ * link-local and node-local all-nodes multicast
+ * address routes
+ */
+ IF_ADDR_RLOCK(ifp);
+ TAILQ_FOREACH(ifa0, &ifp->if_addrhead, ifa_link) {
+ if ((ifa0->ifa_addr->sa_family != AF_INET6) ||
+ memcmp(&satosin6(ifa0->ifa_addr)->sin6_addr,
+ &ia->ia_addr.sin6_addr,
+ sizeof(struct in6_addr)) == 0)
+ continue;
+ else
+ break;
+ }
+ if (ifa0 != NULL)
+ ifa_ref(ifa0);
+ IF_ADDR_RUNLOCK(ifp);
+
+ /*
+ * Remove the loopback route to the interface address.
+ * The check for the current setting of "nd6_useloopback"
+ * is not needed.
+ */
+ if (ia->ia_flags & IFA_RTSELF) {
+ error = ifa_del_loopback_route((struct ifaddr *)ia,
+ (struct sockaddr *)&ia->ia_addr);
+ if (error == 0)
+ ia->ia_flags &= ~IFA_RTSELF;
+ }
+
+ /* stop DAD processing */
+ nd6_dad_stop(ifa);
+
+ /* Remove local address entry from lltable. */
+ in6_ifremloop(ifa);
+
+ /* Leave multicast groups. */
+ error = in6_purgeaddr_mc(ifp, ia, ifa0);
+
if (ifa0 != NULL)
ifa_free(ifa0);
plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */
if ((ia->ia_flags & IFA_ROUTE) && plen == 128) {
- int error;
- struct sockaddr *dstaddr;
-
- /*
- * use the interface address if configuring an
- * interface address with a /128 prefix len
- */
- if (ia->ia_dstaddr.sin6_family == AF_INET6)
- dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
- else
- dstaddr = (struct sockaddr *)&ia->ia_addr;
-
- error = rtrequest(RTM_DELETE,
- (struct sockaddr *)dstaddr,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&ia->ia_prefixmask,
- ia->ia_flags | RTF_HOST, NULL);
+ error = rtinit(&(ia->ia_ifa), RTM_DELETE, ia->ia_flags |
+ (ia->ia_dstaddr.sin6_family == AF_INET6) ? RTF_HOST : 0);
if (error != 0)
- return;
+ log(LOG_INFO, "%s: err=%d, destination address delete "
+ "failed\n", __func__, error);
ia->ia_flags &= ~IFA_ROUTE;
}
@@ -1832,8 +1843,7 @@ in6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data,
}
/*
- * Initialize an interface's intetnet6 address
- * and routing table entry.
+ * Initialize an interface's IPv6 address and routing table entry.
*/
static int
in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
@@ -1883,13 +1893,8 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 &&
ia->ia_dstaddr.sin6_family == AF_INET6) {
int rtflags = RTF_UP | RTF_HOST;
-
- error = rtrequest(RTM_ADD,
- (struct sockaddr *)&ia->ia_dstaddr,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&ia->ia_prefixmask,
- ia->ia_flags | rtflags, NULL);
- if (error != 0)
+ error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags);
+ if (error)
return (error);
ia->ia_flags |= IFA_ROUTE;
/*
@@ -1909,7 +1914,7 @@ in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia,
ia->ia_flags |= IFA_RTSELF;
}
- /* Add ownaddr as loopback rtentry, if necessary (ex. on p2p link). */
+ /* Add local address to lltable, if necessary (ex. on p2p link). */
if (newhost)
in6_ifaddloop(&(ia->ia_ifa));
@@ -2512,8 +2517,10 @@ in6_lltable_rtcheck(struct ifnet *ifp,
KASSERT(l3addr->sa_family == AF_INET6,
("sin_family %d", l3addr->sa_family));
+ /* Our local addresses are always only installed on the default FIB. */
/* XXX rtalloc1 should take a const param */
- rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0);
+ rt = in6_rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0,
+ RT_DEFAULT_FIB);
if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) {
struct ifaddr *ifa;
/*
diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c
index 961fc77..c329e11 100644
--- a/sys/netinet6/in6_gif.c
+++ b/sys/netinet6/in6_gif.c
@@ -228,6 +228,8 @@ in6_gif_output(struct ifnet *ifp,
ip6->ip6_flow &= ~htonl(0xff << 20);
ip6->ip6_flow |= htonl((u_int32_t)otos << 20);
+ M_SETFIB(m, sc->gif_fibnum);
+
if (dst->sin6_family != sin6_dst->sin6_family ||
!IN6_ARE_ADDR_EQUAL(&dst->sin6_addr, &sin6_dst->sin6_addr)) {
/* cache route doesn't match */
@@ -245,7 +247,7 @@ in6_gif_output(struct ifnet *ifp,
}
if (sc->gif_ro6.ro_rt == NULL) {
- rtalloc((struct route *)&sc->gif_ro6);
+ in6_rtalloc(&sc->gif_ro6, sc->gif_fibnum);
if (sc->gif_ro6.ro_rt == NULL) {
m_freem(m);
return ENETUNREACH;
@@ -404,7 +406,8 @@ gif_validate6(const struct ip6_hdr *ip6, struct gif_softc *sc,
sin6.sin6_addr = ip6->ip6_src;
sin6.sin6_scope_id = 0; /* XXX */
- rt = rtalloc1((struct sockaddr *)&sin6, 0, 0UL);
+ rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, 0UL,
+ sc->gif_fibnum);
if (!rt || rt->rt_ifp != ifp) {
#if 0
char ip6buf[INET6_ADDRSTRLEN];
diff --git a/sys/netinet6/in6_ifattach.c b/sys/netinet6/in6_ifattach.c
index f8134ca..28ec920 100644
--- a/sys/netinet6/in6_ifattach.c
+++ b/sys/netinet6/in6_ifattach.c
@@ -790,7 +790,6 @@ in6_ifdetach(struct ifnet *ifp)
struct ifaddr *ifa, *next;
struct radix_node_head *rnh;
struct rtentry *rt;
- short rtflags;
struct sockaddr_in6 sin6;
struct in6_multi_mship *imm;
@@ -821,16 +820,9 @@ in6_ifdetach(struct ifnet *ifp)
in6_leavegroup(imm);
}
- /* remove from the routing table */
- if ((ia->ia_flags & IFA_ROUTE) &&
- (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
- rtflags = rt->rt_flags;
- RTFREE_LOCKED(rt);
- rtrequest(RTM_DELETE, (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&ia->ia_addr,
- (struct sockaddr *)&ia->ia_prefixmask,
- rtflags, (struct rtentry **)0);
- }
+ /* Remove link-local from the routing table. */
+ if (ia->ia_flags & IFA_ROUTE)
+ (void)rtinit(&ia->ia_ifa, RTM_DELETE, ia->ia_flags);
/* remove from the linked list */
IF_ADDR_WLOCK(ifp);
@@ -859,7 +851,10 @@ in6_ifdetach(struct ifnet *ifp)
*/
nd6_purge(ifp);
- /* remove route to link-local allnodes multicast (ff02::1) */
+ /*
+ * Remove route to link-local allnodes multicast (ff02::1).
+ * These only get automatically installed for the default FIB.
+ */
bzero(&sin6, sizeof(sin6));
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_family = AF_INET6;
@@ -868,10 +863,11 @@ in6_ifdetach(struct ifnet *ifp)
/* XXX: should not fail */
return;
/* XXX grab lock first to avoid LOR */
- rnh = rt_tables_get_rnh(0, AF_INET6);
+ rnh = rt_tables_get_rnh(RT_DEFAULT_FIB, AF_INET6);
if (rnh != NULL) {
RADIX_NODE_HEAD_LOCK(rnh);
- rt = rtalloc1((struct sockaddr *)&sin6, 0, RTF_RNH_LOCKED);
+ rt = in6_rtalloc1((struct sockaddr *)&sin6, 0, RTF_RNH_LOCKED,
+ RT_DEFAULT_FIB);
if (rt) {
if (rt->rt_ifp == ifp)
rtexpunge(rt);
diff --git a/sys/netinet6/in6_mcast.c b/sys/netinet6/in6_mcast.c
index e53597b..ce23aa8 100644
--- a/sys/netinet6/in6_mcast.c
+++ b/sys/netinet6/in6_mcast.c
@@ -1764,7 +1764,7 @@ ip6_getmoptions(struct inpcb *inp, struct sockopt *sopt)
* Returns NULL if no ifp could be found.
*/
static struct ifnet *
-in6p_lookup_mcast_ifp(const struct inpcb *in6p __unused,
+in6p_lookup_mcast_ifp(const struct inpcb *in6p,
const struct sockaddr_in6 *gsin6)
{
struct route_in6 ro6;
@@ -1780,11 +1780,8 @@ in6p_lookup_mcast_ifp(const struct inpcb *in6p __unused,
ifp = NULL;
memset(&ro6, 0, sizeof(struct route_in6));
memcpy(&ro6.ro_dst, gsin6, sizeof(struct sockaddr_in6));
-#ifdef notyet
- rtalloc_ign_fib(&ro6, 0, inp ? inp->inp_inc.inc_fibnum : 0);
-#else
- rtalloc_ign((struct route *)&ro6, 0);
-#endif
+ rtalloc_ign_fib((struct route *)&ro6, 0,
+ in6p ? in6p->inp_inc.inc_fibnum : RT_DEFAULT_FIB);
if (ro6.ro_rt != NULL) {
ifp = ro6.ro_rt->rt_ifp;
KASSERT(ifp != NULL, ("%s: null ifp", __func__));
diff --git a/sys/netinet6/in6_rmx.c b/sys/netinet6/in6_rmx.c
index 2a13646..b526030 100644
--- a/sys/netinet6/in6_rmx.c
+++ b/sys/netinet6/in6_rmx.c
@@ -168,7 +168,8 @@ in6_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
* net route entry, 3ffe:0501:: -> if0.
* This case should not raise an error.
*/
- rt2 = rtalloc1((struct sockaddr *)sin6, 0, RTF_RNH_LOCKED);
+ rt2 = in6_rtalloc1((struct sockaddr *)sin6, 0, RTF_RNH_LOCKED,
+ rt->rt_fibnum);
if (rt2) {
if (((rt2->rt_flags & (RTF_HOST|RTF_GATEWAY)) == 0)
&& rt2->rt_gateway
@@ -255,10 +256,11 @@ in6_rtqkill(struct radix_node *rn, void *rock)
if (rt->rt_refcnt > 0)
panic("rtqkill route really not free");
- err = rtrequest(RTM_DELETE,
+ err = in6_rtrequest(RTM_DELETE,
(struct sockaddr *)rt_key(rt),
rt->rt_gateway, rt_mask(rt),
- rt->rt_flags|RTF_RNH_LOCKED, 0);
+ rt->rt_flags|RTF_RNH_LOCKED, 0,
+ rt->rt_fibnum);
if (err) {
log(LOG_WARNING, "in6_rtqkill: error %d", err);
} else {
@@ -287,19 +289,11 @@ static VNET_DEFINE(struct callout, rtq_timer6);
#define V_rtq_timer6 VNET(rtq_timer6)
static void
-in6_rtqtimo(void *rock)
+in6_rtqtimo_one(struct radix_node_head *rnh)
{
- CURVNET_SET_QUIET((struct vnet *) rock);
- struct radix_node_head *rnh;
struct rtqk_arg arg;
- struct timeval atv;
static time_t last_adjusted_timeout = 0;
- rnh = rt_tables_get_rnh(0, AF_INET6);
- if (rnh == NULL) {
- CURVNET_RESTORE();
- return;
- }
arg.found = arg.killed = 0;
arg.rnh = rnh;
arg.nextstop = time_uptime + V_rtq_timeout6;
@@ -335,9 +329,24 @@ in6_rtqtimo(void *rock)
rnh->rnh_walktree(rnh, in6_rtqkill, &arg);
RADIX_NODE_HEAD_UNLOCK(rnh);
}
+}
+
+static void
+in6_rtqtimo(void *rock)
+{
+ CURVNET_SET_QUIET((struct vnet *) rock);
+ struct radix_node_head *rnh;
+ struct timeval atv;
+ u_int fibnum;
+
+ for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+ rnh = rt_tables_get_rnh(fibnum, AF_INET6);
+ if (rnh != NULL)
+ in6_rtqtimo_one(rnh);
+ }
atv.tv_usec = 0;
- atv.tv_sec = arg.nextstop - time_uptime;
+ atv.tv_sec = V_rtq_timeout6;
callout_reset(&V_rtq_timer6, tvtohz(&atv), in6_rtqtimo, rock);
CURVNET_RESTORE();
}
@@ -377,31 +386,33 @@ in6_mtuexpire(struct radix_node *rn, void *rock)
#define MTUTIMO_DEFAULT (60*1)
static void
-in6_mtutimo(void *rock)
+in6_mtutimo_one(struct radix_node_head *rnh)
{
- CURVNET_SET_QUIET((struct vnet *) rock);
- struct radix_node_head *rnh;
struct mtuex_arg arg;
- struct timeval atv;
- rnh = rt_tables_get_rnh(0, AF_INET6);
- if (rnh == NULL) {
- CURVNET_RESTORE();
- return;
- }
arg.rnh = rnh;
arg.nextstop = time_uptime + MTUTIMO_DEFAULT;
RADIX_NODE_HEAD_LOCK(rnh);
rnh->rnh_walktree(rnh, in6_mtuexpire, &arg);
RADIX_NODE_HEAD_UNLOCK(rnh);
+}
- atv.tv_usec = 0;
- atv.tv_sec = arg.nextstop - time_uptime;
- if (atv.tv_sec < 0) {
- printf("invalid mtu expiration time on routing table\n");
- arg.nextstop = time_uptime + 30; /* last resort */
- atv.tv_sec = 30;
+static void
+in6_mtutimo(void *rock)
+{
+ CURVNET_SET_QUIET((struct vnet *) rock);
+ struct radix_node_head *rnh;
+ struct timeval atv;
+ u_int fibnum;
+
+ for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+ rnh = rt_tables_get_rnh(fibnum, AF_INET6);
+ if (rnh != NULL)
+ in6_mtutimo_one(rnh);
}
+
+ atv.tv_sec = MTUTIMO_DEFAULT;
+ atv.tv_usec = 0;
callout_reset(&V_rtq_mtutimer, tvtohz(&atv), in6_mtutimo, rock);
CURVNET_RESTORE();
}
@@ -413,6 +424,9 @@ in6_mtutimo(void *rock)
* value should be so just use that).. FIX AFTER RELENG_7 is MFC'd
* see also comments in in_inithead() vfs_export.c and domain.h
*/
+static VNET_DEFINE(int, _in6_rt_was_here);
+#define V__in6_rt_was_here VNET(_in6_rt_was_here)
+
int
in6_inithead(void **head, int off)
{
@@ -425,13 +439,17 @@ in6_inithead(void **head, int off)
return 1; /* only do the rest for the real thing */
rnh = *head;
- KASSERT(rnh == rt_tables_get_rnh(0, AF_INET6), ("rnh?"));
rnh->rnh_addaddr = in6_addroute;
rnh->rnh_matchaddr = in6_matroute;
- callout_init(&V_rtq_timer6, CALLOUT_MPSAFE);
- callout_init(&V_rtq_mtutimer, CALLOUT_MPSAFE);
- in6_rtqtimo(curvnet); /* kick off timeout first time */
- in6_mtutimo(curvnet); /* kick off timeout first time */
+
+ if (V__in6_rt_was_here == 0) {
+ callout_init(&V_rtq_timer6, CALLOUT_MPSAFE);
+ callout_init(&V_rtq_mtutimer, CALLOUT_MPSAFE);
+ in6_rtqtimo(curvnet); /* kick off timeout first time */
+ in6_mtutimo(curvnet); /* kick off timeout first time */
+ V__in6_rt_was_here = 1;
+ }
+
return 1;
}
@@ -445,3 +463,43 @@ in6_detachhead(void **head, int off)
return (1);
}
#endif
+
+/*
+ * Extended API for IPv6 FIB support.
+ */
+void
+in6_rtredirect(struct sockaddr *dst, struct sockaddr *gw, struct sockaddr *nm,
+ int flags, struct sockaddr *src, u_int fibnum)
+{
+
+ rtredirect_fib(dst, gw, nm, flags, src, fibnum);
+}
+
+int
+in6_rtrequest(int req, struct sockaddr *dst, struct sockaddr *gw,
+ struct sockaddr *mask, int flags, struct rtentry **ret_nrt, u_int fibnum)
+{
+
+ return (rtrequest_fib(req, dst, gw, mask, flags, ret_nrt, fibnum));
+}
+
+void
+in6_rtalloc(struct route_in6 *ro, u_int fibnum)
+{
+
+ rtalloc_ign_fib((struct route *)ro, 0ul, fibnum);
+}
+
+void
+in6_rtalloc_ign(struct route_in6 *ro, u_long ignflags, u_int fibnum)
+{
+
+ rtalloc_ign_fib((struct route *)ro, ignflags, fibnum);
+}
+
+struct rtentry *
+in6_rtalloc1(struct sockaddr *dst, int report, u_long ignflags, u_int fibnum)
+{
+
+ return (rtalloc1_fib(dst, report, ignflags, fibnum));
+}
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c
index 2b3493e..9ed3eab 100644
--- a/sys/netinet6/in6_src.c
+++ b/sys/netinet6/in6_src.c
@@ -129,9 +129,10 @@ VNET_DEFINE(int, ip6_prefer_tempaddr) = 0;
static int selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *,
struct ip6_moptions *, struct route_in6 *, struct ifnet **,
- struct rtentry **, int));
+ struct rtentry **, int, int));
static int in6_selectif __P((struct sockaddr_in6 *, struct ip6_pktopts *,
- struct ip6_moptions *, struct route_in6 *ro, struct ifnet **));
+ struct ip6_moptions *, struct route_in6 *ro, struct ifnet **,
+ struct ifnet *, int));
static struct in6_addrpolicy *lookup_addrsel_policy(struct sockaddr_in6 *);
@@ -182,7 +183,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
struct ifnet **ifpp, struct in6_addr *srcp)
{
struct in6_addr dst, tmp;
- struct ifnet *ifp = NULL;
+ struct ifnet *ifp = NULL, *oifp = NULL;
struct in6_ifaddr *ia = NULL, *ia_best = NULL;
struct in6_pktinfo *pi = NULL;
int dst_scope = -1, best_scope = -1, best_matchlen = -1;
@@ -195,8 +196,18 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
KASSERT(srcp != NULL, ("%s: srcp is NULL", __func__));
dst = dstsock->sin6_addr; /* make a copy for local operation */
- if (ifpp)
+ if (ifpp) {
+ /*
+ * Save a possibly passed in ifp for in6_selectsrc. Only
+ * neighbor discovery code should use this feature, where
+ * we may know the interface but not the FIB number holding
+ * the connected subnet in case someone deleted it from the
+ * default FIB and we need to check the interface.
+ */
+ if (*ifpp != NULL)
+ oifp = *ifpp;
*ifpp = NULL;
+ }
if (inp != NULL) {
INP_LOCK_ASSERT(inp);
@@ -217,7 +228,9 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
struct in6_ifaddr *ia6;
/* get the outgoing interface */
- if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
+ if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp, oifp,
+ (inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB))
+ != 0)
return (error);
/*
@@ -281,7 +294,8 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
* the outgoing interface and the destination address.
*/
/* get the outgoing interface */
- if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
+ if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp, oifp,
+ (inp != NULL) ? inp->inp_inc.inc_fibnum : RT_DEFAULT_FIB)) != 0)
return (error);
#ifdef DIAGNOSTIC
@@ -504,7 +518,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
static int
selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
struct ip6_moptions *mopts, struct route_in6 *ro,
- struct ifnet **retifp, struct rtentry **retrt, int norouteok)
+ struct ifnet **retifp, struct rtentry **retrt, int norouteok, int fibnum)
{
int error = 0;
struct ifnet *ifp = NULL;
@@ -581,7 +595,7 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
if (ron->ro_rt == NULL) {
- rtalloc((struct route *)ron); /* multi path case? */
+ in6_rtalloc(ron, fibnum); /* multi path case? */
if (ron->ro_rt == NULL) {
if (ron->ro_rt) {
RTFREE(ron->ro_rt);
@@ -616,7 +630,7 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
*satosin6(&ron->ro_dst) = *sin6_next;
}
if (ron->ro_rt == NULL) {
- rtalloc((struct route *)ron); /* multi path case? */
+ in6_rtalloc(ron); /* multi path case? */
if (ron->ro_rt == NULL ||
!(ron->ro_rt->rt_flags & RTF_LLINFO)) {
if (ron->ro_rt) {
@@ -661,11 +675,11 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
sa6->sin6_scope_id = 0;
#ifdef RADIX_MPATH
- rtalloc_mpath((struct route *)ro,
- ntohl(sa6->sin6_addr.s6_addr32[3]));
+ rtalloc_mpath_fib((struct route *)ro,
+ ntohl(sa6->sin6_addr.s6_addr32[3]), fibnum);
#else
- ro->ro_rt = rtalloc1(&((struct route *)ro)
- ->ro_dst, 0, 0UL);
+ ro->ro_rt = in6_rtalloc1((struct sockaddr *)
+ &ro->ro_dst, 0, 0UL, fibnum);
if (ro->ro_rt)
RT_UNLOCK(ro->ro_rt);
#endif
@@ -746,21 +760,29 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
static int
in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
- struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp)
+ struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp,
+ struct ifnet *oifp, int fibnum)
{
int error;
struct route_in6 sro;
struct rtentry *rt = NULL;
+ KASSERT(retifp != NULL, ("%s: retifp is NULL", __func__));
+
if (ro == NULL) {
bzero(&sro, sizeof(sro));
ro = &sro;
}
if ((error = selectroute(dstsock, opts, mopts, ro, retifp,
- &rt, 1)) != 0) {
+ &rt, 1, fibnum)) != 0) {
if (ro == &sro && rt && rt == sro.ro_rt)
RTFREE(rt);
+ /* Help ND. See oifp comment in in6_selectsrc(). */
+ if (oifp != NULL && fibnum == RT_DEFAULT_FIB) {
+ *retifp = oifp;
+ error = 0;
+ }
return (error);
}
@@ -795,7 +817,10 @@ in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
}
/*
- * clone - meaningful only for bsdi and freebsd
+ * Public wrapper function to selectroute().
+ *
+ * XXX-BZ in6_selectroute() should and will grow the FIB argument. The
+ * in6_selectroute_fib() function is only there for backward compat on stable.
*/
int
in6_selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
@@ -804,9 +829,21 @@ in6_selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
{
return (selectroute(dstsock, opts, mopts, ro, retifp,
- retrt, 0));
+ retrt, 0, RT_DEFAULT_FIB));
}
+#ifndef BURN_BRIDGES
+int
+in6_selectroute_fib(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
+ struct ip6_moptions *mopts, struct route_in6 *ro,
+ struct ifnet **retifp, struct rtentry **retrt, int fibnum)
+{
+
+ return (selectroute(dstsock, opts, mopts, ro, retifp,
+ retrt, 0, fibnum));
+}
+#endif
+
/*
* Default hop limit selection. The precedence is as follows:
* 1. Hoplimit value specified via ioctl.
@@ -830,7 +867,8 @@ in6_selecthlim(struct inpcb *in6p, struct ifnet *ifp)
ro6.ro_dst.sin6_family = AF_INET6;
ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6);
ro6.ro_dst.sin6_addr = in6p->in6p_faddr;
- rtalloc((struct route *)&ro6);
+ in6_rtalloc(&ro6, in6p ? in6p->inp_inc.inc_fibnum :
+ RT_DEFAULT_FIB);
if (ro6.ro_rt) {
lifp = ro6.ro_rt->rt_ifp;
RTFREE(ro6.ro_rt);
diff --git a/sys/netinet6/in6_var.h b/sys/netinet6/in6_var.h
index c491649..8ea5e04 100644
--- a/sys/netinet6/in6_var.h
+++ b/sys/netinet6/in6_var.h
@@ -792,6 +792,17 @@ void in6_ifaddloop(struct ifaddr *);
int in6_is_addr_deprecated __P((struct sockaddr_in6 *));
int in6_src_ioctl __P((u_long, caddr_t));
+
+/*
+ * Extended API for IPv6 FIB support.
+ */
+void in6_rtredirect(struct sockaddr *, struct sockaddr *, struct sockaddr *,
+ int, struct sockaddr *, u_int);
+int in6_rtrequest(int, struct sockaddr *, struct sockaddr *,
+ struct sockaddr *, int, struct rtentry **, u_int);
+void in6_rtalloc(struct route_in6 *, u_int);
+void in6_rtalloc_ign(struct route_in6 *, u_long, u_int);
+struct rtentry *in6_rtalloc1(struct sockaddr *, int, u_long, u_int);
#endif /* _KERNEL */
#endif /* _NETINET6_IN6_VAR_H_ */
diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c
index 77cb926..bae418a 100644
--- a/sys/netinet6/ip6_forward.c
+++ b/sys/netinet6/ip6_forward.c
@@ -362,7 +362,7 @@ again:
#ifdef IPFIREWALL_FORWARD
again2:
#endif
- rin6.ro_rt = rtalloc1((struct sockaddr *)dst, 0, 0);
+ rin6.ro_rt = in6_rtalloc1((struct sockaddr *)dst, 0, 0, M_GETFIB(m));
if (rin6.ro_rt != NULL)
RT_UNLOCK(rin6.ro_rt);
else {
diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c
index 245f8f4..b733af4 100644
--- a/sys/netinet6/ip6_input.c
+++ b/sys/netinet6/ip6_input.c
@@ -666,7 +666,7 @@ passin:
dst->sin6_len = sizeof(struct sockaddr_in6);
dst->sin6_family = AF_INET6;
dst->sin6_addr = ip6->ip6_dst;
- rin6.ro_rt = rtalloc1((struct sockaddr *)dst, 0, 0);
+ rin6.ro_rt = in6_rtalloc1((struct sockaddr *)dst, 0, 0, M_GETFIB(m));
if (rin6.ro_rt)
RT_UNLOCK(rin6.ro_rt);
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 5372438..43a236d 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -142,7 +142,7 @@ static int ip6_insertfraghdr __P((struct mbuf *, struct mbuf *, int,
static int ip6_insert_jumboopt(struct ip6_exthdrs *, u_int32_t);
static int ip6_splithdr(struct mbuf *, struct ip6_exthdrs *);
static int ip6_getpmtu __P((struct route_in6 *, struct route_in6 *,
- struct ifnet *, struct in6_addr *, u_long *, int *));
+ struct ifnet *, struct in6_addr *, u_long *, int *, int));
static int copypktopts(struct ip6_pktopts *, struct ip6_pktopts *, int);
@@ -241,6 +241,9 @@ ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
goto bad;
}
+ if (inp != NULL)
+ M_SETFIB(m, inp->inp_inc.inc_fibnum);
+
finaldst = ip6->ip6_dst;
bzero(&exthdrs, sizeof(exthdrs));
if (opt) {
@@ -604,8 +607,8 @@ again:
if (flevalid) {
rt = ro->ro_rt;
ifp = ro->ro_rt->rt_ifp;
- } else if ((error = in6_selectroute(&dst_sa, opt, im6o, ro,
- &ifp, &rt)) != 0) {
+ } else if ((error = in6_selectroute_fib(&dst_sa, opt, im6o, ro,
+ &ifp, &rt, inp ? inp->inp_inc.inc_fibnum : M_GETFIB(m))) != 0) {
switch (error) {
case EHOSTUNREACH:
V_ip6stat.ip6s_noroute++;
@@ -773,7 +776,7 @@ again:
/* Determine path MTU. */
if ((error = ip6_getpmtu(ro_pmtu, ro, ifp, &finaldst, &mtu,
- &alwaysfrag)) != 0)
+ &alwaysfrag, inp ? inp->inp_inc.inc_fibnum : M_GETFIB(m))) != 0)
goto bad;
/*
@@ -1064,7 +1067,7 @@ passout:
goto sendorfree;
}
m->m_pkthdr.rcvif = NULL;
- m->m_flags = m0->m_flags & M_COPYFLAGS;
+ m->m_flags = m0->m_flags & M_COPYFLAGS; /* incl. FIB */
*mnext = m;
mnext = &m->m_nextpkt;
m->m_data += max_linkhdr;
@@ -1321,7 +1324,7 @@ ip6_insertfraghdr(struct mbuf *m0, struct mbuf *m, int hlen,
static int
ip6_getpmtu(struct route_in6 *ro_pmtu, struct route_in6 *ro,
struct ifnet *ifp, struct in6_addr *dst, u_long *mtup,
- int *alwaysfragp)
+ int *alwaysfragp, int fibnum)
{
u_int32_t mtu = 0;
int alwaysfrag = 0;
@@ -1343,7 +1346,7 @@ ip6_getpmtu(struct route_in6 *ro_pmtu, struct route_in6 *ro,
sa6_dst->sin6_len = sizeof(struct sockaddr_in6);
sa6_dst->sin6_addr = *dst;
- rtalloc((struct route *)ro_pmtu);
+ in6_rtalloc(ro_pmtu, fibnum);
}
}
if (ro_pmtu->ro_rt) {
@@ -1448,6 +1451,12 @@ ip6_ctloutput(struct socket *so, struct sockopt *sopt)
INP_WUNLOCK(in6p);
error = 0;
break;
+ case SO_SETFIB:
+ INP_WLOCK(in6p);
+ in6p->inp_inc.inc_fibnum = so->so_fibnum;
+ INP_WUNLOCK(in6p);
+ error = 0;
+ break;
default:
break;
}
@@ -1975,7 +1984,8 @@ do { \
* the outgoing interface.
*/
error = ip6_getpmtu(&sro, NULL, NULL,
- &in6p->in6p_faddr, &pmtu, NULL);
+ &in6p->in6p_faddr, &pmtu, NULL,
+ so->so_fibnum);
if (sro.ro_rt)
RTFREE(sro.ro_rt);
if (error)
diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h
index c9d35e0..10dcbb3 100644
--- a/sys/netinet6/ip6_var.h
+++ b/sys/netinet6/ip6_var.h
@@ -445,6 +445,9 @@ int in6_selectsrc(struct sockaddr_in6 *, struct ip6_pktopts *,
int in6_selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *,
struct ip6_moptions *, struct route_in6 *, struct ifnet **,
struct rtentry **));
+int in6_selectroute_fib(struct sockaddr_in6 *, struct ip6_pktopts *,
+ struct ip6_moptions *, struct route_in6 *, struct ifnet **,
+ struct rtentry **, int);
u_int32_t ip6_randomid __P((void));
u_int32_t ip6_randomflowlabel __P((void));
#endif /* _KERNEL */
diff --git a/sys/netinet6/nd6.c b/sys/netinet6/nd6.c
index ec523fc..bf2cd53 100644
--- a/sys/netinet6/nd6.c
+++ b/sys/netinet6/nd6.c
@@ -900,7 +900,10 @@ nd6_is_new_addr_neighbor(struct sockaddr_in6 *addr, struct ifnet *ifp)
if (!(pr->ndpr_stateflags & NDPRF_ONLINK)) {
struct rtentry *rt;
- rt = rtalloc1((struct sockaddr *)&pr->ndpr_prefix, 0, 0);
+
+ /* Always use the default FIB here. */
+ rt = in6_rtalloc1((struct sockaddr *)&pr->ndpr_prefix,
+ 0, 0, RT_DEFAULT_FIB);
if (rt == NULL)
continue;
/*
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index a2aaeea..4b80dc2 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -85,6 +85,8 @@ static void nd6_dad_timer(struct dadq *);
static void nd6_dad_ns_output(struct dadq *, struct ifaddr *);
static void nd6_dad_ns_input(struct ifaddr *);
static void nd6_dad_na_input(struct ifaddr *);
+static void nd6_na_output_fib(struct ifnet *, const struct in6_addr *,
+ const struct in6_addr *, u_long, int, struct sockaddr *, u_int);
VNET_DEFINE(int, dad_ignore_ns) = 0; /* ignore NS in DAD - specwise incorrect*/
VNET_DEFINE(int, dad_maxtry) = 15; /* max # of *tries* to transmit DAD packet */
@@ -242,13 +244,16 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
tsin6.sin6_family = AF_INET6;
tsin6.sin6_addr = taddr6;
+ /* Always use the default FIB. */
#ifdef RADIX_MPATH
bzero(&ro, sizeof(ro));
ro.ro_dst = tsin6;
- rtalloc_mpath((struct route *)&ro, RTF_ANNOUNCE);
+ rtalloc_mpath_fib((struct route *)&ro, RTF_ANNOUNCE,
+ RT_DEFAULT_FIB);
rt = ro.ro_rt;
#else
- rt = rtalloc1((struct sockaddr *)&tsin6, 0, 0);
+ rt = in6_rtalloc1((struct sockaddr *)&tsin6, 0, 0,
+ RT_DEFAULT_FIB);
#endif
need_proxy = (rt && (rt->rt_flags & RTF_ANNOUNCE) != 0 &&
rt->rt_gateway->sa_family == AF_LINK);
@@ -341,19 +346,20 @@ nd6_ns_input(struct mbuf *m, int off, int icmp6len)
in6_all = in6addr_linklocal_allnodes;
if (in6_setscope(&in6_all, ifp, NULL) != 0)
goto bad;
- nd6_na_output(ifp, &in6_all, &taddr6,
+ nd6_na_output_fib(ifp, &in6_all, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
- rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL);
+ rflag, tlladdr, proxy ? (struct sockaddr *)&proxydl : NULL,
+ M_GETFIB(m));
goto freeit;
}
nd6_cache_lladdr(ifp, &saddr6, lladdr, lladdrlen,
ND_NEIGHBOR_SOLICIT, 0);
- nd6_na_output(ifp, &saddr6, &taddr6,
+ nd6_na_output_fib(ifp, &saddr6, &taddr6,
((anycast || proxy || !tlladdr) ? 0 : ND_NA_FLAG_OVERRIDE) |
rflag | ND_NA_FLAG_SOLICITED, tlladdr,
- proxy ? (struct sockaddr *)&proxydl : NULL);
+ proxy ? (struct sockaddr *)&proxydl : NULL, M_GETFIB(m));
freeit:
if (ifa != NULL)
ifa_free(ifa);
@@ -505,14 +511,16 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
int error;
struct sockaddr_in6 dst_sa;
struct in6_addr src_in;
+ struct ifnet *oifp;
bzero(&dst_sa, sizeof(dst_sa));
dst_sa.sin6_family = AF_INET6;
dst_sa.sin6_len = sizeof(dst_sa);
dst_sa.sin6_addr = ip6->ip6_dst;
+ oifp = ifp;
error = in6_selectsrc(&dst_sa, NULL,
- NULL, &ro, NULL, NULL, &src_in);
+ NULL, &ro, NULL, &oifp, &src_in);
if (error) {
char ip6buf[INET6_ADDRSTRLEN];
nd6log((LOG_DEBUG,
@@ -954,13 +962,14 @@ nd6_na_input(struct mbuf *m, int off, int icmp6len)
* tlladdr - 1 if include target link-layer address
* sdl0 - sockaddr_dl (= proxy NA) or NULL
*/
-void
-nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
+static void
+nd6_na_output_fib(struct ifnet *ifp, const struct in6_addr *daddr6_0,
const struct in6_addr *taddr6, u_long flags, int tlladdr,
- struct sockaddr *sdl0)
+ struct sockaddr *sdl0, u_int fibnum)
{
struct mbuf *m;
struct m_tag *mtag;
+ struct ifnet *oifp;
struct ip6_hdr *ip6;
struct nd_neighbor_advert *nd_na;
struct ip6_moptions im6o;
@@ -996,6 +1005,7 @@ nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
if (m == NULL)
return;
m->m_pkthdr.rcvif = NULL;
+ M_SETFIB(m, fibnum);
if (IN6_IS_ADDR_MULTICAST(&daddr6)) {
m->m_flags |= M_MCAST;
@@ -1037,7 +1047,8 @@ nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
* Select a source whose scope is the same as that of the dest.
*/
bcopy(&dst_sa, &ro.ro_dst, sizeof(dst_sa));
- error = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, NULL, &src);
+ oifp = ifp;
+ error = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, &oifp, &src);
if (error) {
char ip6buf[INET6_ADDRSTRLEN];
nd6log((LOG_DEBUG, "nd6_na_output: source can't be "
@@ -1126,6 +1137,18 @@ nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
return;
}
+#ifndef BURN_BRIDGES
+void
+nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
+ const struct in6_addr *taddr6, u_long flags, int tlladdr,
+ struct sockaddr *sdl0)
+{
+
+ nd6_na_output_fib(ifp, daddr6_0, taddr6, flags, tlladdr, sdl0,
+ RT_DEFAULT_FIB);
+}
+#endif
+
caddr_t
nd6_ifptomac(struct ifnet *ifp)
{
diff --git a/sys/netinet6/nd6_rtr.c b/sys/netinet6/nd6_rtr.c
index e77767f..792b5c9 100644
--- a/sys/netinet6/nd6_rtr.c
+++ b/sys/netinet6/nd6_rtr.c
@@ -463,7 +463,7 @@ nd6_rtmsg(int cmd, struct rtentry *rt)
} else
ifa = NULL;
- rt_missmsg(cmd, &info, rt->rt_flags, 0);
+ rt_missmsg_fib(cmd, &info, rt->rt_flags, 0, rt->rt_fibnum);
if (ifa != NULL)
ifa_free(ifa);
}
@@ -486,9 +486,9 @@ defrouter_addreq(struct nd_defrouter *new)
gate.sin6_addr = new->rtaddr;
s = splnet();
- error = rtrequest(RTM_ADD, (struct sockaddr *)&def,
+ error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&def,
(struct sockaddr *)&gate, (struct sockaddr *)&mask,
- RTF_GATEWAY, &newrt);
+ RTF_GATEWAY, &newrt, RT_DEFAULT_FIB);
if (newrt) {
nd6_rtmsg(RTM_ADD, newrt); /* tell user process */
RTFREE(newrt);
@@ -532,9 +532,9 @@ defrouter_delreq(struct nd_defrouter *dr)
def.sin6_family = gate.sin6_family = AF_INET6;
gate.sin6_addr = dr->rtaddr;
- rtrequest(RTM_DELETE, (struct sockaddr *)&def,
+ in6_rtrequest(RTM_DELETE, (struct sockaddr *)&def,
(struct sockaddr *)&gate,
- (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt);
+ (struct sockaddr *)&mask, RTF_GATEWAY, &oldrt, RT_DEFAULT_FIB);
if (oldrt) {
nd6_rtmsg(RTM_DELETE, oldrt);
RTFREE(oldrt);
@@ -1541,18 +1541,91 @@ pfxlist_onlink_check()
}
static int
+nd6_prefix_onlink_rtrequest(struct nd_prefix *pr, struct ifaddr *ifa)
+{
+ static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
+ struct radix_node_head *rnh;
+ struct rtentry *rt;
+ struct sockaddr_in6 mask6;
+ u_long rtflags;
+ int error, a_failure, fibnum;
+
+ /*
+ * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
+ * ifa->ifa_rtrequest = nd6_rtrequest;
+ */
+ bzero(&mask6, sizeof(mask6));
+ mask6.sin6_len = sizeof(mask6);
+ mask6.sin6_addr = pr->ndpr_mask;
+ rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP;
+
+ a_failure = 0;
+ for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+
+ rt = NULL;
+ error = in6_rtrequest(RTM_ADD,
+ (struct sockaddr *)&pr->ndpr_prefix, ifa->ifa_addr,
+ (struct sockaddr *)&mask6, rtflags, &rt, fibnum);
+ if (error == 0) {
+ KASSERT(rt != NULL, ("%s: in6_rtrequest return no "
+ "error(%d) but rt is NULL, pr=%p, ifa=%p", __func__,
+ error, pr, ifa));
+
+ rnh = rt_tables_get_rnh(rt->rt_fibnum, AF_INET6);
+ /* XXX what if rhn == NULL? */
+ RADIX_NODE_HEAD_LOCK(rnh);
+ RT_LOCK(rt);
+ if (rt_setgate(rt, rt_key(rt),
+ (struct sockaddr *)&null_sdl) == 0) {
+ struct sockaddr_dl *dl;
+
+ dl = (struct sockaddr_dl *)rt->rt_gateway;
+ dl->sdl_type = rt->rt_ifp->if_type;
+ dl->sdl_index = rt->rt_ifp->if_index;
+ }
+ RADIX_NODE_HEAD_UNLOCK(rnh);
+ nd6_rtmsg(RTM_ADD, rt);
+ RT_UNLOCK(rt);
+ pr->ndpr_stateflags |= NDPRF_ONLINK;
+ } else {
+ char ip6buf[INET6_ADDRSTRLEN];
+ char ip6bufg[INET6_ADDRSTRLEN];
+ char ip6bufm[INET6_ADDRSTRLEN];
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add "
+ "route for a prefix (%s/%d) on %s, gw=%s, mask=%s, "
+ "flags=%lx errno = %d\n",
+ ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
+ pr->ndpr_plen, if_name(pr->ndpr_ifp),
+ ip6_sprintf(ip6bufg, &sin6->sin6_addr),
+ ip6_sprintf(ip6bufm, &mask6.sin6_addr),
+ rtflags, error));
+
+ /* Save last error to return, see rtinit(). */
+ a_failure = error;
+ }
+
+ if (rt != NULL) {
+ RT_LOCK(rt);
+ RT_REMREF(rt);
+ RT_UNLOCK(rt);
+ }
+ }
+
+ /* Return the last error we got. */
+ return (a_failure);
+}
+
+static int
nd6_prefix_onlink(struct nd_prefix *pr)
{
struct ifaddr *ifa;
struct ifnet *ifp = pr->ndpr_ifp;
- struct sockaddr_in6 mask6;
struct nd_prefix *opr;
- u_long rtflags;
int error = 0;
- struct radix_node_head *rnh;
- struct rtentry *rt = NULL;
char ip6buf[INET6_ADDRSTRLEN];
- struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
/* sanity check */
if ((pr->ndpr_stateflags & NDPRF_ONLINK) != 0) {
@@ -1616,49 +1689,8 @@ nd6_prefix_onlink(struct nd_prefix *pr)
return (0);
}
- /*
- * in6_ifinit() sets nd6_rtrequest to ifa_rtrequest for all ifaddrs.
- * ifa->ifa_rtrequest = nd6_rtrequest;
- */
- bzero(&mask6, sizeof(mask6));
- mask6.sin6_len = sizeof(mask6);
- mask6.sin6_addr = pr->ndpr_mask;
- rtflags = (ifa->ifa_flags & ~IFA_RTSELF) | RTF_UP;
- error = rtrequest(RTM_ADD, (struct sockaddr *)&pr->ndpr_prefix,
- ifa->ifa_addr, (struct sockaddr *)&mask6, rtflags, &rt);
- if (error == 0) {
- if (rt != NULL) /* this should be non NULL, though */ {
- rnh = rt_tables_get_rnh(rt->rt_fibnum, AF_INET6);
- /* XXX what if rhn == NULL? */
- RADIX_NODE_HEAD_LOCK(rnh);
- RT_LOCK(rt);
- if (!rt_setgate(rt, rt_key(rt), (struct sockaddr *)&null_sdl)) {
- ((struct sockaddr_dl *)rt->rt_gateway)->sdl_type =
- rt->rt_ifp->if_type;
- ((struct sockaddr_dl *)rt->rt_gateway)->sdl_index =
- rt->rt_ifp->if_index;
- }
- RADIX_NODE_HEAD_UNLOCK(rnh);
- nd6_rtmsg(RTM_ADD, rt);
- RT_UNLOCK(rt);
- }
- pr->ndpr_stateflags |= NDPRF_ONLINK;
- } else {
- char ip6bufg[INET6_ADDRSTRLEN], ip6bufm[INET6_ADDRSTRLEN];
- nd6log((LOG_ERR, "nd6_prefix_onlink: failed to add route for a"
- " prefix (%s/%d) on %s, gw=%s, mask=%s, flags=%lx "
- "errno = %d\n",
- ip6_sprintf(ip6buf, &pr->ndpr_prefix.sin6_addr),
- pr->ndpr_plen, if_name(ifp),
- ip6_sprintf(ip6bufg, &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr),
- ip6_sprintf(ip6bufm, &mask6.sin6_addr), rtflags, error));
- }
+ error = nd6_prefix_onlink_rtrequest(pr, ifa);
- if (rt != NULL) {
- RT_LOCK(rt);
- RT_REMREF(rt);
- RT_UNLOCK(rt);
- }
if (ifa != NULL)
ifa_free(ifa);
@@ -1672,8 +1704,9 @@ nd6_prefix_offlink(struct nd_prefix *pr)
struct ifnet *ifp = pr->ndpr_ifp;
struct nd_prefix *opr;
struct sockaddr_in6 sa6, mask6;
- struct rtentry *rt = NULL;
+ struct rtentry *rt;
char ip6buf[INET6_ADDRSTRLEN];
+ int fibnum, a_failure;
/* sanity check */
if ((pr->ndpr_stateflags & NDPRF_ONLINK) == 0) {
@@ -1693,15 +1726,28 @@ nd6_prefix_offlink(struct nd_prefix *pr)
mask6.sin6_family = AF_INET6;
mask6.sin6_len = sizeof(sa6);
bcopy(&pr->ndpr_mask, &mask6.sin6_addr, sizeof(struct in6_addr));
- error = rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
- (struct sockaddr *)&mask6, 0, &rt);
+
+ a_failure = 0;
+ for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+ rt = NULL;
+ error = in6_rtrequest(RTM_DELETE, (struct sockaddr *)&sa6, NULL,
+ (struct sockaddr *)&mask6, 0, &rt, fibnum);
+ if (error == 0) {
+ /* report the route deletion to the routing socket. */
+ if (rt != NULL)
+ nd6_rtmsg(RTM_DELETE, rt);
+ } else {
+ /* Save last error to return, see rtinit(). */
+ a_failure = error;
+ }
+ if (rt != NULL) {
+ RTFREE(rt);
+ }
+ }
+ error = a_failure;
if (error == 0) {
pr->ndpr_stateflags &= ~NDPRF_ONLINK;
- /* report the route deletion to the routing socket. */
- if (rt != NULL)
- nd6_rtmsg(RTM_DELETE, rt);
-
/*
* There might be the same prefix on another interface,
* the prefix which could not be on-link just because we have
@@ -1749,10 +1795,6 @@ nd6_prefix_offlink(struct nd_prefix *pr)
if_name(ifp), error));
}
- if (rt != NULL) {
- RTFREE(rt);
- }
-
return (error);
}
@@ -2069,6 +2111,7 @@ void
rt6_flush(struct in6_addr *gateway, struct ifnet *ifp)
{
struct radix_node_head *rnh;
+ u_int fibnum;
int s = splnet();
/* We'll care only link-local addresses */
@@ -2077,13 +2120,16 @@ rt6_flush(struct in6_addr *gateway, struct ifnet *ifp)
return;
}
- rnh = rt_tables_get_rnh(0, AF_INET6);
- if (rnh == NULL)
- return;
+ /* XXX Do we really need to walk any but the default FIB? */
+ for (fibnum = 0; fibnum < rt_numfibs; fibnum++) {
+ rnh = rt_tables_get_rnh(fibnum, AF_INET6);
+ if (rnh == NULL)
+ continue;
- RADIX_NODE_HEAD_LOCK(rnh);
- rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
- RADIX_NODE_HEAD_UNLOCK(rnh);
+ RADIX_NODE_HEAD_LOCK(rnh);
+ rnh->rnh_walktree(rnh, rt6_deleteroute, (void *)gateway);
+ RADIX_NODE_HEAD_UNLOCK(rnh);
+ }
splx(s);
}
@@ -2116,8 +2162,8 @@ rt6_deleteroute(struct radix_node *rn, void *arg)
if ((rt->rt_flags & RTF_HOST) == 0)
return (0);
- return (rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
- rt_mask(rt), rt->rt_flags, 0));
+ return (in6_rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
+ rt_mask(rt), rt->rt_flags, NULL, rt->rt_fibnum));
#undef SIN6
}
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 6c10fc5..d78bf8e 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -582,6 +582,7 @@ rip6_output(m, va_alist)
int
rip6_ctloutput(struct socket *so, struct sockopt *sopt)
{
+ struct inpcb *inp;
int error;
if (sopt->sopt_level == IPPROTO_ICMPV6)
@@ -590,8 +591,17 @@ rip6_ctloutput(struct socket *so, struct sockopt *sopt)
* from protosw?
*/
return (icmp6_ctloutput(so, sopt));
- else if (sopt->sopt_level != IPPROTO_IPV6)
+ else if (sopt->sopt_level != IPPROTO_IPV6) {
+ if (sopt->sopt_level == SOL_SOCKET &&
+ sopt->sopt_name == SO_SETFIB) {
+ inp = sotoinpcb(so);
+ INP_WLOCK(inp);
+ inp->inp_inc.inc_fibnum = so->so_fibnum;
+ INP_WUNLOCK(inp);
+ return (0);
+ }
return (EINVAL);
+ }
error = 0;
diff --git a/sys/netipsec/ipsec_output.c b/sys/netipsec/ipsec_output.c
index 77897ed..38268f7 100644
--- a/sys/netipsec/ipsec_output.c
+++ b/sys/netipsec/ipsec_output.c
@@ -867,7 +867,7 @@ ipsec6_output_tunnel(struct ipsec_output_state *state, struct secpolicy *sp, int
dst6->sin6_family = AF_INET6;
dst6->sin6_len = sizeof(*dst6);
dst6->sin6_addr = ip6->ip6_dst;
- rtalloc(state->ro);
+ rtalloc_ign_fib(state->ro, 0UL, M_GETFIB(m));
}
if (state->ro->ro_rt == NULL) {
V_ip6stat.ip6s_noroute++;
diff --git a/sys/nfs/bootp_subr.c b/sys/nfs/bootp_subr.c
index 1e5e066..b29a0e9 100644
--- a/sys/nfs/bootp_subr.c
+++ b/sys/nfs/bootp_subr.c
@@ -1046,10 +1046,9 @@ bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
clear_sinaddr(&defmask);
/* XXX MRT just table 0 */
error = rtrequest_fib(RTM_ADD,
- (struct sockaddr *) &defdst,
- (struct sockaddr *) gw,
- (struct sockaddr *) &defmask,
- (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, 0);
+ (struct sockaddr *) &defdst, (struct sockaddr *) gw,
+ (struct sockaddr *) &defmask,
+ (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, RT_DEFAULT_FIB);
if (error != 0) {
printf("%s: RTM_ADD, error=%d\n", __func__, error);
return (error);
diff --git a/sys/nfsclient/nfs_vfsops.c b/sys/nfsclient/nfs_vfsops.c
index 58384e8..8f1be3a 100644
--- a/sys/nfsclient/nfs_vfsops.c
+++ b/sys/nfsclient/nfs_vfsops.c
@@ -510,10 +510,10 @@ nfs_mountroot(struct mount *mp)
sin.sin_len = sizeof(sin);
/* XXX MRT use table 0 for this sort of thing */
CURVNET_SET(TD_TO_VNET(td));
- error = rtrequest(RTM_ADD, (struct sockaddr *)&sin,
+ error = rtrequest_fib(RTM_ADD, (struct sockaddr *)&sin,
(struct sockaddr *)&nd->mygateway,
(struct sockaddr *)&mask,
- RTF_UP | RTF_GATEWAY, NULL);
+ RTF_UP | RTF_GATEWAY, NULL, RT_DEFAULT_FIB);
CURVNET_RESTORE();
if (error)
panic("nfs_mountroot: RTM_ADD: %d", error);
diff --git a/usr.bin/netstat/route.c b/usr.bin/netstat/route.c
index 2b4ad2f..996b471 100644
--- a/usr.bin/netstat/route.c
+++ b/usr.bin/netstat/route.c
@@ -113,7 +113,6 @@ typedef union {
static sa_u pt_u;
-int fibnum;
int do_rtent = 0;
struct rtentry rtentry;
struct radix_node rnode;
@@ -148,8 +147,7 @@ routepr(u_long rtree)
{
struct radix_node_head **rnhp, *rnh, head;
size_t intsize;
- int i;
- int numfibs;
+ int fam, fibnum, numfibs;
intsize = sizeof(int);
if (sysctlbyname("net.my_fibnum", &fibnum, &intsize, NULL, 0) == -1)
@@ -181,15 +179,20 @@ routepr(u_long rtree)
if (kread((u_long)(rtree), (char *)(rt_tables), (numfibs *
(AF_MAX+1) * sizeof(struct radix_node_head *))) != 0)
return;
- for (i = 0; i <= AF_MAX; i++) {
+ for (fam = 0; fam <= AF_MAX; fam++) {
int tmpfib;
- if (i != AF_INET)
- tmpfib = 0;
- else
+
+ switch (fam) {
+ case AF_INET6:
+ case AF_INET:
tmpfib = fibnum;
+ break;
+ default:
+ tmpfib = 0;
+ }
rnhp = (struct radix_node_head **)*rt_tables;
/* Calculate the in-kernel address. */
- rnhp += tmpfib * (AF_MAX+1) + i;
+ rnhp += tmpfib * (AF_MAX+1) + fam;
/* Read the in kernel rhn pointer. */
if (kget(rnhp, rnh) != 0)
continue;
@@ -198,16 +201,16 @@ routepr(u_long rtree)
/* Read the rnh data. */
if (kget(rnh, head) != 0)
continue;
- if (i == AF_UNSPEC) {
+ if (fam == AF_UNSPEC) {
if (Aflag && af == 0) {
printf("Netmasks:\n");
p_tree(head.rnh_treetop);
}
- } else if (af == AF_UNSPEC || af == i) {
- size_cols(i, head.rnh_treetop);
- pr_family(i);
+ } else if (af == AF_UNSPEC || af == fam) {
+ size_cols(fam, head.rnh_treetop);
+ pr_family(fam);
do_rtent = 1;
- pr_rthdr(i);
+ pr_rthdr(fam);
p_tree(head.rnh_treetop);
}
}
OpenPOWER on IntegriCloud