The branch main has been updated by glebius:

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

commit 86a6393a7d6766875a9e03daa0273a2e55faacdd
Author:     David Marker <d...@freedave.net>
AuthorDate: 2024-04-08 17:48:22 +0000
Commit:     Gleb Smirnoff <gleb...@freebsd.org>
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 <arc...@freebsd.org>
 .\"
-.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.

Reply via email to