Subject: Merging port numbers.
To: None <tech-net@netbsd.org>
From: Darren Reed <darrenr@reed.wattle.id.au>
List: tech-net
Date: 07/22/2000 21:29:51
Amongst the idle chatter on icb, there was a bit of talk about how bad
dealing with 16bit things is.  One of the more obvious uses of 16bit
things in the kernel is TCP/UDP (for port numbers).  The patches below
introduce some more evilness (in the guise of unions) within the TCP
and UDP headers to present the port numbers as a combined 32bit entity.
I've not tested this at all as I'm just curious to get a feeling for
this.  In a number of places it allows a reduction in the number of
parameters passed to lookup functions as well as reducing the code
path length for comparisons.  IPv6 & IPv4 patches included.

Comments ?  Is this sort of evilness welcome within NetBSD for whatever
minimal performance gain it might provide ?

Darren

Index: in6_pcb.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/in6_pcb.c,v
retrieving revision 1.29
diff -c -r1.29 in6_pcb.c
*** in6_pcb.c	2000/07/07 15:54:18	1.29
--- in6_pcb.c	2000/07/23 04:22:32
***************
*** 731,750 ****
  }
  
  struct in6pcb *
! in6_pcblookup_connect(head, faddr6, fport_arg, laddr6, lport_arg, faith)
  	struct in6pcb *head;
  	struct in6_addr *faddr6, *laddr6;
! 	u_int fport_arg, lport_arg;
  	int faith;
  {
  	struct in6pcb *in6p;
- 	u_int16_t fport = fport_arg, lport = lport_arg;
  
  	for (in6p = head->in6p_next; in6p != head; in6p = in6p->in6p_next) {
  		/* find exact match on both source and dest */
! 		if (in6p->in6p_fport != fport)
! 			continue;
! 		if (in6p->in6p_lport != lport)
  			continue;
  		if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr))
  			continue;
--- 731,747 ----
  }
  
  struct in6pcb *
! in6_pcblookup_connect(head, faddr6, laddr6, ports, faith)
  	struct in6pcb *head;
  	struct in6_addr *faddr6, *laddr6;
