From owner-svn-src-all@freebsd.org Tue Jan 28 17:39:03 2020 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id CB09F235158; Tue, 28 Jan 2020 17:39:03 +0000 (UTC) (envelope-from bz@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 486Ykv5kCjz4HK9; Tue, 28 Jan 2020 17:39:03 +0000 (UTC) (envelope-from bz@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id BF78D269C0; Tue, 28 Jan 2020 17:39:03 +0000 (UTC) (envelope-from bz@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 00SHd3bw089647; Tue, 28 Jan 2020 17:39:03 GMT (envelope-from bz@FreeBSD.org) Received: (from bz@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id 00SHd3cO089645; Tue, 28 Jan 2020 17:39:03 GMT (envelope-from bz@FreeBSD.org) Message-Id: <202001281739.00SHd3cO089645@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: bz set sender to bz@FreeBSD.org using -f From: "Bjoern A. Zeeb" Date: Tue, 28 Jan 2020 17:39:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r357206 - in stable/12: share/man/man4 sys/netgraph X-SVN-Group: stable-12 X-SVN-Commit-Author: bz X-SVN-Commit-Paths: in stable/12: share/man/man4 sys/netgraph X-SVN-Commit-Revision: 357206 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 28 Jan 2020 17:39:03 -0000 Author: bz Date: Tue Jan 28 17:39:03 2020 New Revision: 357206 URL: https://svnweb.freebsd.org/changeset/base/357206 Log: MFC r353026,353030,354244 (glebius), r356386: 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. Reestablish old ABI. PR: 240787 Submitted by: Lutz Donnerhacke (lutz donnerhacke.de) Modified: stable/12/share/man/man4/ng_bridge.4 stable/12/sys/netgraph/ng_bridge.c stable/12/sys/netgraph/ng_bridge.h Directory Properties: stable/12/ (props changed) Modified: stable/12/share/man/man4/ng_bridge.4 ============================================================================== --- stable/12/share/man/man4/ng_bridge.4 Tue Jan 28 17:34:05 2020 (r357205) +++ stable/12/share/man/man4/ng_bridge.4 Tue Jan 28 17:39:03 2020 (r357206) @@ -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: stable/12/sys/netgraph/ng_bridge.c ============================================================================== --- stable/12/sys/netgraph/ng_bridge.c Tue Jan 28 17:34:05 2020 (r357205) +++ stable/12/sys/netgraph/ng_bridge.c Tue Jan 28 17:39:03 2020 (r357206) @@ -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,18 @@ ng_bridge_newhook(node_p node, hook_p hook, const char * Receive a control message */ static int +ng_bridge_reset_link(hook_p hook, void *arg __unused) +{ + link_p priv = NG_HOOK_PRIVATE(hook); + + priv->loopCount = 0; + bzero(&priv->stats, sizeof(priv->stats)); + + return (1); +} + + +static int ng_bridge_rcvmsg(node_p node, item_p item, hook_p lasthook) { const priv_p priv = NG_NODE_PRIVATE(node); @@ -393,6 +393,72 @@ ng_bridge_rcvmsg(node_p node, item_p item, hook_p last NGI_GET_MSG(item, msg); switch (msg->header.typecookie) { +#ifdef NGM_BRIDGE_TABLE_ABI + case NGM_BRIDGE_COOKIE_TBL: + switch (msg->header.cmd) { + case NGM_BRIDGE_GET_CONFIG: + { + struct ng_bridge_config_tbl *conf; + + NG_MKRESPONSE(resp, msg, sizeof(*conf), + M_NOWAIT|M_ZERO); + if (resp == NULL) { + error = ENOMEM; + break; + } + conf = (struct ng_bridge_config_tbl *)resp->data; + conf->cfg = priv->conf; + break; + } + case NGM_BRIDGE_SET_CONFIG: + { + struct ng_bridge_config_tbl *conf; + + if (msg->header.arglen != sizeof(*conf)) { + error = EINVAL; + break; + } + conf = (struct ng_bridge_config_tbl *)msg->data; + priv->conf = conf->cfg; + break; + } + case NGM_BRIDGE_GET_TABLE: + { + struct ng_bridge_host_tbl_ary *ary; + struct ng_bridge_hent *hent; + int i, bucket; + + NG_MKRESPONSE(resp, msg, sizeof(*ary) + + (priv->numHosts * sizeof(*ary->hosts)), M_NOWAIT); + if (resp == NULL) { + error = ENOMEM; + break; + } + ary = (struct ng_bridge_host_tbl_ary *)resp->data; + ary->numHosts = priv->numHosts; + i = 0; + for (bucket = 0; bucket < priv->numBuckets; bucket++) { + 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; + ary->hosts[i].linkNum = strtol( + NG_HOOK_NAME(hent->host.link->hook) + + strlen(NG_BRIDGE_HOOK_LINK_PREFIX), + NULL, 10); + i++; + } + } + break; + } + } + /* If already handled break, otherwise use new ABI. */ + if (resp != NULL || error != 0) + break; +#endif /* NGM_BRIDGE_TABLE_ABI */ case NGM_BRIDGE_COOKIE: switch (msg->header.cmd) { case NGM_BRIDGE_GET_CONFIG: @@ -412,7 +478,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 +486,42 @@ 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, NULL, + 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 +553,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 +591,118 @@ 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, void *arg) +{ + struct ng_bridge_send_ctx *ctx = arg; + 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 +712,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 +723,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 +738,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 +775,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 +850,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 +901,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 +919,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 +995,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 +1011,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 +1027,33 @@ 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, void *arg) +{ + link_p link = NG_HOOK_PRIVATE(hook); + node_p node = NG_HOOK_NODE(hook); + priv_p priv = NG_NODE_PRIVATE(node); + int *counter = arg; + + 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 +1062,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 +1082,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: stable/12/sys/netgraph/ng_bridge.h ============================================================================== --- stable/12/sys/netgraph/ng_bridge.h Tue Jan 28 17:34:05 2020 (r357205) +++ stable/12/sys/netgraph/ng_bridge.h Tue Jan 28 17:39:03 2020 (r357206) @@ -43,29 +43,45 @@ #ifndef _NETGRAPH_NG_BRIDGE_H_ #define _NETGRAPH_NG_BRIDGE_H_ +/* + * Support the older ABI based on fixed size tables. + * ABI is deprecated, to be removed in releases > 12 + * Please note: There is no API support! + * You canno create new messages using the old API but messages conforming the + * old ABI are understood. + */ +#define NGM_BRIDGE_TABLE_ABI + /* Node type name and magic cookie */ #define NG_BRIDGE_NODE_TYPE "bridge" -#define NGM_BRIDGE_COOKIE 967239368 +#define NGM_BRIDGE_COOKIE 1569321993 +#ifdef NGM_BRIDGE_TABLE_ABI +#define NGM_BRIDGE_COOKIE_TBL 967239368 +#define NG_BRIDGE_MAX_LINKS 32 +#endif /* NGM_BRIDGE_TABLE_ABI */ + /* 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 */ u_int32_t minStableAge; /* min time for a stable host */ }; +#ifdef NGM_BRIDGE_TABLE_ABI +struct ng_bridge_config_tbl { + u_char ipfw[NG_BRIDGE_MAX_LINKS]; + struct ng_bridge_config cfg; +}; +#endif /* NGM_BRIDGE_TABLE_ABI */ + /* 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 +126,37 @@ 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 */ + 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 */ +}; + +#ifdef NGM_BRIDGE_TABLE_ABI +struct ng_bridge_host_tbl { + u_char addr[6]; /* ethernet address */ u_int16_t linkNum; /* 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 */ }; +#endif /* NGM_BRIDGE_TABLE_ABI */ +/* 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 +164,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 */ @@ -139,6 +174,19 @@ struct ng_bridge_host_ary { { "hosts", (harytype) }, \ { NULL } \ } + +#ifdef NGM_BRIDGE_TABLE_ABI +struct ng_bridge_hostent_tbl { + u_char addr[6]; /* ethernet address */ + u_int16_t linkNum; /* 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 */ +}; +struct ng_bridge_host_tbl_ary { + u_int32_t numHosts; + struct ng_bridge_hostent_tbl hosts[]; +}; +#endif /* NGM_BRIDGE_TABLE_ABI */ /* Netgraph control messages */ enum {