Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 2 Dec 2013 06:17:30 +0000 (UTC)
From:      "Andrey V. Elsukov" <ae@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r258837 - user/ae/inet6/sys/netinet6
Message-ID:  <201312020617.rB26HUfl067251@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: ae
Date: Mon Dec  2 06:17:29 2013
New Revision: 258837
URL: http://svnweb.freebsd.org/changeset/base/258837

Log:
  Rethink usage of IPV6_USEROIF flag.
  
  We can't just use outgoing interface when destination address is
  not link-reachable, because we must use gateway's layer2 address
  when constructing packet. Add route information where it can be cached
  and then pass it to ip6_output. Also count some errors as bad scope.

Modified:
  user/ae/inet6/sys/netinet6/ip6_output.c
  user/ae/inet6/sys/netinet6/raw_ip6.c
  user/ae/inet6/sys/netinet6/udp6_usrreq.c

Modified: user/ae/inet6/sys/netinet6/ip6_output.c
==============================================================================
--- user/ae/inet6/sys/netinet6/ip6_output.c	Mon Dec  2 06:14:05 2013	(r258836)
+++ user/ae/inet6/sys/netinet6/ip6_output.c	Mon Dec  2 06:17:29 2013	(r258837)
@@ -684,16 +684,20 @@ again:
 		ifp = ro->ro_rt->rt_ifp;
 	} else {
 		/*
-		 * We can just use specified by user outgoing interface when
-		 * IPV6_USEROIF flag is set. But we should determine new
-		 * outgoing interface if PFIL has changed destination address,
-		 * or some packet options is set.
+		 * The caller can use IPV6_USEROIF flag to suggest outgoing
+		 * interface. But destination address should be reachable via
+		 * specified interface. This means, that destination address
+		 * is multicast, or destination/source address is LLA, or
+		 * outgoing interface is PTP tunnel. In other cases we need
+		 * to do route lookup to determine gateway and use its layer2
+		 * address.
+		 * XXX: fwd/nexthop/pktinfo/rthdr ?
 		 */
-		if ((flags & IPV6_USEROIF) != 0 &&
-		    (IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
-		    (fwd_tag == NULL && (opt == NULL ||
-		    (opt->ip6po_nexthop == NULL &&
-		    opt->ip6po_rthdr == NULL)))))
+		if ((flags & IPV6_USEROIF) != 0 && (
+		    ((*ifpp)->if_flags & IFF_POINTOPOINT) != 0 ||
+		    IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst) ||
+		    IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_src) ||
+		    IN6_IS_ADDR_LINKLOCAL(&ip6->ip6_dst)))
 			ifp = *ifpp;
 		else {
 			/*
@@ -717,7 +721,7 @@ again:
 				    IN6_IS_ADDR_MC_INTFACELOCAL(
 				    &ip6->ip6_dst)) {
 					error = EHOSTUNREACH;
-					IP6STAT_INC(ip6s_noroute);
+					IP6STAT_INC(ip6s_badscope);
 					goto bad;
 				}
 			} else if (IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr) ||
@@ -729,7 +733,7 @@ again:
 				if (dst->sin6_scope_id == 0 || !(ifp =
 				    in6_getlinkifnet(dst->sin6_scope_id))) {
 					error = EHOSTUNREACH;
-					IP6STAT_INC(ip6s_noroute);
+					IP6STAT_INC(ip6s_badscope);
 					goto bad;
 				}
 				goto oif_found;

Modified: user/ae/inet6/sys/netinet6/raw_ip6.c
==============================================================================
--- user/ae/inet6/sys/netinet6/raw_ip6.c	Mon Dec  2 06:14:05 2013	(r258836)
+++ user/ae/inet6/sys/netinet6/raw_ip6.c	Mon Dec  2 06:17:29 2013	(r258837)
@@ -392,6 +392,7 @@ rip6_ctlinput(int cmd, struct sockaddr *
 int
 rip6_output(struct mbuf *m, ...)
 {
+	struct route_in6 ro;
 	struct mbuf *control;
 	struct m_tag *mtag;
 	struct socket *so;
@@ -413,6 +414,7 @@ rip6_output(struct mbuf *m, ...)
 	control = va_arg(ap, struct mbuf *);
 	va_end(ap);
 
+	bzero(&ro, sizeof(ro));
 	in6p = sotoinpcb(so);
 	INP_WLOCK(in6p);
 
@@ -453,7 +455,7 @@ rip6_output(struct mbuf *m, ...)
 	/*
 	 * Source address selection.
 	 */
-	error = in6_selectsrc(dstsock, optp, in6p, NULL, so->so_cred,
+	error = in6_selectsrc(dstsock, optp, in6p, &ro, so->so_cred,
 	    &oifp, &in6a);
 	if (error)
 		goto bad;
@@ -523,7 +525,7 @@ rip6_output(struct mbuf *m, ...)
 		}
 	}
 
-	error = ip6_output(m, optp, NULL, IPV6_USEROIF, in6p->in6p_moptions,
+	error = ip6_output(m, optp, &ro, IPV6_USEROIF, in6p->in6p_moptions,
 	    &oifp, in6p);
 	if (so->so_proto->pr_protocol == IPPROTO_ICMPV6) {
 		icmp6_ifoutstat_inc(oifp, type, code);
@@ -543,6 +545,7 @@ rip6_output(struct mbuf *m, ...)
 		m_freem(control);
 	}
 	INP_WUNLOCK(in6p);
+	RO_RTFREE(&ro);
 	return (error);
 }
 

Modified: user/ae/inet6/sys/netinet6/udp6_usrreq.c
==============================================================================
--- user/ae/inet6/sys/netinet6/udp6_usrreq.c	Mon Dec  2 06:14:05 2013	(r258836)
+++ user/ae/inet6/sys/netinet6/udp6_usrreq.c	Mon Dec  2 06:17:29 2013	(r258837)
@@ -615,6 +615,7 @@ static int
 udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
     struct mbuf *control, struct thread *td)
 {
+	struct route_in6 ro;
 	u_int32_t ulen = m->m_pkthdr.len;
 	u_int32_t plen = sizeof(struct udphdr) + ulen;
 	struct ip6_hdr *ip6;
@@ -631,6 +632,7 @@ udp6_output(struct inpcb *inp, struct mb
 	INP_WLOCK_ASSERT(inp);
 	INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
 
+	bzero(&ro, sizeof(ro));
 	/* addr6 has been validated in udp6_send(). */
 	sin6 = (struct sockaddr_in6 *)addr6;
 	if (control) {
@@ -694,7 +696,7 @@ udp6_output(struct inpcb *inp, struct mb
 		}
 
 		if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
-			error = in6_selectsrc(sin6, optp, inp, NULL,
+			error = in6_selectsrc(sin6, optp, inp, &ro,
 			    td->td_ucred, &oifp, &in6a);
 			if (error)
 				goto release;
@@ -785,7 +787,7 @@ udp6_output(struct inpcb *inp, struct mb
 
 		UDP_PROBE(send, NULL, inp, ip6, inp, udp6);
 		UDPSTAT_INC(udps_opackets);
-		error = ip6_output(m, optp, NULL, flags, inp->in6p_moptions,
+		error = ip6_output(m, optp, &ro, flags, inp->in6p_moptions,
 		    &oifp, inp);
 		break;
 	case AF_INET:
@@ -802,6 +804,7 @@ releaseopt:
 		ip6_clearpktopts(&opt, -1);
 		m_freem(control);
 	}
+	RO_RTFREE(&ro);
 	return (error);
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201312020617.rB26HUfl067251>