Skip site navigation (1)Skip section navigation (2)
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>