aboutsummaryrefslogtreecommitdiff
path: root/sys/net/if_clone.c
diff options
context:
space:
mode:
authorGleb Smirnoff <glebius@FreeBSD.org>2012-10-16 13:37:54 +0000
committerGleb Smirnoff <glebius@FreeBSD.org>2012-10-16 13:37:54 +0000
commit42a58907c35af91de3028f15c0039f73149bf732 (patch)
tree0f54a9446bfe2083d3c0a3f744318b2be8a0db05 /sys/net/if_clone.c
parent26c3f6d7e258969047f1c0e3fa86261eafdf3651 (diff)
downloadsrc-42a58907c35af91de3028f15c0039f73149bf732.tar.gz
src-42a58907c35af91de3028f15c0039f73149bf732.zip
Make the "struct if_clone" opaque to users of the cloning API. Users
now use function calls: if_clone_simple() if_clone_advanced() to initialize a cloner, instead of macros that initialize if_clone structure. Discussed with: brooks, bz, 1 year ago
Notes
Notes: svn path=/head/; revision=241610
Diffstat (limited to 'sys/net/if_clone.c')
-rw-r--r--sys/net/if_clone.c224
1 files changed, 162 insertions, 62 deletions
diff --git a/sys/net/if_clone.c b/sys/net/if_clone.c
index 3543e2f71fca..5f68d29dc7ce 100644
--- a/sys/net/if_clone.c
+++ b/sys/net/if_clone.c
@@ -1,4 +1,5 @@
/*-
+ * Copyright (c) 2012 Gleb Smirnoff <glebius@FreeBSD.org>
* Copyright (c) 1980, 1986, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -42,19 +43,65 @@
#include <net/if.h>
#include <net/if_clone.h>
-#if 0
-#include <net/if_dl.h>
-#endif
-#include <net/if_types.h>
#include <net/if_var.h>
#include <net/radix.h>
#include <net/route.h>
#include <net/vnet.h>
+/* Current IF_MAXUNIT expands maximum to 5 characters. */
+#define IFCLOSIZ (IFNAMSIZ - 5)
+
+/*
+ * Structure describing a `cloning' interface.
+ *
+ * List of locks
+ * (c) const until freeing
+ * (d) driver specific data, may need external protection.
+ * (e) locked by if_cloners_mtx
+ * (i) locked by ifc_mtx mtx
+ */
+struct if_clone {
+ char ifc_name[IFCLOSIZ]; /* (c) Name of device, e.g. `gif' */
+ struct unrhdr *ifc_unrhdr; /* (c) alloc_unr(9) header */
+ int ifc_maxunit; /* (c) maximum unit number */
+ long ifc_refcnt; /* (i) Reference count. */
+ LIST_HEAD(, ifnet) ifc_iflist; /* (i) List of cloned interfaces */
+ struct mtx ifc_mtx; /* Mutex to protect members. */
+
+ enum { SIMPLE, ADVANCED } ifc_type; /* (c) */
+
+ /* (c) Driver specific cloning functions. Called with no locks held. */
+ union {
+ struct { /* advanced cloner */
+ ifc_match_t *_ifc_match;
+ ifc_create_t *_ifc_create;
+ ifc_destroy_t *_ifc_destroy;
+ } A;
+ struct { /* simple cloner */
+ ifcs_create_t *_ifcs_create;
+ ifcs_destroy_t *_ifcs_destroy;
+ int _ifcs_minifs; /* minimum ifs */
+
+ } S;
+ } U;
+#define ifc_match U.A._ifc_match
+#define ifc_create U.A._ifc_create
+#define ifc_destroy U.A._ifc_destroy
+#define ifcs_create U.S._ifcs_create
+#define ifcs_destroy U.S._ifcs_destroy
+#define ifcs_minifs U.S._ifcs_minifs
+
+ LIST_ENTRY(if_clone) ifc_list; /* (e) On list of cloners */
+};
+
static void if_clone_free(struct if_clone *ifc);
static int if_clone_createif(struct if_clone *ifc, char *name, size_t len,
caddr_t params);
+static int ifc_simple_match(struct if_clone *, const char *);
+static int ifc_simple_create(struct if_clone *, char *, size_t, caddr_t);
+static int ifc_simple_destroy(struct if_clone *, struct ifnet *);
+
static struct mtx if_cloners_mtx;
static VNET_DEFINE(int, if_cloners_count);
VNET_DEFINE(LIST_HEAD(, if_clone), if_cloners);
@@ -138,18 +185,25 @@ if_clone_create(char *name, size_t len, caddr_t params)
/* Try to find an applicable cloner for this request */
IF_CLONERS_LOCK();
- LIST_FOREACH(ifc, &V_if_cloners, ifc_list) {
- if (ifc->ifc_match(ifc, name)) {
- break;
+ LIST_FOREACH(ifc, &V_if_cloners, ifc_list)
+ if (ifc->ifc_type == SIMPLE) {
+ if (ifc_simple_match(ifc, name))
+ break;
+ } else {
+ if (ifc->ifc_match(ifc, name))
+ break;
}
- }
#ifdef VIMAGE
if (ifc == NULL && !IS_DEFAULT_VNET(curvnet)) {
CURVNET_SET_QUIET(vnet0);
- LIST_FOREACH(ifc, &V_if_cloners, ifc_list) {
- if (ifc->ifc_match(ifc, name))
- break;
- }
+ LIST_FOREACH(ifc, &V_if_cloners, ifc_list)
+ if (ifc->ifc_type == SIMPLE) {
+ if (ifc_simple_match(ifc, name))
+ break;
+ } else {
+ if (ifc->ifc_match(ifc, name))
+ break;
+ }
CURVNET_RESTORE();
}
#endif
@@ -173,7 +227,10 @@ if_clone_createif(struct if_clone *ifc, char *name, size_t len, caddr_t params)
if (ifunit(name) != NULL)
return (EEXIST);
- err = (*ifc->ifc_create)(ifc, name, len, params);
+ if (ifc->ifc_type == SIMPLE)
+ err = ifc_simple_create(ifc, name, len, params);
+ else
+ err = (*ifc->ifc_create)(ifc, name, len, params);
if (!err) {
ifp = ifunit(name);
@@ -214,10 +271,14 @@ if_clone_destroy(const char *name)
#ifdef VIMAGE
if (ifc == NULL && !IS_DEFAULT_VNET(curvnet)) {
CURVNET_SET_QUIET(vnet0);
- LIST_FOREACH(ifc, &V_if_cloners, ifc_list) {
- if (ifc->ifc_match(ifc, name))
- break;
- }
+ LIST_FOREACH(ifc, &V_if_cloners, ifc_list)
+ if (ifc->type == SIMPLE) {
+ if (ifc_simple_match(ifc, name))
+ break;
+ } else {
+ if (ifc->ifc_match(ifc, name))
+ break;
+ }
CURVNET_RESTORE();
}
#endif
@@ -241,7 +302,7 @@ if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp)
int err;
struct ifnet *ifcifp;
- if (ifc->ifc_destroy == NULL)
+ if (ifc->ifc_type == ADVANCED && ifc->ifc_destroy == NULL)
return(EOPNOTSUPP);
/*
@@ -266,7 +327,10 @@ if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp)
if_delgroup(ifp, ifc->ifc_name);
- err = (*ifc->ifc_destroy)(ifc, ifp);
+ if (ifc->ifc_type == SIMPLE)
+ err = ifc_simple_destroy(ifc, ifp);
+ else
+ err = (*ifc->ifc_destroy)(ifc, ifp);
if (err != 0) {
if_addgroup(ifp, ifc->ifc_name);
@@ -279,21 +343,29 @@ if_clone_destroyif(struct if_clone *ifc, struct ifnet *ifp)
return (err);
}
-/*
- * Register a network interface cloner.
- */
-int
-if_clone_attach(struct if_clone *ifc)
+static struct if_clone *
+if_clone_alloc(const char *name, int maxunit)
{
- struct if_clone *ifc1;
+ struct if_clone *ifc;
- KASSERT(ifc->ifc_name != NULL, ("%s: no name\n", __func__));
+ KASSERT(name != NULL, ("%s: no name\n", __func__));
+ ifc = malloc(sizeof(struct if_clone), M_CLONE, M_WAITOK | M_ZERO);
+ strncpy(ifc->ifc_name, name, IFCLOSIZ-1);
IF_CLONE_LOCK_INIT(ifc);
IF_CLONE_ADDREF(ifc);
+ ifc->ifc_maxunit = maxunit ? maxunit : IF_MAXUNIT;
ifc->ifc_unrhdr = new_unrhdr(0, ifc->ifc_maxunit, &ifc->ifc_mtx);
LIST_INIT(&ifc->ifc_iflist);
+ return (ifc);
+}
+
+static int
+if_clone_attach(struct if_clone *ifc)
+{
+ struct if_clone *ifc1;
+
IF_CLONERS_LOCK();
LIST_FOREACH(ifc1, &V_if_cloners, ifc_list)
if (strcmp(ifc->ifc_name, ifc1->ifc_name) == 0) {
@@ -305,11 +377,63 @@ if_clone_attach(struct if_clone *ifc)
V_if_cloners_count++;
IF_CLONERS_UNLOCK();
- if (ifc->ifc_attach != NULL)
- (*ifc->ifc_attach)(ifc);
+ return (0);
+}
+
+struct if_clone *
+if_clone_advanced(const char *name, u_int maxunit, ifc_match_t match,
+ ifc_create_t create, ifc_destroy_t destroy)
+{
+ struct if_clone *ifc;
+
+ ifc = if_clone_alloc(name, maxunit);
+ ifc->ifc_type = ADVANCED;
+ ifc->ifc_match = match;
+ ifc->ifc_create = create;
+ ifc->ifc_destroy = destroy;
+
+ if (if_clone_attach(ifc) != 0) {
+ if_clone_free(ifc);
+ return (NULL);
+ }
+
EVENTHANDLER_INVOKE(if_clone_event, ifc);
- return (0);
+ return (ifc);
+}
+
+struct if_clone *
+if_clone_simple(const char *name, ifcs_create_t create, ifcs_destroy_t destroy,
+ u_int minifs)
+{
+ struct if_clone *ifc;
+ u_int unit;
+
+ ifc = if_clone_alloc(name, 0);
+ ifc->ifc_type = SIMPLE;
+ ifc->ifcs_create = create;
+ ifc->ifcs_destroy = destroy;
+ ifc->ifcs_minifs = minifs;
+
+ if (if_clone_attach(ifc) != 0) {
+ if_clone_free(ifc);
+ return (NULL);
+ }
+
+ for (unit = 0; unit < minifs; unit++) {
+ char name[IFNAMSIZ];
+ int error;
+
+ snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit);
+ error = if_clone_createif(ifc, name, IFNAMSIZ, NULL);
+ KASSERT(error == 0,
+ ("%s: failed to create required interface %s",
+ __func__, name));
+ }
+
+ EVENTHANDLER_INVOKE(if_clone_event, ifc);
+
+ return (ifc);
}
/*
@@ -318,7 +442,6 @@ if_clone_attach(struct if_clone *ifc)
void
if_clone_detach(struct if_clone *ifc)
{
- struct ifc_simple_data *ifcs = ifc->ifc_data;
IF_CLONERS_LOCK();
LIST_REMOVE(ifc, ifc_list);
@@ -326,8 +449,8 @@ if_clone_detach(struct if_clone *ifc)
IF_CLONERS_UNLOCK();
/* Allow all simples to be destroyed */
- if (ifc->ifc_attach == ifc_simple_attach)
- ifcs->ifcs_minifs = 0;
+ if (ifc->ifc_type == SIMPLE)
+ ifc->ifcs_minifs = 0;
/* destroy all interfaces for this cloner */
while (!LIST_EMPTY(&ifc->ifc_iflist))
@@ -345,6 +468,7 @@ if_clone_free(struct if_clone *ifc)
IF_CLONE_LOCK_DESTROY(ifc);
delete_unrhdr(ifc->ifc_unrhdr);
+ free(ifc, M_CLONE);
}
/*
@@ -483,29 +607,7 @@ ifc_free_unit(struct if_clone *ifc, int unit)
IF_CLONE_REMREF(ifc);
}
-void
-ifc_simple_attach(struct if_clone *ifc)
-{
- int err;
- int unit;
- char name[IFNAMSIZ];
- struct ifc_simple_data *ifcs = ifc->ifc_data;
-
- KASSERT(ifcs->ifcs_minifs - 1 <= ifc->ifc_maxunit,
- ("%s: %s requested more units than allowed (%d > %d)",
- __func__, ifc->ifc_name, ifcs->ifcs_minifs,
- ifc->ifc_maxunit + 1));
-
- for (unit = 0; unit < ifcs->ifcs_minifs; unit++) {
- snprintf(name, IFNAMSIZ, "%s%d", ifc->ifc_name, unit);
- err = if_clone_createif(ifc, name, IFNAMSIZ, NULL);
- KASSERT(err == 0,
- ("%s: failed to create required interface %s",
- __func__, name));
- }
-}
-
-int
+static int
ifc_simple_match(struct if_clone *ifc, const char *name)
{
const char *cp;
@@ -526,14 +628,13 @@ ifc_simple_match(struct if_clone *ifc, const char *name)
return (1);
}
-int
+static int
ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
{
char *dp;
int wildcard;
int unit;
int err;
- struct ifc_simple_data *ifcs = ifc->ifc_data;
err = ifc_name2unit(name, &unit);
if (err != 0)
@@ -545,7 +646,7 @@ ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
if (err != 0)
return (err);
- err = ifcs->ifcs_create(ifc, unit, params);
+ err = ifc->ifcs_create(ifc, unit, params);
if (err != 0) {
ifc_free_unit(ifc, unit);
return (err);
@@ -569,18 +670,17 @@ ifc_simple_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
return (0);
}
-int
+static int
ifc_simple_destroy(struct if_clone *ifc, struct ifnet *ifp)
{
int unit;
- struct ifc_simple_data *ifcs = ifc->ifc_data;
unit = ifp->if_dunit;
- if (unit < ifcs->ifcs_minifs)
+ if (unit < ifc->ifcs_minifs)
return (EINVAL);
- ifcs->ifcs_destroy(ifp);
+ ifc->ifcs_destroy(ifp);
ifc_free_unit(ifc, unit);