From owner-dev-commits-src-branches@freebsd.org Thu Feb 25 08:15:12 2021 Return-Path: Delivered-To: dev-commits-src-branches@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 CD52055AD79; Thu, 25 Feb 2021 08:15:12 +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 4DmQZS5Rvgz3rRR; Thu, 25 Feb 2021 08:15:12 +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 ADD3B14432; Thu, 25 Feb 2021 08:15:12 +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 11P8FCeX074617; Thu, 25 Feb 2021 08:15:12 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 11P8FC2H074616; Thu, 25 Feb 2021 08:15:12 GMT (envelope-from git) Date: Thu, 25 Feb 2021 08:15:12 GMT Message-Id: <202102250815.11P8FC2H074616@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Lutz Donnerhacke Subject: git: 08f47db5d580 - stable/12 - netgraph/ng_bridge: Introduce "uplink" ports without MAC learning MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: donner X-Git-Repository: src X-Git-Refname: refs/heads/stable/12 X-Git-Reftype: branch X-Git-Commit: 08f47db5d580e6c7bf1ed91b7488e4d529502731 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-branches@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commits to the stable branches of the FreeBSD src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 25 Feb 2021 08:15:12 -0000 The branch stable/12 has been updated by donner: URL: https://cgit.FreeBSD.org/src/commit/?id=08f47db5d580e6c7bf1ed91b7488e4d529502731 commit 08f47db5d580e6c7bf1ed91b7488e4d529502731 Author: Lutz Donnerhacke AuthorDate: 2021-02-06 10:08:24 +0000 Commit: Lutz Donnerhacke CommitDate: 2021-02-25 08:10:30 +0000 netgraph/ng_bridge: Introduce "uplink" ports without MAC learning The ng_bridge(4) node is designed to work in moderately small environments. Connecting such a node to a larger network rapidly fills the MAC table for no reason. It even become complicated to obtain data from the gettable message, because the result is too large to transmit. This patch introduces, two new functionality bits on the hooks: - Allow or disallow MAC address learning for incoming patckets. - Allow or disallow sending unknown MACs through this hook. Uplinks are characterized by denied learning while sending out unknowns. Normal links are charaterized by allowed learning and sending out unknowns. Reviewed by: kp Differential Revision: https://reviews.freebsd.org/D23963 (cherry picked from commit f961caf2184c94d6f59c8d522207156b3533d977) --- share/man/man4/ng_bridge.4 | 30 +++++++++++++-- sys/netgraph/ng_bridge.c | 95 +++++++++++++++++++++++++++++----------------- sys/netgraph/ng_bridge.h | 2 + 3 files changed, 89 insertions(+), 38 deletions(-) diff --git a/share/man/man4/ng_bridge.4 b/share/man/man4/ng_bridge.4 index 85c2d8871c7c..b5937375e87a 100644 --- a/share/man/man4/ng_bridge.4 +++ b/share/man/man4/ng_bridge.4 @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd October 2, 2019 +.Dd February 6, 2021 .Dt NG_BRIDGE 4 .Os .Sh NAME @@ -92,6 +92,23 @@ To connect the host machine to a bridged network, simply connect the hook of an .Xr ng_ether 4 node to the bridge node. +.Pp +Instead of naming a hook +.Dv linkX +the hook might be also named +.Dv uplinkX . +The node does not learn MAC addresses on uplink hooks, which keeps +the internal address table small. +This way it is desirable to connect the +.Dv lower +hook of an +.Xr ng_ether 4 +node to an +.Dv uplink +hook of the bridge, and ignore the complexity of the outside world. +Frames with unknown MACs are always sent out to +.Dv uplink +hooks, so no functionality is lost. .Sh CONTROL MESSAGES This node type supports the generic control messages, plus the following: @@ -141,8 +158,9 @@ The node configuration is not changed. This command takes a four byte link number as an argument and returns a .Dv "struct ng_bridge_link_stats" -containing statistics for the corresponding link, which must be -currently connected: +containing statistics for the corresponding +.Dv link , +which must be currently connected: .Bd -literal -offset 0n /* Statistics structure (one for each link) */ struct ng_bridge_link_stats { @@ -162,6 +180,12 @@ struct ng_bridge_link_stats { uint64_t memoryFailures; /* times couldn't get mem or mbuf */ }; .Ed +.Pp +Negative numbers refer to the +.Dv uplink +hooks. +So querying for -7 will get the statistics for hook +.Dv uplink7 . .It Dv NGM_BRIDGE_CLR_STATS Pq Ic clrstats This command takes a four byte link number as an argument and clears the statistics for that link. diff --git a/sys/netgraph/ng_bridge.c b/sys/netgraph/ng_bridge.c index e2e533be2c1e..ac1a0f61a89f 100644 --- a/sys/netgraph/ng_bridge.c +++ b/sys/netgraph/ng_bridge.c @@ -91,6 +91,8 @@ static MALLOC_DEFINE(M_NETGRAPH_BRIDGE, "netgraph_bridge", struct ng_bridge_link { hook_p hook; /* netgraph hook */ u_int16_t loopCount; /* loop ignore timer */ + unsigned int learnMac : 1, /* autolearn macs */ + sendUnknown : 1;/* send unknown macs out */ struct ng_bridge_link_stats stats; /* link stats */ }; @@ -334,38 +336,49 @@ 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; /* Check for a link hook */ - if (strlen(name) > strlen(NG_BRIDGE_HOOK_LINK_PREFIX)) { - char linkName[NG_HOOKSIZ]; - u_int32_t linkNum; - link_p link; - - /* primitive parsing */ - linkNum = strtoul(name + strlen(NG_BRIDGE_HOOK_LINK_PREFIX), - NULL, 10); - /* validation by comparing against the reconstucted name */ - snprintf(linkName, sizeof(linkName), - "%s%u", NG_BRIDGE_HOOK_LINK_PREFIX, - linkNum); - if (strcmp(linkName, name) != 0) - return (EINVAL); - - if(NG_PEER_NODE(hook) == node) - return (ELOOP); - - link = malloc(sizeof(*link), M_NETGRAPH_BRIDGE, - M_WAITOK|M_ZERO); - if (link == NULL) - return (ENOMEM); - link->hook = hook; - NG_HOOK_SET_PRIVATE(hook, link); - priv->numLinks++; - return (0); + 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) + return (ELOOP); + + link = malloc(sizeof(*link), M_NETGRAPH_BRIDGE, M_ZERO); + if (link == NULL) + return (ENOMEM); + + link->hook = hook; + if (isUplink) { + link->learnMac = 0; + link->sendUnknown = 1; + } else { + link->learnMac = 1; + link->sendUnknown = 1; } - /* Unknown hook name */ - return (EINVAL); + NG_HOOK_SET_PRIVATE(hook, link); + priv->numLinks++; + return (0); } /* @@ -439,6 +452,11 @@ ng_bridge_rcvmsg(node_p node, item_p item, hook_p lasthook) i = 0; for (bucket = 0; bucket < priv->numBuckets; bucket++) { SLIST_FOREACH(hent, &priv->tab[bucket], next) { + const char *name = NG_HOOK_NAME(hent->host.link->hook); + const char *prefix = name[0] == 'u' ? + NG_BRIDGE_HOOK_UPLINK_PREFIX : + NG_BRIDGE_HOOK_LINK_PREFIX; + memcpy(ary->hosts[i].addr, hent->host.addr, sizeof(ary->hosts[i].addr)); @@ -446,9 +464,7 @@ ng_bridge_rcvmsg(node_p node, item_p item, hook_p lasthook) ary->hosts[i].staleness = hent->host.staleness; ary->hosts[i].linkNum = strtol( - NG_HOOK_NAME(hent->host.link->hook) + - strlen(NG_BRIDGE_HOOK_LINK_PREFIX), - NULL, 10); + name + strlen(prefix), NULL, 10); i++; } } @@ -507,15 +523,20 @@ ng_bridge_rcvmsg(node_p node, item_p item, hook_p lasthook) hook_p hook; link_p link; char linkName[NG_HOOKSIZ]; + int linkNum; /* Get link number */ if (msg->header.arglen != sizeof(u_int32_t)) { error = EINVAL; break; } - snprintf(linkName, sizeof(linkName), - "%s%u", NG_BRIDGE_HOOK_LINK_PREFIX, - *((u_int32_t *)msg->data)); + linkNum = *((int32_t *)msg->data); + if (linkNum < 0) + snprintf(linkName, sizeof(linkName), + "%s%u", NG_BRIDGE_HOOK_UPLINK_PREFIX, -linkNum); + else + snprintf(linkName, sizeof(linkName), + "%s%u", NG_BRIDGE_HOOK_LINK_PREFIX, linkNum); if ((hook = ng_findhook(node, linkName)) == NULL) { error = ENOTCONN; @@ -610,6 +631,10 @@ ng_bridge_send_ctx(hook_p dst, void *arg) return (1); } + /* Skip sending unknowns to undesired links */ + if (!ctx->manycast && !destLink->sendUnknown) + return (1); + if (ctx->foundFirst == NULL) { /* * This is the first usable link we have found. @@ -755,7 +780,7 @@ ng_bridge_rcvdata(hook_p hook, item_p item) host->link = ctx.incoming; host->age = 0; } - } else { + } else if (ctx.incoming->learnMac) { if (!ng_bridge_put(priv, eh->ether_shost, ctx.incoming)) { ctx.incoming->stats.memoryFailures++; NG_FREE_ITEM(item); diff --git a/sys/netgraph/ng_bridge.h b/sys/netgraph/ng_bridge.h index fa4736370e92..b34bc0f5f55e 100644 --- a/sys/netgraph/ng_bridge.h +++ b/sys/netgraph/ng_bridge.h @@ -64,6 +64,8 @@ /* Hook names */ #define NG_BRIDGE_HOOK_LINK_PREFIX "link" /* append decimal integer */ #define NG_BRIDGE_HOOK_LINK_FMT "link%d" /* for use with printf(3) */ +#define NG_BRIDGE_HOOK_UPLINK_PREFIX "uplink" /* append decimal integer */ +#define NG_BRIDGE_HOOK_UPLINK_FMT "uplink%d" /* for use with printf(3) */ /* Node configuration structure */ struct ng_bridge_config {