svn commit: r268562 - head/sys/netinet6

Adrian Chadd adrian at FreeBSD.org
Sat Jul 12 05:46:34 UTC 2014


Author: adrian
Date: Sat Jul 12 05:46:33 2014
New Revision: 268562
URL: http://svnweb.freebsd.org/changeset/base/268562

Log:
  Add IPv6 flowid, bindmulti and RSS awareness.

Modified:
  head/sys/netinet6/in6_pcb.c
  head/sys/netinet6/ip6_output.c

Modified: head/sys/netinet6/in6_pcb.c
==============================================================================
--- head/sys/netinet6/in6_pcb.c	Sat Jul 12 05:45:53 2014	(r268561)
+++ head/sys/netinet6/in6_pcb.c	Sat Jul 12 05:46:33 2014	(r268562)
@@ -202,6 +202,7 @@ in6_pcbbind(register struct inpcb *inp, 
 				    &sin6->sin6_addr, lport,
 				    INPLOOKUP_WILDCARD, cred);
 				if (t &&
+				    ((inp->inp_flags2 & INP_BINDMULTI) == 0) &&
 				    ((t->inp_flags & INP_TIMEWAIT) == 0) &&
 				    (so->so_type != SOCK_STREAM ||
 				     IN6_IS_ADDR_UNSPECIFIED(&t->in6p_faddr)) &&
@@ -211,6 +212,16 @@ in6_pcbbind(register struct inpcb *inp, 
 				    (inp->inp_cred->cr_uid !=
 				     t->inp_cred->cr_uid))
 					return (EADDRINUSE);
+
+				/*
+				 * If the socket is a BINDMULTI socket, then
+				 * the credentials need to match and the
+				 * original socket also has to have been bound
+				 * with BINDMULTI.
+				 */
+				if (t && (! in_pcbbind_check_bindmulti(inp, t)))
+					return (EADDRINUSE);
+
 #ifdef INET
 				if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0 &&
 				    IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
@@ -221,6 +232,7 @@ in6_pcbbind(register struct inpcb *inp, 
 					    sin.sin_addr, lport,
 					    INPLOOKUP_WILDCARD, cred);
 					if (t &&
+					    ((inp->inp_flags2 & INP_BINDMULTI) == 0) &&
 					    ((t->inp_flags &
 					      INP_TIMEWAIT) == 0) &&
 					    (so->so_type != SOCK_STREAM ||
@@ -229,6 +241,9 @@ in6_pcbbind(register struct inpcb *inp, 
 					    (inp->inp_cred->cr_uid !=
 					     t->inp_cred->cr_uid))
 						return (EADDRINUSE);
+
+					if (t && (! in_pcbbind_check_bindmulti(inp, t)))
+						return (EADDRINUSE);
 				}
 #endif
 			}
@@ -891,6 +906,71 @@ in6_pcblookup_group(struct inpcbinfo *pc
 	}
 
 	/*
+	 * Then look for a wildcard match in the pcbgroup.
+	 */
+	if ((lookupflags & INPLOOKUP_WILDCARD) != 0) {
+		struct inpcb *local_wild = NULL, *local_exact = NULL;
+		struct inpcb *jail_wild = NULL;
+		int injail;
+
+		/*
+		 * Order of socket selection - we always prefer jails.
+		 *      1. jailed, non-wild.
+		 *      2. jailed, wild.
+		 *      3. non-jailed, non-wild.
+		 *      4. non-jailed, wild.
+		 */
+		head = &pcbgroup->ipg_hashbase[
+		    INP_PCBHASH(INADDR_ANY, lport, 0, pcbgroup->ipg_hashmask)];
+		LIST_FOREACH(inp, head, inp_pcbgrouphash) {
+			/* XXX inp locking */
+			if ((inp->inp_vflag & INP_IPV6) == 0)
+				continue;
+
+			if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) ||
+			    inp->inp_lport != lport) {
+				continue;
+			}
+
+			/* XXX inp locking */
+			if (faith && (inp->inp_flags & INP_FAITH) == 0)
+				continue;
+
+			injail = prison_flag(inp->inp_cred, PR_IP6);
+			if (injail) {
+				if (prison_check_ip6(inp->inp_cred,
+				    laddr) != 0)
+					continue;
+			} else {
+				if (local_exact != NULL)
+					continue;
+			}
+
+			if (IN6_ARE_ADDR_EQUAL(&inp->in6p_laddr, laddr)) {
+				if (injail)
+					goto found;
+				else
+					local_exact = inp;
+			} else if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
+				if (injail)
+					jail_wild = inp;
+				else
+					local_wild = inp;
+			}
+		} /* LIST_FOREACH */
+
+		inp = jail_wild;
+		if (inp == NULL)
+			inp = jail_wild;
+		if (inp == NULL)
+			inp = local_exact;
+		if (inp == NULL)
+			inp = local_wild;
+		if (inp != NULL)
+			goto found;
+	}
+
+	/*
 	 * Then look for a wildcard match, if requested.
 	 */
 	if ((lookupflags & INPLOOKUP_WILDCARD) != 0) {

Modified: head/sys/netinet6/ip6_output.c
==============================================================================
--- head/sys/netinet6/ip6_output.c	Sat Jul 12 05:45:53 2014	(r268561)
+++ head/sys/netinet6/ip6_output.c	Sat Jul 12 05:46:33 2014	(r268562)
@@ -69,6 +69,7 @@ __FBSDID("$FreeBSD$");
 #include "opt_ipsec.h"
 #include "opt_sctp.h"
 #include "opt_route.h"
+#include "opt_rss.h"
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -102,6 +103,7 @@ __FBSDID("$FreeBSD$");
 #include <netinet/in_pcb.h>
 #include <netinet/tcp_var.h>
 #include <netinet6/nd6.h>
+#include <netinet/in_rss.h>
 
 #ifdef IPSEC
 #include <netipsec/ipsec.h>
@@ -1287,6 +1289,10 @@ ip6_ctloutput(struct socket *so, struct 
 	int level, op, optname;
 	int optlen;
 	struct thread *td;
+#ifdef	RSS
+	uint32_t rss_bucket;
+	int retval;
+#endif
 
 	level = sopt->sopt_level;
 	op = sopt->sopt_dir;
@@ -1390,6 +1396,10 @@ ip6_ctloutput(struct socket *so, struct 
 			case IPV6_V6ONLY:
 			case IPV6_AUTOFLOWLABEL:
 			case IPV6_BINDANY:
+			case IPV6_BINDMULTI:
+#ifdef	RSS
+			case IPV6_RSS_LISTEN_BUCKET:
+#endif
 				if (optname == IPV6_BINDANY && td != NULL) {
 					error = priv_check(td,
 					    PRIV_NETINET_BINDANY);
@@ -1439,6 +1449,16 @@ do { \
 } while (/*CONSTCOND*/ 0)
 #define OPTBIT(bit) (in6p->inp_flags & (bit) ? 1 : 0)
 
+#define OPTSET2(bit, val) do {						\
+	INP_WLOCK(in6p);						\
+	if (val)							\
+		in6p->inp_flags2 |= bit;				\
+	else								\
+		in6p->inp_flags2 &= ~bit;				\
+	INP_WUNLOCK(in6p);						\
+} while (0)
+#define OPTBIT2(bit) (in6p->inp_flags2 & (bit) ? 1 : 0)
+
 				case IPV6_RECVPKTINFO:
 					/* cannot mix with RFC2292 */
 					if (OPTBIT(IN6P_RFC2292)) {
@@ -1557,6 +1577,21 @@ do { \
 				case IPV6_BINDANY:
 					OPTSET(INP_BINDANY);
 					break;
+
+				case IPV6_BINDMULTI:
+					OPTSET2(INP_BINDMULTI, optval);
+					break;
+#ifdef	RSS
+				case IPV6_RSS_LISTEN_BUCKET:
+					if ((optval >= 0) &&
+					    (optval < rss_getnumbuckets())) {
+						in6p->inp_rss_listen_bucket = optval;
+						OPTSET2(INP_RSS_BUCKET_SET, 1);
+					} else {
+						error = EINVAL;
+					}
+					break;
+#endif
 				}
 				break;
 
@@ -1772,6 +1807,11 @@ do { \
 			case IPV6_RECVTCLASS:
 			case IPV6_AUTOFLOWLABEL:
 			case IPV6_BINDANY:
+			case IPV6_FLOWID:
+			case IPV6_FLOWTYPE:
+#ifdef	RSS
+			case IPV6_RSSBUCKETID:
+#endif
 				switch (optname) {
 
 				case IPV6_RECVHOPOPTS:
@@ -1837,6 +1877,31 @@ do { \
 				case IPV6_BINDANY:
 					optval = OPTBIT(INP_BINDANY);
 					break;
+
+				case IPV6_FLOWID:
+					optval = in6p->inp_flowid;
+					break;
+
+				case IPV6_FLOWTYPE:
+					optval = in6p->inp_flowtype;
+					break;
+#ifdef	RSS
+				case IPV6_RSSBUCKETID:
+					retval =
+					    rss_hash2bucket(in6p->inp_flowid,
+					    in6p->inp_flowtype,
+					    &rss_bucket);
+					if (retval == 0)
+						optval = rss_bucket;
+					else
+						error = EINVAL;
+					break;
+#endif
+
+				case IPV6_BINDMULTI:
+					optval = OPTBIT2(INP_BINDMULTI);
+					break;
+
 				}
 				if (error)
 					break;


More information about the svn-src-all mailing list