Date: Sun, 23 Aug 2015 18:23:18 +0000 (UTC) From: "Alexander V. Chernikov" <melifaro@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r287059 - in projects/routing/sys: contrib/ipfilter/netinet dev/cxgbe/tom net netgraph netinet netinet6 netipsec netpfil/ipfw netpfil/pf Message-ID: <201508231823.t7NINIGF046847@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: melifaro Date: Sun Aug 23 18:23:17 2015 New Revision: 287059 URL: https://svnweb.freebsd.org/changeset/base/287059 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/if_vxlan.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/in_gif.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_gre.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 Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c Sun Aug 23 18:23:17 2015 (r287059) @@ -756,7 +756,7 @@ ipf_fastroute(m0, mpp, fin, fdp) * currently "to <if>" and "to <if>: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 Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/dev/cxgbe/tom/t4_listen.c Sun Aug 23 18:23:17 2015 (r287059) @@ -1111,7 +1111,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/if_vxlan.c ============================================================================== --- projects/routing/sys/net/if_vxlan.c Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/net/if_vxlan.c Sun Aug 23 18:23:17 2015 (r287059) @@ -2381,7 +2381,7 @@ vxlan_encap6(struct vxlan_softc *sc, con mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1 : 0; m->m_flags &= ~(M_MCAST | M_BCAST); - error = ip6_output(m, NULL, NULL, 0, sc->vxl_im6o, NULL, NULL); + error = ip6_output(m, NULL, NULL, 0, sc->vxl_im6o, NULL); if (error == 0) { if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); if_inc_counter(ifp, IFCOUNTER_OBYTES, len); Modified: projects/routing/sys/net/rt_nhops.c ============================================================================== --- projects/routing/sys/net/rt_nhops.c Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/net/rt_nhops.c Sun Aug 23 18:23:17 2015 (r287059) @@ -66,6 +66,10 @@ #include <netinet/ip_mroute.h> #include <netinet/ip6.h> #include <netinet6/in6_var.h> +#include <netinet6/nd6.h> +#include <netinet6/scope6_var.h> + +#include <net/if_llatbl.h> #include <net/if_types.h> #include <netinet/if_ether.h> @@ -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, const 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(const 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; @@ -570,19 +588,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(const 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, const 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); @@ -591,19 +925,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); @@ -611,18 +949,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, const 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) @@ -630,7 +972,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); @@ -658,7 +1002,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; @@ -666,6 +1010,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) @@ -674,7 +1024,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); @@ -702,15 +1054,6 @@ fib6_free_nh_ext(uint32_t fibnum, struct } -void -fib6_source_to_sa_ext(const struct nhopu_extended *pnhu, - struct sockaddr_in6 *sin6) -{ - - sin6->sin6_family = AF_INET6; - sin6->sin6_len = sizeof(*sin6); - sin6->sin6_addr = pnhu->u.nh6.nh_src; -} #endif void Modified: projects/routing/sys/net/rt_nhops.h ============================================================================== --- projects/routing/sys/net/rt_nhops.h Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/net/rt_nhops.h Sun Aug 23 18:23:17 2015 (r287059) @@ -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 { @@ -208,14 +210,12 @@ void fib4_source_to_sa_ext(const struct struct sockaddr_in *sin); -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, const 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); -void fib6_source_to_sa_ext(const struct nhopu_extended *pnhu, - struct sockaddr_in6 *sin6); void fib_free_nh_ext(uint32_t fibnum, struct nhopu_extended *pnhu); @@ -232,6 +232,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 Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/netgraph/ng_ipfw.c Sun Aug 23 18:23:17 2015 (r287059) @@ -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/in_gif.c ============================================================================== --- projects/routing/sys/netinet/in_gif.c Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/netinet/in_gif.c Sun Aug 23 18:23:17 2015 (r287059) @@ -61,6 +61,8 @@ __FBSDID("$FreeBSD$"); #include <netinet/ip_encap.h> #include <netinet/ip_ecn.h> +#include <net/rt_nhops.h> + #ifdef INET6 #include <netinet/ip6.h> #endif @@ -188,22 +190,13 @@ in_gif_encapcheck(const struct mbuf *m, /* ingress filters on outer source */ if ((GIF2IFP(sc)->if_flags & IFF_LINK2) == 0) { - struct sockaddr_in sin; - struct rtentry *rt; + struct nhop4_basic nh4; - bzero(&sin, sizeof(sin)); - sin.sin_family = AF_INET; - sin.sin_len = sizeof(struct sockaddr_in); - sin.sin_addr = ip->ip_src; - /* XXX MRT check for the interface we would use on output */ - rt = in_rtalloc1((struct sockaddr *)&sin, 0, - 0UL, sc->gif_fibnum); - if (rt == NULL || rt->rt_ifp != m->m_pkthdr.rcvif) { - if (rt != NULL) - RTFREE_LOCKED(rt); + if (fib4_lookup_nh_basic(sc->gif_fibnum, ip->ip_src, 0, + &nh4) != 0) + return (0); + if (nh4.nh_ifp != m->m_pkthdr.rcvif) return (0); - } - RTFREE_LOCKED(rt); } return (ret); } Modified: projects/routing/sys/netinet/ip_carp.c ============================================================================== --- projects/routing/sys/netinet/ip_carp.c Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/netinet/ip_carp.c Sun Aug 23 18:23:17 2015 (r287059) @@ -921,7 +921,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 Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/netinet/ip_divert.c Sun Aug 23 18:23:17 2015 (r287059) @@ -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 Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/netinet/ip_output.c Sun Aug 23 18:23:17 2015 (r287059) @@ -200,9 +200,13 @@ ip_output_pfil(struct mbuf *m, struct if * 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. @@ -407,19 +411,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)); @@ -586,6 +583,20 @@ sendit: } } + 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; + } + } + /* 127/8 must not appear on wire - RFC1122. */ if ((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET || (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) { Modified: projects/routing/sys/netinet/sctp_os_bsd.h ============================================================================== --- projects/routing/sys/netinet/sctp_os_bsd.h Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/netinet/sctp_os_bsd.h Sun Aug 23 18:23:17 2015 (r287059) @@ -447,9 +447,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 Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/netinet/tcp_offload.c Sun Aug 23 18:23:17 2015 (r287059) @@ -48,6 +48,7 @@ __FBSDID("$FreeBSD$"); #define TCPOUTFLAGS #include <netinet/tcp_fsm.h> #include <netinet/toecore.h> +#include <netinet6/scope6_var.h> 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 Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/netinet/tcp_output.c Sun Aug 23 18:23:17 2015 (r287059) @@ -1268,9 +1268,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. @@ -1297,13 +1297,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) @@ -1340,7 +1339,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 Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/netinet/tcp_subr.c Sun Aug 23 18:23:17 2015 (r287059) @@ -728,7 +728,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 Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/netinet/tcp_syncache.c Sun Aug 23 18:23:17 2015 (r287059) @@ -1569,7 +1569,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 Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/netinet/tcp_timewait.c Sun Aug 23 18:23:17 2015 (r287059) @@ -592,7 +592,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 Sun Aug 23 18:22:41 2015 (r287058) +++ projects/routing/sys/netinet6/icmp6.c Sun Aug 23 18:23:17 2015 (r287059) @@ -2115,13 +2115,17 @@ icmp6_rip6_input(struct mbuf **mp, int o void icmp6_reflect(struct mbuf *m, size_t off) { - struct in6_addr src, *srcp = NULL; struct ip6_hdr *ip6; struct icmp6_hdr *icmp6; struct in6_ifaddr *ia = NULL; - struct ifnet *outif = NULL; int plen; int type, code; + struct ifnet *outif = 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)) { @@ -2175,48 +2179,61 @@ icmp6_reflect(struct mbuf *m, size_t off * (for example) when we encounter an error while forwarding procedure * destined to a duplicated address of ours. */ - if (!IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) { - ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */); - if (ia != NULL && !(ia->ia6_flags & - (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) - srcp = &ia->ia_addr.sin6_addr; + memset(&src, 0, sizeof(src)); + if (!IN6_IS_ADDR_MULTICAST(&origdst)) { + if ((ia = in6ifa_ifwithaddr(&ip6->ip6_dst, 0 /* XXX */))) { + if (!(ia->ia6_flags & + (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) + 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_input() drops a packet if its src is multicast. * So, the src is never multicast. */ ip6->ip6_dst = ip6->ip6_src; - ip6->ip6_src = *srcp; + ip6->ip6_src = src; ip6->ip6_flow = 0; ip6->ip6_vfc &= ~IPV6_VERSION_MASK; ip6->ip6_vfc |= IPV6_VERSION; @@ -2239,17 +2256,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; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201508231823.t7NINIGF046847>