[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

kernel/2165: Network pseudo device cloning support




>Number:         2165
>Category:       kernel
>Synopsis:       Network pseudo device cloning support
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bugs
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Fri Nov  2 02:40:01 MST 2001
>Last-Modified:
>Originator:     Kyunghwan Kim
>Organization:
net
>Release:        -current
>Environment:
	System      : OpenBSD 3.0
	Architecture: OpenBSD.i386
	Machine     : i386
>Description:
	Network pseudo devices such as gif(4) and bridge(4) is configured
	by config(8) and number of devices is static(unchangable) after 
	kernel linking. Even though it can be changed using config(8),
	it also needs another reboot.

	This allows network pseudo devices to be created and destroyed
	on the fly via ifconfig(8) rather than specifying the count in the
	kernel configuration.

	This patch provides pseudo device cloning and ifconfig(8)
	support and is heavily based on device cloning implementation 
	of NetBSD and FreeBSD.

>How-To-Repeat:
	nothing to repeat.
>Fix:
	apply patch below at /usr/src.

--- sys/sys/sockio.h.orig	Fri Nov  2 11:26:19 2001
+++ sys/sys/sockio.h	Fri Nov  2 16:34:29 2001
@@ -1,4 +1,4 @@
-/*	$OpenBSD: sockio.h,v 1.18 2000/12/31 00:14:59 angelos Exp $	*/
+/*	$OpenBSD$	*/
 /*	$NetBSD: sockio.h,v 1.5 1995/08/23 00:40:47 thorpej Exp $	*/
 
 /*-
@@ -134,6 +134,9 @@
 #define GRESPROTO        _IOW('i', 105, struct ifreq)
 #define GREGPROTO       _IOWR('i', 106, struct ifreq)
 
+#define SIOCIFCREATE	_IOWR('i', 120, struct ifreq)	/* create clone if */
+#define SIOCIFDESTROY	 _IOW('i', 121, struct ifreq)	/* destory clone if */
+#define SIOCIFGCLONERS	_IOWR('i', 122, struct if_clonereq) /* get cloners */
 #define	SIOCSIFMTU	 _IOW('i', 127, struct ifreq)	/* set ifnet mtu */
 #define	SIOCGIFMTU	_IOWR('i', 126, struct ifreq)	/* get ifnet mtu */
 #define	SIOCSIFASYNCMAP  _IOW('i', 125, struct ifreq)	/* set ppp asyncmap */
--- sys/net/if.h.orig	Wed Oct 31 15:03:30 2001
+++ sys/net/if.h	Fri Nov  2 17:53:10 2001
@@ -1,4 +1,4 @@
-/*	$OpenBSD: if.h,v 1.30 2001/07/05 08:27:38 jjbg Exp $	*/
+/*	$OpenBSD$	*/
 /*	$NetBSD: if.h,v 1.23 1996/05/07 02:40:27 thorpej Exp $	*/
 
 /*
@@ -423,6 +423,31 @@
 	char 		*if_name;
 };
 
+/*
+ * Structure describing a `cloning' interface.
+ */
+struct if_clone {
+	LIST_ENTRY(if_clone) ifc_list;	/* on list of cloners */
+	const char *ifc_name;		/* name of device */
+	size_t ifc_namelen;		/* length of name */
+
+	int	(*ifc_create)(struct if_clone *, int);
+	void	(*ifc_destroy)(struct ifnet *);
+};
+
+#define IF_CLONE_INITIALIZER(name, create, destroy)		\
+	{ { 0 }, name, sizeof(name) -1, create, destroy }
+
+/*
+ * Structure used to query names of interface cloners.
+ */
+
+struct if_clonereq {
+	int 	ifcr_total;	/* total cloners (out) */
+	int	ifcr_count;	/* room for this many in user buffer */
+	char 	*ifcr_buffer;	/* buffer for cloner names */
+};
+
 #ifndef _KERNEL
 __BEGIN_DECLS
 unsigned int if_nametoindex __P((const char *));
@@ -576,6 +601,12 @@
 struct	ifaddr *ifaof_ifpforaddr __P((struct sockaddr *, struct ifnet *));
 void	ifafree __P((struct ifaddr *));
 void	link_rtrequest __P((int, struct rtentry *, struct rt_addrinfo *));
+
+void	if_clone_attach __P((struct if_clone *));
+void	if_clone_detach __P((struct if_clone *));
+
+int	if_clone_create __P((char *));
+int	if_clone_destroy __P((char *));
 
 int	loioctl __P((struct ifnet *, u_long, caddr_t));
 void	loopattach __P((int));
--- sys/net/if.c.orig	Wed Oct 31 15:03:26 2001
+++ sys/net/if.c	Fri Nov  2 17:57:15 2001
@@ -1,4 +1,4 @@
-/*	$OpenBSD: if.c,v 1.48 2001/06/27 05:50:06 kjc Exp $	*/
+/*	$OpenBSD$	*/
 /*	$NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $	*/
 
 /*
@@ -126,6 +126,12 @@
 extern void nd6_setmtu __P((struct ifnet *));
 #endif 
 
+struct if_clone *if_clone_lookup __P((const char *, int *));
+int if_clone_list __P((struct if_clonereq *));
+
+LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners);
+int if_cloners_count;
+
 /*
  * Network interface utility routines.
  *
@@ -316,6 +322,153 @@
 }
 
 /*
+ * Create a clone network interface.
+ */
+int
+if_clone_create(name)
+	char *name;
+{
+	struct if_clone *ifc;
+	int unit;
+
+	ifc = if_clone_lookup(name, &unit);
+	if (ifc == NULL)
+		return (EINVAL);
+
+	if (ifunit(name) != NULL)
+		return (EEXIST);
+
+	return ((*ifc->ifc_create)(ifc, unit));
+}
+
+/*
+ * Destroy a clone network interface.
+ */
+int
+if_clone_destroy(name)
+	char *name;
+{
+	struct if_clone *ifc;
+	struct ifnet *ifp;
+
+	ifc = if_clone_lookup(name, NULL);
+	if (ifc == NULL)
+		return (EINVAL);
+
+	ifp = ifunit(name);
+	if (ifp == NULL)
+		return (ENXIO);
+
+	if (ifc->ifc_destroy == NULL)
+		return (EOPNOTSUPP);
+
+	(*ifc->ifc_destroy)(ifp);
+	return (0);
+}
+
+/*
+ * Look up a network interface cloner.
+ */
+struct if_clone *
+if_clone_lookup(name, unitp)
+	const char *name;
+	int *unitp;
+{
+	struct if_clone *ifc;
+	const char *cp;
+	int i;
+
+	for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) {
+		for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) {
+			if (ifc->ifc_name[i] != *cp)
+				goto next_ifc;
+		}
+		goto found_name;
+ next_ifc:
+		ifc = LIST_NEXT(ifc, ifc_list);
+	}
+
+	/* No match */
+	return (NULL);
+
+ found_name:
+	if (*cp == '\0') {
+		i = -1;
+	} else {
+		for (i = 0; *cp != '\0'; cp++) {
+			if (*cp < '0' || *cp > '9') {
+				/* Bogus unit number */
+				return (NULL);
+			}
+			i = (i * 10) + (*cp - '0');
+		}
+	}
+
+	if (unitp != NULL)
+		*unitp = i;
+	return (ifc);
+}
+
+/*
+ * Register a network interface cloner.
+ */
+void
+if_clone_attach(ifc)
+	struct if_clone *ifc;
+{
+
+	LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list);
+	if_cloners_count++;
+}
+
+/*
+ * Unregister a network interface cloner.
+ */
+void
+if_clone_detach(ifc)
+	struct if_clone *ifc;
+{
+
+	LIST_REMOVE(ifc, ifc_list);
+	if_cloners_count--;
+}
+
+/*
+ * Provide list of interface cloners to userspace.
+ */
+int
+if_clone_list(ifcr)
+	struct if_clonereq *ifcr;
+{
+	char outbuf[IFNAMSIZ], *dst;
+	struct if_clone *ifc;
+	int count, error = 0;
+
+	ifcr->ifcr_total = if_cloners_count;
+	if ((dst = ifcr->ifcr_buffer) == NULL) {
+		/* Just asking how many there are. */
+		return (0);
+	}
+
+	if (ifcr->ifcr_count < 0)
+		return (EINVAL);
+
+	count = (if_cloners_count < ifcr->ifcr_count) ?
+	    if_cloners_count : ifcr->ifcr_count;
+
+	for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0;
+	    ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) {
+		strncpy(outbuf, ifc->ifc_name, IFNAMSIZ);
+		outbuf[IFNAMSIZ - 1] = '\0';	/* sanity */
+		error = copyout(outbuf, dst, IFNAMSIZ);
+		if (error)
+			break;
+	}
+
+	return (error);
+}
+
+/*
  * Detach an interface from everything in the kernel.  Also deallocate
  * private resources.
  * XXX So far only the INET protocol family has been looked over
@@ -724,6 +877,20 @@
 		return (ifconf(cmd, data));
 	}
 	ifr = (struct ifreq *)data;
+
+	switch (cmd) {
+	case SIOCIFCREATE:
+	case SIOCIFDESTROY:
+		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
+			return (error);
+		return ((cmd == SIOCIFCREATE) ?
+		    if_clone_create(ifr->ifr_name) :
+		    if_clone_destroy(ifr->ifr_name));
+
+	case SIOCIFGCLONERS:
+		return (if_clone_list((struct if_clonereq *)data));
+	}
+
 	ifp = ifunit(ifr->ifr_name);
 	if (ifp == 0)
 		return (ENXIO);
--- ifconfig.c.orig	Fri Nov  2 14:18:13 2001
+++ ifconfig.c	Fri Nov  2 18:27:20 2001
@@ -1,4 +1,4 @@
-/*	$OpenBSD: ifconfig.c,v 1.52 2001/08/19 01:51:34 itojun Exp $	*/
+/*	$OpenBSD$	*/
 /*      $NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $      */
 
 /*
@@ -194,6 +194,8 @@
 void	unsetvlandev __P((char *, int));
 void	vlan_status ();
 void	fixnsel __P((struct sockaddr_iso *));
+void	clone_create __P((const char *, int));
+void	clone_destroy __P((const char *, int));
 int	main __P((int, char *[]));
 int	prefix __P((void *val, int));
 
@@ -274,6 +276,11 @@
 	{ "giftunnel",  NEXTARG2,       0,              settunnel } ,
 	{ "tunnel",  	NEXTARG2,       0,              settunnel } ,
 	{ "deletetunnel",  0,       	0,              deletetunnel } ,
+#if 0
+	/* XXX `create' special-cased below */
+	{ "create",	0,		0,		clone_create },
+#endif
+	{ "destroy",	0,		0,		clone_destroy },
 	{ "link0",	IFF_LINK0,	0,		setifflags } ,
 	{ "-link0",	-IFF_LINK0,	0,		setifflags } ,
 	{ "link1",	IFF_LINK1,	0,		setifflags } ,
