Subject: [RFC] Chage looking PCB(TCB) code

From: KOZUKA Masahiro <[email-masked]>
Date: Mon, 15 Dec 2003 15:21:18 +0900

Hi.
I promote a following change.
This change is related to sctp_pcbfind() and sctp_findassociation_addr_sa().
sctp_pcbfind() will find at TCP pool too only if find_tcp_pool true,
sctp_findassociation_addr_sa() and so on.

This leads to 2 merits.

1) sctp_getcred() or sctp6_getcred will be able to return the proper cred.
   Before this change, it returns the cred only on the basis of local address.
   Without this change, sctp_getcred() must call sctp_findassociation_addr_sa()
   and sctp_tcb_special_locate(), but sctp_tcb_special_locate() not exported.
   And I think this way is not beautiful.
   With this change, sctp_findassociation_addr_sa() will return the correct
   endpoint on TCP pool even if there is no accepting endpoint, so that
   sctp_tcb_special_locate() not needed.

2) The associastions which we sctp_peeroff(2) or accept(2) (ie. on TCP pool)
   will be found more quickly than other associations.
   Before this change, the associations on TCP pool have overheads.
   For looking up an association on TCP pool, sctp_pcbfind() return a listening
   endpoint and sctp_findassociation_ep_addr() call sctp_tcb_special_locate().
   But sctp_findassociation_addr_sa() can call sctp_tcb_special_locate()
   directly because sctp_findassociation_addr_sa() have the information about
   local and remote.
   Of course, other associations will be processed unfaily but the way in which
   we process separate associastions in preference to others isn't so bad, I think.

Comments?
Regards, Masahiro.

--
diff -u -r sctp.kame.20031215/netinet/sctp_pcb.c sctp.kame/netinet/sctp_pcb.c
--- sctp.kame.20031215/netinet/sctp_pcb.c	Sat Dec 13 23:28:19 2003
+++ sctp.kame/netinet/sctp_pcb.c	Sun Dec 14 05:34:37 2003
@@ -657,7 +657,7 @@

 struct sctp_inpcb *
