- 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
This commit is contained in:
Gleb Smirnoff 2019-10-03 02:32:55 +00:00
parent b6fa976de2
commit 631cabba47
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=353026
3 changed files with 221 additions and 241 deletions

View File

@ -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 */
@ -115,11 +112,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.
At level of 2 or greater, detected loops are logged.

View File

@ -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_type = {
};
/* 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 *name)
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);
}
@ -383,6 +371,17 @@ ng_bridge_newhook(node_p node, hook_p hook, const char *name)
/*
* 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)
{
@ -412,7 +411,6 @@ ng_bridge_rcvmsg(node_p node, item_p item, hook_p lasthook)
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 lasthook)
}
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 lasthook)
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 lasthook)
/*
* 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;
/* Get link number */
linkNum = (intptr_t)NG_HOOK_PRIVATE(hook);
KASSERT(linkNum >= 0 && linkNum < NG_BRIDGE_MAX_LINKS,
("%s: linkNum=%u", __func__, linkNum));
link_p link = NG_HOOK_PRIVATE(hook);
/* 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 linkNum)
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, int arg2)
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, int arg2)
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));

View File

@ -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 */