aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander V. Chernikov <melifaro@FreeBSD.org>2021-01-26 07:22:23 +0000
committerAlexander V. Chernikov <melifaro@FreeBSD.org>2021-02-04 22:21:00 +0000
commit8efe1ef1c7415c17899e6d1b5e1984bb3a95c55b (patch)
treec74ee553b43415d106c82c8e46e3510d97b7b445
parent87cefd5c3dc6e52609be1b01087b33511f1d16a8 (diff)
downloadsrc-8efe1ef1c7415c17899e6d1b5e1984bb3a95c55b.tar.gz
src-8efe1ef1c7415c17899e6d1b5e1984bb3a95c55b.zip
MFC 53729367d388: Fix subinterface vlan creation.
D26436 introduced support for stacked vlans that changed the way vlans are configured. In particular, this change broke setups that have same-number vlans as subinterfaces. Vlan support was initially created assuming "vlanX" semantics. In this paradigm, automatic number assignment supported by cloning (ifconfig vlan create) was a natural fit. When "ifaceX.Y" support was added, allowing to have the same vlan number on multiple devices, cloning code became more complex, as the is no unified "vlan" namespace anymore. Such interfaces got the first spare index from "vlan" cloner. This, in turn, led to the following problem: ifconfig ix0.333 create -> index 1 ifconfig ix0.444 create -> index 2 ifconfig vlan2 create -> allocation failure This change fixes such allocations by using cloning indexes only for "vlanX" interfaces. Reviewed by: hselasky Differential Revision: https://reviews.freebsd.org/D27505
-rw-r--r--sys/net/if_clone.c7
-rw-r--r--sys/net/if_vlan.c75
2 files changed, 54 insertions, 28 deletions
diff --git a/sys/net/if_clone.c b/sys/net/if_clone.c
index a55ce9c3005d..a98e43328e0c 100644
--- a/sys/net/if_clone.c
+++ b/sys/net/if_clone.c
@@ -571,7 +571,7 @@ if_clone_addgroup(struct ifnet *ifp, struct if_clone *ifc)
/*
* A utility function to extract unit numbers from interface names of
- * the form name###[.###].
+ * the form name###.
*
* Returns 0 on success and an error on failure.
*/
@@ -582,9 +582,8 @@ ifc_name2unit(const char *name, int *unit)
int cutoff = INT_MAX / 10;
int cutlim = INT_MAX % 10;
- if ((cp = strrchr(name, '.')) == NULL)
- cp = name;
- for (; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++);
+ for (cp = name; *cp != '\0' && (*cp < '0' || *cp > '9'); cp++)
+ ;
if (*cp == '\0') {
*unit = -1;
} else if (cp[0] == '0' && cp[1] != '\0') {
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 9358724844cb..26fb48257c11 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -977,63 +977,86 @@ static int
vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
{
char *dp;
- int wildcard;
+ bool wildcard = false;
+ bool subinterface = false;
int unit;
int error;
- int vid;
- uint16_t proto;
+ int vid = 0;
+ uint16_t proto = ETHERTYPE_VLAN;
struct ifvlan *ifv;
struct ifnet *ifp;
- struct ifnet *p;
+ struct ifnet *p = NULL;
struct ifaddr *ifa;
struct sockaddr_dl *sdl;
struct vlanreq vlr;
static const u_char eaddr[ETHER_ADDR_LEN]; /* 00:00:00:00:00:00 */
- proto = ETHERTYPE_VLAN;
/*
- * There are two ways to specify the cloned device:
+ * There are three ways to specify the cloned device:
* o pass a parameter block with the clone request.
+ * o specify parameters in the text of the clone device name
* o specify no parameters and get an unattached device that
* must be configured separately.
- * The first technique is preferred; the latter is supported
+ * The first technique is preferred; the latter two are supported
* for backwards compatibility.
*
* XXXRW: Note historic use of the word "tag" here. New ioctls may be
* called for.
*/
+
if (params) {
error = copyin(params, &vlr, sizeof(vlr));
if (error)
return error;
+ vid = vlr.vlr_tag;
+ proto = vlr.vlr_proto;
+
p = ifunit_ref(vlr.vlr_parent);
if (p == NULL)
return (ENXIO);
- error = ifc_name2unit(name, &unit);
- if (error != 0) {
- if_rele(p);
- return (error);
- }
- vid = vlr.vlr_tag;
- proto = vlr.vlr_proto;
- wildcard = (unit < 0);
- } else {
- p = NULL;
- error = ifc_name2unit(name, &unit);
- if (error != 0)
- return (error);
+ }
+
+ if ((error = ifc_name2unit(name, &unit)) == 0) {
+ /*
+ * vlanX interface. Set wildcard to true if the unit number
+ * is not fixed (-1)
+ */
wildcard = (unit < 0);
+ } else {
+ struct ifnet *p_tmp = vlan_clone_match_ethervid(name, &vid);
+ if (p_tmp != NULL) {
+ error = 0;
+ subinterface = true;
+ unit = IF_DUNIT_NONE;
+ wildcard = false;
+ if (p != NULL) {
+ if_rele(p_tmp);
+ if (p != p_tmp)
+ error = EINVAL;
+ } else
+ p = p_tmp;
+ } else
+ error = ENXIO;
}
- error = ifc_alloc_unit(ifc, &unit);
if (error != 0) {
if (p != NULL)
if_rele(p);
return (error);
}
+ if (!subinterface) {
+ /* vlanX interface, mark X as busy or allocate new unit # */
+ error = ifc_alloc_unit(ifc, &unit);
+ if (error != 0) {
+ if (p != NULL)
+ if_rele(p);
+ return (error);
+ }
+ }
+
/* In the wildcard case, we need to update the name. */
if (wildcard) {
for (dp = name; *dp != '\0'; dp++);
@@ -1046,7 +1069,8 @@ vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO);
ifp = ifv->ifv_ifp = if_alloc(IFT_ETHER);
if (ifp == NULL) {
- ifc_free_unit(ifc, unit);
+ if (!subinterface)
+ ifc_free_unit(ifc, unit);
free(ifv, M_VLAN);
if (p != NULL)
if_rele(p);
@@ -1094,7 +1118,8 @@ vlan_clone_create(struct if_clone *ifc, char *name, size_t len, caddr_t params)
ether_ifdetach(ifp);
vlan_unconfig(ifp);
if_free(ifp);
- ifc_free_unit(ifc, unit);
+ if (!subinterface)
+ ifc_free_unit(ifc, unit);
free(ifv, M_VLAN);
return (error);
@@ -1108,6 +1133,7 @@ static int
vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
{
struct ifvlan *ifv = ifp->if_softc;
+ int unit = ifp->if_dunit;
if (ifp->if_vlantrunk)
return (EBUSY);
@@ -1123,7 +1149,8 @@ vlan_clone_destroy(struct if_clone *ifc, struct ifnet *ifp)
NET_EPOCH_WAIT();
if_free(ifp);
free(ifv, M_VLAN);
- ifc_free_unit(ifc, ifp->if_dunit);
+ if (unit != IF_DUNIT_NONE)
+ ifc_free_unit(ifc, unit);
return (0);
}