From 6d6a026b47e40c850fdf39d78135c269e1ce3e55 Mon Sep 17 00:00:00 2001 From: David Greenman Date: Mon, 7 Oct 1996 19:06:12 +0000 Subject: [PATCH] Improved in_pcblookuphash() to support wildcarding, and changed relavent callers of it to take advantage of this. This reduces new connection request overhead in the face of a large number of PCBs in the system. Thanks to David Filo for suggesting this and providing a sample implementation (which wasn't used, but showed that it could be done). Reviewed by: wollman --- sys/netinet/in_pcb.c | 75 +++++++++++++++++++++++++--------------- sys/netinet/in_pcb.h | 6 ++-- sys/netinet/tcp_input.c | 14 ++------ sys/netinet/tcp_reass.c | 14 ++------ sys/netinet/tcp_usrreq.c | 4 +-- sys/netinet/udp_usrreq.c | 14 ++------ 6 files changed, 60 insertions(+), 67 deletions(-) diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c index c414ce2f5613..ceebbd94c777 100644 --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)in_pcb.c 8.4 (Berkeley) 5/24/95 - * $Id: in_pcb.c,v 1.20 1996/08/12 14:05:54 peter Exp $ + * $Id: in_pcb.c,v 1.21 1996/08/23 18:59:05 phk Exp $ */ #include @@ -140,7 +140,6 @@ in_pcbbind(inp, nam) struct mbuf *nam; { register struct socket *so = inp->inp_socket; - struct inpcbhead *head = inp->inp_pcbinfo->listhead; unsigned short *lastport = &inp->inp_pcbinfo->lastport; struct sockaddr_in *sin; struct proc *p = curproc; /* XXX */ @@ -155,7 +154,7 @@ in_pcbbind(inp, nam) if ((so->so_options & (SO_REUSEADDR|SO_REUSEPORT)) == 0 && ((so->so_proto->pr_flags & PR_CONNREQUIRED) == 0 || (so->so_options & SO_ACCEPTCONN) == 0)) - wild = INPLOOKUP_WILDCARD; + wild = 1; if (nam) { sin = mtod(nam, struct sockaddr_in *); if (nam->m_len != sizeof (*sin)) @@ -191,7 +190,7 @@ in_pcbbind(inp, nam) if (ntohs(lport) < IPPORT_RESERVED && (error = suser(p->p_ucred, &p->p_acflag))) return (EACCES); - t = in_pcblookup(head, zeroin_addr, 0, + t = in_pcblookup(inp->inp_pcbinfo, zeroin_addr, 0, sin->sin_addr, lport, wild); if (t && (reuseport & t->inp_socket->so_options) == 0) return (EADDRINUSE); @@ -236,7 +235,7 @@ in_pcbbind(inp, nam) if (*lastport > first || *lastport < last) *lastport = first; lport = htons(*lastport); - } while (in_pcblookup(head, + } while (in_pcblookup(inp->inp_pcbinfo, zeroin_addr, 0, inp->inp_laddr, lport, wild)); } else { /* @@ -251,7 +250,7 @@ in_pcbbind(inp, nam) if (*lastport < first || *lastport > last) *lastport = first; lport = htons(*lastport); - } while (in_pcblookup(head, + } while (in_pcblookup(inp->inp_pcbinfo, zeroin_addr, 0, inp->inp_laddr, lport, wild)); } } @@ -405,7 +404,7 @@ in_pcbconnect(inp, nam) if (in_pcblookuphash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, inp->inp_laddr.s_addr ? inp->inp_laddr : ifaddr->sin_addr, - inp->inp_lport) != NULL) + inp->inp_lport, 0) != NULL) return (EADDRINUSE); if (inp->inp_laddr.s_addr == INADDR_ANY) { if (inp->inp_lport == 0) @@ -601,11 +600,11 @@ in_rtchange(inp, errno) } struct inpcb * -in_pcblookup(head, faddr, fport_arg, laddr, lport_arg, flags) - struct inpcbhead *head; +in_pcblookup(pcbinfo, faddr, fport_arg, laddr, lport_arg, wild_okay) + struct inpcbinfo *pcbinfo; struct in_addr faddr, laddr; u_int fport_arg, lport_arg; - int flags; + int wild_okay; { register struct inpcb *inp, *match = NULL; int matchwild = 3, wildcard; @@ -614,7 +613,7 @@ in_pcblookup(head, faddr, fport_arg, laddr, lport_arg, flags) s = splnet(); - for (inp = head->lh_first; inp != NULL; inp = inp->inp_list.le_next) { + for (inp = pcbinfo->listhead->lh_first; inp != NULL; inp = inp->inp_list.le_next) { if (inp->inp_lport != lport) continue; wildcard = 0; @@ -637,7 +636,7 @@ in_pcblookup(head, faddr, fport_arg, laddr, lport_arg, flags) if (laddr.s_addr != INADDR_ANY) wildcard++; } - if (wildcard && (flags & INPLOOKUP_WILDCARD) == 0) + if (wildcard && wild_okay == 0) continue; if (wildcard < matchwild) { match = inp; @@ -655,10 +654,11 @@ in_pcblookup(head, faddr, fport_arg, laddr, lport_arg, flags) * Lookup PCB in hash list. */ struct inpcb * -in_pcblookuphash(pcbinfo, faddr, fport_arg, laddr, lport_arg) +in_pcblookuphash(pcbinfo, faddr, fport_arg, laddr, lport_arg, wildcard) struct inpcbinfo *pcbinfo; struct in_addr faddr, laddr; u_int fport_arg, lport_arg; + int wildcard; { struct inpcbhead *head; register struct inpcb *inp; @@ -670,22 +670,43 @@ in_pcblookuphash(pcbinfo, faddr, fport_arg, laddr, lport_arg) * First look for an exact match. */ head = &pcbinfo->hashbase[(faddr.s_addr + lport + fport) % pcbinfo->hashsize]; - for (inp = head->lh_first; inp != NULL; inp = inp->inp_hash.le_next) { - if (inp->inp_faddr.s_addr != faddr.s_addr || - inp->inp_fport != fport || - inp->inp_lport != lport || - inp->inp_laddr.s_addr != laddr.s_addr) - continue; - /* - * Move PCB to head of this hash chain so that it can be - * found more quickly in the future. - */ - if (inp != head->lh_first) { - LIST_REMOVE(inp, inp_hash); - LIST_INSERT_HEAD(head, inp, inp_hash); + if (inp->inp_faddr.s_addr == faddr.s_addr && + inp->inp_fport == fport && inp->inp_lport == lport && + inp->inp_laddr.s_addr == laddr.s_addr) + goto found; + } + if (wildcard) { + struct inpcb *local_wild = NULL; + + head = &pcbinfo->hashbase[(INADDR_ANY + lport) % pcbinfo->hashsize]; + 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; + } } - break; + 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); diff --git a/sys/netinet/in_pcb.h b/sys/netinet/in_pcb.h index 072d884f0b11..685c66d79de5 100644 --- a/sys/netinet/in_pcb.h +++ b/sys/netinet/in_pcb.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)in_pcb.h 8.1 (Berkeley) 6/10/93 - * $Id: in_pcb.h,v 1.11 1996/02/22 21:32:22 peter Exp $ + * $Id: in_pcb.h,v 1.12 1996/08/23 18:59:07 phk Exp $ */ #ifndef _NETINET_IN_PCB_H_ @@ -96,11 +96,11 @@ void in_pcbdisconnect __P((struct inpcb *)); int in_pcbladdr __P((struct inpcb *, struct mbuf *, struct sockaddr_in **)); struct inpcb * - in_pcblookup __P((struct inpcbhead *, + in_pcblookup __P((struct inpcbinfo *, struct in_addr, u_int, struct in_addr, u_int, int)); struct inpcb * in_pcblookuphash __P((struct inpcbinfo *, - struct in_addr, u_int, struct in_addr, u_int)); + struct in_addr, u_int, struct in_addr, u_int, int)); void in_pcbnotify __P((struct inpcbhead *, struct sockaddr *, u_int, struct in_addr, u_int, int, void (*)(struct inpcb *, int))); void in_pcbrehash __P((struct inpcb *)); diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c index a31fe9f8861b..3b0bde8c6295 100644 --- a/sys/netinet/tcp_input.c +++ b/sys/netinet/tcp_input.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)tcp_input.c 8.12 (Berkeley) 5/24/95 - * $Id: tcp_input.c,v 1.51 1996/09/21 06:39:20 pst Exp $ + * $Id: tcp_input.c,v 1.52 1996/10/07 04:32:39 pst Exp $ */ #ifndef TUBA_INCLUDE @@ -357,18 +357,8 @@ tcp_input(m, iphlen) * Locate pcb for segment. */ findpcb: - /* - * First look for an exact match. - */ inp = in_pcblookuphash(&tcbinfo, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport); - /* - * ...and if that fails, do a wildcard search. - */ - if (inp == NULL) { - inp = in_pcblookup(&tcb, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport, INPLOOKUP_WILDCARD); - } + ti->ti_dst, ti->ti_dport, 1); /* * If the state is CLOSED (i.e., TCB does not exist) then diff --git a/sys/netinet/tcp_reass.c b/sys/netinet/tcp_reass.c index a31fe9f8861b..3b0bde8c6295 100644 --- a/sys/netinet/tcp_reass.c +++ b/sys/netinet/tcp_reass.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)tcp_input.c 8.12 (Berkeley) 5/24/95 - * $Id: tcp_input.c,v 1.51 1996/09/21 06:39:20 pst Exp $ + * $Id: tcp_input.c,v 1.52 1996/10/07 04:32:39 pst Exp $ */ #ifndef TUBA_INCLUDE @@ -357,18 +357,8 @@ tcp_input(m, iphlen) * Locate pcb for segment. */ findpcb: - /* - * First look for an exact match. - */ inp = in_pcblookuphash(&tcbinfo, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport); - /* - * ...and if that fails, do a wildcard search. - */ - if (inp == NULL) { - inp = in_pcblookup(&tcb, ti->ti_src, ti->ti_sport, - ti->ti_dst, ti->ti_dport, INPLOOKUP_WILDCARD); - } + ti->ti_dst, ti->ti_dport, 1); /* * If the state is CLOSED (i.e., TCB does not exist) then diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index 78f8acf71fd4..e38d8c29465f 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * From: @(#)tcp_usrreq.c 8.2 (Berkeley) 1/3/94 - * $Id: tcp_usrreq.c,v 1.24 1996/07/12 17:28:47 davidg Exp $ + * $Id: tcp_usrreq.c,v 1.25 1996/09/13 23:51:44 pst Exp $ */ #include @@ -857,7 +857,7 @@ tcp_connect(tp, nam) error = in_pcbladdr(inp, nam, &ifaddr); if (error) return error; - oinp = in_pcblookup(inp->inp_pcbinfo->listhead, + oinp = in_pcblookuphash(inp->inp_pcbinfo, sin->sin_addr, sin->sin_port, inp->inp_laddr.s_addr != INADDR_ANY ? inp->inp_laddr : ifaddr->sin_addr, diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c index 7dfc52b38aca..0d6994f760f2 100644 --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * @(#)udp_usrreq.c 8.6 (Berkeley) 5/23/95 - * $Id: udp_usrreq.c,v 1.27 1996/06/05 17:20:35 wollman Exp $ + * $Id: udp_usrreq.c,v 1.28 1996/06/08 08:19:03 bde Exp $ */ #include @@ -268,18 +268,10 @@ udp_input(m, iphlen) return; } /* - * Locate pcb for datagram. First look for an exact match. + * Locate pcb for datagram. */ inp = in_pcblookuphash(&udbinfo, ip->ip_src, uh->uh_sport, - ip->ip_dst, uh->uh_dport); - /* - * ...and if that fails, do a wildcard search. - */ - if (inp == NULL) { - udpstat.udpps_pcbhashmiss++; - inp = in_pcblookup(&udb, ip->ip_src, uh->uh_sport, ip->ip_dst, - uh->uh_dport, INPLOOKUP_WILDCARD); - } + ip->ip_dst, uh->uh_dport, 1); if (inp == NULL) { if (log_in_vain) { char buf[4*sizeof "123"];