Author: glebius
Date: Thu Oct  3 02:32:55 2019
New Revision: 353026
URL: https://svnweb.freebsd.org/changeset/base/353026

Log:
  - Remove the compile time limit for number of links a ng_bridge node
    can handle.  Instead using an array on node private data, use per-hook
    private data.
  - Use NG_NODE_FOREACH_HOOK() to traverse through hooks instead of array.
  
  PR:           240787
  Submitted by: Lutz Donnerhacke <lutz donnerhacke.de>
  Differential Revision:          https://reviews.freebsd.org/D21803

Modified:
  head/share/man/man4/ng_bridge.4
  head/sys/netgraph/ng_bridge.c
  head/sys/netgraph/ng_bridge.h

Modified: head/share/man/man4/ng_bridge.4
==============================================================================
--- head/share/man/man4/ng_bridge.4     Wed Oct  2 23:19:34 2019        
(r353025)
+++ head/share/man/man4/ng_bridge.4     Thu Oct  3 02:32:55 2019        
(r353026)
@@ -34,7 +34,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd May 5, 2010
+.Dd October 2, 2019
 .Dt NG_BRIDGE 4
 .Os
 .Sh NAME
@@ -76,9 +76,7 @@ Processing of IP packets via the
 .Xr ipfirewall 4
 mechanism on a per-link basis is not yet implemented.
 .Sh HOOKS
-This node type supports up to
-.Dv NG_BRIDGE_MAX_LINKS
-hooks.
+This node type supports an unlimited number of hooks.
 Each connected hook represents a bridged link.
 The hooks are named
 .Dv link0 ,
