Hash unconnected PCBs.

This commit is contained in:
mycroft 1996-09-15 18:11:06 +00:00
parent 89986fec30
commit 9bfa240a98
6 changed files with 178 additions and 133 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: in_pcb.c,v 1.32 1996/09/09 14:51:12 mycroft Exp $ */
/* $NetBSD: in_pcb.c,v 1.33 1996/09/15 18:11:06 mycroft Exp $ */
/*
* Copyright (c) 1982, 1986, 1991, 1993
@ -59,17 +59,29 @@
struct in_addr zeroin_addr;
#define INPCBHASH(table, faddr, fport, laddr, lport) \
&(table)->inpt_hashtbl[(ntohl((faddr).s_addr) + ntohs((fport)) + ntohs((lport))) & (table->inpt_hash)]
#define INPCBHASH_BIND(table, laddr, lport) \
&(table)->inpt_bindhashtbl[ \
((ntohl((laddr).s_addr) + ntohs(lport))) & (table)->inpt_bindhash]
#define INPCBHASH_CONNECT(table, faddr, fport, laddr, lport) \
&(table)->inpt_connecthashtbl[ \
((ntohl((faddr).s_addr) + ntohs(fport)) + \
(ntohl((laddr).s_addr) + ntohs(lport))) & (table)->inpt_connecthash]
struct inpcb *
in_pcblookup_port __P((struct inpcbtable *,
struct in_addr, u_int, int));
void
in_pcbinit(table, hashsize)
in_pcbinit(table, bindhashsize, connecthashsize)
struct inpcbtable *table;
int hashsize;
int bindhashsize, connecthashsize;
{
CIRCLEQ_INIT(&table->inpt_queue);
table->inpt_hashtbl = hashinit(hashsize, M_PCB, &table->inpt_hash);
table->inpt_bindhashtbl =
hashinit(bindhashsize, M_PCB, &table->inpt_bindhash);
table->inpt_connecthashtbl =
hashinit(connecthashsize, M_PCB, &table->inpt_connecthash);
table->inpt_lastport = 0;
}
@ -88,12 +100,11 @@ in_pcballoc(so, v)
bzero((caddr_t)inp, sizeof(*inp));
inp->inp_table = table;
inp->inp_socket = so;
so->so_pcb = inp;
s = splnet();
CIRCLEQ_INSERT_HEAD(&table->inpt_queue, inp, inp_queue);
LIST_INSERT_HEAD(INPCBHASH(table, inp->inp_faddr, inp->inp_fport,
inp->inp_laddr, inp->inp_lport), inp, inp_hash);
in_pcbstate(inp, INP_ATTACHED);
splx(s);
so->so_pcb = inp;
return (0);
}
@ -156,8 +167,7 @@ in_pcbbind(v, nam, p)
(p == 0 || (error = suser(p->p_ucred, &p->p_acflag))))
return (EACCES);
#endif
t = in_pcblookup(table, zeroin_addr, 0, sin->sin_addr,
lport, wild);
t = in_pcblookup_port(table, sin->sin_addr, lport, wild);
if (t && (reuseport & t->inp_socket->so_options) == 0)
return (EADDRINUSE);
}
@ -169,10 +179,9 @@ noname:
table->inpt_lastport > IPPORT_USERRESERVED)
table->inpt_lastport = IPPORT_RESERVED;
lport = htons(table->inpt_lastport);
} while (in_pcblookup(table,
zeroin_addr, 0, inp->inp_laddr, lport, wild));
} while (in_pcblookup_port(table, inp->inp_laddr, lport, wild));
inp->inp_lport = lport;
in_pcbrehash(inp);
in_pcbstate(inp, INP_BOUND);
return (0);
}
@ -291,7 +300,7 @@ in_pcbconnect(v, nam)
}
ifaddr = satosin(&ia->ia_addr);
}
if (in_pcbhashlookup(inp->inp_table, sin->sin_addr, sin->sin_port,
if (in_pcblookup_connect(inp->inp_table, sin->sin_addr, sin->sin_port,
!in_nullhost(inp->inp_laddr) ? inp->inp_laddr : ifaddr->sin_addr,
inp->inp_lport) != 0)
return (EADDRINUSE);
@ -303,7 +312,7 @@ in_pcbconnect(v, nam)
}
inp->inp_faddr = sin->sin_addr;
inp->inp_fport = sin->sin_port;
in_pcbrehash(inp);
in_pcbstate(inp, INP_CONNECTED);
return (0);
}
@ -315,7 +324,7 @@ in_pcbdisconnect(v)
inp->inp_faddr = zeroin_addr;
inp->inp_fport = 0;
in_pcbrehash(inp);
in_pcbstate(inp, INP_BOUND);
if (inp->inp_socket->so_state & SS_NOFDREF)
in_pcbdetach(inp);
}
@ -336,7 +345,7 @@ in_pcbdetach(v)
rtfree(inp->inp_route.ro_rt);
ip_freemoptions(inp->inp_moptions);
s = splnet();
LIST_REMOVE(inp, inp_hash);
in_pcbstate(inp, INP_ATTACHED);
CIRCLEQ_REMOVE(&inp->inp_table->inpt_queue, inp, inp_queue);
splx(s);
FREE(inp, M_PCB);
@ -393,26 +402,21 @@ in_pcbnotify(table, faddr, fport_arg, laddr, lport_arg, errno, notify)
int errno;
void (*notify) __P((struct inpcb *, int));
{
register struct inpcb *inp, *oinp;
struct inpcbhead *head;
register struct inpcb *inp, *ninp;
u_int16_t fport = fport_arg, lport = lport_arg;
if (in_nullhost(faddr))
if (in_nullhost(faddr) || notify == 0)
return;
for (inp = table->inpt_queue.cqh_first;
inp != (struct inpcb *)&table->inpt_queue;) {
if (!in_hosteq(inp->inp_faddr, faddr) ||
inp->inp_socket == 0 ||
inp->inp_fport != fport ||
inp->inp_lport != lport ||
!in_hosteq(inp->inp_laddr, laddr)) {
inp = inp->inp_queue.cqe_next;
continue;
}
oinp = inp;
inp = inp->inp_queue.cqe_next;
if (notify)
(*notify)(oinp, errno);
head = INPCBHASH_CONNECT(table, faddr, fport, laddr, lport);
for (inp = head->lh_first; inp != NULL; inp = ninp) {
ninp = inp->inp_hash.le_next;
if (in_hosteq(inp->inp_faddr, faddr) &&
inp->inp_fport == fport &&
inp->inp_lport == lport &&
in_hosteq(inp->inp_laddr, laddr))
(*notify)(inp, errno);
}
}
@ -423,22 +427,17 @@ in_pcbnotifyall(table, faddr, errno, notify)
int errno;
void (*notify) __P((struct inpcb *, int));
{
register struct inpcb *inp, *oinp;
register struct inpcb *inp, *ninp;
if (in_nullhost(faddr))
if (in_nullhost(faddr) || notify == 0)
return;
for (inp = table->inpt_queue.cqh_first;
inp != (struct inpcb *)&table->inpt_queue;) {
if (!in_hosteq(inp->inp_faddr, faddr) ||
inp->inp_socket == 0) {
inp = inp->inp_queue.cqe_next;
continue;
}
oinp = inp;
inp = inp->inp_queue.cqe_next;
if (notify)
(*notify)(oinp, errno);
inp != (struct inpcb *)&table->inpt_queue;
inp = ninp) {
ninp = inp->inp_queue.cqe_next;
if (in_hosteq(inp->inp_faddr, faddr))
(*notify)(inp, errno);
}
}
@ -497,15 +496,15 @@ in_rtchange(inp, errno)
}
struct inpcb *
in_pcblookup(table, faddr, fport_arg, laddr, lport_arg, flags)
in_pcblookup_port(table, laddr, lport_arg, flags)
struct inpcbtable *table;
struct in_addr faddr, laddr;
u_int fport_arg, lport_arg;
struct in_addr laddr;
u_int lport_arg;
int flags;
{
register struct inpcb *inp, *match = 0;
int matchwild = 3, wildcard;
u_int16_t fport = fport_arg, lport = lport_arg;
u_int16_t lport = lport_arg;
for (inp = table->inpt_queue.cqh_first;
inp != (struct inpcb *)&table->inpt_queue;
@ -513,18 +512,8 @@ in_pcblookup(table, faddr, fport_arg, laddr, lport_arg, flags)
if (inp->inp_lport != lport)
continue;
wildcard = 0;
if (in_nullhost(inp->inp_faddr)) {
if (!in_nullhost(faddr))
wildcard++;
} else {
if (in_nullhost(faddr))
wildcard++;
else {
if (!in_hosteq(inp->inp_faddr, faddr) ||
inp->inp_fport != fport)
continue;
}
}
if (!in_nullhost(inp->inp_faddr))
wildcard++;
if (in_nullhost(inp->inp_laddr)) {
if (!in_nullhost(laddr))
wildcard++;
@ -548,26 +537,12 @@ in_pcblookup(table, faddr, fport_arg, laddr, lport_arg, flags)
return (match);
}
void
in_pcbrehash(inp)
struct inpcb *inp;
{
struct inpcbtable *table = inp->inp_table;
int s;
s = splnet();
LIST_REMOVE(inp, inp_hash);
LIST_INSERT_HEAD(INPCBHASH(table, inp->inp_faddr, inp->inp_fport,
inp->inp_laddr, inp->inp_lport), inp, inp_hash);
splx(s);
}
#ifdef DIAGNOSTIC
int in_pcbnotifymiss = 0;
#endif
struct inpcb *
in_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg)
in_pcblookup_connect(table, faddr, fport_arg, laddr, lport_arg)
struct inpcbtable *table;
struct in_addr faddr, laddr;
u_int fport_arg, lport_arg;
@ -576,30 +551,91 @@ in_pcbhashlookup(table, faddr, fport_arg, laddr, lport_arg)
register struct inpcb *inp;
u_int16_t fport = fport_arg, lport = lport_arg;
head = INPCBHASH(table, faddr, fport, laddr, lport);
head = INPCBHASH_CONNECT(table, faddr, fport, laddr, lport);
for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
if (!in_hosteq(inp->inp_faddr, faddr) ||
inp->inp_fport != fport ||
inp->inp_lport != lport ||
!in_hosteq(inp->inp_laddr, laddr))
continue;
/*
* Move this PCB to the head of hash chain so that
* repeated accesses are quicker. This is analogous to
* the historic single-entry PCB cache.
*/
if (inp != head->lh_first) {
LIST_REMOVE(inp, inp_hash);
LIST_INSERT_HEAD(head, inp, inp_hash);
}
break;
if (in_hosteq(inp->inp_faddr, faddr) &&
inp->inp_fport == fport &&
inp->inp_lport == lport &&
in_hosteq(inp->inp_laddr, laddr))
goto out;
}
#ifdef DIAGNOSTIC
if (inp == NULL && in_pcbnotifymiss) {
printf("in_pcbhashlookup: faddr=%08x fport=%d laddr=%08x lport=%d\n",
if (in_pcbnotifymiss) {
printf("in_pcblookup_connect: faddr=%08x fport=%d laddr=%08x lport=%d\n",
ntohl(faddr.s_addr), ntohs(fport),
ntohl(laddr.s_addr), ntohs(lport));
}
#endif
return (0);
out:
/* Move this PCB to the head of hash chain. */
if (inp != head->lh_first) {
LIST_REMOVE(inp, inp_hash);
LIST_INSERT_HEAD(head, inp, inp_hash);
}
return (inp);
}
struct inpcb *
in_pcblookup_bind(table, laddr, lport_arg)
struct inpcbtable *table;
struct in_addr laddr;
u_int lport_arg;
{
struct inpcbhead *head;
register struct inpcb *inp;
u_int16_t lport = lport_arg;
head = INPCBHASH_BIND(table, laddr, lport);
for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
if (inp->inp_lport == lport &&
in_hosteq(inp->inp_laddr, laddr))
goto out;
}
head = INPCBHASH_BIND(table, zeroin_addr, lport);
for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) {
if (inp->inp_lport == lport &&
in_hosteq(inp->inp_laddr, zeroin_addr))
goto out;
}
#ifdef DIAGNOSTIC
if (in_pcbnotifymiss) {
printf("in_pcblookup_bind: laddr=%08x lport=%d\n",
ntohl(laddr.s_addr), ntohs(lport));
}
#endif
return (0);
out:
/* Move this PCB to the head of hash chain. */
if (inp != head->lh_first) {
LIST_REMOVE(inp, inp_hash);
LIST_INSERT_HEAD(head, inp, inp_hash);
}
return (inp);
}
void
in_pcbstate(inp, state)
struct inpcb *inp;
int state;
{
if (inp->inp_state > INP_ATTACHED)
LIST_REMOVE(inp, inp_hash);
switch (state) {
case INP_BOUND:
LIST_INSERT_HEAD(INPCBHASH_BIND(inp->inp_table,
inp->inp_laddr, inp->inp_lport), inp, inp_hash);
break;
case INP_CONNECTED:
LIST_INSERT_HEAD(INPCBHASH_CONNECT(inp->inp_table,
inp->inp_faddr, inp->inp_fport,
inp->inp_laddr, inp->inp_lport), inp, inp_hash);
break;
}
inp->inp_state = state;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: in_pcb.h,v 1.16 1996/09/09 14:51:13 mycroft Exp $ */
/* $NetBSD: in_pcb.h,v 1.17 1996/09/15 18:11:07 mycroft Exp $ */
/*
* Copyright (c) 1982, 1986, 1990, 1993
@ -48,6 +48,7 @@ struct inpcb {
LIST_ENTRY(inpcb) inp_hash;
CIRCLEQ_ENTRY(inpcb) inp_queue;
struct inpcbtable *inp_table;
int inp_state; /* bind/connect state */
struct in_addr inp_faddr; /* foreign host table entry */
struct in_addr inp_laddr; /* local host table entry */
u_int16_t inp_fport; /* foreign port */
@ -61,13 +62,22 @@ struct inpcb {
struct ip_moptions *inp_moptions; /* IP multicast options */
};
LIST_HEAD(inpcbhead, inpcb);
struct inpcbtable {
CIRCLEQ_HEAD(, inpcb) inpt_queue;
LIST_HEAD(inpcbhead, inpcb) *inpt_hashtbl;
u_long inpt_hash;
struct inpcbhead *inpt_bindhashtbl;
struct inpcbhead *inpt_connecthashtbl;
u_long inpt_bindhash;
u_long inpt_connecthash;
u_int16_t inpt_lastport;
};
/* states in inp_state: */
#define INP_ATTACHED 0
#define INP_BOUND 1
#define INP_CONNECTED 2
/* flags in inp_flags: */
#define INP_RECVOPTS 0x01 /* receive incoming IP options */
#define INP_RECVRETOPTS 0x02 /* receive IP options for reply */
@ -76,30 +86,29 @@ struct inpcbtable {
#define INP_HDRINCL 0x08 /* user supplies entire IP header */
#define INPLOOKUP_WILDCARD 1
#define INPLOOKUP_SETLOCAL 2
#define sotoinpcb(so) ((struct inpcb *)(so)->so_pcb)
#ifdef _KERNEL
void in_losing __P((struct inpcb *));
int in_pcballoc __P((struct socket *, void *));
int in_pcbbind __P((void *, struct mbuf *, struct proc *));
int in_pcbconnect __P((void *, struct mbuf *));
void in_pcbdetach __P((void *));
void in_pcbdisconnect __P((void *));
void in_losing __P((struct inpcb *));
int in_pcballoc __P((struct socket *, void *));
int in_pcbbind __P((void *, struct mbuf *, struct proc *));
int in_pcbconnect __P((void *, struct mbuf *));
void in_pcbdetach __P((void *));
void in_pcbdisconnect __P((void *));
void in_pcbinit __P((struct inpcbtable *, int, int));
struct inpcb *
in_pcbhashlookup __P((struct inpcbtable *,
in_pcblookup_bind __P((struct inpcbtable *,
struct in_addr, u_int));
struct inpcb *
in_pcblookup_connect __P((struct inpcbtable *,
struct in_addr, u_int, struct in_addr, u_int));
void in_pcbinit __P((struct inpcbtable *, int));
struct inpcb *
in_pcblookup __P((struct inpcbtable *,
struct in_addr, u_int, struct in_addr, u_int, int));
void in_pcbnotify __P((struct inpcbtable *, struct in_addr, u_int,
void in_pcbnotify __P((struct inpcbtable *, struct in_addr, u_int,
struct in_addr, u_int, int, void (*)(struct inpcb *, int)));
void in_pcbnotifyall __P((struct inpcbtable *, struct in_addr, int,
void in_pcbnotifyall __P((struct inpcbtable *, struct in_addr, int,
void (*)(struct inpcb *, int)));
void in_pcbrehash __P((struct inpcb *));
void in_rtchange __P((struct inpcb *, int));
void in_setpeeraddr __P((struct inpcb *, struct mbuf *));
void in_setsockaddr __P((struct inpcb *, struct mbuf *));
void in_pcbstate __P((struct inpcb *, int));
void in_rtchange __P((struct inpcb *, int));
void in_setpeeraddr __P((struct inpcb *, struct mbuf *));
void in_setsockaddr __P((struct inpcb *, struct mbuf *));
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: raw_ip.c,v 1.32 1996/09/09 14:51:19 mycroft Exp $ */
/* $NetBSD: raw_ip.c,v 1.33 1996/09/15 18:11:08 mycroft Exp $ */
/*
* Copyright (c) 1982, 1986, 1988, 1993
@ -81,7 +81,7 @@ void
rip_init()
{
in_pcbinit(&rawcbtable, 1);
in_pcbinit(&rawcbtable, 1, 1);
}
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: tcp_input.c,v 1.25 1996/09/10 23:26:05 mycroft Exp $ */
/* $NetBSD: tcp_input.c,v 1.26 1996/09/15 18:11:09 mycroft Exp $ */
/*
* Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994
@ -348,12 +348,11 @@ tcp_input(m, va_alist)
* Locate pcb for segment.
*/
findpcb:
inp = in_pcbhashlookup(&tcbtable, ti->ti_src, ti->ti_sport,
inp = in_pcblookup_connect(&tcbtable, ti->ti_src, ti->ti_sport,
ti->ti_dst, ti->ti_dport);
if (inp == 0) {
++tcpstat.tcps_pcbhashmiss;
inp = in_pcblookup(&tcbtable, ti->ti_src, ti->ti_sport,
ti->ti_dst, ti->ti_dport, INPLOOKUP_WILDCARD);
inp = in_pcblookup_bind(&tcbtable, ti->ti_dst, ti->ti_dport);
if (inp == 0) {
++tcpstat.tcps_noport;
goto dropwithreset;
@ -403,7 +402,7 @@ findpcb:
inp = (struct inpcb *)so->so_pcb;
inp->inp_laddr = ti->ti_dst;
inp->inp_lport = ti->ti_dport;
in_pcbrehash(inp);
in_pcbstate(inp, INP_BOUND);
#if BSD>=43
inp->inp_options = ip_srcroute();
#endif

View File

@ -1,4 +1,4 @@
/* $NetBSD: tcp_subr.c,v 1.23 1996/09/09 14:51:21 mycroft Exp $ */
/* $NetBSD: tcp_subr.c,v 1.24 1996/09/15 18:11:10 mycroft Exp $ */
/*
* Copyright (c) 1982, 1986, 1988, 1990, 1993
@ -79,7 +79,7 @@ tcp_init()
{
tcp_iss = 1; /* XXX wrong */
in_pcbinit(&tcbtable, tcbhashsize);
in_pcbinit(&tcbtable, tcbhashsize, tcbhashsize);
if (max_protohdr < sizeof(struct tcpiphdr))
max_protohdr = sizeof(struct tcpiphdr);
if (max_linkhdr + sizeof(struct tcpiphdr) > MHLEN)

View File

@ -1,4 +1,4 @@
/* $NetBSD: udp_usrreq.c,v 1.34 1996/09/09 14:51:23 mycroft Exp $ */
/* $NetBSD: udp_usrreq.c,v 1.35 1996/09/15 18:11:11 mycroft Exp $ */
/*
* Copyright (c) 1982, 1986, 1988, 1990, 1993
@ -86,7 +86,7 @@ void
udp_init()
{
in_pcbinit(&udbtable, udbhashsize);
in_pcbinit(&udbtable, udbhashsize, udbhashsize);
}
void
@ -266,12 +266,11 @@ udp_input(m, va_alist)
/*
* Locate pcb for datagram.
*/
inp = in_pcbhashlookup(&udbtable, ip->ip_src, uh->uh_sport,
inp = in_pcblookup_connect(&udbtable, ip->ip_src, uh->uh_sport,
ip->ip_dst, uh->uh_dport);
if (inp == 0) {
++udpstat.udps_pcbhashmiss;
inp = in_pcblookup(&udbtable, ip->ip_src, uh->uh_sport,
ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD);
inp = in_pcblookup_bind(&udbtable, ip->ip_dst, uh->uh_dport);
if (inp == 0) {
udpstat.udps_noport++;
if (m->m_flags & (M_BCAST | M_MCAST)) {
@ -554,6 +553,7 @@ udp_usrreq(so, req, m, nam, control, p)
so->so_state &= ~SS_ISCONNECTED; /* XXX */
in_pcbdisconnect(inp);
inp->inp_laddr = zeroin_addr; /* XXX */
in_pcbstate(inp, INP_BOUND); /* XXX */
break;
case PRU_SHUTDOWN:
@ -572,10 +572,10 @@ udp_usrreq(so, req, m, nam, control, p)
break;
}
{
struct in_addr laddr;
struct in_addr laddr; /* XXX */
if (nam) {
laddr = inp->inp_laddr;
laddr = inp->inp_laddr; /* XXX */
if ((so->so_state & SS_ISCONNECTED) != 0) {
error = EISCONN;
goto die;
@ -595,7 +595,8 @@ udp_usrreq(so, req, m, nam, control, p)
error = udp_output(m, inp);
if (nam) {
in_pcbdisconnect(inp);
inp->inp_laddr = laddr;
inp->inp_laddr = laddr; /* XXX */
in_pcbstate(inp, INP_BOUND); /* XXX */
}
}
break;