From nobody Mon Apr 08 17:48:45 2024 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4VCxR16WKfz5HRCq; Mon, 8 Apr 2024 17:48:45 +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 4VCxR160Rlz4XJ8; Mon, 8 Apr 2024 17:48:45 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1712598525; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=BqGXjy9MCkdrqHLKuNG3ET8cNW/cAsO9VEuLI4LvbSE=; b=tc0tg68mdA72TcePjtX8GZrRF05oiP8uF+2aDIlI677kPhJVbKrkOM2WpimP4jL7ly07bw taqma7cONUOdAA4yYgor03Eo862eS6ApU9a03Pg6j/nyT7mcSLd5Ra24CrE7doF8iwQsRH ThBd/Fb750Ar3zv7f7/HN+1gfd3d1iuPzMCpqYle6VItwjiCj1DnN8G53SvtQMA4C25ILE W0Mw8uxRMLRZsFPkOd/ydlXe8NdUriSl5sLfB7vI3smDpy2mfhIr9h/FFhBkZ9DYupCcUI 4f7tbWo6DOjIveim+GJoOBWndzobP7XXEcFh1CmgnuBR4N0wx4kPgNln6GxNSw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1712598525; a=rsa-sha256; cv=none; b=oMiYMdvKkIJUb84GWcnVZU94oRDFXoSU0ewEU4Npfd2g91Uym5tXJhqsKuI+aWwZ5naUln 22BEtpEgcSW3n6ZrFUvXsLv9cZCSDzjf3kqai5eCm4iW84frMJ7+ChtCAaQFfEKu9666zB 3BDoTvFX0PNr/44+s8W2fR/nBjHNZCkjQOIX3/ReCaqFz9APjC0mMaIjkfvD0G+ghah99d XUsiI56h41ygdsZCbRH9OBsUoZL0Q4lpjIZXLR2OVB9MXSh7ZJYVhnqc4M1D2NXedVA/t7 hZDw3E1IUuY8t2yBxOXMIWyEqZj1l5KN1Ygvl7c/zQPt/RwNzaKTFOcgU2ymNw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1712598525; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=BqGXjy9MCkdrqHLKuNG3ET8cNW/cAsO9VEuLI4LvbSE=; b=Jh8mZDztuu80pApknA0fk8Kp2Rpuzej99mJKtgyk+wf4U90wUvXjyXJXpgaTQYBEHDZv2E SN77DvDke9Hx5SMNJAlhx3+psdONUim71QlkD0lnDm3VBLNUSTyxC6fDot02JWftOcFOzx bGYH642y4C1CnipjEjnOc4hug89eJswZZJWIMLj6iNQhE75d6h0m+ToBVeBRO7mc4cCjXx F9SW6Wd4YhUVK7JSRsEnMOsZHJA2PEOjOWt9LLXlkrIefxcWhZr76UUtC5ksgKmAHD+6V0 EmiiVGMxB2ghD+rFgQdfOxPOMawNAhnYnM3d9hSlYFs25PzU7TkpJZDxoASVow== 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 4VCxR15SnqzKt6; Mon, 8 Apr 2024 17:48:45 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.17.1/8.17.1) with ESMTP id 438Hmjnc057586; Mon, 8 Apr 2024 17:48:45 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.17.1/8.17.1/Submit) id 438Hmjku057583; Mon, 8 Apr 2024 17:48:45 GMT (envelope-from git) Date: Mon, 8 Apr 2024 17:48:45 GMT Message-Id: <202404081748.438Hmjku057583@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Gleb Smirnoff Subject: git: 86a6393a7d67 - main - ng_bridge: allow to automatically assign numbers to new hooks List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-main@freebsd.org X-BeenThere: dev-commits-src-main@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: glebius X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 86a6393a7d6766875a9e03daa0273a2e55faacdd Auto-Submitted: auto-generated The branch main has been updated by glebius: URL: https://cgit.FreeBSD.org/src/commit/?id=86a6393a7d6766875a9e03daa0273a2e55faacdd commit 86a6393a7d6766875a9e03daa0273a2e55faacdd Author: David Marker AuthorDate: 2024-04-08 17:48:22 +0000 Commit: Gleb Smirnoff CommitDate: 2024-04-08 17:48:22 +0000 ng_bridge: allow to automatically assign numbers to new hooks This will allow a userland machinery that orchestrates a bridge (e.g. a jail or vm manager) to not double the number allocation logic. See bug 278130 for longer description and examples. Reviewed by: glebius, afedorov Differential Revision: https://reviews.freebsd.org/D44615 PR: 278130 --- share/man/man4/ng_bridge.4 | 13 +++++- sys/netgraph/ng_bridge.c | 104 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 93 insertions(+), 24 deletions(-) diff --git a/share/man/man4/ng_bridge.4 b/share/man/man4/ng_bridge.4 index 45bc6b3cb6a7..7e5b4e0bd0ca 100644 --- a/share/man/man4/ng_bridge.4 +++ b/share/man/man4/ng_bridge.4 @@ -32,7 +32,7 @@ .\" .\" Author: Archie Cobbs .\" -.Dd May 13, 2021 +.Dd April 8, 2024 .Dt NG_BRIDGE 4 .Os .Sh NAME @@ -108,6 +108,17 @@ Frames with unknown MACs are always sent out to .Ar uplink hooks, so no functionality is lost. .Pp +The +.Ar linkX +and +.Ar uplinkX +hook numbers can be autoassigned. +If a new hook name was specified as +.Ar link +or +.Ar uplink +the node will append lowest available valid number to the name of the new hook. +.Pp Frames with unknown destination MAC addresses are replicated to any available hook, unless the first connected hook is an .Ar uplink diff --git a/sys/netgraph/ng_bridge.c b/sys/netgraph/ng_bridge.c index ebe811acc5b5..70bc581f8570 100644 --- a/sys/netgraph/ng_bridge.c +++ b/sys/netgraph/ng_bridge.c @@ -124,6 +124,8 @@ struct ng_bridge_private { unsigned int persistent : 1, /* can exist w/o hooks */ sendUnknown : 1;/* links receive unknowns by default */ struct callout timer; /* one second periodic timer */ + struct unrhdr *linkUnit; /* link unit number allocator */ + struct unrhdr *uplinkUnit; /* uplink unit number allocator */ }; typedef struct ng_bridge_private *priv_p; typedef struct ng_bridge_private const *priv_cp; /* read only access */ @@ -140,6 +142,21 @@ struct ng_bridge_host { /* Hash table bucket declaration */ SLIST_HEAD(ng_bridge_bucket, ng_bridge_host); +/* [up]link prefix matching */ +struct ng_link_prefix { + const char * const prefix; + size_t len; +}; + +static const struct ng_link_prefix link_pfx = { + .prefix = NG_BRIDGE_HOOK_LINK_PREFIX, + .len = sizeof(NG_BRIDGE_HOOK_LINK_PREFIX) - 1, +}; +static const struct ng_link_prefix uplink_pfx = { + .prefix = NG_BRIDGE_HOOK_UPLINK_PREFIX, + .len = sizeof(NG_BRIDGE_HOOK_UPLINK_PREFIX) - 1, +}; + /* Netgraph node methods */ static ng_constructor_t ng_bridge_constructor; static ng_rcvmsg_t ng_bridge_rcvmsg; @@ -149,6 +166,7 @@ static ng_rcvdata_t ng_bridge_rcvdata; static ng_disconnect_t ng_bridge_disconnect; /* Other internal functions */ +static const struct ng_link_prefix *ng_get_link_prefix(const char *name); static void ng_bridge_free_link(link_p link); static struct ng_bridge_host *ng_bridge_get(priv_cp priv, const u_char *addr); static int ng_bridge_put(priv_p priv, const u_char *addr, link_p link); @@ -350,6 +368,10 @@ ng_bridge_constructor(node_p node) NG_NODE_SET_PRIVATE(node, priv); priv->node = node; + /* Allocators for links. Historically "uplink0" is not allowed. */ + priv->linkUnit = new_unrhdr(0, INT_MAX, NULL); + priv->uplinkUnit = new_unrhdr(1, INT_MAX, NULL); + /* Start timer; timer is always running while node is alive */ ng_callout(&priv->timer, node, NULL, hz, ng_bridge_timeout, NULL, 0); @@ -364,36 +386,50 @@ static int ng_bridge_newhook(node_p node, hook_p hook, const char *name) { const priv_p priv = NG_NODE_PRIVATE(node); - char linkName[NG_HOOKSIZ]; - u_int32_t linkNum; link_p link; - const char *prefix = NG_BRIDGE_HOOK_LINK_PREFIX; bool isUplink; + uint32_t linkNum; + struct unrhdr *unit; + + const struct ng_link_prefix *pfx = ng_get_link_prefix(name); + if (pfx == NULL) + return (EINVAL); /* not a valid prefix */ + + isUplink = (pfx == &uplink_pfx); + unit = isUplink ? priv->uplinkUnit : priv->linkUnit; + + if (strlen(name) > pfx->len) { /* given number */ + char linkName[NG_HOOKSIZ]; + int rvnum __diagused; + + linkNum = strtoul(name + pfx->len, NULL, 10); + /* Validate by comparing against the reconstucted name. */ + snprintf(linkName, sizeof(linkName), "%s%u", pfx->prefix, + linkNum); + if (strcmp(linkName, name) != 0) + return (EINVAL); + if (linkNum == 0 && isUplink) + return (EINVAL); + rvnum = alloc_unr_specific(unit, linkNum); + MPASS(rvnum == linkNum); + } else { + /* auto-assign and update hook name */ + linkNum = alloc_unr(unit); + MPASS(linkNum != -1); + snprintf(NG_HOOK_NAME(hook), NG_HOOKSIZ, "%s%u", pfx->prefix, + linkNum); + } - /* Check for a link hook */ - if (strlen(name) <= strlen(prefix)) - return (EINVAL); /* Unknown hook name */ - - isUplink = (name[0] == 'u'); - if (isUplink) - prefix = NG_BRIDGE_HOOK_UPLINK_PREFIX; - - /* primitive parsing */ - linkNum = strtoul(name + strlen(prefix), NULL, 10); - /* validation by comparing against the reconstucted name */ - snprintf(linkName, sizeof(linkName), "%s%u", prefix, linkNum); - if (strcmp(linkName, name) != 0) - return (EINVAL); - - if (linkNum == 0 && isUplink) - return (EINVAL); - - if(NG_PEER_NODE(hook) == node) + if (NG_PEER_NODE(hook) == node) { + free_unr(unit, linkNum); return (ELOOP); + } link = malloc(sizeof(*link), M_NETGRAPH_BRIDGE, M_NOWAIT | M_ZERO); - if (link == NULL) + if (link == NULL) { + free_unr(unit, linkNum); return (ENOMEM); + } #define NG_BRIDGE_COUNTER_ALLOC(f) do { \ link->stats.f = counter_u64_alloc(M_NOWAIT); \ @@ -431,6 +467,7 @@ ng_bridge_newhook(node_p node, hook_p hook, const char *name) return (0); nomem: + free_unr(unit, linkNum); ng_bridge_free_link(link); return (ENOMEM); } @@ -914,6 +951,8 @@ ng_bridge_shutdown(node_p node) ("%s: numLinks=%d numHosts=%d", __func__, priv->numLinks, priv->numHosts)); ng_uncallout(&priv->timer, node); + delete_unrhdr(priv->linkUnit); + delete_unrhdr(priv->uplinkUnit); NG_NODE_SET_PRIVATE(node, NULL); NG_NODE_UNREF(node); free(priv->tab, M_NETGRAPH_BRIDGE); @@ -927,8 +966,11 @@ ng_bridge_shutdown(node_p node) static int ng_bridge_disconnect(hook_p hook) { + char *name = NG_HOOK_NAME(hook); const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); link_p link = NG_HOOK_PRIVATE(hook); + const struct ng_link_prefix *pfx = ng_get_link_prefix(name); + uint32_t linkNum; /* Remove all hosts associated with this link */ ng_bridge_remove_hosts(priv, link); @@ -937,6 +979,9 @@ ng_bridge_disconnect(hook_p hook) ng_bridge_free_link(link); priv->numLinks--; + linkNum = strtoul(name + pfx->len, NULL, 10); + free_unr(pfx == &link_pfx ? priv->linkUnit: priv->uplinkUnit, linkNum); + /* If no more hooks, go away */ if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) @@ -1095,6 +1140,19 @@ ng_bridge_rehash(priv_p priv) MISC FUNCTIONS ******************************************************************/ +static const struct ng_link_prefix * +ng_get_link_prefix(const char *name) +{ + static const struct ng_link_prefix *pfxs[] = + { &link_pfx, &uplink_pfx, }; + + for (u_int i = 0; i < nitems(pfxs); i++) + if (strncmp(pfxs[i]->prefix, name, pfxs[i]->len) == 0) + return (pfxs[i]); + + return (NULL); +} + /* * Remove all hosts associated with a specific link from the hashtable. * If linkNum == -1, then remove all hosts in the table.