summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet6/in6_pcb.c
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2016-10-07 15:10:20 +0200
committerSebastian Huber <sebastian.huber@embedded-brains.de>2017-01-10 09:53:31 +0100
commitc40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch)
treead4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/sys/netinet6/in6_pcb.c
parentuserspace-header-gen.py: Simplify program ports (diff)
downloadrtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/sys/netinet6/in6_pcb.c')
-rw-r--r--freebsd/sys/netinet6/in6_pcb.c191
1 files changed, 137 insertions, 54 deletions
diff --git a/freebsd/sys/netinet6/in6_pcb.c b/freebsd/sys/netinet6/in6_pcb.c
index bf69996d..95e376c7 100644
--- a/freebsd/sys/netinet6/in6_pcb.c
+++ b/freebsd/sys/netinet6/in6_pcb.c
@@ -77,6 +77,7 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/local/opt_inet6.h>
#include <rtems/bsd/local/opt_ipsec.h>
#include <rtems/bsd/local/opt_pcbgroup.h>
+#include <rtems/bsd/local/opt_rss.h>
#include <rtems/bsd/sys/param.h>
#include <sys/systm.h>
@@ -96,6 +97,8 @@ __FBSDID("$FreeBSD$");
#include <vm/uma.h>
#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_llatbl.h>
#include <net/if_types.h>
#include <net/route.h>
@@ -112,7 +115,8 @@ __FBSDID("$FreeBSD$");
#include <netinet6/in6_pcb.h>
#include <netinet6/scope6_var.h>
-struct in6_addr zeroin6_addr;
+static struct inpcb *in6_pcblookup_hash_locked(struct inpcbinfo *,
+ struct in6_addr *, u_int, struct in6_addr *, u_int, int, struct ifnet *);
int
in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
@@ -208,6 +212,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)) &&
@@ -221,6 +226,16 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
0)
#endif /* __rtems__ */
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)) {
@@ -231,6 +246,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 ||
@@ -243,6 +259,9 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
0)
#endif /* __rtems__ */
return (EADDRINUSE);
+
+ if (t && (! in_pcbbind_check_bindmulti(inp, t)))
+ return (EADDRINUSE);
}
#endif
}
@@ -318,13 +337,12 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
* a bit of a kludge, but cleaning up the internal interfaces would
* have forced minor changes in every protocol).
*/
-int
+static int
in6_pcbladdr(register struct inpcb *inp, struct sockaddr *nam,
struct in6_addr *plocal_addr6)
{
register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
int error = 0;
- struct ifnet *ifp = NULL;
int scope_ambiguous = 0;
struct in6_addr in6a;
@@ -354,20 +372,15 @@ in6_pcbladdr(register struct inpcb *inp, struct sockaddr *nam,
if ((error = prison_remote_ip6(inp->inp_cred, &sin6->sin6_addr)) != 0)
return (error);
- error = in6_selectsrc(sin6, inp->in6p_outputopts,
- inp, NULL, inp->inp_cred, &ifp, &in6a);
+ error = in6_selectsrc_socket(sin6, inp->in6p_outputopts,
+ inp, inp->inp_cred, scope_ambiguous, &in6a, NULL);
if (error)
return (error);
- if (ifp && scope_ambiguous &&
- (error = in6_setscope(&sin6->sin6_addr, ifp, NULL)) != 0) {
- return(error);
- }
-
/*
* Do not update this earlier, in case we return with an error.
*
- * XXX: this in6_selectsrc result might replace the bound local
+ * XXX: this in6_selectsrc_socket result might replace the bound local
* address with the address specified by setsockopt(IPV6_PKTINFO).
* Is it the intended behavior?
*/
@@ -702,8 +715,9 @@ in6_pcblookup_local(struct inpcbinfo *pcbinfo, struct in6_addr *laddr,
* Look for an unconnected (wildcard foreign addr) PCB that
* matches the local address and port we're looking for.
*/
- head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport,
- 0, pcbinfo->ipi_hashmask)];
+ head = &pcbinfo->ipi_hashbase[INP_PCBHASH(
+ INP6_PCBHASHKEY(&in6addr_any), lport, 0,
+ pcbinfo->ipi_hashmask)];
LIST_FOREACH(inp, head, inp_hash) {
/* XXX inp locking */
if ((inp->inp_vflag & INP_IPV6) == 0)
@@ -784,7 +798,7 @@ in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp)
struct ip6_moptions *im6o;
int i, gap;
- INP_INFO_RLOCK(pcbinfo);
+ INP_INFO_WLOCK(pcbinfo);
LIST_FOREACH(in6p, pcbinfo->ipi_listhead, inp_list) {
INP_WLOCK(in6p);
im6o = in6p->in6p_moptions;
@@ -815,7 +829,7 @@ in6_pcbpurgeif0(struct inpcbinfo *pcbinfo, struct ifnet *ifp)
}
INP_WUNLOCK(in6p);
}
- INP_INFO_RUNLOCK(pcbinfo);
+ INP_INFO_WUNLOCK(pcbinfo);
}
/*
@@ -828,9 +842,12 @@ void
in6_losing(struct inpcb *in6p)
{
- /*
- * We don't store route pointers in the routing table anymore
- */
+ if (in6p->inp_route6.ro_rt) {
+ RTFREE(in6p->inp_route6.ro_rt);
+ in6p->inp_route6.ro_rt = (struct rtentry *)NULL;
+ }
+ if (in6p->inp_route.ro_lle)
+ LLE_FREE(in6p->inp_route.ro_lle); /* zeros ro_lle */
return;
}
@@ -841,9 +858,13 @@ in6_losing(struct inpcb *in6p)
struct inpcb *
in6_rtchange(struct inpcb *inp, int errno)
{
- /*
- * We don't store route pointers in the routing table anymore
- */
+
+ if (inp->inp_route6.ro_rt) {
+ RTFREE(inp->inp_route6.ro_rt);
+ inp->inp_route6.ro_rt = (struct rtentry *)NULL;
+ }
+ if (inp->inp_route.ro_lle)
+ LLE_FREE(inp->inp_route.ro_lle); /* zeros ro_lle */
return inp;
}
@@ -859,21 +880,14 @@ in6_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup,
struct inpcbhead *head;
struct inpcb *inp, *tmpinp;
u_short fport = fport_arg, lport = lport_arg;
- int faith;
-
- if (faithprefix_p != NULL)
- faith = (*faithprefix_p)(laddr);
- else
- faith = 0;
/*
* First look for an exact match.
*/
tmpinp = NULL;
INP_GROUP_LOCK(pcbgroup);
- head = &pcbgroup->ipg_hashbase[
- INP_PCBHASH(faddr->s6_addr32[3] /* XXX */, lport, fport,
- pcbgroup->ipg_hashmask)];
+ head = &pcbgroup->ipg_hashbase[INP_PCBHASH(
+ INP6_PCBHASHKEY(faddr), lport, fport, pcbgroup->ipg_hashmask)];
LIST_FOREACH(inp, head, inp_pcbgrouphash) {
/* XXX inp locking */
if ((inp->inp_vflag & INP_IPV6) == 0)
@@ -899,7 +913,7 @@ in6_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup,
}
/*
- * Then look for a wildcard match, if requested.
+ * Then look for a wildcard match in the pcbgroup.
*/
if ((lookupflags & INPLOOKUP_WILDCARD) != 0) {
struct inpcb *local_wild = NULL, *local_exact = NULL;
@@ -913,9 +927,9 @@ in6_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup,
* 3. non-jailed, non-wild.
* 4. non-jailed, wild.
*/
- head = &pcbinfo->ipi_wildbase[INP_PCBHASH(INADDR_ANY, lport,
- 0, pcbinfo->ipi_wildmask)];
- LIST_FOREACH(inp, head, inp_pcbgroup_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;
@@ -925,9 +939,67 @@ in6_pcblookup_group(struct inpcbinfo *pcbinfo, struct inpcbgroup *pcbgroup,
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) {
+ 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 = &pcbinfo->ipi_wildbase[INP_PCBHASH(
+ INP6_PCBHASHKEY(&in6addr_any), lport, 0,
+ pcbinfo->ipi_wildmask)];
+ LIST_FOREACH(inp, head, inp_pcbgroup_wild) {
/* XXX inp locking */
- if (faith && (inp->inp_flags & INP_FAITH) == 0)
+ if ((inp->inp_vflag & INP_IPV6) == 0)
+ continue;
+
+ if (!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_faddr) ||
+ inp->inp_lport != lport) {
continue;
+ }
injail = prison_flag(inp->inp_cred, PR_IP6);
if (injail) {
@@ -985,7 +1057,7 @@ found:
/*
* Lookup PCB in hash list.
*/
-struct inpcb *
+static struct inpcb *
in6_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
u_int fport_arg, struct in6_addr *laddr, u_int lport_arg,
int lookupflags, struct ifnet *ifp)
@@ -993,25 +1065,18 @@ in6_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
struct inpcbhead *head;
struct inpcb *inp, *tmpinp;
u_short fport = fport_arg, lport = lport_arg;
- int faith;
KASSERT((lookupflags & ~(INPLOOKUP_WILDCARD)) == 0,
("%s: invalid lookup flags %d", __func__, lookupflags));
INP_HASH_LOCK_ASSERT(pcbinfo);
- if (faithprefix_p != NULL)
- faith = (*faithprefix_p)(laddr);
- else
- faith = 0;
-
/*
* First look for an exact match.
*/
tmpinp = NULL;
- head = &pcbinfo->ipi_hashbase[
- INP_PCBHASH(faddr->s6_addr32[3] /* XXX */, lport, fport,
- pcbinfo->ipi_hashmask)];
+ head = &pcbinfo->ipi_hashbase[INP_PCBHASH(
+ INP6_PCBHASHKEY(faddr), lport, fport, pcbinfo->ipi_hashmask)];
LIST_FOREACH(inp, head, inp_hash) {
/* XXX inp locking */
if ((inp->inp_vflag & INP_IPV6) == 0)
@@ -1049,8 +1114,9 @@ in6_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
* 3. non-jailed, non-wild.
* 4. non-jailed, wild.
*/
- head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport,
- 0, pcbinfo->ipi_hashmask)];
+ head = &pcbinfo->ipi_hashbase[INP_PCBHASH(
+ INP6_PCBHASHKEY(&in6addr_any), lport, 0,
+ pcbinfo->ipi_hashmask)];
LIST_FOREACH(inp, head, inp_hash) {
/* XXX inp locking */
if ((inp->inp_vflag & INP_IPV6) == 0)
@@ -1061,10 +1127,6 @@ in6_pcblookup_hash_locked(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
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,
@@ -1145,7 +1207,7 @@ struct inpcb *
in6_pcblookup(struct inpcbinfo *pcbinfo, struct in6_addr *faddr, u_int fport,
struct in6_addr *laddr, u_int lport, int lookupflags, struct ifnet *ifp)
{
-#if defined(PCBGROUP)
+#if defined(PCBGROUP) && !defined(RSS)
struct inpcbgroup *pcbgroup;
#endif
@@ -1154,7 +1216,17 @@ in6_pcblookup(struct inpcbinfo *pcbinfo, struct in6_addr *faddr, u_int fport,
KASSERT((lookupflags & (INPLOOKUP_RLOCKPCB | INPLOOKUP_WLOCKPCB)) != 0,
("%s: LOCKPCB not set", __func__));
-#if defined(PCBGROUP)
+ /*
+ * When not using RSS, use connection groups in preference to the
+ * reservation table when looking up 4-tuples. When using RSS, just
+ * use the reservation table, due to the cost of the Toeplitz hash
+ * in software.
+ *
+ * XXXRW: This policy belongs in the pcbgroup code, as in principle
+ * we could be doing RSS with a non-Toeplitz hash that is affordable
+ * in software.
+ */
+#if defined(PCBGROUP) && !defined(RSS)
if (in_pcbgroup_enabled(pcbinfo)) {
pcbgroup = in6_pcbgroup_bytuple(pcbinfo, laddr, lport, faddr,
fport);
@@ -1181,16 +1253,27 @@ in6_pcblookup_mbuf(struct inpcbinfo *pcbinfo, struct in6_addr *faddr,
("%s: LOCKPCB not set", __func__));
#ifdef PCBGROUP
- if (in_pcbgroup_enabled(pcbinfo)) {
+ /*
+ * If we can use a hardware-generated hash to look up the connection
+ * group, use that connection group to find the inpcb. Otherwise
+ * fall back on a software hash -- or the reservation table if we're
+ * using RSS.
+ *
+ * XXXRW: As above, that policy belongs in the pcbgroup code.
+ */
+ if (in_pcbgroup_enabled(pcbinfo) &&
+ M_HASHTYPE_TEST(m, M_HASHTYPE_NONE) == 0) {
pcbgroup = in6_pcbgroup_byhash(pcbinfo, M_HASHTYPE_GET(m),
m->m_pkthdr.flowid);
if (pcbgroup != NULL)
return (in6_pcblookup_group(pcbinfo, pcbgroup, faddr,
fport, laddr, lport, lookupflags, ifp));
+#ifndef RSS
pcbgroup = in6_pcbgroup_bytuple(pcbinfo, laddr, lport, faddr,
fport);
return (in6_pcblookup_group(pcbinfo, pcbgroup, faddr, fport,
laddr, lport, lookupflags, ifp));
+#endif
}
#endif
return (in6_pcblookup_hash(pcbinfo, faddr, fport, laddr, lport,