summaryrefslogtreecommitdiffstats
path: root/sys/net/if_vlan.c
diff options
context:
space:
mode:
authorbrooks <brooks@FreeBSD.org>2004-06-22 20:13:25 +0000
committerbrooks <brooks@FreeBSD.org>2004-06-22 20:13:25 +0000
commite1dd867b5532da103ae1459a89ca3df2b8b6f0f6 (patch)
treebebe9375487f298832806df2423be9c48dba04e6 /sys/net/if_vlan.c
parentdd32b92c2514b98b8c9d9af7ac82532d833c6db2 (diff)
downloadFreeBSD-src-e1dd867b5532da103ae1459a89ca3df2b8b6f0f6.zip
FreeBSD-src-e1dd867b5532da103ae1459a89ca3df2b8b6f0f6.tar.gz
Major overhaul of pseudo-interface cloning. Highlights include:
- Split the code out into if_clone.[ch]. - Locked struct if_clone. [1] - Add a per-cloner match function rather then simply matching names of the form <name><unit> and <name>. - Use the match function to allow creation of <interface>.<tag> vlan interfaces. The old way is preserved unchanged! - Also the match function to allow creation of stf(4) interfaces named stf0, stf, or 6to4. This is the only major user visible change in that "ifconfig stf" creates the interface stf rather then stf0 and does not print "stf0" to stdout. - Allow destroy functions to fail so they can refuse to delete interfaces. Currently, we forbid the deletion of interfaces which were created in the init function, particularly lo0, pflog0, and pfsync0. In the case of lo0 this was a panic implementation so it does not count as a user visiable change. :-) - Since most interfaces do not need the new functionality, an family of wrapper functions, ifc_simple_*(), were created to wrap old style cloner functions. - The IF_CLONE_INITIALIZER macro is replaced with a new incompatible IFC_CLONE_INITIALIZER and ifc_simple consumers use IFC_SIMPLE_DECLARE instead. Submitted by: Maurycy Pawlowski-Wieronski <maurycy at fouk.org> [1] Reviewed by: andre, mlaier Discussed on: net
Diffstat (limited to 'sys/net/if_vlan.c')
-rw-r--r--sys/net/if_vlan.c151
1 files changed, 142 insertions, 9 deletions
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index f9c22d2..9449dec 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -57,6 +57,7 @@
#include <net/bpf.h>
#include <net/ethernet.h>
#include <net/if.h>
+#include <net/if_clone.h>
#include <net/if_arp.h>
#include <net/if_dl.h>
#include <net/if_types.h>
@@ -117,8 +118,6 @@ static struct mtx ifv_mtx;
#define VLAN_LOCK() mtx_lock(&ifv_mtx)
#define VLAN_UNLOCK() mtx_unlock(&ifv_mtx)
-static int vlan_clone_create(struct if_clone *, int);
-static void vlan_clone_destroy(struct ifnet *);
static void vlan_start(struct ifnet *ifp);
static void vlan_ifinit(void *foo);
static void vlan_input(struct ifnet *ifp, struct mbuf *m);
@@ -127,9 +126,16 @@ static int vlan_setmulti(struct ifnet *ifp);
static int vlan_unconfig(struct ifnet *ifp);
static int vlan_config(struct ifvlan *ifv, struct ifnet *p);
static void vlan_link_state(struct ifnet *ifp, int link);
+static int vlan_set_promisc(struct ifnet *ifp);
-struct if_clone vlan_cloner = IF_CLONE_INITIALIZER(VLANNAME,
- vlan_clone_create, vlan_clone_destroy, 0, IF_MAXUNIT);
+static struct ifnet *vlan_clone_match_ethertag(struct if_clone *,
+ const char *, int *);
+static int vlan_clone_match(struct if_clone *, const char *);
+static int vlan_clone_create(struct if_clone *, char *, size_t);
+static int vlan_clone_destroy(struct if_clone *, struct ifnet *);
+
+struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL, IF_MAXUNIT,
+ NULL, vlan_clone_match, vlan_clone_create, vlan_clone_destroy);
/*
* Program our multicast filter. What we're actually doing is
@@ -231,7 +237,8 @@ vlan_modevent(module_t mod, int type, void *data)
vlan_input_p = NULL;
vlan_link_state_p = NULL;
while (!LIST_EMPTY(&ifv_list))
- vlan_clone_destroy(&LIST_FIRST(&ifv_list)->ifv_if);
+ vlan_clone_destroy(&vlan_cloner,
+ &LIST_FIRST(&ifv_list)->ifv_if);
VLAN_LOCK_DESTROY();
break;
}
@@ -247,18 +254,117 @@ static moduledata_t vlan_mod = {
DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
MODULE_DEPEND(if_vlan, miibus, 1, 1, 1);
+static struct ifnet *
+vlan_clone_match_ethertag(struct if_clone *ifc, const char *name, int *tag)
+{
+ int t;
+ const char *cp;
+ struct ifnet *ifp;
+
+ t = 0;
+
+ /* Check for <etherif>.<vlan> style interface names. */
+ IFNET_RLOCK();
+ TAILQ_FOREACH(ifp, &ifnet, if_link) {
+ if (ifp->if_type != IFT_ETHER)
+ continue;
+ if (strncmp(ifp->if_xname, name, strlen(ifp->if_xname)) != 0)
+ continue;
+ cp = name + strlen(ifp->if_xname);
+ if (*cp != '.')
+ continue;
+ for(; *cp != '\0'; cp++) {
+ if (*cp < '0' || *cp > '9')
+ continue;
+ t = (t * 10) + (*cp - '0');
+ }
+ if (tag != NULL)
+ *tag = t;
+ break;
+ }
+ IFNET_RUNLOCK();
+
+ return ifp;
+}
+
+static int
+vlan_clone_match(struct if_clone *ifc, const char *name)
+{
+ const char *cp;
+
+ if (vlan_clone_match_ethertag(ifc, name, NULL) != NULL)
+ return (1);
+
+ if (strncmp(VLANNAME, name, strlen(VLANNAME)) != 0)
+ return (0);
+ for (cp = name + 4; *cp != '\0'; cp++) {
+ if (*cp < '0' || *cp > '9')
+ return (0);
+ }
+
+ return (1);
+}
+
static int
-vlan_clone_create(struct if_clone *ifc, int unit)
+vlan_clone_create(struct if_clone *ifc, char *name, size_t len)
{
+ char *dp;
+ int wildcard;
+ int unit;
+ int error;
+ int tag;
+ int ethertag;
struct ifvlan *ifv;
struct ifnet *ifp;
+ struct ifnet *p;
+
+ if ((p = vlan_clone_match_ethertag(ifc, name, &tag)) != NULL) {
+ ethertag = 1;
+ unit = -1;
+ wildcard = 0;
+
+ /*
+ * Don't let the caller set up a VLAN tag with
+ * anything except VLID bits.
+ */
+ if (tag & ~EVL_VLID_MASK) {
+ return (EINVAL);
+ }
+ } else {
+ ethertag = 0;
+
+ error = ifc_name2unit(name, &unit);
+ if (error != 0)
+ return (error);
+
+ wildcard = (unit < 0);
+ }
+
+ error = ifc_alloc_unit(ifc, &unit);
+ if (error != 0)
+ return (error);
+
+ /* 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) {
+ panic("%s: interface name too long", __func__);
+ }
+ }
ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO);
ifp = &ifv->ifv_if;
SLIST_INIT(&ifv->vlan_mc_listhead);
ifp->if_softc = ifv;
- if_initname(ifp, ifc->ifc_name, unit);
+ /*
+ * Set the name manually rather then using if_initname because
+ * we don't conform to the default naming convention for interfaces.
+ */
+ strlcpy(ifp->if_xname, name, IFNAMSIZ);
+ ifp->if_dname = ifc->ifc_name;
+ ifp->if_dunit = unit;
/* NB: flags are not set here */
ifp->if_linkmib = &ifv->ifv_mib;
ifp->if_linkmiblen = sizeof ifv->ifv_mib;
@@ -278,11 +384,36 @@ vlan_clone_create(struct if_clone *ifc, int unit)
LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
VLAN_UNLOCK();
+ if (ethertag) {
+ VLAN_LOCK();
+ error = vlan_config(ifv, p);
+ if (error != 0) {
+ /*
+ * Since we've partialy failed, we need to back
+ * out all the way, otherwise userland could get
+ * confused. Thus, we destroy the interface.
+ */
+ LIST_REMOVE(ifv, ifv_list);
+ vlan_unconfig(ifp);
+ VLAN_UNLOCK();
+ ether_ifdetach(ifp);
+ free(ifv, M_VLAN);
+
+ return (error);
+ }
+ ifv->ifv_tag = tag;
+ ifp->if_flags |= IFF_RUNNING;
+ VLAN_UNLOCK();
+
+ /* Update promiscuous mode, if necessary. */
+ vlan_set_promisc(ifp);
+ }
+
return (0);
}
-static void
-vlan_clone_destroy(struct ifnet *ifp)
+static int
+vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
{
struct ifvlan *ifv = ifp->if_softc;
@@ -294,6 +425,8 @@ vlan_clone_destroy(struct ifnet *ifp)
ether_ifdetach(ifp);
free(ifv, M_VLAN);
+
+ return (0);
}
static void
OpenPOWER on IntegriCloud