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;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to