aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLutz Donnerhacke <donner@FreeBSD.org>2021-05-04 20:14:59 +0000
committerLutz Donnerhacke <donner@FreeBSD.org>2021-05-04 20:14:59 +0000
commitb1bd44732d8332930dc6a17092f47a201caff1ef (patch)
treeb6b1426216d9e40ba12a1cc8b004529c93d6eb2c
parent36be84b96699310e0020e194f81fe8e4a6c3f787 (diff)
downloadsrc-b1bd44732d8332930dc6a17092f47a201caff1ef.tar.gz
src-b1bd44732d8332930dc6a17092f47a201caff1ef.zip
netgraph/ng_bridge: learn MACs via control message
Add a new control message to move ethernet addresses to a given link in ng_bridge(4). Send this message instead of doing the work directly. This decouples the read-only activity from the modification under a more strict writer lock. Decoupling the work is a prerequisite for multithreaded operation. Approved by: manpages (bcr), kp (earlier version) MFC: 3 weeks Differential Revision: https://reviews.freebsd.org/D28516
-rw-r--r--share/man/man4/ng_bridge.421
-rw-r--r--sys/netgraph/ng_bridge.c69
-rw-r--r--sys/netgraph/ng_bridge.h11
3 files changed, 91 insertions, 10 deletions
diff --git a/share/man/man4/ng_bridge.4 b/share/man/man4/ng_bridge.4
index be128d62c938..216dea3c392a 100644
--- a/share/man/man4/ng_bridge.4
+++ b/share/man/man4/ng_bridge.4
@@ -34,7 +34,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 6, 2021
+.Dd February 17, 2021
.Dt NG_BRIDGE 4
.Os
.Sh NAME
@@ -214,6 +214,25 @@ Returns the current host mapping table used to direct packets, in a
.Vt "struct ng_bridge_host_ary" .
.It Dv NGM_BRIDGE_SET_PERSISTENT Pq Ar setpersistent
This command sets the persistent flag on the node, and takes no arguments.
+.It Dv NGM_BRIDGE_MOVE_HOST Pq Ar movehost
+This command takes a
+.Vt "struct ng_bridge_move_host"
+as an argument.
+It assigns the MAC
+.Va addr
+to the
+.Va hook ,
+which must not be assigned yet.
+If the
+.Va hook
+is the empty string, the incoming hook of the control message is
+used as fallback.
+.Bd -literal -offset 0n
+struct ng_bridge_move_host {
+ u_char addr[ETHER_ADDR_LEN]; /* ethernet address */
+ char hook[NG_HOOKSIZ]; /* link where addr can be found */
+};
+.Ed
.El
.Sh SHUTDOWN
This node shuts down upon receipt of a
diff --git a/sys/netgraph/ng_bridge.c b/sys/netgraph/ng_bridge.c
index 7b03b1a2599b..915a18550cba 100644
--- a/sys/netgraph/ng_bridge.c
+++ b/sys/netgraph/ng_bridge.c
@@ -234,6 +234,13 @@ static const struct ng_parse_type ng_bridge_stats_type = {
&ng_parse_struct_type,
&ng_bridge_stats_type_fields
};
+/* Parse type for struct ng_bridge_move_host */
+static const struct ng_parse_struct_field ng_bridge_move_host_type_fields[]
+ = NG_BRIDGE_MOVE_HOST_TYPE_INFO(&ng_parse_enaddr_type);
+static const struct ng_parse_type ng_bridge_move_host_type = {
+ &ng_parse_struct_type,
+ &ng_bridge_move_host_type_fields
+};
/* List of commands and how to convert arguments to/from ASCII */
static const struct ng_cmdlist ng_bridge_cmdlist[] = {
@@ -293,6 +300,13 @@ static const struct ng_cmdlist ng_bridge_cmdlist[] = {
NULL,
NULL
},
+ {
+ NGM_BRIDGE_COOKIE,
+ NGM_BRIDGE_MOVE_HOST,
+ "movehost",
+ &ng_bridge_move_host_type,
+ NULL
+ },
{ 0 }
};
@@ -601,6 +615,32 @@ ng_bridge_rcvmsg(node_p node, item_p item, hook_p lasthook)
priv->persistent = 1;
break;
}
+ case NGM_BRIDGE_MOVE_HOST:
+ {
+ struct ng_bridge_move_host *mh;
+ hook_p hook;
+ struct ng_bridge_host *host;
+
+ if (msg->header.arglen < sizeof(*mh)) {
+ error = EINVAL;
+ break;
+ }
+ mh = (struct ng_bridge_move_host *)msg->data;
+ hook = (mh->hook[0] == 0)
+ ? lasthook
+ : ng_findhook(node, mh->hook);
+ if (hook == NULL) {
+ error = ENOENT;
+ break;
+ }
+ host = ng_bridge_get(priv, mh->addr);
+ if (host != NULL) {
+ error = EADDRINUSE;
+ break;
+ }
+ error = ng_bridge_put(priv, mh->addr, NG_HOOK_PRIVATE(hook));
+ break;
+ }
default:
error = EINVAL;
break;
@@ -809,12 +849,26 @@ ng_bridge_rcvdata(hook_p hook, item_p item)
host->age = 0;
}
} else if (ctx.incoming->learnMac) {
- if (!ng_bridge_put(priv, eh->ether_shost, ctx.incoming)) {
+ struct ng_mesg *msg;
+ struct ng_bridge_move_host *mh;
+ int error = 0;
+
+ NG_MKMESSAGE(msg, NGM_BRIDGE_COOKIE, NGM_BRIDGE_MOVE_HOST,
+ sizeof(*mh), M_NOWAIT);
+ if (msg == NULL) {
counter_u64_add(ctx.incoming->stats.memoryFailures, 1);
NG_FREE_ITEM(item);
NG_FREE_M(ctx.m);
return (ENOMEM);
}
+ mh = (struct ng_bridge_move_host *)msg->data;
+ strncpy(mh->hook, NG_HOOK_NAME(ctx.incoming->hook),
+ sizeof(mh->hook));
+ memcpy(mh->addr, eh->ether_shost, sizeof(mh->addr));
+ NG_SEND_MSG_ID(error, node, msg, NG_NODE_ID(node),
+ NG_NODE_ID(node));
+ if (error)
+ counter_u64_add(ctx.incoming->stats.memoryFailures, 1);
}
/* Run packet through ipfw processing, if enabled */
@@ -959,8 +1013,7 @@ ng_bridge_get(priv_cp priv, const u_char *addr)
/*
* Add a new host entry to the table. This assumes the host doesn't
- * already exist in the table. Returns 1 on success, 0 if there
- * was a memory allocation failure.
+ * already exist in the table. Returns 0 on success.
*/
static int
ng_bridge_put(priv_p priv, const u_char *addr, link_p link)
@@ -970,16 +1023,14 @@ ng_bridge_put(priv_p priv, const u_char *addr, link_p link)
#ifdef INVARIANTS
/* Assert that entry does not already exist in hashtable */
- SLIST_FOREACH(host, &priv->tab[bucket], next) {
- KASSERT(!ETHER_EQUAL(host->addr, addr),
- ("%s: entry %6D exists in table", __func__, addr, ":"));
- }
+ KASSERT(ng_bridge_get(priv, addr) == NULL,
+ ("%s: entry %6D exists in table", __func__, addr, ":"));
#endif
/* Allocate and initialize new hashtable entry */
host = malloc(sizeof(*host), M_NETGRAPH_BRIDGE, M_NOWAIT);
if (host == NULL)
- return (0);
+ return (ENOMEM);
bcopy(addr, host->addr, ETHER_ADDR_LEN);
host->link = link;
host->staleness = 0;
@@ -991,7 +1042,7 @@ ng_bridge_put(priv_p priv, const u_char *addr, link_p link)
/* Resize table if necessary */
ng_bridge_rehash(priv);
- return (1);
+ return (0);
}
/*
diff --git a/sys/netgraph/ng_bridge.h b/sys/netgraph/ng_bridge.h
index 03541deceacd..12717d16ac7a 100644
--- a/sys/netgraph/ng_bridge.h
+++ b/sys/netgraph/ng_bridge.h
@@ -140,6 +140,16 @@ struct ng_bridge_host_ary {
{ NULL } \
}
+struct ng_bridge_move_host {
+ u_char addr[ETHER_ADDR_LEN]; /* ethernet address */
+ char hook[NG_HOOKSIZ]; /* link where addr can be found */
+};
+/* Keep this in sync with the above structure definition */
+#define NG_BRIDGE_MOVE_HOST_TYPE_INFO(entype) { \
+ { "addr", (entype) }, \
+ { "hook", &ng_parse_hookbuf_type }, \
+}
+
/* Netgraph control messages */
enum {
NGM_BRIDGE_SET_CONFIG = 1, /* set node configuration */
@@ -150,6 +160,7 @@ enum {
NGM_BRIDGE_GETCLR_STATS, /* atomically get & clear link stats */
NGM_BRIDGE_GET_TABLE, /* get link table */
NGM_BRIDGE_SET_PERSISTENT, /* set persistent mode */
+ NGM_BRIDGE_MOVE_HOST, /* move a host to a link */
};
#endif /* _NETGRAPH_NG_BRIDGE_H_ */