! 	u_int32_t ports;
  	int faith;
  {
  	struct in6pcb *in6p;
  
  	for (in6p = head->in6p_next; in6p != head; in6p = in6p->in6p_next) {
  		/* find exact match on both source and dest */
! 		if (in6p->in6p_ports != ports)
  			continue;
  		if (IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr))
  			continue;
Index: in6_pcb.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet6/in6_pcb.h,v
retrieving revision 1.12
diff -c -r1.12 in6_pcb.h
*** in6_pcb.h	2000/07/07 15:54:18	1.12
--- in6_pcb.h	2000/07/23 04:22:36
***************
*** 86,94 ****
  	struct	in6pcb *in6p_head;	/* pointer back to chain of
  					   in6pcb's for this protocol */
  	struct	in6_addr in6p_faddr;	/* foreign host table entry */
- 	u_int16_t in6p_fport;		/* foreign port */
  	struct	in6_addr in6p_laddr;	/* local host table entry */
! 	u_int16_t in6p_lport;		/* local port */
  	u_int32_t in6p_flowinfo;	/* priority and flowlabel */
  	struct	socket *in6p_socket;	/* back pointer to socket */
  	caddr_t	in6p_ppcb;		/* pointer to per-protocol pcb */
--- 86,99 ----
  	struct	in6pcb *in6p_head;	/* pointer back to chain of
  					   in6pcb's for this protocol */
  	struct	in6_addr in6p_faddr;	/* foreign host table entry */
  	struct	in6_addr in6p_laddr;	/* local host table entry */
! 	union	{
! 		u_int16_t in6pu_port[2];
! 		u_int16_t in6pu_ports;
! 	} in6p_un;
! #define	in6p_fport	in6p_un.in6pu_port[0]	/* foreign port */
! #define	in6p_lport	in6p_un.in6pu_port[1]	/* local port */
! #define	in6p_ports	in6p_un.in6pu_ports
  	u_int32_t in6p_flowinfo;	/* priority and flowlabel */
  	struct	socket *in6p_socket;	/* back pointer to socket */
  	caddr_t	in6p_ppcb;		/* pointer to per-protocol pcb */
***************
*** 186,192 ****
  extern struct rtentry *
  	in6_pcbrtentry __P((struct in6pcb *));
  extern struct in6pcb *in6_pcblookup_connect __P((struct in6pcb *,
! 	struct in6_addr *, u_int, struct in6_addr *, u_int, int));
  extern struct in6pcb *in6_pcblookup_bind __P((struct in6pcb *,
  	struct in6_addr *, u_int, int));
  #endif
--- 191,197 ----
  extern struct rtentry *
  	in6_pcbrtentry __P((struct in6pcb *));
  extern struct in6pcb *in6_pcblookup_connect __P((struct in6pcb *,
! 	struct in6_addr *, struct in6_addr *, u_int32_t, int));
  extern struct in6pcb *in6_pcblookup_bind __P((struct in6pcb *,
  	struct in6_addr *, u_int, int));
  #endif
Index: tcp.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/tcp.h,v
retrieving revision 1.12
diff -c -r1.12 tcp.h
*** tcp.h	2000/07/05 02:45:03	1.12
--- tcp.h	2000/07/23 04:23:49
***************
*** 44,51 ****
   * Per RFC 793, September, 1981.
   */
  struct tcphdr {
! 	u_int16_t th_sport;		/* source port */
! 	u_int16_t th_dport;		/* destination port */
  	tcp_seq	  th_seq;		/* sequence number */
  	tcp_seq	  th_ack;		/* acknowledgement number */
  #if BYTE_ORDER == LITTLE_ENDIAN
--- 44,56 ----
   * Per RFC 793, September, 1981.
   */
  struct tcphdr {
! 	union	{
! 		u_int16_t thu_port[2];
! 		u_int32_t thu_ports;
! 	} th_un;
! #define	th_sport	th_un.thu_port[2]	/* source port */
! #define	th_dport	th_un.thu_port[1]	/* destination port */
! #define	th_ports	th_un.thu_ports		/* combined ports */
  	tcp_seq	  th_seq;		/* sequence number */
  	tcp_seq	  th_ack;		/* acknowledgement number */
  #if BYTE_ORDER == LITTLE_ENDIAN
Index: in_pcb.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/in_pcb.c,v
retrieving revision 1.66
diff -c -r1.66 in_pcb.c
*** in_pcb.c	2000/07/06 12:51:39	1.66
--- in_pcb.c	2000/07/23 04:24:00
***************
*** 339,344 ****
--- 339,345 ----
  	struct in_ifaddr *ia;
  	struct sockaddr_in *ifaddr = NULL;
  	struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *);
+ 	u_int32_t ports;
  	int error;
  
  	if (nam->m_len != sizeof (*sin))
***************
*** 462,470 ****
  		}
  #endif
  	}
! 	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);
  	if (in_nullhost(inp->inp_laddr)) {
  		if (inp->inp_lport == 0) {
--- 463,472 ----
  		}
  #endif
  	}
! 	ports = (sin->sin_port << 16) | inp->inp_lport;
! 	if (in_pcblookup_connect(inp->inp_table, sin->sin_addr,
  	    !in_nullhost(inp->inp_laddr) ? inp->inp_laddr : ifaddr->sin_addr,
! 	    ports) != 0)
  		return (EADDRINUSE);
  	if (in_nullhost(inp->inp_laddr)) {
  		if (inp->inp_lport == 0) {
***************
*** 764,783 ****
  #endif
  
  struct inpcb *
! in_pcblookup_connect(table, faddr, fport_arg, laddr, lport_arg)
  	struct inpcbtable *table;
  	struct in_addr faddr, laddr;
! 	u_int fport_arg, lport_arg;
  {
  	struct inpcbhead *head;
  	struct inpcb *inp;
- 	u_int16_t fport = fport_arg, lport = lport_arg;
  
  	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))
  			goto out;
  	}