@@ -106,7 +104,6 @@ as an argument:
 .Bd -literal -offset 0n
 /* Node configuration structure */
 struct ng_bridge_config {
-  u_char      ipfw[NG_BRIDGE_MAX_LINKS]; /* enable ipfw */
   u_char      debugLevel;           /* debug level */
   uint32_t    loopTimeout;          /* link loopback mute time */
   uint32_t    maxStaleness;         /* max host age before nuking */
@@ -114,11 +111,6 @@ struct ng_bridge_config {
 };
 .Ed
 .Pp
-The
-.Dv ipfw
-array enables
-.Xr ipfirewall 4
-processing of IP packets received on the corresponding links.
 The
 .Dv debugLevel
 field sets the debug level on the node.

Modified: head/sys/netgraph/ng_bridge.c
==============================================================================
--- head/sys/netgraph/ng_bridge.c       Wed Oct  2 23:19:34 2019        
(r353025)
+++ head/sys/netgraph/ng_bridge.c       Thu Oct  3 02:32:55 2019        
(r353026)
@@ -1,7 +1,3 @@
-/*
- * ng_bridge.c
- */
-
 /*-
  * Copyright (c) 2000 Whistle Communications, Inc.
  * All rights reserved.
@@ -101,7 +97,6 @@ struct ng_bridge_link {
 /* Per-node private data */
 struct ng_bridge_private {
        struct ng_bridge_bucket *tab;           /* hash table bucket array */
-       struct ng_bridge_link   *links[NG_BRIDGE_MAX_LINKS];
        struct ng_bridge_config conf;           /* node configuration */
        node_p                  node;           /* netgraph node */
        u_int                   numHosts;       /* num entries in table */
@@ -132,9 +127,9 @@ static ng_disconnect_t      ng_bridge_disconnect;
 
 /* Other internal functions */
 static struct  ng_bridge_host *ng_bridge_get(priv_p priv, const u_char *addr);
-static int     ng_bridge_put(priv_p priv, const u_char *addr, int linkNum);
+static int     ng_bridge_put(priv_p priv, const u_char *addr, link_p link);
 static void    ng_bridge_rehash(priv_p priv);
-static void    ng_bridge_remove_hosts(priv_p priv, int linkNum);
+static void    ng_bridge_remove_hosts(priv_p priv, link_p link);
 static void    ng_bridge_timeout(node_p node, hook_p hook, void *arg1, int 
arg2);
 static const   char *ng_bridge_nodename(node_p node);
 
@@ -142,9 +137,6 @@ static const        char *ng_bridge_nodename(node_p node);
 static const u_char ng_bridge_bcast_addr[ETHER_ADDR_LEN] =
     { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 
-/* Store each hook's link number in the private field */
-#define LINK_NUM(hook)         (*(u_int16_t *)(&(hook)->private))
-
 /* Compare Ethernet addresses using 32 and 16 bit words instead of bytewise */
 #define ETHER_EQUAL(a,b)       (((const u_int32_t *)(a))[0] \
                                        == ((const u_int32_t *)(b))[0] \
@@ -200,16 +192,8 @@ static const struct ng_parse_type ng_bridge_host_ary_t
 };
 
 /* Parse type for struct ng_bridge_config */
-static const struct ng_parse_fixedarray_info ng_bridge_ipfwary_type_info = {
-       &ng_parse_uint8_type,
-       NG_BRIDGE_MAX_LINKS
-};
-static const struct ng_parse_type ng_bridge_ipfwary_type = {
-       &ng_parse_fixedarray_type,
-       &ng_bridge_ipfwary_type_info
-};
 static const struct ng_parse_struct_field ng_bridge_config_type_fields[]
-       = NG_BRIDGE_CONFIG_TYPE_INFO(&ng_bridge_ipfwary_type);
+       = NG_BRIDGE_CONFIG_TYPE_INFO;
 static const struct ng_parse_type ng_bridge_config_type = {
        &ng_parse_struct_type,
        &ng_bridge_config_type_fields
@@ -352,26 +336,30 @@ ng_bridge_newhook(node_p node, hook_p hook, const char
        const priv_p priv = NG_NODE_PRIVATE(node);
 
        /* Check for a link hook */
-       if (strncmp(name, NG_BRIDGE_HOOK_LINK_PREFIX,
-           strlen(NG_BRIDGE_HOOK_LINK_PREFIX)) == 0) {
-               const char *cp;
-               char *eptr;
-               u_long linkNum;
+       if (strlen(name) > strlen(NG_BRIDGE_HOOK_LINK_PREFIX)) {
+               char linkName[NG_HOOKSIZ];
+               u_int32_t linkNum;
+               link_p link;
 
-               cp = name + strlen(NG_BRIDGE_HOOK_LINK_PREFIX);
-               if (!isdigit(*cp) || (cp[0] == '0' && cp[1] != '\0'))
+               /* 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);
-               linkNum = strtoul(cp, &eptr, 10);
-               if (*eptr != '\0' || linkNum >= NG_BRIDGE_MAX_LINKS)
-                       return (EINVAL);
-               if (priv->links[linkNum] != NULL)
-                       return (EISCONN);
-               priv->links[linkNum] = malloc(sizeof(*priv->links[linkNum]),
-                   M_NETGRAPH_BRIDGE, M_NOWAIT|M_ZERO);
-               if (priv->links[linkNum] == NULL)
+               
+               if(NG_PEER_NODE(hook) == node)
+                       return (ELOOP);
+
+               link = malloc(sizeof(*link), M_NETGRAPH_BRIDGE,
+                             M_WAITOK|M_ZERO);
+               if (link == NULL)
                        return (ENOMEM);
-               priv->links[linkNum]->hook = hook;
-               NG_HOOK_SET_PRIVATE(hook, (void *)linkNum);
+               link->hook = hook;
+               NG_HOOK_SET_PRIVATE(hook, link);
                priv->numLinks++;
                return (0);
        }
@@ -384,6 +372,17 @@ ng_bridge_newhook(node_p node, hook_p hook, const char
  * Receive a control message
  */
 static int
+ng_bridge_reset_link(hook_p hook, int ret)
+{
+       link_p priv = NG_HOOK_PRIVATE(hook);
+
+       priv->loopCount = 0;
+       bzero(&priv->stats, sizeof(priv->stats));
+       return (ret);
+}
+
+
+static int
 ng_bridge_rcvmsg(node_p node, item_p item, hook_p lasthook)
 {
        const priv_p priv = NG_NODE_PRIVATE(node);
@@ -412,7 +411,6 @@ ng_bridge_rcvmsg(node_p node, item_p item, hook_p last
                case NGM_BRIDGE_SET_CONFIG:
                    {
                        struct ng_bridge_config *conf;
-                       int i;
 
                        if (msg->header.arglen
                            != sizeof(struct ng_bridge_config)) {
@@ -421,48 +419,41 @@ ng_bridge_rcvmsg(node_p node, item_p item, hook_p last
                        }
                        conf = (struct ng_bridge_config *)msg->data;
                        priv->conf = *conf;
-                       for (i = 0; i < NG_BRIDGE_MAX_LINKS; i++)
-                               priv->conf.ipfw[i] = !!priv->conf.ipfw[i];
                        break;
                    }
                case NGM_BRIDGE_RESET:
                    {
-                       int i;
+                       hook_p rethook;
 
                        /* Flush all entries in the hash table */
-                       ng_bridge_remove_hosts(priv, -1);
+                       ng_bridge_remove_hosts(priv, NULL);
 
                        /* Reset all loop detection counters and stats */
-                       for (i = 0; i < NG_BRIDGE_MAX_LINKS; i++) {
-                               if (priv->links[i] == NULL)
-                                       continue;
-                               priv->links[i]->loopCount = 0;
-                               bzero(&priv->links[i]->stats,
-                                   sizeof(priv->links[i]->stats));
-                       }
+                       NG_NODE_FOREACH_HOOK(node, ng_bridge_reset_link, 1, 
rethook);
                        break;
                    }
                case NGM_BRIDGE_GET_STATS:
                case NGM_BRIDGE_CLR_STATS:
                case NGM_BRIDGE_GETCLR_STATS:
                    {
-                       struct ng_bridge_link *link;
-                       int linkNum;
-
+                       hook_p hook;
+                       link_p link;
+                       char linkName[NG_HOOKSIZ];
+                           
                        /* Get link number */
                        if (msg->header.arglen != sizeof(u_int32_t)) {
                                error = EINVAL;
                                break;
                        }
-                       linkNum = *((u_int32_t *)msg->data);
-                       if (linkNum < 0 || linkNum >= NG_BRIDGE_MAX_LINKS) {
-                               error = EINVAL;
-                               break;
-                       }
-                       if ((link = priv->links[linkNum]) == NULL) {
+                       snprintf(linkName, sizeof(linkName),
+                                "%s%u", NG_BRIDGE_HOOK_LINK_PREFIX,
+                                *((u_int32_t *)msg->data));
+                           
+                       if ((hook = ng_findhook(node, linkName)) == NULL) {
                                error = ENOTCONN;
                                break;
                        }
+                       link = NG_HOOK_PRIVATE(hook);
 
                        /* Get/clear stats */
                        if (msg->header.cmd != NGM_BRIDGE_CLR_STATS) {
@@ -494,8 +485,17 @@ ng_bridge_rcvmsg(node_p node, item_p item, hook_p last
                        ary = (struct ng_bridge_host_ary *)resp->data;
                        ary->numHosts = priv->numHosts;
                        for (bucket = 0; bucket < priv->numBuckets; bucket++) {
-                               SLIST_FOREACH(hent, &priv->tab[bucket], next)
-                                       ary->hosts[i++] = hent->host;
+                               SLIST_FOREACH(hent, &priv->tab[bucket], next) {
+                                       memcpy(ary->hosts[i].addr,
+                                              hent->host.addr,
+                                              sizeof(ary->hosts[i].addr));
+                                       ary->hosts[i].age       = 
hent->host.age;
+                                       ary->hosts[i].staleness = 
hent->host.staleness;
+                                       strncpy(ary->hosts[i].hook,
+                                               
NG_HOOK_NAME(hent->host.link->hook),
+                                               sizeof(ary->hosts[i].hook));
+                                       i++;
+                               }
                        }
                        break;
                    }
@@ -523,64 +523,117 @@ ng_bridge_rcvmsg(node_p node, item_p item, hook_p last
 /*
  * Receive data on a hook
  */
+struct ng_bridge_send_ctx {
+       link_p foundFirst, incoming;
+       struct mbuf * m;
+       int manycast, error;
+};
+
 static int
+ng_bridge_send_ctx(hook_p dst, struct ng_bridge_send_ctx * ctx)
+{
+       link_p destLink = NG_HOOK_PRIVATE(dst);
+       struct mbuf *m2 = NULL;
+       int error = 0;
+
+       /* Skip incoming link */
+       if (destLink == ctx->incoming) {
+               return (1);
+       }
+
+       if (ctx->foundFirst == NULL) {
+               /*
+                * This is the first usable link we have found.
+                * Reserve it for the originals.
+                * If we never find another we save a copy.
+                */
+               ctx->foundFirst = destLink;
+               return (1);
+       }
+
+       /*
+        * It's usable link but not the reserved (first) one.
+        * Copy mbuf info for sending.
+        */
+       m2 = m_dup(ctx->m, M_NOWAIT);   /* XXX m_copypacket() */
+       if (m2 == NULL) {
+               ctx->incoming->stats.memoryFailures++;
+               ctx->error = ENOBUFS;
+               return (0);            /* abort loop */
+       }
+
+
+       /* Update stats */
+       destLink->stats.xmitPackets++;
+       destLink->stats.xmitOctets += m2->m_pkthdr.len;
+       switch (ctx->manycast) {
+        default:                                       /* unknown unicast */
+               break;
+        case 1:                                        /* multicast */
+               destLink->stats.xmitMulticasts++;
+               break;
+        case 2:                                        /* broadcast */
+               destLink->stats.xmitBroadcasts++;
+               break;
+       }
+
+       /* Send packet */
+       NG_SEND_DATA_ONLY(error, destLink->hook, m2);
+       if(error)
+         ctx->error = error;
+       return (1);
+}
+
+static int
 ng_bridge_rcvdata(hook_p hook, item_p item)
 {
        const node_p node = NG_HOOK_NODE(hook);
        const priv_p priv = NG_NODE_PRIVATE(node);
        struct ng_bridge_host *host;
-       struct ng_bridge_link *link;
        struct ether_header *eh;
-       int error = 0, linkNum, linksSeen;
-       int manycast;
-       struct mbuf *m;
-       struct ng_bridge_link *firstLink;
+       struct ng_bridge_send_ctx ctx = { 0 };
+       hook_p ret;
 
-       NGI_GET_M(item, m);
-       /* Get link number */
-       linkNum = (intptr_t)NG_HOOK_PRIVATE(hook);
-       KASSERT(linkNum >= 0 && linkNum < NG_BRIDGE_MAX_LINKS,
-           ("%s: linkNum=%u", __func__, linkNum));
-       link = priv->links[linkNum];
-       KASSERT(link != NULL, ("%s: link%d null", __func__, linkNum));
+       NGI_GET_M(item, ctx.m);
 
+       ctx.incoming = NG_HOOK_PRIVATE(hook);
        /* Sanity check packet and pull up header */
-       if (m->m_pkthdr.len < ETHER_HDR_LEN) {
-               link->stats.recvRunts++;
+       if (ctx.m->m_pkthdr.len < ETHER_HDR_LEN) {
+               ctx.incoming->stats.recvRunts++;
                NG_FREE_ITEM(item);
-               NG_FREE_M(m);
+               NG_FREE_M(ctx.m);
                return (EINVAL);
        }
-       if (m->m_len < ETHER_HDR_LEN && !(m = m_pullup(m, ETHER_HDR_LEN))) {
-               link->stats.memoryFailures++;
+       if (ctx.m->m_len < ETHER_HDR_LEN && !(ctx.m = m_pullup(ctx.m, 
ETHER_HDR_LEN))) {
+               ctx.incoming->stats.memoryFailures++;
                NG_FREE_ITEM(item);
                return (ENOBUFS);
        }
-       eh = mtod(m, struct ether_header *);
+       eh = mtod(ctx.m, struct ether_header *);
        if ((eh->ether_shost[0] & 1) != 0) {
-               link->stats.recvInvalid++;
+               ctx.incoming->stats.recvInvalid++;
                NG_FREE_ITEM(item);
-               NG_FREE_M(m);
+               NG_FREE_M(ctx.m);
                return (EINVAL);
        }
 
        /* Is link disabled due to a loopback condition? */
-       if (link->loopCount != 0) {
-               link->stats.loopDrops++;
+       if (ctx.incoming->loopCount != 0) {
+               ctx.incoming->stats.loopDrops++;
                NG_FREE_ITEM(item);
-               NG_FREE_M(m);
+               NG_FREE_M(ctx.m);
                return (ELOOP);         /* XXX is this an appropriate error? */
        }
 
        /* Update stats */
-       link->stats.recvPackets++;
-       link->stats.recvOctets += m->m_pkthdr.len;
-       if ((manycast = (eh->ether_dhost[0] & 1)) != 0) {
+       ctx.incoming->stats.recvPackets++;
+       ctx.incoming->stats.recvOctets += ctx.m->m_pkthdr.len;
+       if ((ctx.manycast = (eh->ether_dhost[0] & 1)) != 0) {
                if (ETHER_EQUAL(eh->ether_dhost, ng_bridge_bcast_addr)) {
-                       link->stats.recvBroadcasts++;
-                       manycast = 2;
+                       ctx.incoming->stats.recvBroadcasts++;
+                       ctx.manycast = 2;
                } else
-                       link->stats.recvMulticasts++;
+                       ctx.incoming->stats.recvMulticasts++;
        }
 
        /* Look up packet's source Ethernet address in hashtable */
@@ -590,7 +643,7 @@ ng_bridge_rcvdata(hook_p hook, item_p item)
                host->staleness = 0;
 
                /* Did host jump to a different link? */
-               if (host->linkNum != linkNum) {
+               if (host->link != ctx.incoming) {
 
                        /*
                         * If the host's old link was recently established
@@ -601,7 +654,7 @@ ng_bridge_rcvdata(hook_p hook, item_p item)
 
                                /* Log the problem */
                                if (priv->conf.debugLevel >= 2) {
-                                       struct ifnet *ifp = m->m_pkthdr.rcvif;
+                                       struct ifnet *ifp = 
ctx.m->m_pkthdr.rcvif;
                                        char suffix[32];
 
                                        if (ifp != NULL)
@@ -616,28 +669,28 @@ ng_bridge_rcvdata(hook_p hook, item_p item)
                                }
 
                                /* Mark link as linka non grata */
-                               link->loopCount = priv->conf.loopTimeout;
-                               link->stats.loopDetects++;
+                               ctx.incoming->loopCount = 
priv->conf.loopTimeout;
+                               ctx.incoming->stats.loopDetects++;
 
                                /* Forget all hosts on this link */
-                               ng_bridge_remove_hosts(priv, linkNum);
+                               ng_bridge_remove_hosts(priv, ctx.incoming);
 
                                /* Drop packet */
-                               link->stats.loopDrops++;
+                               ctx.incoming->stats.loopDrops++;
                                NG_FREE_ITEM(item);
-                               NG_FREE_M(m);
+                               NG_FREE_M(ctx.m);
                                return (ELOOP);         /* XXX appropriate? */
                        }
 
                        /* Move host over to new link */
-                       host->linkNum = linkNum;
+                       host->link = ctx.incoming;
                        host->age = 0;
                }
        } else {
-               if (!ng_bridge_put(priv, eh->ether_shost, linkNum)) {
-                       link->stats.memoryFailures++;
+               if (!ng_bridge_put(priv, eh->ether_shost, ctx.incoming)) {
+                       ctx.incoming->stats.memoryFailures++;
                        NG_FREE_ITEM(item);
-                       NG_FREE_M(m);
+                       NG_FREE_M(ctx.m);
                        return (ENOMEM);
                }
        }
@@ -653,109 +706,46 @@ ng_bridge_rcvdata(hook_p hook, item_p item)
         * If unicast and destination host known, deliver to host's link,
         * unless it is the same link as the packet came in on.
         */
-       if (!manycast) {
+       if (!ctx.manycast) {
 
                /* Determine packet destination link */
                if ((host = ng_bridge_get(priv, eh->ether_dhost)) != NULL) {
-                       struct ng_bridge_link *const destLink
-                           = priv->links[host->linkNum];
+                       link_p destLink = host->link;
 
                        /* If destination same as incoming link, do nothing */
-                       KASSERT(destLink != NULL,
-                           ("%s: link%d null", __func__, host->linkNum));
-                       if (destLink == link) {
+                       if (destLink == ctx.incoming) {
                                NG_FREE_ITEM(item);
-                               NG_FREE_M(m);
+                               NG_FREE_M(ctx.m);
                                return (0);
                        }
 
                        /* Deliver packet out the destination link */
                        destLink->stats.xmitPackets++;
-                       destLink->stats.xmitOctets += m->m_pkthdr.len;
-                       NG_FWD_NEW_DATA(error, item, destLink->hook, m);
-                       return (error);
+                       destLink->stats.xmitOctets += ctx.m->m_pkthdr.len;
+                       NG_FWD_NEW_DATA(ctx.error, item, destLink->hook, ctx.m);
+                       return (ctx.error);
                }
 
                /* Destination host is not known */
-               link->stats.recvUnknown++;
+               ctx.incoming->stats.recvUnknown++;
        }
 
        /* Distribute unknown, multicast, broadcast pkts to all other links */
-       firstLink = NULL;
-       for (linkNum = linksSeen = 0; linksSeen <= priv->numLinks; linkNum++) {
-               struct ng_bridge_link *destLink;
-               struct mbuf *m2 = NULL;
+       NG_NODE_FOREACH_HOOK(node, ng_bridge_send_ctx, &ctx, ret);
 
-               /*
-                * If we have checked all the links then now
-                * send the original on its reserved link
-                */
-               if (linksSeen == priv->numLinks) {
-                       /* If we never saw a good link, leave. */
-                       if (firstLink == NULL) {
-                               NG_FREE_ITEM(item);
-                               NG_FREE_M(m);
-                               return (0);
-                       }       
-                       destLink = firstLink;
-               } else {
-                       destLink = priv->links[linkNum];
-                       if (destLink != NULL)
-                               linksSeen++;
-                       /* Skip incoming link and disconnected links */
-                       if (destLink == NULL || destLink == link) {
-                               continue;
-                       }
-                       if (firstLink == NULL) {
-                               /*
-                                * This is the first usable link we have found.
-                                * Reserve it for the originals.
-                                * If we never find another we save a copy.
-                                */
-                               firstLink = destLink;
-                               continue;
-                       }
-
-                       /*
-                        * It's usable link but not the reserved (first) one.
-                        * Copy mbuf info for sending.
-                        */
-                       m2 = m_dup(m, M_NOWAIT);        /* XXX m_copypacket() */
-                       if (m2 == NULL) {
-                               link->stats.memoryFailures++;
-                               NG_FREE_ITEM(item);
-                               NG_FREE_M(m);
-                               return (ENOBUFS);
-                       }
-               }
-
-               /* Update stats */
-               destLink->stats.xmitPackets++;
-               destLink->stats.xmitOctets += m->m_pkthdr.len;
-               switch (manycast) {
-               case 0:                                 /* unicast */
-                       break;
-               case 1:                                 /* multicast */
-                       destLink->stats.xmitMulticasts++;
-                       break;
-               case 2:                                 /* broadcast */
-                       destLink->stats.xmitBroadcasts++;
-                       break;
-               }
-
-               /* Send packet */
-               if (destLink == firstLink) { 
-                       /*
-                        * If we've sent all the others, send the original
-                        * on the first link we found.
-                        */
-                       NG_FWD_NEW_DATA(error, item, destLink->hook, m);
-                       break; /* always done last - not really needed. */
-               } else {
-                       NG_SEND_DATA_ONLY(error, destLink->hook, m2);
-               }
+       /* If we never saw a good link, leave. */
+       if (ctx.foundFirst == NULL || ctx.error != 0) {
+               NG_FREE_ITEM(item);
+               NG_FREE_M(ctx.m);
+               return (ctx.error);
        }
-       return (error);
+       
+       /*
+        * If we've sent all the others, send the original
+        * on the first link we found.
+        */
+       NG_FWD_NEW_DATA(ctx.error, item, ctx.foundFirst->hook, ctx.m);
+       return (ctx.error);
 }
 
 /*
@@ -791,20 +781,13 @@ static int
 ng_bridge_disconnect(hook_p hook)
 {
        const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
-       int linkNum;
+       link_p link = NG_HOOK_PRIVATE(hook);
 
-       /* Get link number */
-       linkNum = (intptr_t)NG_HOOK_PRIVATE(hook);
-       KASSERT(linkNum >= 0 && linkNum < NG_BRIDGE_MAX_LINKS,
-           ("%s: linkNum=%u", __func__, linkNum));
-
        /* Remove all hosts associated with this link */
-       ng_bridge_remove_hosts(priv, linkNum);
+       ng_bridge_remove_hosts(priv, link);
 
        /* Free associated link information */
-       KASSERT(priv->links[linkNum] != NULL, ("%s: no link", __func__));
-       free(priv->links[linkNum], M_NETGRAPH_BRIDGE);
-       priv->links[linkNum] = NULL;
+       free(link, M_NETGRAPH_BRIDGE);
        priv->numLinks--;
 
        /* If no more hooks, go away */
@@ -849,7 +832,7 @@ ng_bridge_get(priv_p priv, const u_char *addr)
  * was a memory allocation failure.
  */
 static int
-ng_bridge_put(priv_p priv, const u_char *addr, int linkNum)
+ng_bridge_put(priv_p priv, const u_char *addr, link_p link)
 {
        const int bucket = HASH(addr, priv->hashMask);
        struct ng_bridge_hent *hent;
@@ -867,7 +850,7 @@ ng_bridge_put(priv_p priv, const u_char *addr, int lin
        if (hent == NULL)
                return (0);
        bcopy(addr, hent->host.addr, ETHER_ADDR_LEN);
-       hent->host.linkNum = linkNum;
+       hent->host.link = link;
        hent->host.staleness = 0;
        hent->host.age = 0;
 
@@ -943,12 +926,13 @@ ng_bridge_rehash(priv_p priv)
                    MISC FUNCTIONS
 ******************************************************************/
 
+
 /*
  * Remove all hosts associated with a specific link from the hashtable.
  * If linkNum == -1, then remove all hosts in the table.
  */
 static void
-ng_bridge_remove_hosts(priv_p priv, int linkNum)
+ng_bridge_remove_hosts(priv_p priv, link_p link)
 {
        int bucket;
 
@@ -958,7 +942,7 @@ ng_bridge_remove_hosts(priv_p priv, int linkNum)
                while (*hptr != NULL) {
                        struct ng_bridge_hent *const hent = *hptr;
 
-                       if (linkNum == -1 || hent->host.linkNum == linkNum) {
+                       if (link == NULL || hent->host.link == link) {
                                *hptr = SLIST_NEXT(hent, next);
                                free(hent, M_NETGRAPH_BRIDGE);
                                priv->numHosts--;
@@ -974,13 +958,32 @@ ng_bridge_remove_hosts(priv_p priv, int linkNum)
  * a detected loopback condition, and we remove any hosts from
  * the hashtable whom we haven't heard from in a long while.
  */
+static int
+ng_bridge_unmute(hook_p hook, int *counter)
+{
+       link_p link = NG_HOOK_PRIVATE(hook);
+       node_p node = NG_HOOK_NODE(hook);
+       priv_p priv = NG_NODE_PRIVATE(node);
+
+       if (link->loopCount != 0) {
+               link->loopCount--;
+               if (link->loopCount == 0 && priv->conf.debugLevel >= 2) {
+                       log(LOG_INFO, "ng_bridge: %s:"
+                           " restoring looped back %s\n",
+                           ng_bridge_nodename(node), NG_HOOK_NAME(hook));
+               }
+       }
+       counter++;
+       return (1);
+}
+
 static void
 ng_bridge_timeout(node_p node, hook_p hook, void *arg1, int arg2)
 {
        const priv_p priv = NG_NODE_PRIVATE(node);
        int bucket;
        int counter = 0;
-       int linkNum;
+       hook_p ret;
 
        /* Update host time counters and remove stale entries */
        for (bucket = 0; bucket < priv->numBuckets; bucket++) {
@@ -989,12 +992,6 @@ ng_bridge_timeout(node_p node, hook_p hook, void *arg1
                while (*hptr != NULL) {
                        struct ng_bridge_hent *const hent = *hptr;
 
-                       /* Make sure host's link really exists */
-                       KASSERT(priv->links[hent->host.linkNum] != NULL,
-                           ("%s: host %6D on nonexistent link %d\n",
-                           __func__, hent->host.addr, ":",
-                           hent->host.linkNum));
-
                        /* Remove hosts we haven't heard from in a while */
                        if (++hent->host.staleness >= priv->conf.maxStaleness) {
                                *hptr = SLIST_NEXT(hent, next);
@@ -1015,22 +1012,8 @@ ng_bridge_timeout(node_p node, hook_p hook, void *arg1
        ng_bridge_rehash(priv);
 
        /* Decrease loop counter on muted looped back links */
-       for (counter = linkNum = 0; linkNum < NG_BRIDGE_MAX_LINKS; linkNum++) {
-               struct ng_bridge_link *const link = priv->links[linkNum];
-
-               if (link != NULL) {
-                       if (link->loopCount != 0) {
-                               link->loopCount--;
-                               if (link->loopCount == 0
-                                   && priv->conf.debugLevel >= 2) {
-                                       log(LOG_INFO, "ng_bridge: %s:"
-                                           " restoring looped back link%d\n",
-                                           ng_bridge_nodename(node), linkNum);
-                               }
-                       }
-                       counter++;
-               }
-       }
+       counter = 0;
+       NG_NODE_FOREACH_HOOK(node, ng_bridge_unmute, &counter, ret);
        KASSERT(priv->numLinks == counter,
            ("%s: links: %d != %d", __func__, priv->numLinks, counter));
 

Modified: head/sys/netgraph/ng_bridge.h
==============================================================================
--- head/sys/netgraph/ng_bridge.h       Wed Oct  2 23:19:34 2019        
(r353025)
+++ head/sys/netgraph/ng_bridge.h       Thu Oct  3 02:32:55 2019        
(r353026)
@@ -45,18 +45,14 @@
 
 /* Node type name and magic cookie */
 #define NG_BRIDGE_NODE_TYPE            "bridge"
-#define NGM_BRIDGE_COOKIE              967239368
+#define NGM_BRIDGE_COOKIE              1569321993
 
 /* 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) */
 
-/* Maximum number of supported links */
-#define NG_BRIDGE_MAX_LINKS            32
-
 /* Node configuration structure */
 struct ng_bridge_config {
-       u_char          ipfw[NG_BRIDGE_MAX_LINKS];      /* enable ipfw */
        u_char          debugLevel;             /* debug level */
        u_int32_t       loopTimeout;            /* link loopback mute time */
        u_int32_t       maxStaleness;           /* max host age before nuking */
@@ -64,8 +60,7 @@ struct ng_bridge_config {
 };
 
 /* Keep this in sync with the above structure definition */
-#define NG_BRIDGE_CONFIG_TYPE_INFO(ainfo)      {               \
-         { "ipfw",             (ainfo)                 },      \
+#define NG_BRIDGE_CONFIG_TYPE_INFO     {                       \
          { "debugLevel",       &ng_parse_uint8_type    },      \
          { "loopTimeout",      &ng_parse_uint32_type   },      \
          { "maxStaleness",     &ng_parse_uint32_type   },      \
@@ -110,18 +105,28 @@ struct ng_bridge_link_stats {
          { NULL }                                              \
 }
 
+struct ng_bridge_link;
+typedef struct ng_bridge_link *link_p;
 /* Structure describing a single host */
 struct ng_bridge_host {
        u_char          addr[6];        /* ethernet address */
-       u_int16_t       linkNum;        /* link where addr can be found */
+       link_p          link;           /* link where addr can be found */
        u_int16_t       age;            /* seconds ago entry was created */
        u_int16_t       staleness;      /* seconds ago host last heard from */
 };
 
+/* external representation of the host */
+struct ng_bridge_hostent {
+       u_char          addr[6];                /* ethernet address */
+       char            hook[NG_HOOKSIZ];       /* link where addr can be found 
*/
+       u_int16_t       age;                    /* seconds ago entry was 
created */
+       u_int16_t       staleness;              /* seconds ago host last heard 
from */
+};
+
 /* Keep this in sync with the above structure definition */
 #define NG_BRIDGE_HOST_TYPE_INFO(entype)       {               \
          { "addr",             (entype)                },      \
-         { "linkNum",          &ng_parse_uint16_type   },      \
+         { "hook",             &ng_parse_hookbuf_type  },      \
          { "age",              &ng_parse_uint16_type   },      \
          { "staleness",        &ng_parse_uint16_type   },      \
          { NULL }                                              \
@@ -129,8 +134,8 @@ struct ng_bridge_host {
 
 /* Structure returned by NGM_BRIDGE_GET_TABLE */
 struct ng_bridge_host_ary {
-       u_int32_t               numHosts;
-       struct ng_bridge_host   hosts[];
+       u_int32_t                       numHosts;
+       struct ng_bridge_hostent        hosts[];
 };
 
 /* Keep this in sync with the above structure definition */
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to