Date: Mon, 5 Mar 2012 20:44:54 +0000 (UTC) From: "Bjoern A. Zeeb" <bz@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r232573 - in projects/multi-fibv6/7: contrib/netcat etc etc/rc.d share/man/man4 sys/kern sys/net sys/netinet sys/netinet6 sys/netipsec sys/nfsclient usr.bin/netstat Message-ID: <201203052044.q25Kis57004155@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: bz Date: Mon Mar 5 20:44:54 2012 New Revision: 232573 URL: http://svn.freebsd.org/changeset/base/232573 Log: Initial backport of the multi-FIB IPv6 changes from HEAD. Contrary to stable/[98] and head, stable/7 is still using the rtables to store neighbor information (arp and nd6) and still uses route cloning. This means that a lot more neighbor handling is per-FIB as neighbor entires might expire independently, etc. Sponsored by: Cisco Systems, Inc. Modified: projects/multi-fibv6/7/contrib/netcat/netcat.c projects/multi-fibv6/7/etc/network.subr projects/multi-fibv6/7/etc/rc.d/network_ipv6 projects/multi-fibv6/7/share/man/man4/faith.4 projects/multi-fibv6/7/sys/kern/uipc_socket.c projects/multi-fibv6/7/sys/net/if_faith.c projects/multi-fibv6/7/sys/net/route.c projects/multi-fibv6/7/sys/net/route.h projects/multi-fibv6/7/sys/netinet/ip_fw2.c projects/multi-fibv6/7/sys/netinet/sctp_os_bsd.h projects/multi-fibv6/7/sys/netinet/tcp_subr.c projects/multi-fibv6/7/sys/netinet6/icmp6.c projects/multi-fibv6/7/sys/netinet6/in6.c projects/multi-fibv6/7/sys/netinet6/in6_gif.c projects/multi-fibv6/7/sys/netinet6/in6_ifattach.c projects/multi-fibv6/7/sys/netinet6/in6_rmx.c projects/multi-fibv6/7/sys/netinet6/in6_src.c projects/multi-fibv6/7/sys/netinet6/in6_var.h projects/multi-fibv6/7/sys/netinet6/ip6_forward.c projects/multi-fibv6/7/sys/netinet6/ip6_input.c projects/multi-fibv6/7/sys/netinet6/ip6_output.c projects/multi-fibv6/7/sys/netinet6/ip6_var.h projects/multi-fibv6/7/sys/netinet6/nd6.c projects/multi-fibv6/7/sys/netinet6/nd6.h projects/multi-fibv6/7/sys/netinet6/nd6_nbr.c projects/multi-fibv6/7/sys/netinet6/nd6_rtr.c projects/multi-fibv6/7/sys/netinet6/raw_ip6.c projects/multi-fibv6/7/sys/netipsec/ipsec_output.c projects/multi-fibv6/7/sys/nfsclient/bootp_subr.c projects/multi-fibv6/7/sys/nfsclient/nfs_vfsops.c projects/multi-fibv6/7/usr.bin/netstat/route.c Modified: projects/multi-fibv6/7/contrib/netcat/netcat.c ============================================================================== --- projects/multi-fibv6/7/contrib/netcat/netcat.c Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/contrib/netcat/netcat.c Mon Mar 5 20:44:54 2012 (r232573) @@ -561,8 +561,10 @@ remote_connect(const char *host, const c #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. */ @@ -636,8 +638,11 @@ local_listen(char *host, char *port, str 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)); Modified: projects/multi-fibv6/7/etc/network.subr ============================================================================== --- projects/multi-fibv6/7/etc/network.subr Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/etc/network.subr Mon Mar 5 20:44:54 2012 (r232573) @@ -1005,6 +1005,8 @@ network6_faith_setup() # as the default route when there's no router. network6_default_interface_setup() { + local fibs + # Choose IPv6 default interface if it is not clearly specified. case ${ipv6_default_interface} in '') @@ -1027,17 +1029,35 @@ network6_default_interface_setup() ;; esac + # Get the number of FIBs supported. + fibs=`sysctl -n net.fibs` + : ${fibs:=1} + # Disallow unicast packets without outgoing scope identifiers, # or route such packets to a "default" interface, if it is specified. route add -inet6 fe80:: -prefixlen 10 ::1 -reject case ${ipv6_default_interface} in [Nn][Oo] | '') - route add -inet6 ff02:: -prefixlen 16 ::1 -reject + i=0 + while test ${i} -lt ${fibs}; do + setfib -F ${i} \ + route add -inet6 ff02:: -prefixlen 16 ::1 -reject + i=$((i + 1)) + done ;; *) laddr=`network6_getladdr ${ipv6_default_interface}` + # Only add the laddr route to the default FIB and a reject + # route to all others. + # XXX-BZ is that the right thing with 7.x and route cloning? route add -inet6 ff02:: ${laddr} -prefixlen 16 -interface \ -cloning + i=1 + while test ${i} -lt ${fibs}; do + setfib -F ${i} \ + route add -inet6 ff02:: -prefixlen 16 ::1 -reject + i=$((i + 1)) + done # Disable installing the default interface with the # case net.inet6.ip6.forwarding=0 and Modified: projects/multi-fibv6/7/etc/rc.d/network_ipv6 ============================================================================== --- projects/multi-fibv6/7/etc/rc.d/network_ipv6 Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/etc/rc.d/network_ipv6 Mon Mar 5 20:44:54 2012 (r232573) @@ -41,9 +41,22 @@ start_cmd="network_ipv6_start" network_ipv6_start() { + local _action i fibs + + # get the number of FIBs supported. + fibs=`sysctl -n net.fibs` + : ${fibs:=1} + # disallow "internal" addresses to appear on the wire - route add -inet6 ::ffff:0.0.0.0 -prefixlen 96 ::1 -reject - route add -inet6 ::0.0.0.0 -prefixlen 96 ::1 -reject + i=0 + _action="add" + 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_network_interfaces} in [Aa][Uu][Tt][Oo]) Modified: projects/multi-fibv6/7/share/man/man4/faith.4 ============================================================================== --- projects/multi-fibv6/7/share/man/man4/faith.4 Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/share/man/man4/faith.4 Mon Mar 5 20:44:54 2012 (r232573) @@ -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, Modified: projects/multi-fibv6/7/sys/kern/uipc_socket.c ============================================================================== --- projects/multi-fibv6/7/sys/kern/uipc_socket.c Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/sys/kern/uipc_socket.c Mon Mar 5 20:44:54 2012 (r232573) @@ -362,6 +362,7 @@ socreate(int dom, struct socket **aso, i 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 @@ -2207,12 +2208,13 @@ sosetopt(struct socket *so, struct socko case SO_SETFIB: error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); - if (optval < 0 || optval > rt_numfibs) { + if (optval < 0 || optval >= rt_numfibs) { error = EINVAL; goto bad; } 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 */ Modified: projects/multi-fibv6/7/sys/net/if_faith.c ============================================================================== --- projects/multi-fibv6/7/sys/net/if_faith.c Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/sys/net/if_faith.c Mon Mar 5 20:44:54 2012 (r232573) @@ -334,7 +334,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; Modified: projects/multi-fibv6/7/sys/net/route.c ============================================================================== --- projects/multi-fibv6/7/sys/net/route.c Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/sys/net/route.c Mon Mar 5 20:44:54 2012 (r232573) @@ -91,6 +91,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_INT(_net, OID_AUTO, add_addr_allfibs, CTLFLAG_RW, @@ -164,25 +167,21 @@ route_init(void) rn_init(); /* initialize all zeroes, all ones, mask table */ 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) - */ - dom->dom_rtattach( - (void **)&rt_tables[table][fam], - 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). + */ + dom->dom_rtattach((void **)&rt_tables[table][fam], + dom->dom_rtoffset); } } } @@ -207,7 +206,8 @@ setfib(struct thread *td, struct setfib_ void rtalloc(struct route *ro) { - rtalloc_ign_fib(ro, 0UL, 0); + + rtalloc_ign_fib(ro, 0UL, RT_DEFAULT_FIB); } void @@ -227,7 +227,7 @@ rtalloc_ign(struct route *ro, u_long ign 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); } @@ -257,7 +257,8 @@ rtalloc_ign_fib(struct route *ro, u_long 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 * @@ -274,8 +275,15 @@ rtalloc1_fib(struct sockaddr *dst, int r 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[fibnum][dst->sa_family]; newrt = NULL; /* @@ -470,7 +478,7 @@ rtredirect(struct sockaddr *dst, struct sockaddr *src) { - rtredirect_fib(dst, gateway, netmask, flags, src, 0); + rtredirect_fib(dst, gateway, netmask, flags, src, RT_DEFAULT_FIB); } void @@ -592,7 +600,8 @@ out: int rtioctl(u_long req, caddr_t data) { - return (rtioctl_fib(req, data, 0)); + + return (rtioctl_fib(req, data, RT_DEFAULT_FIB)); } /* @@ -619,7 +628,8 @@ rtioctl_fib(u_long req, caddr_t data, u_ 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 * @@ -708,7 +718,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 @@ -747,7 +759,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)); } int @@ -878,7 +891,8 @@ bad: int rtrequest1(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt) { - return (rtrequest1_fib(req, info, ret_nrt, 0)); + + return (rtrequest1_fib(req, info, ret_nrt, RT_DEFAULT_FIB)); } int @@ -894,8 +908,16 @@ rtrequest1_fib(int req, struct rt_addrin #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 */ @@ -1396,8 +1418,17 @@ rtinit1(struct ifaddr *ifa, int cmd, int 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; @@ -1410,8 +1441,6 @@ rtinit1(struct ifaddr *ifa, int cmd, int startfib = fibnum; endfib = fibnum; } - if (dst->sa_len == 0) - return(EINVAL); /* * If it's a delete, check that if it exists, @@ -1435,9 +1464,7 @@ rtinit1(struct ifaddr *ifa, int cmd, int * 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) { @@ -1516,12 +1543,14 @@ rtinit1(struct ifaddr *ifa, int cmd, int 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 @@ -1531,7 +1560,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; @@ -1539,8 +1568,13 @@ rtinit(struct ifaddr *ifa, int cmd, int dst = ifa->ifa_addr; } - if (dst->sa_family == AF_INET) - fib = -1; + switch (dst->sa_family) { + case AF_INET6: + case AF_INET: + /* We do support multiple FIBs. */ + fib = -1; + break; + } return (rtinit1(ifa, cmd, flags, fib)); } Modified: projects/multi-fibv6/7/sys/net/route.h ============================================================================== --- projects/multi-fibv6/7/sys/net/route.h Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/sys/net/route.h Mon Mar 5 20:44:54 2012 (r232573) @@ -82,6 +82,7 @@ struct rt_metrics { #define RTM_RTTUNIT 1000000 /* units for rtt, rttvar, as units per sec */ #define RTTTOPRHZ(r) ((r) / (RTM_RTTUNIT / PR_SLOWHZ)) +#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. @@ -385,8 +386,10 @@ int rtrequest(int, struct sockaddr *, struct sockaddr *, struct sockaddr *, int, struct rtentry **); int rtrequest1(int, struct rt_addrinfo *, 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 Modified: projects/multi-fibv6/7/sys/netinet/ip_fw2.c ============================================================================== --- projects/multi-fibv6/7/sys/netinet/ip_fw2.c Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/sys/netinet/ip_fw2.c Mon Mar 5 20:44:54 2012 (r232573) @@ -586,7 +586,7 @@ search_ip6_addr_net (struct in6_addr * i } 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; @@ -597,9 +597,8 @@ verify_path6(struct in6_addr *src, struc 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, RTF_CLONING); + in6_rtalloc_ign(&ro, RTF_CLONING, fib); if (ro.ro_rt == NULL) return 0; @@ -2935,7 +2934,7 @@ check_body: #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))); @@ -2947,7 +2946,7 @@ check_body: #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; @@ -2965,7 +2964,8 @@ check_body: #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, Modified: projects/multi-fibv6/7/sys/netinet/sctp_os_bsd.h ============================================================================== --- projects/multi-fibv6/7/sys/netinet/sctp_os_bsd.h Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/sys/netinet/sctp_os_bsd.h Mon Mar 5 20:44:54 2012 (r232573) @@ -437,6 +437,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 */ Modified: projects/multi-fibv6/7/sys/netinet/tcp_subr.c ============================================================================== --- projects/multi-fibv6/7/sys/netinet/tcp_subr.c Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/sys/netinet/tcp_subr.c Mon Mar 5 20:44:54 2012 (r232573) @@ -1580,7 +1580,7 @@ tcp_maxmtu6(struct in_conninfo *inc, int 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, RTF_CLONING); + in6_rtalloc_ign(&sro6, RTF_CLONING, inc->inc_fibnum); } if (sro6.ro_rt != NULL) { ifp = sro6.ro_rt->rt_ifp; Modified: projects/multi-fibv6/7/sys/netinet6/icmp6.c ============================================================================== --- projects/multi-fibv6/7/sys/netinet6/icmp6.c Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/sys/netinet6/icmp6.c Mon Mar 5 20:44:54 2012 (r232573) @@ -341,7 +341,7 @@ icmp6_error(struct mbuf *m, int type, in 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) { @@ -545,7 +545,7 @@ icmp6_input(struct mbuf **mp, int *offp, 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) { @@ -1383,7 +1383,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) { /* @@ -2277,7 +2277,7 @@ icmp6_redirect_input(struct mbuf *m, int 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, M_GETFIB(m)); if (rt) { if (rt->rt_gateway == NULL || rt->rt_gateway->sa_family != AF_INET6) { @@ -2358,14 +2358,15 @@ icmp6_redirect_input(struct mbuf *m, int } /* RFC 2461 8.3 */ - nd6_cache_lladdr(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT, - is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER); + nd6_cache_lladdr_fib(ifp, &redtgt6, lladdr, lladdrlen, ND_REDIRECT, + is_onlink ? ND_REDIRECT_ONLINK : ND_REDIRECT_ROUTER, M_GETFIB(m)); if (!is_onlink) { /* better router case. perform rtredirect. */ /* perform rtredirect */ struct sockaddr_in6 sdst; struct sockaddr_in6 sgw; struct sockaddr_in6 ssrc; + u_int fibnum; bzero(&sdst, sizeof(sdst)); bzero(&sgw, sizeof(sgw)); @@ -2376,9 +2377,11 @@ icmp6_redirect_input(struct mbuf *m, int 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 */ { @@ -2439,7 +2442,7 @@ icmp6_redirect_output(struct mbuf *m0, s src_sa.sin6_family = AF_INET6; src_sa.sin6_len = sizeof(src_sa); src_sa.sin6_addr = sip6->ip6_src; - if (nd6_is_addr_neighbor(&src_sa, ifp) == 0) + if (nd6_is_addr_neighbor_fib(&src_sa, ifp, M_GETFIB(m0)) == 0) goto fail; if (IN6_IS_ADDR_MULTICAST(&sip6->ip6_dst)) goto fail; /* what should we do here? */ @@ -2461,6 +2464,7 @@ icmp6_redirect_output(struct mbuf *m0, s 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); @@ -2540,7 +2544,7 @@ icmp6_redirect_output(struct mbuf *m0, s struct nd_opt_hdr *nd_opt; char *lladdr; - rt_router = nd6_lookup(router_ll6, 0, ifp); + rt_router = nd6_lookup_fib(router_ll6, 0, ifp, M_GETFIB(m)); if (!rt_router) goto nolladdropt; len = sizeof(*nd_opt) + ifp->if_addrlen; Modified: projects/multi-fibv6/7/sys/netinet6/in6.c ============================================================================== --- projects/multi-fibv6/7/sys/netinet6/in6.c Mon Mar 5 20:43:06 2012 (r232572) +++ projects/multi-fibv6/7/sys/netinet6/in6.c Mon Mar 5 20:44:54 2012 (r232573) @@ -138,7 +138,7 @@ int (*faithprefix_p)(struct in6_addr *); * This routine does actual work. */ static void -in6_ifloop_request(int cmd, struct ifaddr *ifa) +in6_ifloop_request(int cmd, struct ifaddr *ifa, u_int fibnum) { struct sockaddr_in6 all1_sa; struct rtentry *nrt = NULL; @@ -158,8 +158,9 @@ in6_ifloop_request(int cmd, struct ifadd * (probably implicitly) set nd6_rtrequest() to ifa->ifa_rtrequest, * which changes the outgoing interface to the loopback interface. */ - e = rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr, - (struct sockaddr *)&all1_sa, RTF_UP|RTF_HOST|RTF_LLINFO, &nrt); + e = in6_rtrequest(cmd, ifa->ifa_addr, ifa->ifa_addr, + (struct sockaddr *)&all1_sa, RTF_UP|RTF_HOST|RTF_LLINFO, &nrt, + fibnum); if (e != 0) { /* XXX need more descriptive message */ @@ -190,7 +191,7 @@ in6_ifloop_request(int cmd, struct ifadd nrt->rt_ifa = ifa; } - rt_newaddrmsg(cmd, ifa, e, nrt); + rt_newaddrmsg_fib(cmd, ifa, e, nrt, fibnum); if (cmd == RTM_DELETE) RTFREE_LOCKED(nrt); else { @@ -213,15 +214,18 @@ in6_ifaddloop(struct ifaddr *ifa) { struct rtentry *rt; int need_loop; + u_int fibnum; /* If there is no loopback entry, allocate one. */ - rt = rtalloc1(ifa->ifa_addr, 0, 0); - need_loop = (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 || - (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0); - if (rt) - RTFREE_LOCKED(rt); - if (need_loop) - in6_ifloop_request(RTM_ADD, ifa); + for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { + rt = in6_rtalloc1(ifa->ifa_addr, 0, 0, fibnum); + need_loop = (rt == NULL || (rt->rt_flags & RTF_HOST) == 0 || + (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0); + if (rt) + RTFREE_LOCKED(rt); + if (need_loop) + in6_ifloop_request(RTM_ADD, ifa, fibnum); + } } /* @@ -234,6 +238,7 @@ in6_ifremloop(struct ifaddr *ifa) struct in6_ifaddr *ia; struct rtentry *rt; int ia_count = 0; + u_int fibnum; /* * Some of BSD variants do not remove cloned routes @@ -267,12 +272,14 @@ in6_ifremloop(struct ifaddr *ifa) * a subnet-router anycast address on an interface attahced * to a shared medium. */ - rt = rtalloc1(ifa->ifa_addr, 0, 0); - if (rt != NULL) { + for (fibnum = 0; fibnum < rt_numfibs; fibnum++) { + rt = in6_rtalloc1(ifa->ifa_addr, 0, 0, fibnum); + if (rt == NULL) + continue; if ((rt->rt_flags & RTF_HOST) != 0 && (rt->rt_ifp->if_flags & IFF_LOOPBACK) != 0) { RTFREE_LOCKED(rt); - in6_ifloop_request(RTM_DELETE, ifa); + in6_ifloop_request(RTM_DELETE, ifa, fibnum); } else RT_UNLOCK(rt); } @@ -331,6 +338,11 @@ in6_control(struct socket *so, u_long cm 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); } @@ -367,7 +379,7 @@ in6_control(struct socket *so, u_long cm case SIOCGPRLST_IN6: case SIOCGNBRINFO_IN6: case SIOCGDEFIFACE_IN6: - return (nd6_ioctl(cmd, data, ifp)); + return (nd6_ioctl_fib(cmd, data, ifp, so->so_fibnum)); } switch (cmd) { @@ -789,6 +801,217 @@ in6_control(struct socket *so, u_long cm } /* + * 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) { + if (memcmp(&mltaddr.sin6_addr, + &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, + MLTMASK_LEN)) { + RTFREE_LOCKED(rt); + rt = NULL; + } + } + if (rt == NULL) { + /* XXX: we need RTF_CLONING to fake nd6_rtrequest */ + error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, + (struct sockaddr *)&ia->ia_addr, + (struct sockaddr *)&mltmask, RTF_UP | RTF_CLONING, + (struct rtentry **)0, RT_DEFAULT_FIB); + if (error) + goto cleanup; + } else + RTFREE_LOCKED(rt); + + /* + * 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 | RTF_CLONING, + (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) { + 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. + */ +#define hostnamelen strlen(hostname) + 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, hostname, hostnamelen, &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); + } +#undef hostnamelen + + /* + * 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 | RTF_CLONING, + (struct rtentry **)0, RT_DEFAULT_FIB); + if (error) + goto cleanup; + } else + RTFREE_LOCKED(rt); + + /* 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 | RTF_CLONING, + (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. * This function is separated from in6_control(). @@ -802,9 +1025,7 @@ in6_update_ifa(struct ifnet *ifp, struct struct in6_ifaddr *oia; 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]; @@ -1052,226 +1273,14 @@ in6_update_ifa(struct ifnet *ifp, struct /* 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"); + error = in6_update_ifa_join_mc(ifp, ifra, ia, flags, &in6m_sol); + if (error) 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. - * [draft-ietf-ipv6-rfc2462bis-02.txt] - */ - 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)); - in6_purgeaddr((struct ifaddr *)ia); - return (error); - } - 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) */ - *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201203052044.q25Kis57004155>