@@ -404,6 +411,18 @@
 	} else
 		(void) strlcpy(name, *argv, sizeof(name));
 	argc--, argv++;
+
+	/*
+	 * NOTE: We must special-case the `create' command right
+	 * here as we would otherwise fail in getinfo().
+	 */
+	if (argc > 0 && strcmp(argv[0], "create") == 0) {
+		clone_create(argv[0], 0);
+		argc--, argv++;
+		if (argc == 0)
+			exit(0);
+	}
+
 	if (argc > 0) {
 		for (afp = rafp = afs; rafp->af_name; rafp++)
 			if (strcmp(rafp->af_name, *argv) == 0) {
@@ -2263,7 +2282,9 @@
 		"\t[ -802.2 | -802.3 | -802.2tr | -snap | -EtherII ]\n"
 		"\t[ link0 | -link0 ] [ link1 | -link1 ] [ link2 | -link2 ]\n"
 		"       ifconfig [-a | -A | -am | -Am] [ af ]\n"
-		"       ifconfig -m interface [af]\n");
+		"       ifconfig -m interface [af]\n"
+		"	ifconfig interface create\n"
+		"	ifconfig interface destroy\n");
 	exit(1);
 }
 
@@ -2407,3 +2428,28 @@
 	return(result);
 }
 #endif
