Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 23 May 2009 16:51:13 +0000 (UTC)
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r192649 - in head/sys: netinet netinet6 sys
Message-ID:  <200905231651.n4NGpDtI061174@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bz
Date: Sat May 23 16:51:13 2009
New Revision: 192649
URL: http://svn.freebsd.org/changeset/base/192649

Log:
  Implement UDP control block support.
  
  So far the udp_tun_func_t had been (ab)using inp_ppcb for udp in kernel
  tunneling callbacks.  Move that into the udpcb and add a field for flags
  there to be used by upcoming changes instead of sticking udp only flags
  into in_pcb flags2.
  
  Bump __FreeBSD_version for ports to detect it and because of vnet* struct
  size changes.
  
  Submitted by:	jhb (7.x version)
  Reviewed by:	rwatson

Modified:
  head/sys/netinet/udp_usrreq.c
  head/sys/netinet/udp_var.h
  head/sys/netinet/vinet.h
  head/sys/netinet6/udp6_usrreq.c
  head/sys/sys/param.h

Modified: head/sys/netinet/udp_usrreq.c
==============================================================================
--- head/sys/netinet/udp_usrreq.c	Sat May 23 16:42:38 2009	(r192648)
+++ head/sys/netinet/udp_usrreq.c	Sat May 23 16:51:13 2009	(r192649)
@@ -137,6 +137,7 @@ SYSCTL_ULONG(_net_inet_udp, UDPCTL_RECVS
 #ifdef VIMAGE_GLOBALS
 struct inpcbhead	udb;		/* from udp_var.h */
 struct inpcbinfo	udbinfo;
+static uma_zone_t	udpcb_zone;
 struct udpstat		udpstat;	/* from udp_var.h */
 #endif
 
@@ -158,6 +159,7 @@ udp_zone_change(void *tag)
 	INIT_VNET_INET(curvnet);
 
 	uma_zone_set_max(V_udbinfo.ipi_zone, maxsockets);
+	uma_zone_set_max(V_udpcb_zone, maxsockets);
 }
 
 static int
@@ -187,13 +189,39 @@ udp_init(void)
 	    &V_udbinfo.ipi_hashmask);
 	V_udbinfo.ipi_porthashbase = hashinit(UDBHASHSIZE, M_PCB,
 	    &V_udbinfo.ipi_porthashmask);
-	V_udbinfo.ipi_zone = uma_zcreate("udpcb", sizeof(struct inpcb), NULL,
-	    NULL, udp_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+	V_udbinfo.ipi_zone = uma_zcreate("udp_inpcb", sizeof(struct inpcb),
+	    NULL, NULL, udp_inpcb_init, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
 	uma_zone_set_max(V_udbinfo.ipi_zone, maxsockets);
+
+	V_udpcb_zone = uma_zcreate("udpcb", sizeof(struct udpcb),
+	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
+	uma_zone_set_max(V_udpcb_zone, maxsockets);
+
 	EVENTHANDLER_REGISTER(maxsockets_change, udp_zone_change, NULL,
 	    EVENTHANDLER_PRI_ANY);
 }
 
+int
+udp_newudpcb(struct inpcb *inp)
+{
+	INIT_VNET_INET(curvnet);
+	struct udpcb *up;
+
+	up = uma_zalloc(V_udpcb_zone, M_NOWAIT | M_ZERO);
+	if (up == NULL)
+		return (ENOBUFS);
+	inp->inp_ppcb = up;
+	return (0);
+}
+
+void
+udp_discardcb(struct udpcb *up)
+{
+	INIT_VNET_INET(curvnet);
+
+	uma_zfree(V_udpcb_zone, up);
+}
+
 /*
  * Subroutine of udp_input(), which appends the provided mbuf chain to the
  * passed pcb/socket.  The caller must provide a sockaddr_in via udp_in that
@@ -272,6 +300,7 @@ udp_input(struct mbuf *m, int off)
 	struct udphdr *uh;
 	struct ifnet *ifp;
 	struct inpcb *inp;
+	struct udpcb *up;
 	int len;
 	struct ip save_ip;
 	struct sockaddr_in udp_in;
@@ -455,28 +484,25 @@ udp_input(struct mbuf *m, int off)
 				struct mbuf *n;
 
 				n = m_copy(m, 0, M_COPYALL);
-				if (last->inp_ppcb == NULL) {
+				up = intoudpcb(last);
+				if (up->u_tun_func == 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's.
-					 * 
 					 */
-					udp_tun_func_t tunnel_func;
 
-					tunnel_func = (udp_tun_func_t)last->inp_ppcb;
-					tunnel_func(n, iphlen, last);
-					INP_RUNLOCK(last);
+					(*up->u_tun_func)(n, iphlen, last);
 				}
+				INP_RUNLOCK(last);
 			}
 			last = inp;
 			/*
@@ -501,22 +527,18 @@ udp_input(struct mbuf *m, int off)
 			UDPSTAT_INC(udps_noportbcast);
 			goto badheadlocked;
 		}
-		if (last->inp_ppcb == NULL) {
+		up = intoudpcb(last);
+		if (up->u_tun_func == 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.
 			 */