--- 766,783 ----
  #endif
  
  struct inpcb *
! in_pcblookup_connect(table, faddr, laddr, ports)
  	struct inpcbtable *table;
  	struct in_addr faddr, laddr;
! 	u_in32_t ports;
  {
  	struct inpcbhead *head;
  	struct inpcb *inp;
  
  	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_ports == ports &&
  		    in_hosteq(inp->inp_laddr, laddr))
  			goto out;
  	}
Index: in_pcb.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/in_pcb.h,v
retrieving revision 1.29
diff -c -r1.29 in_pcb.h
*** in_pcb.h	2000/02/02 23:28:09	1.29
--- in_pcb.h	2000/07/23 04:24:04
***************
*** 84,91 ****
  	CIRCLEQ_ENTRY(inpcb) inp_queue;
  	caddr_t	  inp_ppcb;		/* pointer to per-protocol pcb */
  	int	  inp_state;		/* bind/connect state */
! 	u_int16_t inp_fport;		/* foreign port */
! 	u_int16_t inp_lport;		/* local port */
  	struct	  socket *inp_socket;	/* back pointer to socket */
  	struct	  route inp_route;	/* placeholder for routing entry */
  	int	  inp_flags;		/* generic IP/datagram flags */
--- 84,96 ----
  	CIRCLEQ_ENTRY(inpcb) inp_queue;
  	caddr_t	  inp_ppcb;		/* pointer to per-protocol pcb */
  	int	  inp_state;		/* bind/connect state */
! 	union	{
! 		u_int16_t inpu_port[2];
! 		u_int32_t inpu_ports;
! 	} inp_un;
! #define	inp_fport	inp_un.inpu_port[0]	/* foreign port */
! #define	inp_lport	inp_un.inpu_port[1]	/* local port */
! #define	inp_ports	inp_un.inpu_ports
  	struct	  socket *inp_socket;	/* back pointer to socket */
  	struct	  route inp_route;	/* placeholder for routing entry */
  	int	  inp_flags;		/* generic IP/datagram flags */
***************
*** 146,152 ****
  	    struct in_addr, u_int));
  struct inpcb *
  	in_pcblookup_connect __P((struct inpcbtable *,
! 	    struct in_addr, u_int, struct in_addr, u_int));
  int	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,
--- 151,157 ----
  	    struct in_addr, u_int));
  struct inpcb *
  	in_pcblookup_connect __P((struct inpcbtable *,
! 	    struct in_addr, struct in_addr, u_int32_t));
  int	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,
Index: udp.h
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/udp.h,v
retrieving revision 1.9
diff -c -r1.9 udp.h
*** udp.h	1999/11/20 00:38:00	1.9
--- udp.h	2000/07/23 04:24:06
***************
*** 43,50 ****
   * Per RFC 768, September, 1981.
   */
  struct udphdr {
! 	u_int16_t uh_sport;		/* source port */
! 	u_int16_t uh_dport;		/* destination port */
  	u_int16_t uh_ulen;		/* udp length */
  	u_int16_t uh_sum;		/* udp checksum */
  } __attribute__((__packed__));
--- 43,55 ----
   * Per RFC 768, September, 1981.
   */
  struct udphdr {
! 	union	{
! 		u_int16_t uhu_port[2];
! 		u_int32_t uhu_ports;
! 	} uh_un;
! #define	uh_sport	uh_un.uhu_port[0]	/* source port */
! #define	uh_dport	uh_un.uhu_port[1]	/* destination port */
! #define	uh_ports	uh_un.uhu_ports
  	u_int16_t uh_ulen;		/* udp length */
  	u_int16_t uh_sum;		/* udp checksum */
  } __attribute__((__packed__));
