aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorLutz Donnerhacke <donner@FreeBSD.org>2021-02-06 10:08:24 +0000
committerLutz Donnerhacke <donner@FreeBSD.org>2021-02-06 10:09:26 +0000
commitf961caf2184c94d6f59c8d522207156b3533d977 (patch)
tree3482f22256f85361f139150b662ca9118deb122c /sys
parent344f1083e128d8d41ca31853dac513ca3efd9d1f (diff)
downloadsrc-f961caf2184c94d6f59c8d522207156b3533d977.tar.gz
src-f961caf2184c94d6f59c8d522207156b3533d977.zip
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 learing while sending out unknowns. Normal links are charaterized by allowed learning and sending out unknowns. Reviewed by: kp Approved by: kp (mentor) MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D23963
Diffstat (limited to 'sys')
-rw-r--r--sys/netgraph/ng_bridge.c95
-rw-r--r--sys/netgraph/ng_bridge.h2
2 files changed, 62 insertions, 35 deletions
diff --git a/sys/netgraph/ng_bridge.c b/sys/netgraph/ng_bridge.c
index 1521b1cee901..a21da545e210 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);
}
/*
@@ -438,6 +451,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));
@@ -445,9 +463,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++;
}
}
@@ -506,15 +522,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;
@@ -609,6 +630,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.
@@ -750,7 +775,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 e4b74efbfc5e..2aecf7f9f9cb 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 {