Add IPv6 flowid, bindmulti and RSS awareness.
This commit is contained in:
parent
a8a2d8003a
commit
c7c0d94874
@ -202,6 +202,7 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
|
||||
&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, struct sockaddr *nam,
|
||||
(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, struct sockaddr *nam,
|
||||
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, struct sockaddr *nam,
|
||||
(inp->inp_cred->cr_uid !=
|
||||
t->inp_cred->cr_uid))
|
||||
return (EADDRINUSE);
|
||||
|
||||
if (t && (! in_pcbbind_check_bindmulti(inp, t)))
|
||||
return (EADDRINUSE);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -890,6 +905,71 @@ in6_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup,
|
||||
goto found;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
@ -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 sockopt *sopt)
|
||||
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 sockopt *sopt)
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user