Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 4 Feb 2021 22:34:51 GMT
From:      "Alexander V. Chernikov" <melifaro@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 8efe1ef1c741 - stable/13 - MFC 53729367d388: Fix subinterface vlan creation.
Message-ID:  <202102042234.114MYpAI007479@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by melifaro:

URL: https://cgit.FreeBSD.org/src/commit/?id=8efe1ef1c7415c17899e6d1b5e1984bb3a95c55b

commit 8efe1ef1c7415c17899e6d1b5e1984bb3a95c55b
Author:     Alexander V. Chernikov <melifaro@FreeBSD.org>
AuthorDate: 2021-01-26 07:22:23 +0000
Commit:     Alexander V. Chernikov <melifaro@FreeBSD.org>
CommitDate: 2021-02-04 22:21:00 +0000

    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
---
 sys/net/if_clone.c |  7 +++--
 sys/net/if_vlan.c  | 75 +++++++++++++++++++++++++++++++++++++-----------------
 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);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202102042234.114MYpAI007479>