+
+void
+clone_destroy(addr, param)
+	const char *addr;
+	int param;
+{
+
+	(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+        if (ioctl(s, SIOCIFDESTROY, (caddr_t)&ifr) < 0)
+                warn("SIOCIFDESTROY");
+}
+
+void
+clone_create(addr, param)
+	const char *addr;
+	int param;
+{
+
+	/* clone_create is called early */
+	getsock(AF_INET);
+
+	(void)strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
+        if (ioctl(s, SIOCIFCREATE, (caddr_t)&ifr) < 0)
+                warn("SIOCIFCREATE");
+}
--- ifconfig.8.orig	Fri Nov  2 14:18:20 2001
+++ ifconfig.8	Fri Nov  2 16:47:41 2001
@@ -1,4 +1,4 @@
-.\"	$OpenBSD: ifconfig.8,v 1.51 2001/05/02 06:44:23 itojun Exp $
+.\"	$OpenBSD$
 .\"	$NetBSD: ifconfig.8,v 1.11 1996/01/04 21:27:29 pk Exp $
 .\"     $FreeBSD: ifconfig.8,v 1.16 1998/02/01 07:03:29 steve Exp $
 .\"
@@ -75,6 +75,12 @@
 .Nm ifconfig
 .Op Fl A | Am
 .Op Ar address_family
+.Nm ifconfig
+.Ar interface
+.Cm create
+.Nm ifconfig
+.Ar interface
+.Cm destroy
 .Sh DESCRIPTION
 The
 .Nm
@@ -219,6 +225,10 @@
 .It Cm deletetunnel
 Removes the source and dsetination tunnel addresses,
 configured onto a tunnel interface.
+.It Cm create
+Create the specified network pseudo-device.
+.It Cm destroy
+Destroy the specified network pseudo-device.
 .It Cm ipdst
 This is used to specify an Internet host who is willing to receive
 ip packets encapsulating NS packets bound for a remote network.

>Audit-Trail:
>Unformatted: