Heads up --- Thinking about UDP and tunneling

Max Laier max at love2party.net
Sat Dec 13 11:30:18 PST 2008


On Friday 12 December 2008 14:46:30 Randall Stewart wrote:
> Ok:
>
> Here is an updated patch it:
>
> 1) Fixes style9 issues
> 2) move to _t typedef

I won't get into this.

> 3) Allow multicast/broadcast to also be tunneled.

There seems to be an error with your patch.  You RUNLOCK twice in some places 
- should be fixed in my version of the patch (see attached).

> 4) Binding is now no longer a requirement to set tunneling mode, in
> fact most protocols had better NOT have bound.. first set options, then
> bind :-)

Yep.

> There was one thing I was a bit leary of for <3>. In the loop for
> going through all the inp's of UDP that are listening to a m-cast/b-cast
> I could not release the INP_INFO_LOCK() in other cases I make sure all
> locks are released when we call into the tunneling protocol. I think
> this will be ok as long as the tunnelee does not try to use the
> INP_INFO_LOCK of the UDP world... I know for SCTP this is a non-issue.. but 
> it may be something we want to think about... not sure.

I added a comment inline.  Maybe we should add a flag to the tunnel function 
prototype, so that the called party can figure out if they need to defer work 
that is not allowed under the lock (e.g. malloc WAITOK).

On top of that, I was wondering if it might make sense to pass in the inp as 
an argument - so that the tunnel consumer can figure out which tunnel the 
packet was received on (without relying on data off the wire).  In that case 
I'd leave the inp RLOCK'ed and leave it up the the called party to release the 
lock if they so desire.

> If there are no serious objections I will submit this into head.. and

There are some open issues, see above - but in general okay with me.

> followed behind it I will send in the changes so SCTP can be tunneled over 
> this new mechanism :-)

-- 
/"\  Best regards,                      | mlaier at freebsd.org
\ /  Max Laier                          | ICQ #67774661
 X   http://pf4freebsd.love2party.net/  | mlaier at EFnet
/ \  ASCII Ribbon Campaign              | Against HTML Mail and News
-------------- next part --------------
Index: netinet/udp_var.h
===================================================================
--- netinet/udp_var.h	(revision 186046)
+++ netinet/udp_var.h	(working copy)
@@ -110,6 +110,10 @@
 void		 udp_input(struct mbuf *, int);
 struct inpcb	*udp_notify(struct inpcb *inp, int errno);
 int		 udp_shutdown(struct socket *so);
+
+
+typedef void(*udp_tunnel_function_t)(struct mbuf *, int off);
+int udp_set_kernel_tunneling(struct socket *so, udp_tunnel_function_t f);
 #endif
 
 #endif
Index: netinet/udp_usrreq.c
===================================================================
--- netinet/udp_usrreq.c	(revision 186046)
+++ netinet/udp_usrreq.c	(working copy)
@@ -488,10 +488,29 @@
 				struct mbuf *n;
 
 				n = m_copy(m, 0, M_COPYALL);
-				if (n != NULL)
-					udp_append(last, ip, n, iphlen +
-					    sizeof(struct udphdr), &udp_in);
-				INP_RUNLOCK(last);
+
+				if (last->inp_ppcb == NULL) {
+					if (n != NULL)
+						udp_append(last, ip, n, iphlen +
+						   sizeof(struct udphdr), &udp_in);
+				 	INP_RUNLOCK(last);
+				} else {
+					/* Engage the tunneling protocol
+					 * we will have to leave the info_lock
+					 * up, since we are hunting through 
+					 * multiple UDP inp's hope we don't break :-(
+					 *
+					 * XXXML: Maybe add a flag to the
+					 * prototype so that the tunneling
+					 * can defer work that can't be done
+					 * under the info lock?
+					 */
+					udp_tunnel_function_t tunnel_func;
+
+					tunnel_func = (udp_tunnel_function_t)last->inp_ppcb;
+					INP_RUNLOCK(last);
+					tunnel_func(m, iphlen);
+				}
 			}
 			last = inp;
 			/*
@@ -516,10 +535,24 @@
 			V_udpstat.udps_noportbcast++;
 			goto badheadlocked;
 		}
-		udp_append(last, ip, m, iphlen + sizeof(struct udphdr),
-		    &udp_in);
-		INP_RUNLOCK(last);
-		INP_INFO_RUNLOCK(&V_udbinfo);
+		if (last->inp_ppcb == NULL) {
+			udp_append(last, ip, m, iphlen + sizeof(struct udphdr),
+			   &udp_in);
+			INP_RUNLOCK(last);
+			INP_INFO_RUNLOCK(&V_udbinfo);
+		} else {
+			/* Engage the tunneling protocol
+			 * we must make sure all locks
+			 * are released when we call the
+			 * tunneling protocol.
+			 */
+			udp_tunnel_function_t tunnel_func;
+
+			tunnel_func = (udp_tunnel_function_t)last->inp_ppcb;
+			INP_RUNLOCK(last);
+			INP_INFO_RUNLOCK(&V_udbinfo);
+			tunnel_func(m, iphlen);
+		}
 		return;
 	}
 
