Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 27 May 2021 11:07:46 GMT
From:      Lutz Donnerhacke <donner@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: d9a06ae65043 - stable/12 - netgraph/ng_bridge: learn MACs via control message
Message-ID:  <202105271107.14RB7k0K013953@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/12 has been updated by donner:

URL: https://cgit.FreeBSD.org/src/commit/?id=d9a06ae65043b6a21cb816ed10d26cb947876d67

commit d9a06ae65043b6a21cb816ed10d26cb947876d67
Author:     Lutz Donnerhacke <donner@FreeBSD.org>
AuthorDate: 2021-05-04 20:14:59 +0000
Commit:     Lutz Donnerhacke <donner@FreeBSD.org>
CommitDate: 2021-05-27 11:00:17 +0000

    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)
    Differential Revision:  https://reviews.freebsd.org/D28516
    
    (cherry picked from commit b1bd44732d8332930dc6a17092f47a201caff1ef)
---
 share/man/man4/ng_bridge.4 | 21 +++++++++++++-
 sys/netgraph/ng_bridge.c   | 69 ++++++++++++++++++++++++++++++++++++++++------
 sys/netgraph/ng_bridge.h   | 11 ++++++++
 3 files changed, 91 insertions(+), 10 deletions(-)

diff --git a/share/man/man4/ng_bridge.4 b/share/man/man4/ng_bridge.4
index 1451773711e9..e3f406c3f437 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
 .Dv "struct ng_bridge_host_ary" .
 .It Dv NGM_BRIDGE_SET_PERSISTENT Pq Ic 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 3243319c99e8..0d5e2ffb196d 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 }
 };
 
@@ -669,6 +683,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;
@@ -885,12 +925,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 */
@@ -1035,8 +1089,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)
@@ -1046,16 +1099,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;
@@ -1067,7 +1118,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 790e9c5da11e..7d9c1a22bb6e 100644
--- a/sys/netgraph/ng_bridge.h
+++ b/sys/netgraph/ng_bridge.h
@@ -183,6 +183,16 @@ struct ng_bridge_host_tbl_ary {
 };
 #endif /* NGM_BRIDGE_TABLE_ABI */
 
+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 */
@@ -193,6 +203,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_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202105271107.14RB7k0K013953>