-sctp_pcb_findep(struct sockaddr *nam)
+sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool)
 {
 	/*
 	 * First we check the hash table to see if someone has this port
@@ -707,7 +707,7 @@
 	 * may NOT be the correct one but the sctp_findassociation_ep_addr
 	 * has further code to look at all TCP models.
 	 */
-	if (ep == NULL) {
+	if (ep == NULL && find_tcp_pool) {
 		int i;
 #ifdef SCTP_DEBUG
 		if (sctp_debug_on & SCTP_DEBUG_PCB1) {
@@ -748,11 +748,25 @@
 struct sctp_tcb *
 sctp_findassociation_addr_sa(struct sockaddr *to, struct sockaddr *from,
 			     struct sctp_inpcb **inp,
-			     struct sctp_nets **netp)
+			     struct sctp_nets **netp,
+			     int find_tcp_pool)
 {
 	struct sctp_inpcb *ep;
+#ifdef SCTP_TCP_MODEL_SUPPORT
+	struct sctp_tcb *tcb;
 
-	ep = sctp_pcb_findep(to);
+	if (find_tcp_pool) {
+		if (inp != NULL) {
+			tcb = sctp_tcb_special_locate(inp, from, to, netp);
+		} else {
+			tcb = sctp_tcb_special_locate(&ep, from, to, netp);
+		}
+		if (tcb != NULL) {
+			return tcb;
+		}
+	}
+#endif
+	ep = sctp_pcb_findep(to, 0);
 	if (inp != NULL) {
 		*inp = ep;
 	}
@@ -938,9 +949,7 @@
 			  struct sctp_nets **netp,
 			  uint32_t vtag)
 {
-#ifdef SCTP_TCP_MODEL_SUPPORT
-	int to_tcp_pool;
-#endif
+	int find_tcp_pool;
 	struct ip *iph;
 	struct sctphdr *sh;
 	struct sctp_chunkhdr *chdr;
@@ -1005,40 +1014,31 @@
 		}
 	}
 
+	find_tcp_pool = 0;
+#ifdef SCTP_TCP_MODEL_SUPPORT
+	chdr = (struct sctp_chunkhdr *)((caddr_t)sh +
+					sizeof(struct sctphdr));
+	if ((chdr->chunk_type != SCTP_INITIATION) &&
+	    (chdr->chunk_type != SCTP_INITIATION_ACK) &&
+	    (chdr->chunk_type != SCTP_COOKIE_ACK) &&
+	    (chdr->chunk_type != SCTP_COOKIE_ECHO))
+		/* Other chunk types go to the tcp pool. */
+		find_tcp_pool = 1;
+#endif
 	if (inp) {
-		ret = sctp_findassociation_addr_sa(to, from, inp, netp);
+		ret = sctp_findassociation_addr_sa(to, from,
+						   inp, netp, find_tcp_pool);
 		linp = *inp;
 	} else {
-		ret = sctp_findassociation_addr_sa(to, from, &linp, netp);
+		ret = sctp_findassociation_addr_sa(to, from,
+						   &linp, netp, find_tcp_pool);
 	}
 #ifdef SCTP_DEBUG
 	if (sctp_debug_on & SCTP_DEBUG_PCB1) {
 		printf("ret:%p linp:%p\n", ret, linp);
 	}
 #endif
-#ifdef SCTP_TCP_MODEL_SUPPORT
-	chdr = (struct sctp_chunkhdr *)((caddr_t)sh +
-					sizeof(struct sctphdr));
-	if ((chdr->chunk_type == SCTP_INITIATION) ||
-	    (chdr->chunk_type == SCTP_INITIATION_ACK) ||
-	    (chdr->chunk_type == SCTP_COOKIE_ACK) ||
-	    (chdr->chunk_type == SCTP_COOKIE_ECHO)) {
-		/* These chunk types go back to the main
-		 * pool and can't go to the tcp pool.
-		 */
-		to_tcp_pool = 0;
-	} else {
-		to_tcp_pool = 1;
-	}
-	if (to_tcp_pool) {
-		if (ret == NULL) {
-			ret = sctp_tcb_special_locate(inp, from, to, netp);
-		}
-		if (ret && *inp) {
-			return (ret);
-		}
-	}
-#endif
 	if ((ret == NULL) && (linp)) {
 		/* Found a EP but not this address */
 #ifdef SCTP_DEBUG
@@ -1612,20 +1613,9 @@
 		if (p == NULL)
 			return (error);
 
-
-
-		lep = sctp_pcb_findep(addr);
+		lep = sctp_pcb_findep(addr, 0); /* not find at TCP pool. */
 		if (lep != NULL) {
-			/* If it is NOT in the TCP pool then it exists */
-			if ((lep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) {
-				return (EADDRNOTAVAIL);
-			} else
-				/*
-				 * In this case it IS only found in the TCP
-				 * pool which means the main listner went away
-				 * so it is now ok to re-bind.
-				 */
-				lep = NULL;
+			return (EADDRNOTAVAIL);
 		}
 		if (bindall) {
 			/* verify that no lport is not used by a singleton */
diff -u -r sctp.kame.20031215/netinet/sctp_pcb.h sctp.kame/netinet/sctp_pcb.h
--- sctp.kame.20031215/netinet/sctp_pcb.h	Sat Dec 13 23:28:21 2003
+++ sctp.kame/netinet/sctp_pcb.h	Sun Dec 14 05:24:33 2003
@@ -376,7 +386,7 @@
 
 struct sctp_nets *sctp_findnet(struct sctp_tcb *, struct sockaddr *);
 
-struct sctp_inpcb *sctp_pcb_findep(struct sockaddr *);
+struct sctp_inpcb *sctp_pcb_findep(struct sockaddr *, int);
 
 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000
 int sctp_inpcb_bind(struct socket *, struct sockaddr *, struct thread *);
@@ -388,7 +398,7 @@
 	struct sctp_inpcb **, struct sctp_nets **, uint32_t vtag);
 
 struct sctp_tcb *sctp_findassociation_addr_sa(struct sockaddr *,
-	struct sockaddr *, struct sctp_inpcb **, struct sctp_nets **);
+	struct sockaddr *, struct sctp_inpcb **, struct sctp_nets **, int);
 
 #ifdef SCTP_TCP_MODEL_SUPPORT
 void sctp_move_pcb_and_assoc(struct sctp_inpcb *, struct sctp_inpcb *,
diff -u -r sctp.kame.20031215/netinet/sctp_usrreq.c sctp.kame/netinet/sctp_usrreq.c
--- sctp.kame.20031215/netinet/sctp_usrreq.c	Sat Dec 13 23:28:25 2003
+++ sctp.kame/netinet/sctp_usrreq.c	Sun Dec 14 05:30:59 2003
@@ -496,7 +496,7 @@
 #endif
 		stcb = sctp_findassociation_addr_sa((struct sockaddr *)&from,
 						    (struct sockaddr *)&to,
-						    &inp, &netp);
+						    &inp, &netp, 1); /* find at TCP pool too. */
 		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
 			if (cmd != PRC_MSGSIZE) {
 				int cm;
@@ -536,6 +536,8 @@
 {
 	struct sockaddr_in addrs[2];
 	struct sctp_inpcb *inp;
+	struct sctp_nets *net;
+	struct sctp_tcb *tcb;
 	int error, s;
 
 #if __FreeBSD_version >= 500000
@@ -549,13 +551,11 @@
 	if (error)
 		return (error);
 
-#if defined(__NetBSD__) || defined(__OpenBSD__)
-	s = splsoftnet();
-#else
 	s = splnet();
-#endif
-	inp = sctp_pcb_findep((struct sockaddr *)&addrs[0]);
-	if (inp == NULL || inp->sctp_socket == NULL) {
+	tcb = sctp_findassociation_addr_sa(sintosa(&addrs[0]),
+					   sintosa(&addrs[1]),
+					   &inp, &net, 1);
+	if (tcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
 		error = ENOENT;
 		goto out;
 	}
@@ -2830,7 +2830,7 @@
 			struct sctp_inpcb  *lep;
 
 			((struct sockaddr_in *)addrs->addr)->sin_port = inp->sctp_lport;
-			lep = sctp_pcb_findep(addrs->addr);
+			lep = sctp_pcb_findep(addrs->addr, 1); /* find at TCP pool too. */
 			if (lep == inp) {
 				/* already bound to it.. ok */
 				break;
diff -u -r sctp.kame.20031215/netinet6/sctp6_usrreq.c sctp.kame/netinet6/sctp6_usrreq.c
--- sctp.kame.20031215/netinet6/sctp6_usrreq.c	Fri Nov 28 06:13:57 2003
+++ sctp.kame/netinet6/sctp6_usrreq.c	Sun Dec 14 05:38:06 2003
@@ -539,7 +539,7 @@
 #endif
 		stcb = sctp_findassociation_addr_sa((struct sockaddr *)ip6cp->ip6c_src,
 						    (struct sockaddr *)&final,
-						    &inp, &netp);
+						    &inp, &netp, 1);
 		if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
 			if (cmd == PRC_MSGSIZE) {
 				sctp6_notify_mbuf(inp,
@@ -582,6 +582,8 @@
 {
 	struct sockaddr_in6 addrs[2];
 	struct sctp_inpcb *inp;
+	struct sctp_nets *net;
+	struct sctp_tcb *tcb;
 	int error, s;
 
 #if __FreeBSD_version >= 500000
@@ -605,8 +607,10 @@
 	s = splnet();
 #endif
 
-	inp = sctp_pcb_findep((struct sockaddr *)&addrs[0]);
-	if (inp == NULL || inp->sctp_socket == NULL) {
+        tcb = sctp_findassociation_addr_sa(sin6tosa(&addrs[0]),
+                                           sin6tosa(&addrs[1]),
+                                           &inp, &net, 1); /* find at TCP pool too. */
+	if (tcb == NULL || inp == NULL || inp->sctp_socket == NULL) {
 		error = ENOENT;
 		goto out;
 	}
 --

-- 
{^-^}/@kozuka.jp / KOZUKA Masahiro