Changeset View
Standalone View
sys/netinet/in_pcb.c
Context not available. | |||||
#include <security/mac/mac_framework.h> | #include <security/mac/mac_framework.h> | ||||
#define INPCBLBGROUP_SIZMIN 8 | |||||
#define INPCBLBGROUP_SIZMAX 256 | |||||
static struct callout ipport_tick_callout; | static struct callout ipport_tick_callout; | ||||
/* | /* | ||||
Context not available. | |||||
* functions often modify hash chains or addresses in pcbs. | * functions often modify hash chains or addresses in pcbs. | ||||
*/ | */ | ||||
static struct inpcblbgroup * | |||||
in_pcblbgroup_alloc(struct inpcblbgrouphead *hdr, u_char vflag, | |||||
uint16_t port, const union in_dependaddr *addr, int size) | |||||
{ | |||||
struct inpcblbgroup *grp; | |||||
size_t bytes = __offsetof(struct inpcblbgroup, il_inp[size]); | |||||
grp = malloc(bytes, M_PCB, M_ZERO | M_NOWAIT); | |||||
if(!grp) | |||||
return NULL; | |||||
grp->il_vflag = vflag; | |||||
grp->il_lport = port; | |||||
grp->il_dependladdr = *addr; | |||||
rwatson: Should there be a lock assertion here? | |||||
Not Done Inline Actionsin_pcblbgroup_{alloc,free,resize,reorder} are only called from in_pcb{ins,rem}lbgrouphash where locks are asserted. To assert locks again in these functions we'd need to pass the inpcb as argument. What do you recommend? johalun0_gmail.com: in_pcblbgroup_{alloc,free,resize,reorder} are only called from in_pcb{ins,rem}lbgrouphash where… | |||||
grp->il_inpsiz = size; | |||||
LIST_INSERT_HEAD(hdr, grp, il_list); | |||||
return grp; | |||||
} | |||||
static void | |||||
in_pcblbgroup_free(struct inpcblbgroup *grp) | |||||
{ | |||||
LIST_REMOVE(grp, il_list); | |||||
Done Inline ActionsThis vertical whitespace is probably not needed. rwatson: This vertical whitespace is probably not needed. | |||||
free(grp, M_TEMP); | |||||
} | |||||
static struct inpcblbgroup * | |||||
in_pcblbgroup_resize(struct inpcblbgrouphead *hdr, | |||||
struct inpcblbgroup *old_grp, int size) | |||||
{ | |||||
Not Done Inline ActionsShould there be a lock assertion here? rwatson: Should there be a lock assertion here? | |||||
struct inpcblbgroup *grp; | |||||
int i; | |||||
grp = in_pcblbgroup_alloc(hdr, old_grp->il_vflag, | |||||
old_grp->il_lport, &old_grp->il_dependladdr, size); | |||||
if(!grp) | |||||
return NULL; | |||||
KASSERT(old_grp->il_inpcnt < grp->il_inpsiz, | |||||
("invalid new local group size %d and old local group count %d", | |||||
grp->il_inpsiz, old_grp->il_inpcnt)); | |||||
Not Done Inline ActionsShould there be a lock assertion here? rwatson: Should there be a lock assertion here? | |||||
for (i = 0; i < old_grp->il_inpcnt; ++i) | |||||
grp->il_inp[i] = old_grp->il_inp[i]; | |||||
grp->il_inpcnt = old_grp->il_inpcnt; | |||||
in_pcblbgroup_free(old_grp); | |||||
return grp; | |||||
} | |||||
/* | |||||
* Add PCB to lb group (load balance used by SO_REUSEPORT_LB) | |||||
*/ | |||||
Done Inline ActionsCan probably drop this blank line here. rwatson: Can probably drop this blank line here. | |||||
static int | |||||
in_pcbinslbgrouphash(struct inpcb *inp, struct inpcbinfo *pcbinfo) | |||||
Done Inline ActionsCan probably drop this blank line here. rwatson: Can probably drop this blank line here. | |||||
{ | |||||
struct inpcblbgrouphead *hdr; | |||||
struct inpcblbgroup *grp; | |||||
uint16_t hashmask = pcbinfo->ipi_lbgrouphashmask; | |||||
Done Inline ActionsAdd a "." at the end -- style(9) would like comments to be complete sentences. rwatson: Add a "." at the end -- style(9) would like comments to be complete sentences. | |||||
uint16_t lport = inp->inp_lport; | |||||
uint32_t group_index = INP_PCBLBGROUP_PORTHASH(lport, hashmask); | |||||
Done Inline ActionsIn other in_..._inshash() functions, the pcbinfo argument is implied by the 'inp' argument. Do we need it to be explicit here? rwatson: In other in_..._inshash() functions, the pcbinfo argument is implied by the 'inp' argument. Do… | |||||
hdr = &pcbinfo->ipi_lbgrouphashbase[group_index]; | |||||
struct ucred *cred; | |||||
if (pcbinfo->ipi_lbgrouphashbase == NULL) | |||||
return 0; | |||||
/* | |||||
* don't allow jailed socket to join local group | |||||
*/ | |||||
if (inp->inp_socket != NULL) | |||||
cred = inp->inp_socket->so_cred; | |||||
else | |||||
cred = NULL; | |||||
if (cred != NULL && jailed(cred)) | |||||
return 0; | |||||
#ifdef INET6 | |||||
/* | |||||
* don't allow IPv4 mapped INET6 wild socket | |||||
Done Inline ActionsComment should be a full sentence. rwatson: Comment should be a full sentence. | |||||
*/ | |||||
if ((inp->inp_vflag & INP_IPV4) && | |||||
inp->inp_laddr.s_addr == INADDR_ANY && | |||||
INP_CHECK_SOCKAF(inp->inp_socket, AF_INET6)) { | |||||
return 0; | |||||
} | |||||
#endif | |||||
hdr = &pcbinfo->ipi_lbgrouphashbase[ | |||||
INP_PCBLBGROUP_PORTHASH(inp->inp_lport, pcbinfo->ipi_lbgrouphashmask)]; | |||||
Done Inline ActionsComment should be a full sentence. rwatson: Comment should be a full sentence. | |||||
LIST_FOREACH(grp, hdr, il_list) { | |||||
if (grp->il_vflag == inp->inp_vflag && | |||||
grp->il_lport == inp->inp_lport && | |||||
memcmp(&grp->il_dependladdr, | |||||
&inp->inp_inc.inc_ie.ie_dependladdr, | |||||
sizeof(grp->il_dependladdr)) == 0) { | |||||
break; | |||||
} | |||||
} | |||||
if (grp == NULL) { | |||||
/* Create new load balance group */ | |||||
grp = in_pcblbgroup_alloc(hdr, inp->inp_vflag, | |||||
Done Inline ActionsThis vertical whitespace is probably not needed. rwatson: This vertical whitespace is probably not needed. | |||||
inp->inp_lport, &inp->inp_inc.inc_ie.ie_dependladdr, | |||||
INPCBLBGROUP_SIZMIN); | |||||
if(!grp) | |||||
return (ENOBUFS); | |||||
} else if (grp->il_inpcnt == grp->il_inpsiz) { | |||||
if (grp->il_inpsiz >= INPCBLBGROUP_SIZMAX) { | |||||
static int limit_logged = 0; | |||||
if (!limit_logged) { | |||||
limit_logged = 1; | |||||
printf("lb group port %d, " | |||||
Done Inline ActionsComment should be a full sentence. rwatson: Comment should be a full sentence. | |||||
"limit reached\n", ntohs(grp->il_lport)); | |||||
} | |||||
return 0; | |||||
} | |||||
/* Expand this local group */ | |||||
grp = in_pcblbgroup_resize(hdr, grp, grp->il_inpsiz * 2); | |||||
if(!grp) | |||||
Done Inline ActionsThis variable would ideally be declared at the top of the function, in style(9). rwatson: This variable would ideally be declared at the top of the function, in style(9). | |||||
return (ENOBUFS); | |||||
} | |||||
KASSERT(grp->il_inpcnt < grp->il_inpsiz, | |||||
("invalid local group size %d and count %d", | |||||
grp->il_inpsiz, grp->il_inpcnt)); | |||||
grp->il_inp[grp->il_inpcnt] = inp; | |||||
grp->il_inpcnt++; | |||||
return 0; | |||||
Done Inline ActionsComment should be a full sentence. rwatson: Comment should be a full sentence. | |||||
} | |||||
static void | |||||
in_pcbremlbgrouphash(struct inpcb *inp, struct inpcbinfo *pcbinfo) | |||||
{ | |||||
struct inpcblbgrouphead *hdr; | |||||
struct inpcblbgroup *grp; | |||||
if (pcbinfo->ipi_lbgrouphashbase == NULL) | |||||
return; | |||||
hdr = &pcbinfo->ipi_lbgrouphashbase[ | |||||
INP_PCBLBGROUP_PORTHASH(inp->inp_lport, pcbinfo->ipi_lbgrouphashmask)]; | |||||
LIST_FOREACH(grp, hdr, il_list) { | |||||
int i; | |||||
Done Inline ActionsHere, as above, can pcbinfo be implied by inp? rwatson: Here, as above, can pcbinfo be implied by inp? | |||||
for (i = 0; i < grp->il_inpcnt; ++i) { | |||||
if (grp->il_inp[i] != inp) | |||||
continue; | |||||
if (grp->il_inpcnt == 1) { | |||||
/* Free this local group */ | |||||
in_pcblbgroup_free(grp); | |||||
} else { | |||||
/* Pull up inpcbs */ | |||||
for (; i + 1 < grp->il_inpcnt; ++i) | |||||
grp->il_inp[i] = grp->il_inp[i + 1]; | |||||
grp->il_inpcnt--; | |||||
if (grp->il_inpsiz > INPCBLBGROUP_SIZMIN && | |||||
grp->il_inpcnt <= (grp->il_inpsiz / 4)) { | |||||
/* Shrink this local group */ | |||||
struct inpcblbgroup *new_grp = | |||||
in_pcblbgroup_resize(hdr, grp, grp->il_inpsiz / 2); | |||||
if(new_grp) | |||||
grp = new_grp; | |||||
} | |||||
} | |||||
Done Inline ActionsComment should be a full sentence. rwatson: Comment should be a full sentence. | |||||
return; | |||||
} | |||||
} | |||||
Done Inline ActionsComment should be a full sentence. rwatson: Comment should be a full sentence. | |||||
} | |||||
/* | /* | ||||
* Different protocols initialize their inpcbs differently - giving | * Different protocols initialize their inpcbs differently - giving | ||||
* different name to the lock. But they all are disposed the same. | * different name to the lock. But they all are disposed the same. | ||||
Done Inline ActionsComment should be a full sentence. rwatson: Comment should be a full sentence. | |||||
Done Inline ActionsThis structure is visually confusing. Could we break some of this out into another function, or use another control-flow structure? Currently it's hard to see how the return fits. rwatson: This structure is visually confusing. Could we break some of this out into another function, or… | |||||
Context not available. | |||||
&pcbinfo->ipi_hashmask); | &pcbinfo->ipi_hashmask); | ||||
pcbinfo->ipi_porthashbase = hashinit(porthash_nelements, M_PCB, | pcbinfo->ipi_porthashbase = hashinit(porthash_nelements, M_PCB, | ||||
&pcbinfo->ipi_porthashmask); | &pcbinfo->ipi_porthashmask); | ||||
pcbinfo->ipi_lbgrouphashbase = hashinit(hash_nelements, M_PCB, | |||||
&pcbinfo->ipi_lbgrouphashmask); | |||||
#ifdef PCBGROUP | #ifdef PCBGROUP | ||||
in_pcbgroup_init(pcbinfo, hashfields, hash_nelements); | in_pcbgroup_init(pcbinfo, hashfields, hash_nelements); | ||||
#endif | #endif | ||||
Context not available. | |||||
hashdestroy(pcbinfo->ipi_hashbase, M_PCB, pcbinfo->ipi_hashmask); | hashdestroy(pcbinfo->ipi_hashbase, M_PCB, pcbinfo->ipi_hashmask); | ||||
hashdestroy(pcbinfo->ipi_porthashbase, M_PCB, | hashdestroy(pcbinfo->ipi_porthashbase, M_PCB, | ||||
pcbinfo->ipi_porthashmask); | pcbinfo->ipi_porthashmask); | ||||
hashdestroy(pcbinfo->ipi_lbgrouphashbase, M_PCB, | |||||
pcbinfo->ipi_lbgrouphashmask); | |||||
#ifdef PCBGROUP | #ifdef PCBGROUP | ||||
in_pcbgroup_destroy(pcbinfo); | in_pcbgroup_destroy(pcbinfo); | ||||
#endif | #endif | ||||
Context not available. | |||||
/* | /* | ||||
* Return cached socket options. | * Return cached socket options. | ||||
*/ | */ | ||||
short | int | ||||
inp_so_options(const struct inpcb *inp) | inp_so_options(const struct inpcb *inp) | ||||
{ | { | ||||
short so_options; | int so_options; | ||||
so_options = 0; | so_options = 0; | ||||
if ((inp->inp_flags2 & INP_REUSEPORT) != 0) | if ((inp->inp_flags2 & INP_REUSEPORT_LB) != 0) | ||||
so_options |= SO_REUSEPORT; | so_options |= SO_REUSEPORT_LB; | ||||
if ((inp->inp_flags2 & INP_REUSEADDR) != 0) | if ((inp->inp_flags2 & INP_REUSEPORT) != 0) | ||||
so_options |= SO_REUSEADDR; | so_options |= SO_REUSEPORT; | ||||
return (so_options); | if ((inp->inp_flags2 & INP_REUSEADDR) != 0) | ||||
so_options |= SO_REUSEADDR; | |||||
return (so_options); | |||||
} | } | ||||
#endif /* INET || INET6 */ | #endif /* INET || INET6 */ | ||||
Context not available. | |||||
int lookupflags = 0, reuseport = (so->so_options & SO_REUSEPORT); | int lookupflags = 0, reuseport = (so->so_options & SO_REUSEPORT); | ||||
int error; | int error; | ||||
/* | |||||
* XXX Maybe we could let SO_REUSEPORT_LB set SO_REUSEPORT bit here | |||||
* so that we don't have to add to the (already messy) code below | |||||
*/ | |||||
int reuseport_lb = (so->so_options & SO_REUSEPORT_LB); | |||||
/* | /* | ||||
* No state changes, so read locks are sufficient here. | * No state changes, so read locks are sufficient here. | ||||
*/ | */ | ||||
Context not available. | |||||
laddr.s_addr = *laddrp; | laddr.s_addr = *laddrp; | ||||
if (nam != NULL && laddr.s_addr != INADDR_ANY) | if (nam != NULL && laddr.s_addr != INADDR_ANY) | ||||
return (EINVAL); | return (EINVAL); | ||||
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0) | if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT|SO_REUSEPORT_LB)) == 0) | ||||
lookupflags = INPLOOKUP_WILDCARD; | lookupflags = INPLOOKUP_WILDCARD; | ||||
if (nam == NULL) { | if (nam == NULL) { | ||||
Done Inline ActionsComment should be a full sentence. rwatson: Comment should be a full sentence. | |||||
if ((error = prison_local_ip4(cred, &laddr)) != 0) | if ((error = prison_local_ip4(cred, &laddr)) != 0) | ||||
Context not available. | |||||
*/ | */ | ||||
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) != 0) | if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) != 0) | ||||
reuseport = SO_REUSEADDR|SO_REUSEPORT; | reuseport = SO_REUSEADDR|SO_REUSEPORT; | ||||
// XXX: How to deal with SO_REUSEPORT_LB here? | |||||
// Added equivalent treatment as SO_REUSEPORT here for now | |||||
if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT_LB)) != 0) | |||||
reuseport_lb = SO_REUSEADDR|SO_REUSEPORT_LB; | |||||
} else if (sin->sin_addr.s_addr != INADDR_ANY) { | } else if (sin->sin_addr.s_addr != INADDR_ANY) { | ||||
sin->sin_port = 0; /* yech... */ | sin->sin_port = 0; /* yech... */ | ||||
bzero(&sin->sin_zero, sizeof(sin->sin_zero)); | bzero(&sin->sin_zero, sizeof(sin->sin_zero)); | ||||
/* | /* | ||||
* Is the address a local IP address? | * Is the address a local IP address? | ||||
* If INP_BINDANY is set, then the socket may be bound | * If INP_BINDANY is set, then the socket may be bound | ||||
* to any endpoint address, local or not. | * to any endpoint address, local or not. | ||||
*/ | */ | ||||
if ((inp->inp_flags & INP_BINDANY) == 0 && | if ((inp->inp_flags & INP_BINDANY) == 0 && | ||||
ifa_ifwithaddr_check((struct sockaddr *)sin) == 0) | ifa_ifwithaddr_check((struct sockaddr *)sin) == 0) | ||||
return (EADDRNOTAVAIL); | return (EADDRNOTAVAIL); | ||||
} | } | ||||
laddr = sin->sin_addr; | laddr = sin->sin_addr; | ||||
Context not available. | |||||
ntohl(t->inp_faddr.s_addr) == INADDR_ANY) && | ntohl(t->inp_faddr.s_addr) == INADDR_ANY) && | ||||
(ntohl(sin->sin_addr.s_addr) != INADDR_ANY || | (ntohl(sin->sin_addr.s_addr) != INADDR_ANY || | ||||
ntohl(t->inp_laddr.s_addr) != INADDR_ANY || | ntohl(t->inp_laddr.s_addr) != INADDR_ANY || | ||||
(t->inp_flags2 & INP_REUSEPORT) == 0) && | (t->inp_flags2 & INP_REUSEPORT) || | ||||
(t->inp_flags2 & INP_REUSEPORT_LB) == 0) && | |||||
(inp->inp_cred->cr_uid != | (inp->inp_cred->cr_uid != | ||||
t->inp_cred->cr_uid)) | t->inp_cred->cr_uid)) | ||||
return (EADDRINUSE); | return (EADDRINUSE); | ||||
Context not available. | |||||
*/ | */ | ||||
tw = intotw(t); | tw = intotw(t); | ||||
if (tw == NULL || | if (tw == NULL || | ||||
(reuseport & tw->tw_so_options) == 0) | ((reuseport & tw->tw_so_options) == 0 && | ||||
(reuseport_lb & tw->tw_so_options) == 0)) { | |||||
return (EADDRINUSE); | return (EADDRINUSE); | ||||
} | |||||
} else if (t && | } else if (t && | ||||
((inp->inp_flags2 & INP_BINDMULTI) == 0) && | ((inp->inp_flags2 & INP_BINDMULTI) == 0) && | ||||
(reuseport & inp_so_options(t)) == 0) { | (reuseport & inp_so_options(t)) == 0 && | ||||
(reuseport_lb & inp_so_options(t)) == 0) { | |||||
#ifdef INET6 | #ifdef INET6 | ||||
if (ntohl(sin->sin_addr.s_addr) != | if (ntohl(sin->sin_addr.s_addr) != | ||||
INADDR_ANY || | INADDR_ANY || | ||||
Context not available. | |||||
(inp->inp_vflag & INP_IPV6PROTO) == 0 || | (inp->inp_vflag & INP_IPV6PROTO) == 0 || | ||||
(t->inp_vflag & INP_IPV6PROTO) == 0) | (t->inp_vflag & INP_IPV6PROTO) == 0) | ||||
#endif | #endif | ||||
return (EADDRINUSE); | return (EADDRINUSE); | ||||
if (t && (! in_pcbbind_check_bindmulti(inp, t))) | if (t && (! in_pcbbind_check_bindmulti(inp, t))) | ||||
return (EADDRINUSE); | return (EADDRINUSE); | ||||
} | } | ||||
Context not available. | |||||
struct inpcbport *phd = inp->inp_phd; | struct inpcbport *phd = inp->inp_phd; | ||||
INP_HASH_WLOCK(inp->inp_pcbinfo); | INP_HASH_WLOCK(inp->inp_pcbinfo); | ||||
in_pcbremlbgrouphash(inp, inp->inp_pcbinfo); | |||||
LIST_REMOVE(inp, inp_hash); | LIST_REMOVE(inp, inp_hash); | ||||
LIST_REMOVE(inp, inp_portlist); | LIST_REMOVE(inp, inp_portlist); | ||||
if (LIST_FIRST(&phd->phd_pcblist) == NULL) { | if (LIST_FIRST(&phd->phd_pcblist) == NULL) { | ||||
Context not available. | |||||
} | } | ||||
#undef INP_LOOKUP_MAPPED_PCB_COST | #undef INP_LOOKUP_MAPPED_PCB_COST | ||||
struct inpcb * | |||||
in_pcblookup_lbgroup_last(const struct inpcb *inp) | |||||
{ | |||||
const struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; | |||||
const struct inpcblbgrouphead *hdr; | |||||
const struct inpcblbgroup *grp; | |||||
int i; | |||||
if (pcbinfo->ipi_lbgrouphashbase == NULL) | |||||
return NULL; | |||||
hdr = &pcbinfo->ipi_lbgrouphashbase[ | |||||
INP_PCBLBGROUP_PORTHASH(inp->inp_lport, pcbinfo->ipi_lbgrouphashmask)]; | |||||
LIST_FOREACH(grp, hdr, il_list) { | |||||
if (grp->il_vflag == inp->inp_vflag && | |||||
grp->il_lport == inp->inp_lport && | |||||
memcmp(&grp->il_dependladdr, | |||||
&inp->inp_inc.inc_ie.ie_dependladdr, | |||||
sizeof(grp->il_dependladdr)) == 0) { | |||||
break; | |||||
} | |||||
} | |||||
if (grp == NULL || grp->il_inpcnt == 1) | |||||
return NULL; | |||||
KASSERT(grp->il_inpcnt >= 2, | |||||
("invalid lbgroup inp count %d", grp->il_inpcnt)); | |||||
for (i = 0; i < grp->il_inpcnt; ++i) { | |||||
if (grp->il_inp[i] == inp) { | |||||
int last = grp->il_inpcnt - 1; | |||||
if (i == last) | |||||
last = grp->il_inpcnt - 2; | |||||
return grp->il_inp[last]; | |||||
} | |||||
} | |||||
return NULL; | |||||
} | |||||
static struct inpcb * | |||||
in_pcblookup_lbgroup(const struct inpcbinfo *pcbinfo, | |||||
const struct in_addr *laddr, uint16_t lport, const struct in_addr *faddr, | |||||
uint16_t fport, int lookupflags) | |||||
{ | |||||
struct inpcb *local_wild = NULL; | |||||
const struct inpcblbgrouphead *hdr; | |||||
struct inpcblbgroup *grp; | |||||
struct inpcblbgroup *grp_local_wild; | |||||
hdr = &pcbinfo->ipi_lbgrouphashbase[ | |||||
INP_PCBLBGROUP_PORTHASH(lport, pcbinfo->ipi_lbgrouphashmask)]; | |||||
/* | |||||
* Order of socket selection: | |||||
* 1. non-wild. | |||||
* 2. wild (if lookupflags contains INPLOOKUP_WILDCARD). | |||||
* | |||||
* NOTE: | |||||
* - Load balanced group does not contain jailed sockets | |||||
* - Load balanced group does not contain IPv4 mapped INET6 wild sockets | |||||
*/ | |||||
LIST_FOREACH(grp, hdr, il_list) { | |||||
#ifdef INET6 | |||||
if (!(grp->il_vflag & INP_IPV4)) | |||||
continue; | |||||
#endif | |||||
if (grp->il_lport == lport) { | |||||
uint32_t idx = 0; | |||||
int pkt_hash = INP_PCBLBGROUP_PKTHASH(faddr->s_addr, lport, fport); | |||||
idx = pkt_hash % grp->il_inpcnt; | |||||
if (grp->il_laddr.s_addr == laddr->s_addr) { | |||||
Done Inline ActionsShould these assertions be before the if() clause above? rwatson: Should these assertions be before the if() clause above? | |||||
return grp->il_inp[idx]; | |||||
} else { | |||||
if (grp->il_laddr.s_addr == INADDR_ANY && | |||||
(lookupflags & INPLOOKUP_WILDCARD)) { | |||||
local_wild = grp->il_inp[idx]; | |||||
grp_local_wild = grp; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
if (local_wild != NULL) { | |||||
return local_wild; | |||||
} | |||||
return NULL; | |||||
} | |||||
#ifdef PCBGROUP | #ifdef PCBGROUP | ||||
/* | /* | ||||
* Lookup PCB in hash list, using pcbgroup tables. | * Lookup PCB in hash list, using pcbgroup tables. | ||||
Done Inline ActionsThis variable declaration would ideally be above. rwatson: This variable declaration would ideally be above. | |||||
Context not available. | |||||
if (tmpinp != NULL) | if (tmpinp != NULL) | ||||
return (tmpinp); | return (tmpinp); | ||||
/* | |||||
* Then look in lb group (for wildcard match) | |||||
*/ | |||||
if (pcbinfo->ipi_lbgrouphashbase != NULL && | |||||
(lookupflags & INPLOOKUP_WILDCARD)) { | |||||
inp = in_pcblookup_lbgroup(pcbinfo, &laddr, lport, &faddr, fport, | |||||
lookupflags); | |||||
if (inp != NULL) { | |||||
return inp; | |||||
} | |||||
} | |||||
/* | /* | ||||
* Then look for a wildcard match, if requested. | * Then look for a wildcard match, if requested. | ||||
*/ | */ | ||||
Done Inline ActionsComment should be a full sentence. rwatson: Comment should be a full sentence. | |||||
Context not available. | |||||
struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; | struct inpcbinfo *pcbinfo = inp->inp_pcbinfo; | ||||
struct inpcbport *phd; | struct inpcbport *phd; | ||||
u_int32_t hashkey_faddr; | u_int32_t hashkey_faddr; | ||||
int so_options; | |||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
INP_HASH_WLOCK_ASSERT(pcbinfo); | INP_HASH_WLOCK_ASSERT(pcbinfo); | ||||
Context not available. | |||||
pcbporthash = &pcbinfo->ipi_porthashbase[ | pcbporthash = &pcbinfo->ipi_porthashbase[ | ||||
INP_PCBPORTHASH(inp->inp_lport, pcbinfo->ipi_porthashmask)]; | INP_PCBPORTHASH(inp->inp_lport, pcbinfo->ipi_porthashmask)]; | ||||
/* | |||||
* Add entry in lb group | |||||
* Only do this if SO_REUSEPORT_LB is set | |||||
*/ | |||||
so_options = inp_so_options(inp); | |||||
if(so_options & SO_REUSEPORT_LB) { | |||||
int ret = in_pcbinslbgrouphash(inp, pcbinfo); | |||||
if(ret) { | |||||
// pcb lb group malloc fail (ret=ENOBUFS) | |||||
return ret; | |||||
} | |||||
} | |||||
/* | /* | ||||
* Go through port list and look for a head for this lport. | * Go through port list and look for a head for this lport. | ||||
*/ | */ | ||||
Done Inline ActionsComment should be a full sentence. rwatson: Comment should be a full sentence. | |||||
Done Inline ActionsUse a C-style comment, not C++, for a block comment. Comment should be a full sentence. rwatson: Use a C-style comment, not C++, for a block comment. Comment should be a full sentence. | |||||
Done Inline Actionsstyle(9) requires () around return arguments. rwatson: style(9) requires () around return arguments. | |||||
Context not available. | |||||
struct inpcbport *phd = inp->inp_phd; | struct inpcbport *phd = inp->inp_phd; | ||||
INP_HASH_WLOCK(pcbinfo); | INP_HASH_WLOCK(pcbinfo); | ||||
// XXX Only do if SO_REUSEPORT_LB set? | |||||
in_pcbremlbgrouphash(inp, pcbinfo); | |||||
LIST_REMOVE(inp, inp_hash); | LIST_REMOVE(inp, inp_hash); | ||||
LIST_REMOVE(inp, inp_portlist); | LIST_REMOVE(inp, inp_portlist); | ||||
if (LIST_FIRST(&phd->phd_pcblist) == NULL) { | if (LIST_FIRST(&phd->phd_pcblist) == NULL) { | ||||
Context not available. | |||||
Done Inline ActionsUse a C-style comment. rwatson: Use a C-style comment. |
Should there be a lock assertion here?