Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102680102
D33254.id99423.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D33254.id99423.diff
View Options
Index: sys/netinet/in_pcb.h
===================================================================
--- sys/netinet/in_pcb.h
+++ sys/netinet/in_pcb.h
@@ -73,7 +73,8 @@
/*
* PCB with AF_INET6 null bind'ed laddr can receive AF_INET input packet.
* So, AF_INET6 null laddr is also used as AF_INET null laddr, by utilizing
- * the following structure.
+ * the following structure. This requires padding always be zeroed out,
+ * which is done right after inpcb allocation and stays through its lifetime.
*/
struct in_addr_4in6 {
u_int32_t ia46_pad32[3];
@@ -536,13 +537,36 @@
#define INP_HASH_WLOCK_ASSERT(ipi) mtx_assert(&(ipi)->ipi_hash_lock, \
MA_OWNED)
-#define INP_PCBHASH(faddr, lport, fport, mask) \
- (((faddr) ^ ((faddr) >> 16) ^ ntohs((lport) ^ (fport))) & (mask))
-#define INP_PCBPORTHASH(lport, mask) \
- (ntohs((lport)) & (mask))
-#define INP_PCBLBGROUP_PKTHASH(faddr, lport, fport) \
- ((faddr) ^ ((faddr) >> 16) ^ ntohs((lport) ^ (fport)))
-#define INP6_PCBHASHKEY(faddr) ((faddr)->s6_addr32[3])
+/*
+ * Wildcard matching hash is not just a microoptimisation! The hash for
+ * wildcard IPv4 and wildcard IPv6 must be the same, otherwise AF_INET6
+ * wildcard bound pcb won't be able to receive AF_INET connections, while:
+ * jenkins_hash(&zeroes, 1, s) != jenkins_hash(&zeroes, 4, s)
+ * See also comment above struct in_addr_4in6.
+ */
+#define IN_ADDR_JHASH32(addr) \
+ ((addr)->s_addr == INADDR_ANY ? V_in_pcbhashseed : \
+ jenkins_hash32((&(addr)->s_addr), 1, V_in_pcbhashseed))
+#define IN6_ADDR_JHASH32(addr) \
+ (memcmp((addr), &in6addr_any, sizeof(in6addr_any)) == 0 ? \
+ V_in_pcbhashseed : \
+ jenkins_hash32((addr)->__u6_addr.__u6_addr32, \
+ nitems((addr)->__u6_addr.__u6_addr32), V_in_pcbhashseed))
+
+#define INP_PCBHASH(faddr, lport, fport, mask) \
+ ((IN_ADDR_JHASH32(faddr) ^ ntohs((lport) ^ (fport))) & (mask))
+#define INP6_PCBHASH(faddr, lport, fport, mask) \
+ ((IN6_ADDR_JHASH32(faddr) ^ ntohs((lport) ^ (fport))) & (mask))
+
+#define INP_PCBHASH_WILD(lport, mask) \
+ ((V_in_pcbhashseed ^ ntohs(lport)) & (mask))
+
+#define INP_PCBLBGROUP_PKTHASH(faddr, lport, fport) \
+ (IN_ADDR_JHASH32(faddr) ^ ntohs((lport) ^ (fport)))
+#define INP6_PCBLBGROUP_PKTHASH(faddr, lport, fport) \
+ (IN6_ADDR_JHASH32(faddr) ^ ntohs((lport) ^ (fport)))
+
+#define INP_PCBPORTHASH(lport, mask) (ntohs((lport)) & (mask))
/*
* Flags for inp_vflags -- historically version flags only
Index: sys/netinet/in_pcb.c
===================================================================
--- sys/netinet/in_pcb.c
+++ sys/netinet/in_pcb.c
@@ -49,7 +49,9 @@
#include "opt_rss.h"
#include <sys/param.h>
+#include <sys/hash.h>
#include <sys/systm.h>
+#include <sys/libkern.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
@@ -246,6 +248,16 @@
#endif /* INET */
+VNET_DEFINE(uint32_t, in_pcbhashseed);
+static void
+in_pcbhashseed_init(void)
+{
+
+ V_in_pcbhashseed = arc4random();
+}
+VNET_SYSINIT(in_pcbhashseed_init, SI_SUB_PROTO_DOMAIN, SI_ORDER_FIRST,
+ in_pcbhashseed_init, 0);
+
/*
* in_pcb.c: manage the Protocol Control Blocks.
*
@@ -2074,8 +2086,8 @@
* 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_WILD(lport,
+ pcbinfo->ipi_hashmask)];
CK_LIST_FOREACH(inp, head, inp_hash) {
#ifdef INET6
/* XXX inp locking */
@@ -2203,7 +2215,7 @@
if (grp->il_lport != lport)
continue;
- idx = INP_PCBLBGROUP_PKTHASH(faddr->s_addr, lport, fport) %
+ idx = INP_PCBLBGROUP_PKTHASH(faddr, lport, fport) %
grp->il_inpcnt;
if (grp->il_laddr.s_addr == laddr->s_addr) {
if (numa_domain == M_NODOM ||
@@ -2249,7 +2261,7 @@
* First look for an exact match.
*/
tmpinp = NULL;
- head = &pcbinfo->ipi_hashbase[INP_PCBHASH(faddr.s_addr, lport, fport,
+ head = &pcbinfo->ipi_hashbase[INP_PCBHASH(&faddr, lport, fport,
pcbinfo->ipi_hashmask)];
CK_LIST_FOREACH(inp, head, inp_hash) {
#ifdef INET6
@@ -2304,8 +2316,8 @@
* 4. non-jailed, wild.
*/
- head = &pcbinfo->ipi_hashbase[INP_PCBHASH(INADDR_ANY, lport,
- 0, pcbinfo->ipi_hashmask)];
+ head = &pcbinfo->ipi_hashbase[INP_PCBHASH_WILD(lport,
+ pcbinfo->ipi_hashmask)];
CK_LIST_FOREACH(inp, head, inp_hash) {
#ifdef INET6
/* XXX inp locking */
@@ -2428,7 +2440,6 @@
struct inpcbporthead *pcbporthash;
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
struct inpcbport *phd;
- u_int32_t hashkey_faddr;
int so_options;
INP_WLOCK_ASSERT(inp);
@@ -2439,13 +2450,12 @@
#ifdef INET6
if (inp->inp_vflag & INP_IPV6)
- hashkey_faddr = INP6_PCBHASHKEY(&inp->in6p_faddr);
+ pcbhash = &pcbinfo->ipi_hashbase[INP6_PCBHASH(&inp->in6p_faddr,
+ inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
else
#endif
- hashkey_faddr = inp->inp_faddr.s_addr;
-
- pcbhash = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr,
- inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
+ pcbhash = &pcbinfo->ipi_hashbase[INP_PCBHASH(&inp->inp_faddr,
+ inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
pcbporthash = &pcbinfo->ipi_porthashbase[
INP_PCBPORTHASH(inp->inp_lport, pcbinfo->ipi_porthashmask)];
@@ -2505,7 +2515,6 @@
{
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo;
struct inpcbhead *head;
- u_int32_t hashkey_faddr;
INP_WLOCK_ASSERT(inp);
INP_HASH_WLOCK_ASSERT(pcbinfo);
@@ -2515,13 +2524,12 @@
#ifdef INET6
if (inp->inp_vflag & INP_IPV6)
- hashkey_faddr = INP6_PCBHASHKEY(&inp->in6p_faddr);
+ head = &pcbinfo->ipi_hashbase[INP6_PCBHASH(&inp->in6p_faddr,
+ inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
else
#endif
- hashkey_faddr = inp->inp_faddr.s_addr;
-
- head = &pcbinfo->ipi_hashbase[INP_PCBHASH(hashkey_faddr,
- inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
+ head = &pcbinfo->ipi_hashbase[INP_PCBHASH(&inp->inp_faddr,
+ inp->inp_lport, inp->inp_fport, pcbinfo->ipi_hashmask)];
CK_LIST_REMOVE(inp, inp_hash);
CK_LIST_INSERT_HEAD(head, inp, inp_hash);
Index: sys/netinet/in_pcb_var.h
===================================================================
--- sys/netinet/in_pcb_var.h
+++ sys/netinet/in_pcb_var.h
@@ -44,6 +44,9 @@
* Definitions shared between netinet/in_pcb.c and netinet6/in6_pcb.c
*/
+VNET_DECLARE(uint32_t, in_pcbhashseed);
+#define V_in_pcbhashseed VNET(in_pcbhashseed)
+
bool inp_smr_lock(struct inpcb *, const inp_lookup_t);
int in_pcb_lport(struct inpcb *, struct in_addr *, u_short *,
struct ucred *, int);
Index: sys/netinet6/in6_pcb.c
===================================================================
--- sys/netinet6/in6_pcb.c
+++ sys/netinet6/in6_pcb.c
@@ -75,6 +75,7 @@
#include "opt_route.h"
#include "opt_rss.h"
+#include <sys/hash.h>
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/malloc.h>
@@ -787,8 +788,7 @@
* 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(
- INP6_PCBHASHKEY(&in6addr_any), lport, 0,
+ head = &pcbinfo->ipi_hashbase[INP_PCBHASH_WILD(lport,
pcbinfo->ipi_hashmask)];
CK_LIST_FOREACH(inp, head, inp_hash) {
/* XXX inp locking */
@@ -972,8 +972,8 @@
if (grp->il_lport != lport)
continue;
- idx = INP_PCBLBGROUP_PKTHASH(INP6_PCBHASHKEY(faddr), lport,
- fport) % grp->il_inpcnt;
+ idx = INP6_PCBLBGROUP_PKTHASH(faddr, lport, fport) %
+ grp->il_inpcnt;
if (IN6_ARE_ADDR_EQUAL(&grp->il6_laddr, laddr)) {
if (numa_domain == M_NODOM ||
grp->il_numa_domain == numa_domain) {
@@ -1015,8 +1015,8 @@
* First look for an exact match.
*/
tmpinp = NULL;
- head = &pcbinfo->ipi_hashbase[INP_PCBHASH(
- INP6_PCBHASHKEY(faddr), lport, fport, pcbinfo->ipi_hashmask)];
+ head = &pcbinfo->ipi_hashbase[INP6_PCBHASH(faddr, lport, fport,
+ pcbinfo->ipi_hashmask)];
CK_LIST_FOREACH(inp, head, inp_hash) {
/* XXX inp locking */
if ((inp->inp_vflag & INP_IPV6) == 0)
@@ -1064,8 +1064,7 @@
* 3. non-jailed, non-wild.
* 4. non-jailed, wild.
*/
- head = &pcbinfo->ipi_hashbase[INP_PCBHASH(
- INP6_PCBHASHKEY(&in6addr_any), lport, 0,
+ head = &pcbinfo->ipi_hashbase[INP_PCBHASH_WILD(lport,
pcbinfo->ipi_hashmask)];
CK_LIST_FOREACH(inp, head, inp_hash) {
/* XXX inp locking */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 16, 6:54 PM (7 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14663094
Default Alt Text
D33254.id99423.diff (8 KB)
Attached To
Mode
D33254: in_pcb: use jenkins hash over the entire IPv6 (or IPv4) address
Attached
Detach File
Event Timeline
Log In to Comment