From 3e61dca08d9d435f0efc3ea3efe41fdee852200a Mon Sep 17 00:00:00 2001 From: Brooks Davis Date: Mon, 2 Jul 2001 20:52:34 +0000 Subject: [PATCH] Support network device cloning via create and destroy options. Reviewed by: ru, ume Obtained from: NetBSD MFC after: 1 week --- sbin/ifconfig/ifconfig.8 | 29 ++++++++ sbin/ifconfig/ifconfig.c | 153 +++++++++++++++++++++++++++++++++++---- 2 files changed, 166 insertions(+), 16 deletions(-) diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8 index e4ef0f4da39f..d56418098c3b 100644 --- a/sbin/ifconfig/ifconfig.8 +++ b/sbin/ifconfig/ifconfig.8 @@ -43,6 +43,7 @@ .Op Fl L .Op Fl m .Ar interface +.Op Cm create .Op Ar address_family .Oo .Ar address Ns Op Cm / Ns Ar prefixlength @@ -50,6 +51,9 @@ .Oc .Op Ar parameters .Nm +.Ar interface +.Cm destroy +.Nm .Fl a .Op Fl L .Op Fl d @@ -66,6 +70,7 @@ .Op Fl d .Op Fl m .Op Fl u +.Op Fl C .Sh DESCRIPTION .Nm Ifconfig is used to assign an address @@ -269,6 +274,24 @@ IPv4/IPv6 header. Unconfigure the physical source and destination address for IP tunnel interfaces previously configured with .Cm tunnel . +.It Cm create +Create the specified network pseudo-device. +If the interface is given without a unit number, try to create a new +device with an arbitrary unit number. +If creation of an arbitrary device is sucessful, the new device name is +printed to stdout. +.It Cm destroy +Destroy the specified network pseudo-device. +.It Cm plumb +Another name for the +.Fl create +parameter. +Included for Solaris compatibility. +.It Cm unplumb +Another name for the +.Fl destroy +parameter. +Included for Solaris compatibility. .It Cm vlan Ar vlan_tag If the interface is a vlan pseudo interface, set the vlan tag value to @@ -587,6 +610,12 @@ and .Fl u (only list interfaces that are up). .Pp +The +.Fl C +flag may be used to list all of the interface cloners available on +the system, with no additional information. +Use of this flag is mutually exclusive with all other flags and commands. +.Pp Only the super-user may modify the configuration of a network interface. .Sh NOTES The media selection system is relatively new and only some drivers support diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c index 72c0f1622029..131cf068cd3a 100644 --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -135,6 +135,7 @@ static int ip6lifetime; struct afswtch; int supmedia = 0; +int listcloners = 0; #ifdef INET6 char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/ @@ -144,6 +145,7 @@ void Perror __P((const char *cmd)); void checkatrange __P((struct sockaddr_at *)); int ifconfig __P((int argc, char *const *argv, const struct afswtch *afp)); void notealias __P((const char *, int, int, const struct afswtch *afp)); +void list_cloners __P((void)); void printb __P((const char *s, unsigned value, const char *bits)); void rt_xaddrs __P((caddr_t, caddr_t, struct rt_addrinfo *)); void status __P((const struct afswtch *afp, int addrcount, @@ -175,6 +177,10 @@ c_func2 setip6lifetime; #endif c_func setifipdst; c_func setifflags, setifmetric, setifmtu, setiflladdr; +c_func clone_destroy; + + +void clone_create __P((void)); #define NEXTARG 0xffffff @@ -239,6 +245,13 @@ struct cmd { { "vlandev", NEXTARG, setvlandev }, { "-vlandev", NEXTARG, unsetvlandev }, #endif +#if 0 + /* XXX `create' special-cased below */ + {"create", 0, clone_create }, + {"plumb", 0, clone_create }, +#endif + {"destroy", 0, clone_destroy }, + {"unplumb", 0, clone_destroy }, #ifdef USE_IEEE80211 { "ssid", NEXTARG, set80211ssid }, { "nwid", NEXTARG, set80211ssid }, @@ -364,16 +377,20 @@ void usage() { #ifndef INET6 - fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", + fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "usage: ifconfig interface address_family [address [dest_address]]", " [parameters]", + " ifconfig -C", + " ifconfig interface create", " ifconfig -a [-d] [-m] [-u] [address_family]", " ifconfig -l [-d] [-u] [address_family]", " ifconfig [-d] [-m] [-u]"); #else - fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n", + fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", "usage: ifconfig [-L] interface address_family [address [dest_address]]", " [parameters]", + " ifconfig -C", + " ifconfig interface create", " ifconfig -a [-L] [-d] [-m] [-u] [address_family]", " ifconfig -l [-d] [-u] [address_family]", " ifconfig [-L] [-d] [-m] [-u]"); @@ -402,7 +419,7 @@ main(argc, argv) /* Parse leading line options */ all = downonly = uponly = namesonly = 0; - while ((c = getopt(argc, argv, "adlmu" + while ((c = getopt(argc, argv, "adlmuC" #ifdef INET6 "L" #endif @@ -411,23 +428,26 @@ main(argc, argv) case 'a': /* scan all interfaces */ all++; break; + case 'd': /* restrict scan to "down" interfaces */ + downonly++; + break; + case 'l': /* scan interface names only */ + namesonly++; + break; + case 'm': /* show media choices in status */ + supmedia = 1; + break; + case 'u': /* restrict scan to "up" interfaces */ + uponly++; + break; + case 'C': + listcloners = 1; + break; #ifdef INET6 case 'L': ip6lifetime++; /* print IPv6 address lifetime */ break; #endif - case 'l': /* scan interface names only */ - namesonly++; - break; - case 'd': /* restrict scan to "down" interfaces */ - downonly++; - break; - case 'u': /* restrict scan to "up" interfaces */ - uponly++; - break; - case 'm': /* show media choices in status */ - supmedia = 1; - break; default: usage(); break; @@ -436,6 +456,16 @@ main(argc, argv) argc -= optind; argv += optind; + if (listcloners) { + /* -C must be solitary */ + if (all || supmedia || uponly || downonly || namesonly || + argc > 0) + usage(); + + list_cloners(); + exit(0); + } + /* -l cannot be used with -a or -m */ if (namesonly && (all || supmedia)) usage(); @@ -473,6 +503,18 @@ main(argc, argv) /* check and maybe load support for this interface */ ifmaybeload(name); + + /* + * NOTE: We must special-case the `create' command right + * here as we would otherwise fail when trying to find + * the interface. + */ + if (argc > 0 && strcmp(argv[0], "create") == 0) { + clone_create(); + argc--, argv++; + if (argc == 0) + exit(0); + } } /* Check for address family */ @@ -1861,7 +1903,8 @@ ifmaybeload(name) /* turn interface and unit into module name */ strcpy(ifkind, "if_"); - for (cp = name, dp = ifkind + 3; (*cp != 0) && !isdigit(*cp); cp++, dp++) + for (cp = name, dp = ifkind + 3; + (*cp != 0) && !isdigit(*cp); cp++, dp++) *dp = *cp; *dp = 0; @@ -1888,3 +1931,81 @@ ifmaybeload(name) /* not present, we should try to load it */ kldload(ifkind); } + +void +list_cloners(void) +{ + struct if_clonereq ifcr; + char *cp, *buf; + int idx; + int s; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s == -1) + err(1, "socket"); + + memset(&ifcr, 0, sizeof(ifcr)); + + if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0) + err(1, "SIOCIFGCLONERS for count"); + + buf = malloc(ifcr.ifcr_total * IFNAMSIZ); + if (buf == NULL) + err(1, "unable to allocate cloner name buffer"); + + ifcr.ifcr_count = ifcr.ifcr_total; + ifcr.ifcr_buffer = buf; + + if (ioctl(s, SIOCIFGCLONERS, &ifcr) < 0) + err(1, "SIOCIFGCLONERS for names"); + + /* + * In case some disappeared in the mean time, clamp it down. + */ + if (ifcr.ifcr_count > ifcr.ifcr_total) + ifcr.ifcr_count = ifcr.ifcr_total; + + for (cp = buf, idx = 0; idx < ifcr.ifcr_count; idx++, cp += IFNAMSIZ) { + if (idx > 0) + putchar(' '); + printf("%s", cp); + } + + putchar('\n'); + free(buf); +} + +void +clone_create() +{ + int s; + + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s == -1) + err(1, "socket"); + + memset(&ifr, 0, sizeof(ifr)); + (void) strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCIFCREATE, &ifr) < 0) + err(1, "SIOCIFCREATE"); + + if (strcmp(name, ifr.ifr_name) != 0) { + printf("%s\n", ifr.ifr_name); + strlcpy(name, ifr.ifr_name, sizeof(name)); + } + + close(s); +} + +void +clone_destroy(val, d, s, rafp) + const char *val; + int d; + int s; + const struct afswtch *rafp; +{ + + (void) strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCIFDESTROY, &ifr) < 0) + err(1, "SIOCIFDESTROY"); +}