-			udp_tun_func_t tunnel_func;
-
-			tunnel_func = (udp_tun_func_t)last->inp_ppcb;
-			tunnel_func(m, iphlen, last);
-			INP_RUNLOCK(last);
-			INP_INFO_RUNLOCK(&V_udbinfo);
+			(*up->u_tun_func)(m, iphlen, last);
 		}
+		INP_RUNLOCK(last);
+		INP_INFO_RUNLOCK(&V_udbinfo);
 		return;
 	}
 
@@ -560,18 +582,16 @@ udp_input(struct mbuf *m, int off)
 		INP_RUNLOCK(inp);
 		goto badunlocked;
 	}
-	if (inp->inp_ppcb != NULL) {
+	up = intoudpcb(inp);
+	if (up->u_tun_func == NULL) {
+		udp_append(inp, ip, m, iphlen + sizeof(struct udphdr), &udp_in);
+	} else {
 		/*
 		 * Engage the tunneling protocol.
 		 */
-		udp_tun_func_t tunnel_func;
 
-		tunnel_func = (udp_tun_func_t)inp->inp_ppcb;
-		tunnel_func(m, iphlen, inp);
-		INP_RUNLOCK(inp);
-		return;
+		(*up->u_tun_func)(m, iphlen, inp);
 	}
-	udp_append(inp, ip, m, iphlen + sizeof(struct udphdr), &udp_in);
 	INP_RUNLOCK(inp);
 	return;
 
@@ -1142,18 +1162,19 @@ udp_attach(struct socket *so, int proto,
 	}
 
 	inp = (struct inpcb *)so->so_pcb;
-	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;
+
+	error = udp_newudpcb(inp);
+	if (error) {
+		in_pcbdetach(inp);
+		in_pcbfree(inp);
+		INP_INFO_WUNLOCK(&V_udbinfo);
+		return (error);
+	}
+
 	INP_WUNLOCK(inp);
+	INP_INFO_WUNLOCK(&V_udbinfo);
 	return (0);
 }
 
@@ -1161,24 +1182,26 @@ int
 udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f)
 {
 	struct inpcb *inp;
+	struct udpcb *up;
 
-	inp = (struct inpcb *)so->so_pcb;
 	KASSERT(so->so_type == SOCK_DGRAM, ("udp_set_kernel_tunneling: !dgram"));
 	KASSERT(so->so_pcb != NULL, ("udp_set_kernel_tunneling: NULL inp"));
 	if (so->so_type != SOCK_DGRAM) {
 		/* Not UDP socket... sorry! */
 		return (ENOTSUP);
 	}
+	inp = (struct inpcb *)so->so_pcb;
 	if (inp == NULL) {
 		/* NULL INP? */
 		return (EINVAL);
 	}
 	INP_WLOCK(inp);
-	if (inp->inp_ppcb != NULL) {
+	up = intoudpcb(inp);
+	if (up->u_tun_func != NULL) {
 		INP_WUNLOCK(inp);
 		return (EBUSY);
 	}
-	inp->inp_ppcb = f;
+	up->u_tun_func = f;
 	INP_WUNLOCK(inp);
 	return (0);
 }
@@ -1256,6 +1279,7 @@ udp_detach(struct socket *so)
 {
 	INIT_VNET_INET(so->so_vnet);
 	struct inpcb *inp;
+	struct udpcb *up;
 
 	inp = sotoinpcb(so);
 	KASSERT(inp != NULL, ("udp_detach: inp == NULL"));
@@ -1263,9 +1287,13 @@ udp_detach(struct socket *so)
 	    ("udp_detach: not disconnected"));
 	INP_INFO_WLOCK(&V_udbinfo);
 	INP_WLOCK(inp);
+	up = intoudpcb(inp);
+	KASSERT(up != NULL, ("%s: up == NULL", __func__));
+	inp->inp_ppcb = NULL;
 	in_pcbdetach(inp);
 	in_pcbfree(inp);
 	INP_INFO_WUNLOCK(&V_udbinfo);
+	udp_discardcb(up);
 }
 
 static int

