From owner-svn-src-projects@FreeBSD.ORG Tue Nov 4 15:40:01 2014 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 150D06BF; Tue, 4 Nov 2014 15:40:01 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id F3109324; Tue, 4 Nov 2014 15:40:00 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id sA4Fe0CD046425; Tue, 4 Nov 2014 15:40:00 GMT (envelope-from melifaro@FreeBSD.org) Received: (from melifaro@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id sA4Fdva7046350; Tue, 4 Nov 2014 15:39:57 GMT (envelope-from melifaro@FreeBSD.org) Message-Id: <201411041539.sA4Fdva7046350@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: melifaro set sender to melifaro@FreeBSD.org using -f From: "Alexander V. Chernikov" Date: Tue, 4 Nov 2014 15:39:57 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r274089 - in projects/routing/sys: contrib/ipfilter/netinet dev/cxgbe/tom net netgraph netinet netinet6 netipsec netpfil/ipfw netpfil/pf X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 04 Nov 2014 15:40:01 -0000 Author: melifaro Date: Tue Nov 4 15:39:56 2014 New Revision: 274089 URL: https://svnweb.freebsd.org/changeset/base/274089 Log: Convert netinet6/ to use new routing API. * Remove &ifpp from ip6_output() in favor of ri->ri_nh_info * Provide different wrappers to in6_selectsrc: Currently it is used by 2 differenct type of customers: - socket-based one, which all are unsure about provided address scope and - in-kernel ones (ND code mostly), which don't have any sockets, options, crededentials, etc. So, we provide two different wrappers to in6_selectsrc() returning select source. * Make different versions of selectroute(): Currenly selectroute() is used in two scenarios: - SAS, via in6_selecsrc() -> in6_selectif() -> selectroute() - output, via in6_output -> wrapper -> selectroute() Provide different versions for each customer: - fib6_lookup_nh_basic()-based in6_selectif() which is capable of returning interface only, without MTU/NHOP/L2 calculations - full-blown fib6_selectroute() with cached route/multipath/ MTU/L2 * Stop using routing table for link-local address lookups * Add in6_ifawithifp_lla() to make for-us check faster for link-local * Add in6_splitscope / in6_setllascope for faster embed/deembed scopes Modified: projects/routing/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c projects/routing/sys/dev/cxgbe/tom/t4_listen.c projects/routing/sys/net/rt_nhops.c projects/routing/sys/net/rt_nhops.h projects/routing/sys/netgraph/ng_ipfw.c projects/routing/sys/netinet/ip_carp.c projects/routing/sys/netinet/ip_divert.c projects/routing/sys/netinet/ip_output.c projects/routing/sys/netinet/sctp_os_bsd.h projects/routing/sys/netinet/tcp_offload.c projects/routing/sys/netinet/tcp_output.c projects/routing/sys/netinet/tcp_subr.c projects/routing/sys/netinet/tcp_syncache.c projects/routing/sys/netinet/tcp_timewait.c projects/routing/sys/netinet6/icmp6.c projects/routing/sys/netinet6/in6.c projects/routing/sys/netinet6/in6.h projects/routing/sys/netinet6/in6_gif.c projects/routing/sys/netinet6/in6_pcb.c projects/routing/sys/netinet6/in6_src.c projects/routing/sys/netinet6/ip6_mroute.c projects/routing/sys/netinet6/ip6_output.c projects/routing/sys/netinet6/ip6_var.h projects/routing/sys/netinet6/mld6.c projects/routing/sys/netinet6/nd6_nbr.c projects/routing/sys/netinet6/raw_ip6.c projects/routing/sys/netinet6/scope6.c projects/routing/sys/netinet6/scope6_var.h projects/routing/sys/netinet6/udp6_usrreq.c projects/routing/sys/netipsec/ipsec_output.c projects/routing/sys/netpfil/ipfw/ip_dn_io.c projects/routing/sys/netpfil/ipfw/ip_fw2.c projects/routing/sys/netpfil/ipfw/ip_fw_dynamic.c projects/routing/sys/netpfil/pf/pf.c Modified: projects/routing/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c ============================================================================== --- projects/routing/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c Tue Nov 4 15:39:56 2014 (r274089) @@ -750,7 +750,7 @@ ipf_fastroute(m0, mpp, fin, fdp) * currently "to " and "to :ip#" are not supported * for IPv6 */ - return ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); + return ip6_output(m, NULL, NULL, 0, NULL, NULL); } #endif Modified: projects/routing/sys/dev/cxgbe/tom/t4_listen.c ============================================================================== --- projects/routing/sys/dev/cxgbe/tom/t4_listen.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/dev/cxgbe/tom/t4_listen.c Tue Nov 4 15:39:56 2014 (r274089) @@ -1140,7 +1140,7 @@ get_l2te_for_nexthop(struct port_info *p } /* TODO: Multipath */ - if (fib6_lookup_nh_ext(inc->inc_fibnum, inc->inc6_faddr, + if (fib6_lookup_nh_ext(inc->inc_fibnum, &inc->inc6_faddr, 0, 0, 0, &nhu.u.nh6) != 0) return (NULL); ((struct sockaddr_in6 *)dst)->sin6_addr = nhu.u.nh6.nh_addr; Modified: projects/routing/sys/net/rt_nhops.c ============================================================================== --- projects/routing/sys/net/rt_nhops.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/net/rt_nhops.c Tue Nov 4 15:39:56 2014 (r274089) @@ -66,6 +66,10 @@ #include #include #include +#include +#include + +#include #include #include @@ -117,11 +121,20 @@ static void fib4_rte_to_nh_extended(stru static void fib4_rte_to_nh_basic(struct rtentry *rte, struct in_addr dst, struct nhop4_basic *pnh4); #endif -#ifdef INET -static void fib6_rte_to_nh_extended(struct rtentry *rte, struct in6_addr dst, +#ifdef INET6 +static void fib6_rte_to_nh_extended(struct rtentry *rte, struct in6_addr *dst, struct nhop6_extended *pnh6); -static void fib6_rte_to_nh_basic(struct rtentry *rte, struct in6_addr dst, +static void fib6_rte_to_nh_basic(struct rtentry *rte, struct in6_addr *dst, struct nhop6_basic *pnh6); +static int fib6_storelladdr(struct ifnet *ifp, struct in6_addr *dst, + int mm_flags, u_char *desten); +static uint16_t fib6_get_ifa(struct rtentry *rte); +static int fib6_lla_to_nh_basic(struct in6_addr *dst, uint32_t scopeid, + struct nhop6_basic *pnh6); +static int fib6_lla_to_nh_extended(struct in6_addr *dst, uint32_t scopeid, + struct nhop6_extended *pnh6); +static int fib6_lla_to_nh(struct in6_addr *dst, uint32_t scopeid, + struct nhop_prepend *nh, struct ifnet **lifp); #endif MALLOC_DEFINE(M_RTFIB, "rtfib", "routing fwd"); @@ -292,8 +305,11 @@ fib4_lookup_prepend(uint32_t fibnum, str * Currently all we have is rte ifp. * Simply use it. */ - lifp = rte->rt_ifp; + /* Save interface address ifp */ + lifp = rte->rt_ifa->ifa_ifp; + nh->aifp_idx = lifp->if_index; /* Save both logical and transmit interface indexes */ + lifp = rte->rt_ifp; nh->lifp_idx = lifp->if_index; nh->i.ifp_idx = nh->lifp_idx; @@ -407,6 +423,7 @@ fib4_rte_to_nh_basic(struct rtentry *rte gw = (struct sockaddr_in *)rt_key(rte); if (gw->sin_addr.s_addr == 0) pnh4->nh_flags |= NHF_DEFAULT; + /* XXX: Set RTF_BROADCAST if GW address is broadcast */ } static void @@ -428,6 +445,7 @@ fib4_rte_to_nh_extended(struct rtentry * gw = (struct sockaddr_in *)rt_key(rte); if (gw->sin_addr.s_addr == 0) pnh4->nh_flags |= NHF_DEFAULT; + /* XXX: Set RTF_BROADCAST if GW address is broadcast */ ia = ifatoia(rte->rt_ifa); pnh4->nh_src = IA_SIN(ia)->sin_addr; @@ -561,19 +579,335 @@ fib6_choose_prepend(uint32_t fibnum, str */ } +/* + * Temporary function to copy ethernet address from valid lle + */ +static int +fib6_storelladdr(struct ifnet *ifp, struct in6_addr *dst, int mm_flags, + u_char *desten) +{ + struct llentry *ln; + struct sockaddr_in6 dst_sa; + + if (mm_flags & M_MCAST) { + ETHER_MAP_IPV6_MULTICAST(&dst, desten); + return (0); + } + + memset(&dst_sa, 0, sizeof(dst_sa)); + dst_sa.sin6_family = AF_INET6; + dst_sa.sin6_len = sizeof(dst_sa); + dst_sa.sin6_addr = *dst; + dst_sa.sin6_scope_id = ifp->if_index; + + + /* + * the entry should have been created in nd6_store_lladdr + */ + IF_AFDATA_RLOCK(ifp); + ln = lla_lookup(LLTABLE6(ifp), 0, (struct sockaddr *)&dst_sa); + + /* + * Perform fast path for the following cases: + * 1) lle state is REACHABLE + * 2) lle state is DELAY (NS message sentNS message sent) + * + * Every other case involves lle modification, so we handle + * them separately. + */ + if (ln == NULL || (ln->ln_state != ND6_LLINFO_REACHABLE && + ln->ln_state != ND6_LLINFO_DELAY)) { + if (ln != NULL) + LLE_RUNLOCK(ln); + IF_AFDATA_RUNLOCK(ifp); + return (1); + } + bcopy(&ln->ll_addr, desten, ifp->if_addrlen); + LLE_RUNLOCK(ln); + IF_AFDATA_RUNLOCK(ifp); + + return (0); +} + +int +fib6_lookup_prepend(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid, + struct mbuf *m, struct nhop_prepend *nh, struct nhop6_extended *nh_ext) +{ + struct radix_node_head *rnh; + struct radix_node *rn; + struct sockaddr_in6 sin6, *gw_sa; + struct in6_addr gw6; + struct rtentry *rte; + struct ifnet *lifp; + struct ether_header *eh; + uint32_t flags; + int error; + + if (IN6_IS_SCOPE_LINKLOCAL(dst)) { + /* Do not lookup link-local addresses in rtable */ + error = fib6_lla_to_nh(dst, scopeid, nh, &lifp); + if (error != 0) + return (error); + /* */ + gw6 = *dst; + goto do_l2; + } + + + KASSERT((fibnum < rt_numfibs), ("fib6_lookup_prepend: bad fibnum")); + rnh = rt_tables_get_rnh(fibnum, AF_INET6); + if (rnh == NULL) + return (ENOENT); + + /* Prepare lookup key */ + memset(&sin6, 0, sizeof(sin6)); + sin6.sin6_len = sizeof(struct sockaddr_in6); + sin6.sin6_addr = *dst; + sin6.sin6_scope_id = scopeid; + sa6_embedscope(&sin6, 0); + + + RADIX_NODE_HEAD_RLOCK(rnh); + rn = rnh->rnh_matchaddr((void *)&sin6, rnh); + rte = RNTORT(rn); + if (rn == NULL || ((rn->rn_flags & RNF_ROOT) != 0) || + RT_LINK_IS_UP(rte->rt_ifp) == 0) { + RADIX_NODE_HEAD_RUNLOCK(rnh); + return (EHOSTUNREACH); + } + + /* Explicitly zero nexthop */ + memset(nh, 0, sizeof(*nh)); + flags = 0; + nh->nh_mtu = min(rte->rt_mtu, IN6_LINKMTU(rte->rt_ifp)); + if (rte->rt_flags & RTF_GATEWAY) { + gw_sa = (struct sockaddr_in6 *)rte->rt_gateway; + gw6 = gw_sa->sin6_addr; + in6_clearscope(&gw6); + } else + gw6 = *dst; + /* Set flags */ + flags = fib_rte_to_nh_flags(rte->rt_flags); + gw_sa = (struct sockaddr_in6 *)rt_key(rte); + if (IN6_IS_ADDR_UNSPECIFIED(&gw_sa->sin6_addr)) + flags |= NHF_DEFAULT; + + /* + * TODO: nh L2/L3 resolve. + * Currently all we have is rte ifp. + * Simply use it. + */ + /* Save interface address ifp */ + nh->aifp_idx = fib6_get_ifa(rte); + /* Save both logical and transmit interface indexes */ + lifp = rte->rt_ifp; + nh->lifp_idx = lifp->if_index; + nh->i.ifp_idx = nh->lifp_idx; + + RADIX_NODE_HEAD_RUNLOCK(rnh); + + nh->nh_flags = flags; +do_l2: + /* + * Try to lookup L2 info. + * Do this using separate LLE locks. + * TODO: move this under radix lock. + */ + if (lifp->if_type == IFT_ETHER) { + eh = (struct ether_header *)nh->d.data; + + /* + * Fill in ethernet header. + * It should be already presented if we're + * sending data via known gateway. + */ + error = fib6_storelladdr(lifp, &gw6, m ? m->m_flags : 0, + eh->ether_dhost); + if (error == 0) { + memcpy(&eh->ether_shost, IF_LLADDR(lifp), ETHER_ADDR_LEN); + eh->ether_type = htons(ETHERTYPE_IPV6); + nh->nh_count = ETHER_HDR_LEN; + return (0); + } + } + + /* Notify caller that no L2 info is linked */ + nh->nh_count = 0; + nh->nh_flags |= NHF_L2_INCOMPLETE; + /* ..And save gateway address */ + nh->d.gw6 = gw6; + return (0); +} + +int +fib6_sendmbuf(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m, + struct nhop_prepend *nh) +{ + int error; + + if (nh != NULL && (nh->nh_flags & NHF_L2_INCOMPLETE) == 0) { + + /* + * Fast path case. Most packets should + * be sent from here. + * TODO: Make special ifnet + * 'if_output_frame' handler for that. + */ + struct route_compat rc; + struct ether_header *eh; + rc.ro_flags = AF_INET6 << 8 | RT_NHOP; + rc.ro_nh = nh; + + M_PREPEND(m, nh->nh_count, M_NOWAIT); + if (m == NULL) + return (ENOBUFS); + eh = mtod(m, struct ether_header *); + memcpy(eh, nh->d.data, nh->nh_count); + error = (*ifp->if_output)(ifp, m, + NULL, (struct route *)&rc); + } else { + /* We need to perform ND lookup */ + struct sockaddr_in6 gw_out; + + memset(&gw_out, 0, sizeof(gw_out)); + gw_out.sin6_family = AF_INET6; + gw_out.sin6_len = sizeof(gw_out); + gw_out.sin6_addr = nh->d.gw6; + gw_out.sin6_scope_id = ifp->if_index; + sa6_embedscope(&gw_out, 0); + + error = nd6_output(ifp, origifp, m, &gw_out, NULL); + } + + return (error); +} + +static uint16_t +fib6_get_ifa(struct rtentry *rte) +{ + struct ifnet *ifp; + struct sockaddr_dl *sdl; + + ifp = rte->rt_ifp; + if ((ifp->if_flags & IFF_LOOPBACK) && + rte->rt_gateway->sa_family == AF_LINK) { + sdl = (struct sockaddr_dl *)rte->rt_gateway; + return (sdl->sdl_index); + } + + return (ifp->if_index); +#if 0 + /* IPv6 case */ + /* Alternative way to get interface address ifp */ + /* + * Adjust the "outgoing" interface. If we're going to loop + * the packet back to ourselves, the ifp would be the loopback + * interface. However, we'd rather know the interface associated + * to the destination address (which should probably be one of + * our own addresses.) + */ + if (rt) { + if ((rt->rt_ifp->if_flags & IFF_LOOPBACK) && + (rt->rt_gateway->sa_family == AF_LINK)) + *retifp = + ifnet_byindex(((struct sockaddr_dl *) + rt->rt_gateway)->sdl_index); + } + /* IPv4 case */ + //pnh6->nh_ifp = rte->rt_ifa->ifa_ifp; +#endif +} + +static int +fib6_lla_to_nh_basic(struct in6_addr *dst, uint32_t scopeid, + struct nhop6_basic *pnh6) +{ + struct ifnet *ifp; + + ifp = ifnet_byindex_locked(scopeid); + if (ifp == NULL) + return (ENOENT); + + /* Do explicit nexthop zero unless we're copying it */ + memset(pnh6, 0, sizeof(*pnh6)); + + pnh6->nh_ifp = ifp; + pnh6->nh_mtu = IN6_LINKMTU(ifp); + /* No flags set */ + pnh6->nh_addr = *dst; + + return (0); +} + +static int +fib6_lla_to_nh_extended(struct in6_addr *dst, uint32_t scopeid, + struct nhop6_extended *pnh6) +{ + struct ifnet *ifp; + + ifp = ifnet_byindex_locked(scopeid); + if (ifp == NULL) + return (ENOENT); + + /* Do explicit nexthop zero unless we're copying it */ + memset(pnh6, 0, sizeof(*pnh6)); + + pnh6->nh_ifp = ifp; + pnh6->nh_mtu = IN6_LINKMTU(ifp); + /* No flags set */ + pnh6->nh_addr = *dst; + + return (0); +} + +static int +fib6_lla_to_nh(struct in6_addr *dst, uint32_t scopeid, + struct nhop_prepend *nh, struct ifnet **lifp) +{ + struct ifnet *ifp; + + ifp = ifnet_byindex_locked(scopeid); + if (ifp == NULL) + return (ENOENT); + + /* Do explicit nexthop zero unless we're copying it */ + memset(nh, 0, sizeof(*nh)); + /* No flags set */ + nh->nh_mtu = IN6_LINKMTU(ifp); + + /* Save lifp */ + *lifp = ifp; + + nh->aifp_idx = scopeid; + nh->lifp_idx = scopeid; + /* Check id this is for-us address */ + if (in6_ifawithifp_lla(ifp, dst)) { + if ((ifp = V_loif) != NULL) + nh->lifp_idx = ifp->if_index; + } + + return (0); +} + + static void -fib6_rte_to_nh_basic(struct rtentry *rte, struct in6_addr dst, +fib6_rte_to_nh_basic(struct rtentry *rte, struct in6_addr *dst, struct nhop6_basic *pnh6) { struct sockaddr_in6 *gw; - pnh6->nh_ifp = rte->rt_ifa->ifa_ifp; - pnh6->nh_mtu = min(rte->rt_mtu, rte->rt_ifp->if_mtu); + /* Do explicit nexthop zero unless we're copying it */ + memset(pnh6, 0, sizeof(*pnh6)); + + pnh6->nh_ifp = ifnet_byindex(fib6_get_ifa(rte)); + + pnh6->nh_mtu = min(rte->rt_mtu, IN6_LINKMTU(rte->rt_ifp)); if (rte->rt_flags & RTF_GATEWAY) { gw = (struct sockaddr_in6 *)rte->rt_gateway; pnh6->nh_addr = gw->sin6_addr; + in6_clearscope(&pnh6->nh_addr); } else - pnh6->nh_addr = dst; + pnh6->nh_addr = *dst; /* Set flags */ pnh6->nh_flags = fib_rte_to_nh_flags(rte->rt_flags); gw = (struct sockaddr_in6 *)rt_key(rte); @@ -582,19 +916,23 @@ fib6_rte_to_nh_basic(struct rtentry *rte } static void -fib6_rte_to_nh_extended(struct rtentry *rte, struct in6_addr dst, +fib6_rte_to_nh_extended(struct rtentry *rte, struct in6_addr *dst, struct nhop6_extended *pnh6) { struct sockaddr_in6 *gw; struct in6_ifaddr *ia; - pnh6->nh_ifp = rte->rt_ifa->ifa_ifp; - pnh6->nh_mtu = min(rte->rt_mtu, rte->rt_ifp->if_mtu); + /* Do explicit nexthop zero unless we're copying it */ + memset(pnh6, 0, sizeof(*pnh6)); + + pnh6->nh_ifp = ifnet_byindex(fib6_get_ifa(rte)); + pnh6->nh_mtu = min(rte->rt_mtu, IN6_LINKMTU(rte->rt_ifp)); if (rte->rt_flags & RTF_GATEWAY) { gw = (struct sockaddr_in6 *)rte->rt_gateway; pnh6->nh_addr = gw->sin6_addr; + in6_clearscope(&pnh6->nh_addr); } else - pnh6->nh_addr = dst; + pnh6->nh_addr = *dst; /* Set flags */ pnh6->nh_flags = fib_rte_to_nh_flags(rte->rt_flags); gw = (struct sockaddr_in6 *)rt_key(rte); @@ -602,18 +940,22 @@ fib6_rte_to_nh_extended(struct rtentry * pnh6->nh_flags |= NHF_DEFAULT; ia = ifatoia6(rte->rt_ifa); - pnh6->nh_src = IA6_SIN6(ia)->sin6_addr; } int -fib6_lookup_nh_basic(uint32_t fibnum, struct in6_addr dst, uint32_t flowid, - struct nhop6_basic *pnh6) +fib6_lookup_nh_basic(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid, + uint32_t flowid, struct nhop6_basic *pnh6) { struct radix_node_head *rnh; struct radix_node *rn; struct sockaddr_in6 sin6; struct rtentry *rte; + if (IN6_IS_SCOPE_LINKLOCAL(dst)) { + /* Do not lookup link-local addresses in rtable */ + return (fib6_lla_to_nh_basic(dst, scopeid, pnh6)); + } + KASSERT((fibnum < rt_numfibs), ("fib6_lookup_nh_basic: bad fibnum")); rnh = rt_tables_get_rnh(fibnum, AF_INET6); if (rnh == NULL) @@ -621,7 +963,9 @@ fib6_lookup_nh_basic(uint32_t fibnum, st /* Prepare lookup key */ memset(&sin6, 0, sizeof(sin6)); - sin6.sin6_addr = dst; + sin6.sin6_addr = *dst; + sin6.sin6_scope_id = scopeid; + sa6_embedscope(&sin6, 0); RADIX_NODE_HEAD_RLOCK(rnh); rn = rnh->rnh_matchaddr((void *)&sin6, rnh); @@ -649,7 +993,7 @@ fib6_lookup_nh_basic(uint32_t fibnum, st * - mtu from logical transmit interface will be returned. */ int -fib6_lookup_nh_ext(uint32_t fibnum, struct in6_addr dst, uint32_t scopeid, +fib6_lookup_nh_ext(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid, uint32_t flowid, uint32_t flags, struct nhop6_extended *pnh6) { struct radix_node_head *rnh; @@ -657,6 +1001,12 @@ fib6_lookup_nh_ext(uint32_t fibnum, stru struct sockaddr_in6 sin6; struct rtentry *rte; + if (IN6_IS_SCOPE_LINKLOCAL(dst)) { + /* Do not lookup link-local addresses in rtable */ + /* XXX: Do lwref on egress ifp */ + return (fib6_lla_to_nh_extended(dst, scopeid, pnh6)); + } + KASSERT((fibnum < rt_numfibs), ("fib4_lookup_nh_ext: bad fibnum")); rnh = rt_tables_get_rnh(fibnum, AF_INET6); if (rnh == NULL) @@ -665,7 +1015,9 @@ fib6_lookup_nh_ext(uint32_t fibnum, stru /* Prepare lookup key */ memset(&sin6, 0, sizeof(sin6)); sin6.sin6_len = sizeof(struct sockaddr_in6); - sin6.sin6_addr = dst; + sin6.sin6_addr = *dst; + sin6.sin6_scope_id = scopeid; + sa6_embedscope(&sin6, 0); RADIX_NODE_HEAD_RLOCK(rnh); rn = rnh->rnh_matchaddr((void *)&sin6, rnh); Modified: projects/routing/sys/net/rt_nhops.h ============================================================================== --- projects/routing/sys/net/rt_nhops.h Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/net/rt_nhops.h Tue Nov 4 15:39:56 2014 (r274089) @@ -74,7 +74,8 @@ struct nhop_prepend { uint16_t ifp_idx; /* Transmit interface index */ uint16_t nhop_idx; /* L2 multipath nhop index */ } i; - uint16_t spare1[3]; + uint16_t aifp_idx; /* Interface address index */ + uint16_t spare1[2]; union { char data[MAX_PREPEND_LEN]; /* data to prepend */ #ifdef INET @@ -102,6 +103,7 @@ struct nhop_prepend { #define NH_LIFP(nh) ifnet_byindex_locked((nh)->lifp_idx) #define NH_TIFP(nh) ifnet_byindex_locked((nh)->i.ifp_idx) +#define NH_AIFP(nh) ifnet_byindex_locked((nh)->aifp_idx) /* L2/L3 recursive nexthop */ struct nhop_multi { @@ -173,7 +175,6 @@ struct nhop6_extended { uint16_t nh_flags; /* nhop flags */ uint8_t spare[4]; struct in6_addr nh_addr; /* GW/DST IPv6 address */ - struct in6_addr nh_src; /* default source IPv6 address */ uint64_t spare2[2]; }; @@ -186,9 +187,10 @@ struct nhopu_extended { struct route_info { struct nhop_prepend *ri_nh; /* Desired nexthop to use */ - struct nhop64_basic *ri_nh_info; /* Get selected route info */ - uint16_t ri_mtu; - uint16_t spare[3]; + struct nhopu_basic *ri_nh_info; /* Get selected route info */ + uint16_t ri_mtu; /* Get selected route MTU */ + uint16_t spare; + uint32_t scopeid; /* Desired scope id to use */ }; struct route_compat { @@ -206,9 +208,9 @@ void fib4_free_nh_ext(uint32_t fibnum, s #define NHOP_LOOKUP_REF 0x01 -int fib6_lookup_nh_basic(uint32_t fibnum, struct in6_addr dst, uint32_t flowid, - struct nhop6_basic *pnh6); -int fib6_lookup_nh_ext(uint32_t fibnum, struct in6_addr dst, +int fib6_lookup_nh_basic(uint32_t fibnum, struct in6_addr *dst, + uint32_t scopeid, uint32_t flowid, struct nhop6_basic *pnh6); +int fib6_lookup_nh_ext(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid, uint32_t flowid, uint32_t flags, struct nhop6_extended *pnh6); void fib6_free_nh_ext(uint32_t fibnum, struct nhop6_extended *pnh6); @@ -228,6 +230,11 @@ int fib4_sendmbuf(struct ifnet *ifp, str void fib6_free_nh_prepend(uint32_t fibnum, struct nhop_prepend *nh); void fib6_choose_prepend(uint32_t fibnum, struct nhop_prepend *nh_src, uint32_t flowid, struct nhop_prepend *nh, struct nhop6_extended *nh_ext); +int fib6_lookup_prepend(uint32_t fibnum, struct in6_addr *dst, uint32_t scopeid, + struct mbuf *m, struct nhop_prepend *nh, struct nhop6_extended *nh_ext); + +int fib6_sendmbuf(struct ifnet *ifp, struct ifnet *origifp, struct mbuf *m, + struct nhop_prepend *nh); #define FWD_INET 0 #define FWD_INET6 1 Modified: projects/routing/sys/netgraph/ng_ipfw.c ============================================================================== --- projects/routing/sys/netgraph/ng_ipfw.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/netgraph/ng_ipfw.c Tue Nov 4 15:39:56 2014 (r274089) @@ -271,8 +271,7 @@ ng_ipfw_rcvdata(hook_p hook, item_p item #endif #ifdef INET6 case IPV6_VERSION >> 4: - return (ip6_output(m, NULL, NULL, 0, NULL, - NULL, NULL)); + return (ip6_output(m, NULL, NULL, 0, NULL, NULL)); #endif } } Modified: projects/routing/sys/netinet/ip_carp.c ============================================================================== --- projects/routing/sys/netinet/ip_carp.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/netinet/ip_carp.c Tue Nov 4 15:39:56 2014 (r274089) @@ -930,7 +930,7 @@ carp_send_ad_locked(struct carp_softc *s CARPSTATS_INC(carps_opackets6); carp_send_ad_error(sc, ip6_output(m, NULL, NULL, 0, - &sc->sc_carpdev->if_carp->cif_im6o, NULL, NULL)); + &sc->sc_carpdev->if_carp->cif_im6o, NULL)); } #endif /* INET6 */ Modified: projects/routing/sys/netinet/ip_divert.c ============================================================================== --- projects/routing/sys/netinet/ip_divert.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/netinet/ip_divert.c Tue Nov 4 15:39:56 2014 (r274089) @@ -456,7 +456,7 @@ div_output(struct socket *so, struct mbu break; #ifdef INET6 case IPV6_VERSION >> 4: - error = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); + error = ip6_output(m, NULL, NULL, 0, NULL, NULL); break; #endif } Modified: projects/routing/sys/netinet/ip_output.c ============================================================================== --- projects/routing/sys/netinet/ip_output.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/netinet/ip_output.c Tue Nov 4 15:39:56 2014 (r274089) @@ -110,9 +110,13 @@ extern struct protosw inetsw[]; * header (with len, off, ttl, proto, tos, src, dst). * The mbuf chain containing the packet will be freed. * The mbuf opt, if present, will not be freed. - * If route ro is present and has ro_rt initialized, route lookup would be - * skipped and ro->ro_rt would be used. If ro is present but ro->ro_rt is NULL, - * then result of route lookup is stored in ro->ro_rt. + * + * If @ri is present: + * - if ri->ri_nh is not null, route will be calculated using ri_nh. + * - if ri->ri_nh_info is set, nhop4_basic route info will be stored on + * successful transmit (error=0). + * - ri->ri_mtu will be set if packet fails to be transmitted due to MTU + * issues * * In the IP forwarding case, the packet will arrive with options already * inserted, so must have a NULL opt pointer. @@ -364,21 +368,12 @@ again: nh = &local_nh; ifp = NH_LIFP(nh); mtu = nh->nh_mtu; - if (nh->nh_flags & (RTF_HOST|RTF_GATEWAY)) { - /* XXX: Set RTF_BROADCAST if GW address is broadcast */ + if (nh->nh_flags & (RTF_HOST|RTF_GATEWAY)) isbroadcast = (nh->nh_flags & RTF_BROADCAST); - } else + else isbroadcast = in_broadcast(dst, ifp); } - /* - * XXX: Move somewhere to sendit - */ - if (ri != NULL) { - ri->ri_mtu = mtu; - } - - /* Catch a possible divide by zero later. */ KASSERT(mtu > 0, ("%s: mtu %d <= 0, rte=%p (rt_flags=0x%08x) ifp=%p", __func__, mtu, nh, (nh != NULL) ? nh->nh_flags : 0, ifp)); @@ -607,6 +602,20 @@ sendit: goto again; } + if (ri != NULL) { + ri->ri_mtu = mtu; + if (ri->ri_nh_info != NULL) { + struct nhop4_basic *pnh4; + + pnh4 = &ri->ri_nh_info->u.nh4; + pnh4->nh_ifp = ifp; + pnh4->nh_flags = nh ? nh->nh_flags : 0; + pnh4->nh_mtu = mtu; + /* XXX: This is not always correct. */ + pnh4->nh_addr = dst; + } + } + passout: /* 127/8 must not appear on wire - RFC1122. */ if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || Modified: projects/routing/sys/netinet/sctp_os_bsd.h ============================================================================== --- projects/routing/sys/netinet/sctp_os_bsd.h Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/netinet/sctp_os_bsd.h Tue Nov 4 15:39:56 2014 (r274089) @@ -452,9 +452,9 @@ typedef struct rtentry sctp_rtentry_t; if (local_stcb && local_stcb->sctp_ep) \ result = ip6_output(o_pak, \ ((struct in6pcb *)(local_stcb->sctp_ep))->in6p_outputopts, \ - (ro), 0, 0, ifp, NULL); \ + NULL, 0, NULL, NULL); \ else \ - result = ip6_output(o_pak, NULL, (ro), 0, 0, ifp, NULL); \ + result = ip6_output(o_pak, NULL, NULL, 0, NULL, NULL); \ } struct mbuf * Modified: projects/routing/sys/netinet/tcp_offload.c ============================================================================== --- projects/routing/sys/netinet/tcp_offload.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/netinet/tcp_offload.c Tue Nov 4 15:39:56 2014 (r274089) @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #define TCPOUTFLAGS #include #include +#include int registered_toedevs; @@ -86,11 +87,13 @@ tcp_offload_connect(struct socket *so, s goto done; } else if (af == AF_INET6) { struct sockaddr_in6 *sin6; + struct in6_addr dst; + uint32_t scopeid; sin6 = (struct sockaddr_in6 *)nam; + in6_splitscope(&sin6->sin6_addr, &dst, &scopeid); - if (fib6_lookup_nh_ext(fibnum, - sin6->sin6_addr, sin6->sin6_scope_id, + if (fib6_lookup_nh_ext(fibnum, &dst, scopeid, 0, NHOP_LOOKUP_REF, &nhu_ext.u.nh6) != 0) return (EHOSTUNREACH); Modified: projects/routing/sys/netinet/tcp_output.c ============================================================================== --- projects/routing/sys/netinet/tcp_output.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/netinet/tcp_output.c Tue Nov 4 15:39:56 2014 (r274089) @@ -1257,9 +1257,9 @@ send: */ #ifdef INET6 if (isipv6) { - struct route_in6 ro; + struct route_info ri; - bzero(&ro, sizeof(ro)); + bzero(&ri, sizeof(ri)); /* * we separately set hoplimit for every segment, since the * user might want to change the value via setsockopt. @@ -1281,13 +1281,12 @@ send: TCP_PROBE5(send, NULL, tp, ip6, tp, th); /* TODO: IPv6 IP6TOS_ECT bit on */ - error = ip6_output(m, tp->t_inpcb->in6p_outputopts, &ro, + error = ip6_output(m, tp->t_inpcb->in6p_outputopts, &ri, ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), - NULL, NULL, tp->t_inpcb); + NULL, tp->t_inpcb); - if (error == EMSGSIZE && ro.ro_rt != NULL) - mtu = ro.ro_rt->rt_mtu; - RO_RTFREE(&ro); + if (error == EMSGSIZE) + mtu = ri.ri_mtu; } #endif /* INET6 */ #if defined(INET) && defined(INET6) @@ -1324,7 +1323,7 @@ send: TCP_PROBE5(send, NULL, tp, ip, tp, th); error = ip_output(m, tp->t_inpcb->inp_options, &ri, - ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), 0, + ((so->so_options & SO_DONTROUTE) ? IP_ROUTETOIF : 0), NULL, tp->t_inpcb); if (error == EMSGSIZE) Modified: projects/routing/sys/netinet/tcp_subr.c ============================================================================== --- projects/routing/sys/netinet/tcp_subr.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/netinet/tcp_subr.c Tue Nov 4 15:39:56 2014 (r274089) @@ -725,7 +725,7 @@ tcp_respond(struct tcpcb *tp, void *ipge TCP_PROBE5(send, NULL, tp, mtod(m, const char *), tp, nth); #ifdef INET6 if (isipv6) - (void) ip6_output(m, NULL, NULL, ipflags, NULL, NULL, inp); + (void) ip6_output(m, NULL, NULL, ipflags, NULL, inp); #endif /* INET6 */ #if defined(INET) && defined(INET6) else Modified: projects/routing/sys/netinet/tcp_syncache.c ============================================================================== --- projects/routing/sys/netinet/tcp_syncache.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/netinet/tcp_syncache.c Tue Nov 4 15:39:56 2014 (r274089) @@ -1571,7 +1571,7 @@ syncache_respond(struct syncache *sc, st return (error); } #endif - error = ip6_output(m, NULL, NULL, 0, NULL, NULL, NULL); + error = ip6_output(m, NULL, NULL, 0, NULL, NULL); } #endif #if defined(INET6) && defined(INET) Modified: projects/routing/sys/netinet/tcp_timewait.c ============================================================================== --- projects/routing/sys/netinet/tcp_timewait.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/netinet/tcp_timewait.c Tue Nov 4 15:39:56 2014 (r274089) @@ -596,7 +596,7 @@ tcp_twrespond(struct tcptw *tw, int flag sizeof(struct tcphdr) + optlen, IPPROTO_TCP, 0); ip6->ip6_hlim = in6_selecthlim(inp, NULL); error = ip6_output(m, inp->in6p_outputopts, NULL, - (tw->tw_so_options & SO_DONTROUTE), NULL, NULL, inp); + (tw->tw_so_options & SO_DONTROUTE), NULL, inp); } #endif #if defined(INET6) && defined(INET) Modified: projects/routing/sys/netinet6/icmp6.c ============================================================================== --- projects/routing/sys/netinet6/icmp6.c Tue Nov 4 11:29:49 2014 (r274088) +++ projects/routing/sys/netinet6/icmp6.c Tue Nov 4 15:39:56 2014 (r274089) @@ -2142,7 +2142,12 @@ icmp6_reflect(struct mbuf *m, size_t off int plen; int type, code; struct ifnet *outif = NULL; - struct in6_addr origdst, src, *srcp = NULL; + struct in6_addr origdst, src, dst; + struct route_info ri; + struct nhop6_basic nh6; + uint32_t scopeid; + int e; + /* too short to reflect */ if (off < sizeof(struct ip6_hdr)) { @@ -2206,11 +2211,13 @@ icmp6_reflect(struct mbuf *m, size_t off * procedure of an outgoing packet of our own, in which case we need * to search in the ifaddr list. */ + memset(&src, 0, sizeof(src)); if (!IN6_IS_ADDR_MULTICAST(&origdst)) { if ((ia = ip6_getdstifaddr(m))) { if (!(ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) - srcp = &ia->ia_addr.sin6_addr; + src = ia->ia_addr.sin6_addr; + ifa_free(&ia->ia_ifa); } else { struct sockaddr_in6 d; @@ -2223,54 +2230,53 @@ icmp6_reflect(struct mbuf *m, size_t off if (ia && !(ia->ia6_flags & (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) { - srcp = &ia->ia_addr.sin6_addr; + src = ia->ia_addr.sin6_addr; + ifa_free(&ia->ia_ifa); } } } - if (srcp == NULL) { - int e; - struct sockaddr_in6 sin6; - struct route_in6 ro; + + ip6->ip6_src = src; + ip6->ip6_flow = 0; + ip6->ip6_vfc &= ~IPV6_VERSION_MASK; + ip6->ip6_vfc |= IPV6_VERSION; + ip6->ip6_nxt = IPPROTO_ICMPV6; + if (outif) + ip6->ip6_hlim = ND_IFINFO(outif)->chlim; + else if (m->m_pkthdr.rcvif) { + /* XXX: This may not be the outgoing interface */ + ip6->ip6_hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim; + } else + ip6->ip6_hlim = V_ip6_defhlim; + + + /* + * Deembed scope + */ + in6_splitscope(&ip6->ip6_dst, &dst, &scopeid); + + if (IN6_IS_ADDR_UNSPECIFIED(&src)) { /* * This case matches to multicasts, our anycast, or unicasts * that we do not own. Select a source address based on the * source address of the erroneous packet. */ - bzero(&sin6, sizeof(sin6)); - sin6.sin6_family = AF_INET6; - sin6.sin6_len = sizeof(sin6); - sin6.sin6_addr = ip6->ip6_dst; /* zone ID should be embedded */ - - bzero(&ro, sizeof(ro)); - e = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, &outif, &src); - if (ro.ro_rt) - RTFREE(ro.ro_rt); /* XXX: we could use this */ + + e = in6_selectsrc_addr(M_GETFIB(m), &dst, scopeid, &src); if (e) { char ip6buf[INET6_ADDRSTRLEN]; nd6log((LOG_DEBUG, "icmp6_reflect: source can't be determined: " "dst=%s, error=%d\n", - ip6_sprintf(ip6buf, &sin6.sin6_addr), e)); + ip6_sprintf(ip6buf, &dst), e)); goto bad; } - srcp = &src; + ip6->ip6_src = src; } - ip6->ip6_src = *srcp; - ip6->ip6_flow = 0; - ip6->ip6_vfc &= ~IPV6_VERSION_MASK; - ip6->ip6_vfc |= IPV6_VERSION; - ip6->ip6_nxt = IPPROTO_ICMPV6; - if (outif) - ip6->ip6_hlim = ND_IFINFO(outif)->chlim; - else if (m->m_pkthdr.rcvif) { - /* XXX: This may not be the outgoing interface */ - ip6->ip6_hlim = ND_IFINFO(m->m_pkthdr.rcvif)->chlim; - } else - ip6->ip6_hlim = V_ip6_defhlim; - + /* finalize header */ icmp6->icmp6_cksum = 0; icmp6->icmp6_cksum = in6_cksum(m, IPPROTO_ICMPV6, sizeof(struct ip6_hdr), plen); @@ -2281,17 +2287,20 @@ icmp6_reflect(struct mbuf *m, size_t off m->m_flags &= ~(M_BCAST|M_MCAST); - ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL); - if (outif) - icmp6_ifoutstat_inc(outif, type, code); + memset(&ri, 0, sizeof(ri)); + ri.ri_nh_info = (struct nhopu_basic *)&nh6; + ri.scopeid = scopeid; + + e = ip6_output(m, NULL, &ri, 0, NULL, NULL); + if (e == 0) { + /* XXX: Possible use after free */ + outif = nh6.nh_ifp; + //icmp6_ifoutstat_inc(outif, type, code); + } - if (ia != NULL) - ifa_free(&ia->ia_ifa); return; bad: - if (ia != NULL) - ifa_free(&ia->ia_ifa); m_freem(m); return; } @@ -2387,11 +2396,11 @@ icmp6_redirect_input(struct mbuf *m, int } { /* ip6->ip6_src must be equal to gw for icmp6->icmp6_reddst */ - struct nhop6_extended nh_ext; + struct nhop6_basic nh6; - if (fib6_lookup_nh_ext(RT_DEFAULT_FIB, reddst6, 0, 0, 0, &nh_ext) == 0){ + if (fib6_lookup_nh_basic(RT_DEFAULT_FIB, &reddst6, 0, 0, &nh6)==0) { /* XXX: Think about AF_LINK GW */ - if ((nh_ext.nh_flags & NHF_GATEWAY) == 0) { + if ((nh6.nh_flags & NHF_GATEWAY) == 0) { nd6log((LOG_ERR, "ICMP6 redirect rejected; no route " "with inet6 gateway found for redirect dst: %s\n", @@ -2399,12 +2408,12 @@ icmp6_redirect_input(struct mbuf *m, int goto bad; } - if (bcmp(&src6, &nh_ext.nh_addr, sizeof(struct in6_addr)) != 0){ + if (IN6_ARE_ADDR_EQUAL(&src6, &nh6.nh_addr) == 0) { nd6log((LOG_ERR, "ICMP6 redirect rejected; " "not equal to gw-for-src=%s (must be same): " "%s\n", - ip6_sprintf(ip6buf, &nh_ext.nh_addr), + ip6_sprintf(ip6buf, &nh6.nh_addr), icmp6_redirect_diag(&src6, &reddst6, &redtgt6))); goto bad; } @@ -2526,6 +2535,9 @@ icmp6_redirect_output(struct mbuf *m0, s u_char *p; struct ifnet *outif = NULL; struct sockaddr_in6 src_sa; + struct route_info ri; + struct nhop6_basic nh6; + int e; icmp6_errcount(ND_REDIRECT, 0); @@ -2784,9 +2796,14 @@ noredhdropt:; m_tag_prepend(m, mtag); } + memset(&ri, 0, sizeof(ri)); + memset(&nh6, 0, sizeof(nh6)); + ri.ri_nh_info = (struct nhopu_basic *)&nh6; + /* send the packet to outside... */ - ip6_output(m, NULL, NULL, 0, NULL, &outif, NULL); - if (outif) { + e = ip6_output(m, NULL, &ri, 0, NULL, NULL); + if (e == 0) { *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***