Index: tcp_input.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/tcp_input.c,v
retrieving revision 1.113
diff -c -r1.113 tcp_input.c
*** tcp_input.c	2000/07/09 12:49:08	1.113
--- tcp_input.c	2000/07/23 04:24:44
***************
*** 787,794 ****
  #endif
  	switch (af) {
  	case AF_INET:
! 		inp = in_pcblookup_connect(&tcbtable, ip->ip_src, th->th_sport,
! 		    ip->ip_dst, th->th_dport);
  		if (inp == 0) {
  			++tcpstat.tcps_pcbhashmiss;
  			inp = in_pcblookup_bind(&tcbtable, ip->ip_dst, th->th_dport);
--- 787,794 ----
  #endif
  	switch (af) {
  	case AF_INET:
! 		inp = in_pcblookup_connect(&tcbtable, ip->ip_src, ip->ip_dst,
! 		    th->th_ports);
  		if (inp == 0) {
  			++tcpstat.tcps_pcbhashmiss;
  			inp = in_pcblookup_bind(&tcbtable, ip->ip_dst, th->th_dport);
***************
*** 804,811 ****
  			bzero(&d, sizeof(d));
  			d.s6_addr16[5] = htons(0xffff);
  			bcopy(&ip->ip_dst, &d.s6_addr32[3], sizeof(ip->ip_dst));
! 			in6p = in6_pcblookup_connect(&tcb6, &s, th->th_sport,
! 				&d, th->th_dport, 0);
  			if (in6p == 0) {
  				++tcpstat.tcps_pcbhashmiss;
  				in6p = in6_pcblookup_bind(&tcb6, &d,
--- 804,811 ----
  			bzero(&d, sizeof(d));
  			d.s6_addr16[5] = htons(0xffff);
  			bcopy(&ip->ip_dst, &d.s6_addr32[3], sizeof(ip->ip_dst));
! 			in6p = in6_pcblookup_connect(&tcb6, &s, &d,
! 			     th->th_ports, 0);
  			if (in6p == 0) {
  				++tcpstat.tcps_pcbhashmiss;
  				in6p = in6_pcblookup_bind(&tcb6, &d,
***************
*** 877,884 ****
  #else
  		faith = 0;
  #endif
! 		in6p = in6_pcblookup_connect(&tcb6, &ip6->ip6_src, th->th_sport,
! 			&ip6->ip6_dst, th->th_dport, faith);
  		if (in6p == NULL) {
  			++tcpstat.tcps_pcbhashmiss;
  			in6p = in6_pcblookup_bind(&tcb6, &ip6->ip6_dst,
--- 877,884 ----
  #else
  		faith = 0;
  #endif
! 		in6p = in6_pcblookup_connect(&tcb6, &ip6->ip6_src,
! 		     &ip6->ip6_dst, th->th_ports, faith);
  		if (in6p == NULL) {
  			++tcpstat.tcps_pcbhashmiss;
  			in6p = in6_pcblookup_bind(&tcb6, &ip6->ip6_dst,
Index: udp_usrreq.c
===================================================================
RCS file: /cvsroot/syssrc/sys/netinet/udp_usrreq.c,v
retrieving revision 1.69
diff -c -r1.69 udp_usrreq.c
*** udp_usrreq.c	2000/07/07 15:54:16	1.69
--- udp_usrreq.c	2000/07/23 04:24:59
***************
*** 528,536 ****
  	int off;	/* offset of udphdr */
  {
  	u_int16_t *sport, *dport;
- 	int rcvcnt;
  	struct in_addr *src4, *dst4;
  	struct inpcb *inp;
  
  	rcvcnt = 0;
  	off += sizeof(struct udphdr);	/* now, offset of payload */
--- 528,537 ----
  	int off;	/* offset of udphdr */
  {
  	u_int16_t *sport, *dport;
  	struct in_addr *src4, *dst4;
  	struct inpcb *inp;
+ 	u_int32_t ports;
+ 	int rcvcnt;
  
  	rcvcnt = 0;
  	off += sizeof(struct udphdr);	/* now, offset of payload */
***************
*** 542,547 ****
--- 543,549 ----
  	sport = &src->sin_port;
  	dst4 = &dst->sin_addr;
  	dport = &dst->sin_port;
+ 	ports = (sport << 16) | dport;
  
  	if (IN_MULTICAST(src4->s_addr) ||
  	    in_broadcast(*dst4, m->m_pkthdr.rcvif)) {
***************
*** 617,623 ****
  		/*
  		 * Locate pcb for datagram.
  		 */
! 		inp = in_pcblookup_connect(&udbtable, *src4, *sport, *dst4, *dport);
  		if (inp == 0) {
  			++udpstat.udps_pcbhashmiss;
  			inp = in_pcblookup_bind(&udbtable, *dst4, *dport);
--- 619,625 ----
  		/*
  		 * Locate pcb for datagram.
  		 */
! 		inp = in_pcblookup_connect(&udbtable, *src4, *dst4, ports);
  		if (inp == 0) {
  			++udpstat.udps_pcbhashmiss;
  			inp = in_pcblookup_bind(&udbtable, *dst4, *dport);
***************
*** 690,699 ****
  	int off;	/* offset of udphdr */
  {
  	u_int16_t *sport, *dport;
- 	int rcvcnt;
  	struct in6_addr *src6, *dst6;
  	struct in_addr *src4;
  	struct in6pcb *in6p;
  
  	rcvcnt = 0;
  	off += sizeof(struct udphdr);	/* now, offset of payload */
--- 692,702 ----
  	int off;	/* offset of udphdr */
  {
  	u_int16_t *sport, *dport;
  	struct in6_addr *src6, *dst6;
  	struct in_addr *src4;
  	struct in6pcb *in6p;
+ 	u_int32_t ports;
+ 	int rcvcnt;
  
  	rcvcnt = 0;
  	off += sizeof(struct udphdr);	/* now, offset of payload */
***************
*** 707,712 ****
--- 710,716 ----
  	sport = &src->sin6_port;
  	dst6 = &dst->sin6_addr;
  	dport = &dst->sin6_port;
+ 	ports = (sport << 16) | dport;
  	src4 = (struct in_addr *)&src->sin6_addr.s6_addr32[12];
  
  	if (IN6_IS_ADDR_MULTICAST(dst6)
***************
*** 804,811 ****
  		/*
  		 * Locate pcb for datagram.
  		 */
! 		in6p = in6_pcblookup_connect(&udb6, src6, *sport,
! 			dst6, *dport, 0);
  		if (in6p == 0) {
  			++udpstat.udps_pcbhashmiss;
  			in6p = in6_pcblookup_bind(&udb6, dst6, *dport, 0);
--- 808,814 ----
  		/*
  		 * Locate pcb for datagram.
  		 */
! 		in6p = in6_pcblookup_connect(&udb6, src6, dst6, ports, 0);
  		if (in6p == 0) {
  			++udpstat.udps_pcbhashmiss;
  			in6p = in6_pcblookup_bind(&udb6, dst6, *dport, 0);
***************
*** 1070,1077 ****
  	/*
  	 * Locate pcb for datagram.
  	 */
! 	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_bind(&udbtable, ip->ip_dst, uh->uh_dport);
--- 1073,1080 ----
  	/*
  	 * Locate pcb for datagram.
  	 */
! 	inp = in_pcblookup_connect(&udbtable, ip->ip_src, ip->ip_dst,
! 	    uh->uh_ports);
  	if (inp == 0) {
  		++udpstat.udps_pcbhashmiss;
  		inp = in_pcblookup_bind(&udbtable, ip->ip_dst, uh->uh_dport);