From owner-dev-commits-src-all@freebsd.org Fri Jan 29 21:43:38 2021 Return-Path: Delivered-To: dev-commits-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id D79CF4FA13B; Fri, 29 Jan 2021 21:43:38 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4DS9nk5nQmz4SnR; Fri, 29 Jan 2021 21:43:38 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id B947E1B5B; Fri, 29 Jan 2021 21:43:38 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 10TLhctH065462; Fri, 29 Jan 2021 21:43:38 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 10TLhchD065461; Fri, 29 Jan 2021 21:43:38 GMT (envelope-from git) Date: Fri, 29 Jan 2021 21:43:38 GMT Message-Id: <202101292143.10TLhchD065461@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: "Alexander V. Chernikov" Subject: git: 53729367d388 - main - Fix subinterface vlan creation. MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: melifaro X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 53729367d388e4a6d0ff9be9995bcd4957e9c114 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-all@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commit messages for all branches of the src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 29 Jan 2021 21:43:38 -0000 The branch main has been updated by melifaro: URL: https://cgit.FreeBSD.org/src/commit/?id=53729367d388e4a6d0ff9be9995bcd4957e9c114 commit 53729367d388e4a6d0ff9be9995bcd4957e9c114 Author: Alexander V. Chernikov AuthorDate: 2021-01-26 07:22:23 +0000 Commit: Alexander V. Chernikov CommitDate: 2021-01-29 21:43:20 +0000 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 MFC after: 3 days 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 e1c4160495bc..229cd331c7a1 100644 --- a/sys/net/if_vlan.c +++ b/sys/net/if_vlan.c @@ -980,63 +980,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++); @@ -1049,7 +1072,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); @@ -1099,7 +1123,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); @@ -1113,6 +1138,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); @@ -1128,7 +1154,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); }