Add kernel infrastructure for network device cloning.
Reviewed by: ru, ume Obtained from: NetBSD MFC after: 1 week
This commit is contained in:
parent
cf7ae120d9
commit
30aad87d72
197
sys/net/if.c
197
sys/net/if.c
@ -56,6 +56,7 @@
|
||||
#include <net/if_arp.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/radix.h>
|
||||
#include <net/route.h>
|
||||
|
||||
@ -96,6 +97,12 @@ struct ifnethead ifnet; /* depend on static init XXX */
|
||||
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.
|
||||
*
|
||||
@ -349,6 +356,178 @@ if_rtdel(rn, arg)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a clone network interface.
|
||||
*/
|
||||
int
|
||||
if_clone_create(name, len)
|
||||
char *name;
|
||||
int len;
|
||||
{
|
||||
struct if_clone *ifc;
|
||||
char *dp;
|
||||
int wildcard;
|
||||
int unit;
|
||||
int err;
|
||||
|
||||
ifc = if_clone_lookup(name, &unit);
|
||||
if (ifc == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
if (ifunit(name) != NULL)
|
||||
return (EEXIST);
|
||||
|
||||
wildcard = (unit < 0);
|
||||
|
||||
err = (*ifc->ifc_create)(ifc, &unit);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
/* In the wildcard case, we need to update the name. */
|
||||
if (wildcard) {
|
||||
for (dp = name; *dp != '\0'; dp++);
|
||||
if (snprintf(dp, len - (dp-name), "%d", unit) >
|
||||
len - (dp-name) - 1) {
|
||||
/*
|
||||
* This can only be a programmer error and
|
||||
* there's no straightforward way to recover if
|
||||
* it happens.
|
||||
*/
|
||||
panic("if_clone_create(): interface name too long");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a clone network interface.
|
||||
*/
|
||||
int
|
||||
if_clone_destroy(name)
|
||||
const 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 ((struct if_clone *)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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Locate an interface based on a complete address.
|
||||
*/
|
||||
@ -687,10 +866,10 @@ if_slowtimo(arg)
|
||||
* interface structure pointer.
|
||||
*/
|
||||
struct ifnet *
|
||||
ifunit(char *name)
|
||||
ifunit(const char *name)
|
||||
{
|
||||
char namebuf[IFNAMSIZ + 1];
|
||||
char *cp;
|
||||
const char *cp;
|
||||
struct ifnet *ifp;
|
||||
int unit;
|
||||
unsigned len, m;
|
||||
@ -781,6 +960,20 @@ ifioctl(so, cmd, data, p)
|
||||
return (ifconf(cmd, data));
|
||||
}
|
||||
ifr = (struct ifreq *)data;
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCIFCREATE:
|
||||
case SIOCIFDESTROY:
|
||||
if ((error = suser(p)) != 0)
|
||||
return (error);
|
||||
return ((cmd == SIOCIFCREATE) ?
|
||||
if_clone_create(ifr->ifr_name, sizeof(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);
|
||||
|
38
sys/net/if.h
38
sys/net/if.h
@ -37,6 +37,8 @@
|
||||
#ifndef _NET_IF_H_
|
||||
#define _NET_IF_H_
|
||||
|
||||
#include <sys/queue.h>
|
||||
|
||||
/*
|
||||
* <net/if.h> does not depend on <sys/time.h> on most other systems. This
|
||||
* helps userland compatibility. (struct timeval ifi_lastchange)
|
||||
@ -45,6 +47,40 @@
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
struct ifnet;
|
||||
|
||||
/*
|
||||
* Length of interface external name, including terminating '\0'.
|
||||
* Note: this is the same size as a generic device's external name.
|
||||
*/
|
||||
#define IFNAMSIZ 16
|
||||
#define IF_NAMESIZE IFNAMSIZ
|
||||
|
||||
/*
|
||||
* 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, e.g. `gif' */
|
||||
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 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure describing information about an interface
|
||||
* which may be of interest to management entities.
|
||||
@ -151,8 +187,6 @@ struct ifma_msghdr {
|
||||
* remainder may be interface specific.
|
||||
*/
|
||||
struct ifreq {
|
||||
#define IFNAMSIZ 16
|
||||
#define IF_NAMESIZE IFNAMSIZ
|
||||
char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */
|
||||
union {
|
||||
struct sockaddr ifru_addr;
|
||||
|
@ -401,7 +401,7 @@ void if_up __P((struct ifnet *));
|
||||
/*void ifinit __P((void));*/ /* declared in systm.h for main() */
|
||||
int ifioctl __P((struct socket *, u_long, caddr_t, struct proc *));
|
||||
int ifpromisc __P((struct ifnet *, int));
|
||||
struct ifnet *ifunit __P((char *));
|
||||
struct ifnet *ifunit __P((const char *));
|
||||
struct ifnet *if_withname __P((struct sockaddr *));
|
||||
|
||||
int if_poll_recv_slow __P((struct ifnet *ifp, int *quotap));
|
||||
@ -423,6 +423,12 @@ struct ifmultiaddr *ifmaof_ifpforaddr __P((struct sockaddr *,
|
||||
struct ifnet *));
|
||||
int if_simloop __P((struct ifnet *ifp, struct mbuf *m, int af, int hlen));
|
||||
|
||||
void if_clone_attach __P((struct if_clone *));
|
||||
void if_clone_detach __P((struct if_clone *));
|
||||
|
||||
int if_clone_create __P((char *, int));
|
||||
int if_clone_destroy __P((const char *));
|
||||
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* !_NET_IF_VAR_H_ */
|
||||
|
@ -100,4 +100,8 @@
|
||||
#define SIOCGIFSTATUS _IOWR('i', 59, struct ifstat) /* get IF status */
|
||||
#define SIOCSIFLLADDR _IOW('i', 60, struct ifreq) /* set link level addr */
|
||||
|
||||
#define SIOCIFCREATE _IOWR('i', 122, struct ifreq) /* create clone if */
|
||||
#define SIOCIFDESTROY _IOW('i', 121, struct ifreq) /* destroy clone if */
|
||||
#define SIOCIFGCLONERS _IOWR('i', 120, struct if_clonereq) /* get cloners */
|
||||
|
||||
#endif /* !_SYS_SOCKIO_H_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user