Modified: head/sys/netinet/udp_var.h
==============================================================================
--- head/sys/netinet/udp_var.h	Sat May 23 16:42:38 2009	(r192648)
+++ head/sys/netinet/udp_var.h	Sat May 23 16:51:13 2009	(r192649)
@@ -51,6 +51,19 @@ struct udpiphdr {
 #define	ui_ulen		ui_u.uh_ulen
 #define	ui_sum		ui_u.uh_sum
 
+typedef void(*udp_tun_func_t)(struct mbuf *, int off, struct inpcb *);
+
+/*
+ * UDP control block; one per udp.
+ */
+struct udpcb {
+	udp_tun_func_t	u_tun_func;	/* UDP kernel tunneling callback. */
+	u_int		u_flags;	/* Generic UDP flags. */
+};
+
+#define	intoudpcb(ip)	((struct udpcb *)(ip)->inp_ppcb)
+#define	sotoudpcb(so)	(intoudpcb(sotoinpcb(so)))
+
 struct udpstat {
 				/* input statistics: */
 	u_long	udps_ipackets;		/* total input packets */
@@ -110,14 +123,15 @@ extern u_long			udp_sendspace;
 extern u_long			udp_recvspace;
 extern int			udp_log_in_vain;
 
+int		 udp_newudpcb(struct inpcb *);
+void		 udp_discardcb(struct udpcb *);
+
 void		 udp_ctlinput(int, struct sockaddr *, void *);
 void		 udp_init(void);
 void		 udp_input(struct mbuf *, int);
 struct inpcb	*udp_notify(struct inpcb *inp, int errno);
 int		 udp_shutdown(struct socket *so);
 
-
-typedef void(*udp_tun_func_t)(struct mbuf *, int off, struct inpcb *);
 int udp_set_kernel_tunneling(struct socket *so, udp_tun_func_t f);
 #endif
 

Modified: head/sys/netinet/vinet.h
==============================================================================
--- head/sys/netinet/vinet.h	Sat May 23 16:42:38 2009	(r192648)
+++ head/sys/netinet/vinet.h	Sat May 23 16:51:13 2009	(r192649)
@@ -149,6 +149,7 @@ struct vnet_inet {
 
 	struct inpcbhead	_udb;
 	struct inpcbinfo	_udbinfo;
+	uma_zone_t		_udpcb_zone;
 	struct udpstat		_udpstat;
 	int			_udp_blackhole;
 
@@ -373,6 +374,7 @@ extern struct vnet_inet vnet_inet_0;
 #define	V_twq_2msl		VNET_INET(twq_2msl)
 #define	V_udb			VNET_INET(udb)
 #define	V_udbinfo		VNET_INET(udbinfo)
+#define	V_udpcb_zone		VNET_INET(udpcb_zone)
 #define	V_udp_blackhole		VNET_INET(udp_blackhole)
 #define	V_udpstat		VNET_INET(udpstat)
 #define	V_useloopback		VNET_INET(useloopback)

Modified: head/sys/netinet6/udp6_usrreq.c
==============================================================================
--- head/sys/netinet6/udp6_usrreq.c	Sat May 23 16:42:38 2009	(r192648)
+++ head/sys/netinet6/udp6_usrreq.c	Sat May 23 16:51:13 2009	(r192649)
@@ -181,6 +181,7 @@ udp6_input(struct mbuf **mp, int *offp, 
 	struct ip6_hdr *ip6;
 	struct udphdr *uh;
 	struct inpcb *inp;
+	struct udpcb *up;
 	int off = *offp;
 	int plen, ulen;
 	struct sockaddr_in6 fromsa;
@@ -315,7 +316,10 @@ udp6_input(struct mbuf **mp, int *offp, 
 
 				if ((n = m_copy(m, 0, M_COPYALL)) != NULL) {
 					INP_RLOCK(last);
-					if (last->inp_ppcb != NULL) {
+					up = intoudpcb(last);
+					if (up->u_tun_func == NULL) {
+						udp6_append(last, n, off, &fromsa);
+					} else {
 						/*
 						 * Engage the tunneling
 						 * protocol we will have to
@@ -324,15 +328,9 @@ udp6_input(struct mbuf **mp, int *offp, 
 						 * through multiple UDP's.
 						 * 
 						 */
-						udp_tun_func_t tunnel_func;
-
-						tunnel_func = (udp_tun_func_t)last->inp_ppcb;
-						tunnel_func(n, off, last);
-						INP_RUNLOCK(last);
-					} else {
-						udp6_append(last, n, off, &fromsa);
-						INP_RUNLOCK(last);
+						(*up->u_tun_func)(n, off, last);
 					}
+					INP_RUNLOCK(last);
 				}
 			}
 			last = inp;
@@ -361,18 +359,15 @@ udp6_input(struct mbuf **mp, int *offp, 
 		}
 		INP_RLOCK(last);
 		INP_INFO_RUNLOCK(&V_udbinfo);
-		if (last->inp_ppcb != NULL) {
+		up = intoudpcb(last);
+		if (up->u_tun_func == NULL) {
+			udp6_append(last, m, off, &fromsa);
+		} else {
 			/*
 			 * Engage the tunneling protocol.
 			 */
-			udp_tun_func_t tunnel_func;
-
-			tunnel_func = (udp_tun_func_t)inp->inp_ppcb;
-			tunnel_func(m, off, last);
-			INP_RUNLOCK(last);
-			return (IPPROTO_DONE);
+			(*up->u_tun_func)(m, off, last);
 		}
-		udp6_append(last, m, off, &fromsa);
 		INP_RUNLOCK(last);
 		return (IPPROTO_DONE);
 	}
@@ -409,18 +404,16 @@ udp6_input(struct mbuf **mp, int *offp, 
 	}
 	INP_RLOCK(inp);
 	INP_INFO_RUNLOCK(&V_udbinfo);
-	if (inp->inp_ppcb != NULL) {
+	up = intoudpcb(inp);
+	if (up->u_tun_func == NULL) {
+		udp6_append(inp, m, off, &fromsa);
+	} else {
 		/*
 		 * Engage the tunneling protocol.
 		 */
-		udp_tun_func_t tunnel_func;
 
-		tunnel_func = (udp_tun_func_t)inp->inp_ppcb;
-		tunnel_func(m, off, inp);
-		INP_RUNLOCK(inp);
-		return (IPPROTO_DONE);
+		(*up->u_tun_func)(m, off, inp);
 	}
-	udp6_append(inp, m, off, &fromsa);
 	INP_RUNLOCK(inp);
 	return (IPPROTO_DONE);
 
@@ -820,7 +813,6 @@ udp6_attach(struct socket *so, int proto
 		return (error);
 	}
 	inp = (struct inpcb *)so->so_pcb;
-	INP_INFO_WUNLOCK(&V_udbinfo);
 	inp->inp_vflag |= INP_IPV6;
 	if ((inp->inp_flags & IN6P_IPV6_V6ONLY) == 0)
 		inp->inp_vflag |= INP_IPV4;
@@ -833,7 +825,16 @@ udp6_attach(struct socket *so, int proto
 	 * which may match an IPv4-mapped IPv6 address.
 	 */
 	inp->inp_ip_ttl = V_ip_defttl;
+
+	error = udp_newudpcb(inp);
+	if (error) {
+		in_pcbdetach(inp);
+		in_pcbfree(inp);
+		INP_INFO_WUNLOCK(&V_udbinfo);
+		return (error);
+	}
 	INP_WUNLOCK(inp);
+	INP_INFO_WUNLOCK(&V_udbinfo);
 	return (0);
 }
 
@@ -968,15 +969,19 @@ udp6_detach(struct socket *so)
 {
 	INIT_VNET_INET(so->so_vnet);
 	struct inpcb *inp;
+	struct udpcb *up;
 
 	inp = sotoinpcb(so);
 	KASSERT(inp != NULL, ("udp6_detach: inp == NULL"));
 
 	INP_INFO_WLOCK(&V_udbinfo);
 	INP_WLOCK(inp);
+	up = intoudpcb(inp);
+	KASSERT(up != NULL, ("%s: up == NULL", __func__));
 	in_pcbdetach(inp);
 	in_pcbfree(inp);
 	INP_INFO_WUNLOCK(&V_udbinfo);
+	udp_discardcb(up);
 }
 
 static int

Modified: head/sys/sys/param.h
==============================================================================
--- head/sys/sys/param.h	Sat May 23 16:42:38 2009	(r192648)
+++ head/sys/sys/param.h	Sat May 23 16:51:13 2009	(r192649)
@@ -57,7 +57,7 @@
  *		is created, otherwise 1.
  */
 #undef __FreeBSD_version
-#define __FreeBSD_version 800088	/* Master, propagated to newvers */
+#define __FreeBSD_version 800089	/* Master, propagated to newvers */
 
 #ifndef LOCORE
 #include <sys/types.h>



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905231651.n4NGpDtI061174>