NetBSD Problem Report #46633

From darrenr@netbsd.org  Wed Jun 27 11:44:41 2012
Return-Path: <darrenr@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [149.20.53.66])
	by www.NetBSD.org (Postfix) with ESMTP id C332763B85F
	for <gnats-bugs@gnats.NetBSD.org>; Wed, 27 Jun 2012 11:44:41 +0000 (UTC)
Message-Id: <20120627114441.ADE9E14A565@mail.netbsd.org>
Date: Wed, 27 Jun 2012 11:44:41 +0000 (UTC)
From: darrenr@netbsd.org
Reply-To: darrenr@netbsd.org
To: gnats-bugs@gnats.NetBSD.org
Subject: create network cloned devices without specifying a unit
X-Send-Pr-Version: 3.95

>Number:         46633
>Category:       kern
>Synopsis:       create clone network interface without unit
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Class:          change-request
>Submitter-Id:   net
>Arrival-Date:   Wed Jun 27 11:45:00 +0000 2012
>Last-Modified:  Wed Jun 27 13:25:45 +0000 2012
>Originator:     Darren Reed
>Release:        NetBSD 5.99.59
>Organization:
NetBSD
>Environment:
>Description:
The ifconfig command currently requires that network devices that support
cloning be created by specifying the unit number when ifconfig is run.
This requires the caller of ifconfig to have somehow decided that the
unit number to be used to have already been allocated. This change removes
that need.

Whereas in the past a script was required to create an interface
like this:

# ifconfig gif0 create

the following will now work:

# ifconfig gif create
gif0
>How-To-Repeat:
Create a cloned network interface.
>Fix:
--- usr/src/sys/net/if.h.dist	2011-10-26 10:00:24.000000000 +0200
+++ usr/src/sys/net/if.h	2012-06-27 12:53:11.000000000 +0200
@@ -905,7 +905,7 @@
 void	if_clone_attach(struct if_clone *);
 void	if_clone_detach(struct if_clone *);

-int	if_clone_create(const char *);
+int	if_clone_create(const char *, char *, int);
 int	if_clone_destroy(const char *);

 int	ifq_enqueue(struct ifnet *, struct mbuf * ALTQ_COMMA
--- usr/src/sys/net/if.c.dist	2011-11-27 22:42:44.000000000 +0100
+++ usr/src/sys/net/if.c	2012-06-27 13:27:36.000000000 +0200
@@ -154,6 +154,7 @@

 static int	if_rt_walktree(struct rtentry *, void *);

+static struct if_clone *if_clone_find(const char *, const int);
 static struct if_clone *if_clone_lookup(const char *, int *);
 static int	if_clone_list(struct if_clonereq *);

@@ -927,15 +928,52 @@
 	return ERESTART;
 }

+static struct if_clone *
+if_clone_find(const char *name, const int len)
+{
+	struct if_clone *ifc;
+
+	LIST_FOREACH(ifc, &if_cloners, ifc_list) {
+		if (strlen(ifc->ifc_name) == len &&
+		    strncmp(name, ifc->ifc_name, len) == 0)
+			return ifc;
+	}
+
+	return NULL;
+}
+
 /*
  * Create a clone network interface.
  */
 int
-if_clone_create(const char *name)
+if_clone_create(const char *name, char *newname, int dynamic)
 {
+	char buffer[IFNAMSIZ];
 	struct if_clone *ifc;
 	int unit;

+	if (dynamic == 1) {
+		/*
+		 * If "name" is the name of a device that supports cloning
+		 * and thus excludes a unit number and the dynamic flag is
+		 * set then attempt to allocate a unit number, construct
+		 * the name for the new device and return it in newname.
+		 * The assumption is newname is at least IFNAMSIZ in length.
+		 */
+		ifc = if_clone_find(name, strlen(name));
+		if (newname != NULL && ifc != NULL) {
+			for (unit = 0; unit < INT_MAX / 10; unit++) {
+				snprintf(buffer, IFNAMSIZ, "%s%d",
+				    name, unit);
+				if (ifunit(buffer) == NULL) {
+					strlcpy(newname, buffer, IFNAMSIZ);
+					return (*ifc->ifc_create)(ifc, unit);
+				}
+			}
+			return EINVAL;
+		}
+	}
+
 	ifc = if_clone_lookup(name, &unit);
 	if (ifc == NULL)
 		return EINVAL;
@@ -988,12 +1026,7 @@
 	if (cp == name || cp - name == IFNAMSIZ || !*cp)
 		return NULL;	/* No name or unit number */

-	LIST_FOREACH(ifc, &if_cloners, ifc_list) {
-		if (strlen(ifc->ifc_name) == cp - name &&
-		    strncmp(name, ifc->ifc_name, cp - name) == 0)
-			break;
-	}
-
+	ifc = if_clone_find(name, cp - name);
 	if (ifc == NULL)
 		return NULL;

@@ -1776,6 +1809,7 @@

 	switch (cmd) {
 	case SIOCIFCREATE:
+	case OSIOCIFCREATE:
 	case SIOCIFDESTROY:
 		if (l != NULL) {
 			error = kauth_authorize_network(l->l_cred,
@@ -1785,9 +1819,11 @@
 			if (error != 0)
 				return error;
 		}
-		return (cmd == SIOCIFCREATE) ?
-			if_clone_create(ifr->ifr_name) :
-			if_clone_destroy(ifr->ifr_name);
+		if (cmd == OSIOCIFCREATE)
+			return if_clone_create(ifr->ifr_name, NULL, 0);
+		if (cmd == SIOCIFDESTROY)
+			return if_clone_destroy(ifr->ifr_name);
+		return if_clone_create(ifr->ifr_name, ifr->ifr_name, 1);

 	case SIOCIFGCLONERS:
 		return if_clone_list((struct if_clonereq *)data);
--- usr/src/sbin/ifconfig/util.c.dist	2010-12-14 08:52:22.000000000 +0100
+++ usr/src/sbin/ifconfig/util.c	2012-06-27 13:20:59.000000000 +0200
@@ -230,13 +230,19 @@
 int
 indirect_ioctl(prop_dictionary_t env, unsigned long cmd, void *data)
 {
+	struct ifreq oifr;
 	struct ifreq ifr;
+	int error;

 	memset(&ifr, 0, sizeof(ifr));

 	ifr.ifr_data = data;
+	oifr = ifr;

-	return direct_ioctl(env, cmd, &ifr);
+	error = direct_ioctl(env, cmd, &ifr);
+	if (error == 0 && strncmp(ifr.ifr_name, oifr.ifr_name, IFNAMSIZ))
+		printf("%s\n", ifr.ifr_name);
+	return error;
 }

 void
--- usr/src/sbin/ifconfig/ifconfig.8.dist	2012-06-27 13:42:23.000000000 +0200
+++ usr/src/sbin/ifconfig/ifconfig.8	2012-06-27 13:42:15.000000000 +0200
@@ -530,7 +530,9 @@
 interfaces previously configured with
 .Cm tunnel .
 .It Cm create
-Create the specified network pseudo-device.
+Create the specified network pseudo-device. When used without a unit
+number for the network interface, the kernel will allocate a unit and
+the full interface name is printed on stdout before the program exits.
 .It Cm destroy
 Destroy the specified network pseudo-device.
 .It Cm pltime Ar n

>Release-Note:

>Audit-Trail:

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.