@@ -563,6 +596,18 @@
 		INP_RUNLOCK(inp);
 		goto badunlocked;
 	}
+	if (inp->inp_ppcb) {
+		/* Engage the tunneling protocol
+		 * we must make sure all locks
+		 * are released when we call the
+		 * tunneling protocol.
+		 */
+		udp_tunnel_function_t tunnel_func;
+		tunnel_func = (udp_tunnel_function_t)inp->inp_ppcb;
+		INP_RUNLOCK(inp);
+		tunnel_func(m, iphlen);
+		return;
+	}
 	udp_append(inp, ip, m, iphlen + sizeof(struct udphdr), &udp_in);
 	INP_RUNLOCK(inp);
 	return;
@@ -1138,10 +1183,41 @@
 	INP_INFO_WUNLOCK(&V_udbinfo);
 	inp->inp_vflag |= INP_IPV4;
 	inp->inp_ip_ttl = V_ip_defttl;
+	/*
+	 * UDP does not have a per-protocol
+	 * pcb (inp->inp_ppcb). We use this
+	 * pointer for kernel tunneling pointer.
+	 * If we ever need to have a protocol
+	 * block we will need to move this
+	 * function pointer there. Null
+	 * in this pointer means "do the normal
+	 * thing".
+	 */
+	inp->inp_ppcb = NULL;
 	INP_WUNLOCK(inp);
 	return (0);
 }
 
+int
+udp_set_kernel_tunneling(struct socket *so, udp_tunnel_function_t f)
+{
+	struct inpcb *inp;
+	inp = (struct inpcb *)so->so_pcb;
+
+	if (so->so_type != SOCK_DGRAM) {
+		/* Not UDP socket... sorry */
+		return (ENOTSUP);
+	}
+	if (inp == NULL) {
+		/* NULL INP? */
+		return (EINVAL);
+	}
+	INP_WLOCK(inp);
+	inp->inp_ppcb = f;
+	INP_WUNLOCK(inp);
+	return (0);
+}
+
 static int
 udp_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
 {
Index: netinet6/udp6_usrreq.c
===================================================================
--- netinet6/udp6_usrreq.c	(revision 186046)
+++ netinet6/udp6_usrreq.c	(working copy)
@@ -287,8 +287,20 @@
 
 				if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
 					INP_RLOCK(last);
-					udp6_append(last, n, off, &fromsa);
-					INP_RUNLOCK(last);
+					if (last->inp_ppcb) {
+						/* Engage the tunneling protocol
+						 * we will have to leave the info_lock
+						 * up, since we are hunting through 
+						 * multiple UDP inp's hope we don't break :-(
+						 */
+						udp_tunnel_function_t tunnel_func;
+						tunnel_func = (udp_tunnel_function_t)last->inp_ppcb;
+						INP_RUNLOCK(last);
+						tunnel_func(m, off);
+					} else {
+						udp6_append(last, n, off, &fromsa);
+						INP_RUNLOCK(last);
+					}	
 				}
 			}
 			last = inp;
@@ -317,6 +329,19 @@
 		}
 		INP_RLOCK(last);
 		INP_INFO_RUNLOCK(&V_udbinfo);
+		if (last->inp_ppcb) {
+			/* Engage the tunneling protocol
+			 * we must make sure all locks
+			 * are released when we call the
+			 * tunneling protocol.
+			 */
+			udp_tunnel_function_t tunnel_func;
+
+			tunnel_func = (udp_tunnel_function_t)inp->inp_ppcb;
+			INP_RUNLOCK(last);
+			tunnel_func(m, off);
+			return (IPPROTO_DONE);
+		}
 		udp6_append(last, m, off, &fromsa);
 		INP_RUNLOCK(last);
 		return (IPPROTO_DONE);
@@ -354,6 +379,18 @@
 	}
 	INP_RLOCK(inp);
 	INP_INFO_RUNLOCK(&V_udbinfo);
+	if (inp->inp_ppcb) {
+		/* Engage the tunneling protocol
+		 * we must make sure all locks
+		 * are released when we call the
+		 * tunneling protocol.
+		 */
+		udp_tunnel_function_t tunnel_func;
+		tunnel_func = (udp_tunnel_function_t)inp->inp_ppcb;
+		INP_RUNLOCK(inp);
+		tunnel_func(m, off);
+		return (IPPROTO_DONE);
+	}
 	udp6_append(inp, m, off, &fromsa);
 	INP_RUNLOCK(inp);
 	return (IPPROTO_DONE);


More information about the freebsd-net mailing list