/* * Lookup PCB in hash list. */ struct inpcb * in_pcblookuphash(struct inpcbinfo *pcbinfo, struct in_addr faddr, u_int fport_arg, struct in_addr laddr, u_int lport_arg, int wildcard) { struct inpcbhead *head; register struct inpcb *inp; u_short fport = fport_arg, lport = lport_arg; int s; s = splnet(); /* * First look for an exact match. */ head = &pcbinfo->hashbase[INP_PCBHASH(faddr.s_addr, lport, fport, pcbinfo->hashmask)]; for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { if (inp->inp_faddr.s_addr == faddr.s_addr && inp->inp_laddr.s_addr == laddr.s_addr && inp->inp_fport == fport && inp->inp_lport == lport) goto found; } if (wildcard) { struct inpcb *local_wild = NULL; head = &pcbinfo->hashbase[INP_PCBHASH(INADDR_ANY, lport, 0, pcbinfo->hashmask)]; for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { if (inp->inp_faddr.s_addr == INADDR_ANY && inp->inp_fport == 0 && inp->inp_lport == lport) { if (inp->inp_laddr.s_addr == laddr.s_addr) goto found; else if (inp->inp_laddr.s_addr == INADDR_ANY) local_wild = inp; } } if (local_wild != NULL) { inp = local_wild; goto found; } } splx(s); return (NULL); found: /* * Move PCB to head of this hash chain so that it can be * found more quickly in the future. * XXX - this is a pessimization on machines with few * concurrent connections. */ if (inp != head->lh_first) { LIST_REMOVE(inp, inp_hash); LIST_INSERT_HEAD(head, inp, inp_hash); } splx(s); return (inp); }
/* * Update the pcbgroup of an inpcb, which might include removing an old * pcbgroup reference and/or adding a new one. Wildcard processing is not * performed here, although ideally we'll never install a pcbgroup for a * wildcard inpcb (asserted below). */ static void in_pcbgroup_update_internal(struct inpcbinfo *pcbinfo, struct inpcbgroup *newpcbgroup, struct inpcb *inp) { struct inpcbgroup *oldpcbgroup; struct inpcbhead *pcbhash; uint32_t hashkey_faddr; INP_WLOCK_ASSERT(inp); oldpcbgroup = inp->inp_pcbgroup; if (oldpcbgroup != NULL && oldpcbgroup != newpcbgroup) { INP_GROUP_LOCK(oldpcbgroup); LIST_REMOVE(inp, inp_pcbgrouphash); inp->inp_pcbgroup = NULL; INP_GROUP_UNLOCK(oldpcbgroup); } if (newpcbgroup != NULL && oldpcbgroup != newpcbgroup) { #ifdef INET6 if (inp->inp_vflag & INP_IPV6) hashkey_faddr = INP6_PCBHASHKEY(&inp->in6p_faddr); else #endif hashkey_faddr = inp->inp_faddr.s_addr; INP_GROUP_LOCK(newpcbgroup); /* * If the inp is an RSS bucket wildcard entry, ensure * that the PCB hash is calculated correctly. * * The wildcard hash calculation differs from the * non-wildcard definition. The source address is * INADDR_ANY and the far port is 0. */ if (inp->inp_flags2 & INP_RSS_BUCKET_SET) { pcbhash = &newpcbgroup->ipg_hashbase[ INP_PCBHASH(INADDR_ANY, inp->inp_lport, 0, newpcbgroup->ipg_hashmask)]; } else { pcbhash = &newpcbgroup->ipg_hashbase[ INP_PCBHASH(hashkey_faddr, inp->inp_lport, inp->inp_fport, newpcbgroup->ipg_hashmask)]; } LIST_INSERT_HEAD(pcbhash, inp, inp_pcbgrouphash); inp->inp_pcbgroup = newpcbgroup; INP_GROUP_UNLOCK(newpcbgroup); } KASSERT(!(newpcbgroup != NULL && in_pcbwild_needed(inp)), ("%s: pcbgroup and wildcard!", __func__)); }
/* * Insert PCB into hash chain. Must be called at splnet. */ static void in_pcbinshash(struct inpcb *inp) { struct inpcbhead *head; head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; LIST_INSERT_HEAD(head, inp, inp_hash); }
void in_pcbrehash(struct inpcb *inp) { struct inpcbhead *head; int s; s = splnet(); LIST_REMOVE(inp, inp_hash); head = &inp->inp_pcbinfo->hashbase[INP_PCBHASH(inp->inp_faddr.s_addr, inp->inp_lport, inp->inp_fport, inp->inp_pcbinfo->hashmask)]; LIST_INSERT_HEAD(head, inp, inp_hash); inp->inp_pcbinfo->ipi_count--; splx(s); }
static void in_pcbwild_add(struct inpcb *inp) { struct inpcbinfo *pcbinfo; struct inpcbhead *head; u_int pgn; INP_WLOCK_ASSERT(inp); KASSERT(!(inp->inp_flags2 & INP_PCBGROUPWILD), ("%s: is wild",__func__)); pcbinfo = inp->inp_pcbinfo; for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++) INP_GROUP_LOCK(&pcbinfo->ipi_pcbgroups[pgn]); head = &pcbinfo->ipi_wildbase[INP_PCBHASH(INADDR_ANY, inp->inp_lport, 0, pcbinfo->ipi_wildmask)]; LIST_INSERT_HEAD(head, inp, inp_pcbgroup_wild); inp->inp_flags2 |= INP_PCBGROUPWILD; for (pgn = 0; pgn < pcbinfo->ipi_npcbgroups; pgn++) INP_GROUP_UNLOCK(&pcbinfo->ipi_pcbgroups[pgn]); }
/* * Update the pcbgroup of an inpcb, which might include removing an old * pcbgroup reference and/or adding a new one. Wildcard processing is not * performed here, although ideally we'll never install a pcbgroup for a * wildcard inpcb (asserted below). */ static void in_pcbgroup_update_internal(struct inpcbinfo *pcbinfo, struct inpcbgroup *newpcbgroup, struct inpcb *inp) { struct inpcbgroup *oldpcbgroup; struct inpcbhead *pcbhash; uint32_t hashkey_faddr; INP_WLOCK_ASSERT(inp); oldpcbgroup = inp->inp_pcbgroup; if (oldpcbgroup != NULL && oldpcbgroup != newpcbgroup) { INP_GROUP_LOCK(oldpcbgroup); LIST_REMOVE(inp, inp_pcbgrouphash); inp->inp_pcbgroup = NULL; INP_GROUP_UNLOCK(oldpcbgroup); } if (newpcbgroup != NULL && oldpcbgroup != newpcbgroup) { #ifdef INET6 if (inp->inp_vflag & INP_IPV6) hashkey_faddr = inp->in6p_faddr.s6_addr32[3]; /* XXX */ else #endif hashkey_faddr = inp->inp_faddr.s_addr; INP_GROUP_LOCK(newpcbgroup); pcbhash = &newpcbgroup->ipg_hashbase[ INP_PCBHASH(hashkey_faddr, inp->inp_lport, inp->inp_fport, newpcbgroup->ipg_hashmask)]; LIST_INSERT_HEAD(pcbhash, inp, inp_pcbgrouphash); inp->inp_pcbgroup = newpcbgroup; INP_GROUP_UNLOCK(newpcbgroup); } KASSERT(!(newpcbgroup != NULL && in_pcbwild_needed(inp)), ("%s: pcbgroup and wildcard!", __func__)); }