Changeset View
Changeset View
Standalone View
Standalone View
sys/netgraph/ng_bridge.c
Show First 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | |||||
#include <sys/lock.h> | #include <sys/lock.h> | ||||
#include <sys/malloc.h> | #include <sys/malloc.h> | ||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/errno.h> | #include <sys/errno.h> | ||||
#include <sys/rwlock.h> | #include <sys/rwlock.h> | ||||
#include <sys/syslog.h> | #include <sys/syslog.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
#include <sys/ctype.h> | #include <sys/ctype.h> | ||||
#include <sys/types.h> | |||||
#include <sys/counter.h> | |||||
#include <net/if.h> | #include <net/if.h> | ||||
#include <net/if_var.h> | #include <net/if_var.h> | ||||
#include <net/ethernet.h> | #include <net/ethernet.h> | ||||
#include <net/vnet.h> | #include <net/vnet.h> | ||||
#include <netinet/in.h> | #include <netinet/in.h> | ||||
#if 0 /* not used yet */ | #if 0 /* not used yet */ | ||||
#include <netinet/ip_fw.h> | #include <netinet/ip_fw.h> | ||||
#endif | #endif | ||||
#include <netgraph/ng_message.h> | #include <netgraph/ng_message.h> | ||||
#include <netgraph/netgraph.h> | #include <netgraph/netgraph.h> | ||||
#include <netgraph/ng_parse.h> | #include <netgraph/ng_parse.h> | ||||
#include <netgraph/ng_bridge.h> | #include <netgraph/ng_bridge.h> | ||||
#ifdef NG_SEPARATE_MALLOC | #ifdef NG_SEPARATE_MALLOC | ||||
static MALLOC_DEFINE(M_NETGRAPH_BRIDGE, "netgraph_bridge", | static MALLOC_DEFINE(M_NETGRAPH_BRIDGE, "netgraph_bridge", | ||||
"netgraph bridge node"); | "netgraph bridge node"); | ||||
#else | #else | ||||
#define M_NETGRAPH_BRIDGE M_NETGRAPH | #define M_NETGRAPH_BRIDGE M_NETGRAPH | ||||
#endif | #endif | ||||
/* Counter based stats */ | |||||
struct ng_bridge_link_kernel_stats { | |||||
melifaro: Maybe _kstats? | |||||
counter_u64_t recvOctets; /* total octets rec'd on link */ | |||||
counter_u64_t recvPackets; /* total pkts rec'd on link */ | |||||
counter_u64_t recvMulticasts; /* multicast pkts rec'd on link */ | |||||
counter_u64_t recvBroadcasts; /* broadcast pkts rec'd on link */ | |||||
counter_u64_t recvUnknown; /* pkts rec'd with unknown dest addr */ | |||||
counter_u64_t recvRunts; /* pkts rec'd less than 14 bytes */ | |||||
counter_u64_t recvInvalid; /* pkts rec'd with bogus source addr */ | |||||
counter_u64_t xmitOctets; /* total octets xmit'd on link */ | |||||
counter_u64_t xmitPackets; /* total pkts xmit'd on link */ | |||||
counter_u64_t xmitMulticasts; /* multicast pkts xmit'd on link */ | |||||
counter_u64_t xmitBroadcasts; /* broadcast pkts xmit'd on link */ | |||||
counter_u64_t loopDrops; /* pkts dropped due to loopback */ | |||||
counter_u64_t loopDetects; /* number of loop detections */ | |||||
counter_u64_t memoryFailures; /* times couldn't get mem or mbuf */ | |||||
}; | |||||
/* Per-link private data */ | /* Per-link private data */ | ||||
struct ng_bridge_link { | struct ng_bridge_link { | ||||
hook_p hook; /* netgraph hook */ | hook_p hook; /* netgraph hook */ | ||||
u_int16_t loopCount; /* loop ignore timer */ | u_int16_t loopCount; /* loop ignore timer */ | ||||
struct ng_bridge_link_stats stats; /* link stats */ | struct ng_bridge_link_kernel_stats stats; /* link stats */ | ||||
}; | }; | ||||
/* Per-node private data */ | /* Per-node private data */ | ||||
struct ng_bridge_private { | struct ng_bridge_private { | ||||
struct ng_bridge_bucket *tab; /* hash table bucket array */ | struct ng_bridge_bucket *tab; /* hash table bucket array */ | ||||
struct ng_bridge_config conf; /* node configuration */ | struct ng_bridge_config conf; /* node configuration */ | ||||
node_p node; /* netgraph node */ | node_p node; /* netgraph node */ | ||||
u_int numHosts; /* num entries in table */ | u_int numHosts; /* num entries in table */ | ||||
▲ Show 20 Lines • Show All 207 Lines • ▼ Show 20 Lines | ng_bridge_constructor(node_p node) | ||||
/* | /* | ||||
* This node has all kinds of stuff that could be screwed by SMP. | * This node has all kinds of stuff that could be screwed by SMP. | ||||
* Until it gets it's own internal protection, we go through in | * Until it gets it's own internal protection, we go through in | ||||
* single file. This could hurt a machine bridging between two | * single file. This could hurt a machine bridging between two | ||||
* GB ethernets so it should be fixed. | * GB ethernets so it should be fixed. | ||||
* When it's fixed the process SHOULD NOT SLEEP, spinlocks please! | * When it's fixed the process SHOULD NOT SLEEP, spinlocks please! | ||||
* (and atomic ops ) | * (and atomic ops ) | ||||
* | |||||
* TODO: | |||||
* - revdata path works on const node data | |||||
* - modify the the host table via control messages only | |||||
* - stat used the counter framework | |||||
* - remove the WRITER limitation | |||||
*/ | */ | ||||
NG_NODE_FORCE_WRITER(node); | NG_NODE_FORCE_WRITER(node); | ||||
NG_NODE_SET_PRIVATE(node, priv); | NG_NODE_SET_PRIVATE(node, priv); | ||||
priv->node = node; | priv->node = node; | ||||
/* Start timer; timer is always running while node is alive */ | /* Start timer; timer is always running while node is alive */ | ||||
ng_callout(&priv->timer, node, NULL, hz, ng_bridge_timeout, NULL, 0); | ng_callout(&priv->timer, node, NULL, hz, ng_bridge_timeout, NULL, 0); | ||||
Show All 27 Lines | if (strlen(name) > strlen(NG_BRIDGE_HOOK_LINK_PREFIX)) { | ||||
if(NG_PEER_NODE(hook) == node) | if(NG_PEER_NODE(hook) == node) | ||||
return (ELOOP); | return (ELOOP); | ||||
link = malloc(sizeof(*link), M_NETGRAPH_BRIDGE, | link = malloc(sizeof(*link), M_NETGRAPH_BRIDGE, | ||||
M_WAITOK|M_ZERO); | M_WAITOK|M_ZERO); | ||||
if (link == NULL) | if (link == NULL) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
link->stats.recvOctets = counter_u64_alloc(M_WAITOK); | |||||
link->stats.recvPackets = counter_u64_alloc(M_WAITOK); | |||||
link->stats.recvMulticasts = counter_u64_alloc(M_WAITOK); | |||||
link->stats.recvBroadcasts = counter_u64_alloc(M_WAITOK); | |||||
link->stats.recvUnknown = counter_u64_alloc(M_WAITOK); | |||||
link->stats.recvRunts = counter_u64_alloc(M_WAITOK); | |||||
link->stats.recvInvalid = counter_u64_alloc(M_WAITOK); | |||||
link->stats.xmitOctets = counter_u64_alloc(M_WAITOK); | |||||
link->stats.xmitPackets = counter_u64_alloc(M_WAITOK); | |||||
link->stats.xmitMulticasts = counter_u64_alloc(M_WAITOK); | |||||
link->stats.xmitBroadcasts = counter_u64_alloc(M_WAITOK); | |||||
link->stats.loopDrops = counter_u64_alloc(M_WAITOK); | |||||
link->stats.loopDetects = counter_u64_alloc(M_WAITOK); | |||||
link->stats.memoryFailures = counter_u64_alloc(M_WAITOK); | |||||
link->hook = hook; | link->hook = hook; | ||||
NG_HOOK_SET_PRIVATE(hook, link); | NG_HOOK_SET_PRIVATE(hook, link); | ||||
priv->numLinks++; | priv->numLinks++; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* Unknown hook name */ | /* Unknown hook name */ | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* | /* | ||||
* Receive a control message | * Receive a control message | ||||
*/ | */ | ||||
static void ng_bridge_clear_link_stats(struct ng_bridge_link_kernel_stats * p) | |||||
{ | |||||
counter_u64_zero(p->recvOctets); | |||||
counter_u64_zero(p->recvPackets); | |||||
counter_u64_zero(p->recvMulticasts); | |||||
counter_u64_zero(p->recvBroadcasts); | |||||
counter_u64_zero(p->recvUnknown); | |||||
counter_u64_zero(p->recvRunts); | |||||
counter_u64_zero(p->recvInvalid); | |||||
counter_u64_zero(p->xmitOctets); | |||||
counter_u64_zero(p->xmitPackets); | |||||
counter_u64_zero(p->xmitMulticasts); | |||||
counter_u64_zero(p->xmitBroadcasts); | |||||
counter_u64_zero(p->loopDrops); | |||||
counter_u64_zero(p->loopDetects); | |||||
counter_u64_zero(p->memoryFailures); | |||||
}; | |||||
static int | static int | ||||
ng_bridge_reset_link(hook_p hook, void *arg __unused) | ng_bridge_reset_link(hook_p hook, void *arg __unused) | ||||
{ | { | ||||
link_p priv = NG_HOOK_PRIVATE(hook); | link_p priv = NG_HOOK_PRIVATE(hook); | ||||
priv->loopCount = 0; | priv->loopCount = 0; | ||||
bzero(&priv->stats, sizeof(priv->stats)); | ng_bridge_clear_link_stats(&priv->stats); | ||||
Done Inline Actions_statS() for consistency? melifaro: _statS() for consistency? | |||||
return (1); | return (1); | ||||
} | } | ||||
static int | static int | ||||
ng_bridge_rcvmsg(node_p node, item_p item, hook_p lasthook) | ng_bridge_rcvmsg(node_p node, item_p item, hook_p lasthook) | ||||
{ | { | ||||
const priv_p priv = NG_NODE_PRIVATE(node); | const priv_p priv = NG_NODE_PRIVATE(node); | ||||
struct ng_mesg *resp = NULL; | struct ng_mesg *resp = NULL; | ||||
▲ Show 20 Lines • Show All 129 Lines • ▼ Show 20 Lines | case NGM_BRIDGE_GETCLR_STATS: | ||||
if ((hook = ng_findhook(node, linkName)) == NULL) { | if ((hook = ng_findhook(node, linkName)) == NULL) { | ||||
error = ENOTCONN; | error = ENOTCONN; | ||||
break; | break; | ||||
} | } | ||||
link = NG_HOOK_PRIVATE(hook); | link = NG_HOOK_PRIVATE(hook); | ||||
/* Get/clear stats */ | /* Get/clear stats */ | ||||
if (msg->header.cmd != NGM_BRIDGE_CLR_STATS) { | if (msg->header.cmd != NGM_BRIDGE_CLR_STATS) { | ||||
struct ng_bridge_link_stats *rs; | |||||
NG_MKRESPONSE(resp, msg, | NG_MKRESPONSE(resp, msg, | ||||
sizeof(link->stats), M_NOWAIT); | sizeof(link->stats), M_NOWAIT); | ||||
if (resp == NULL) { | if (resp == NULL) { | ||||
error = ENOMEM; | error = ENOMEM; | ||||
break; | break; | ||||
} | } | ||||
bcopy(&link->stats, | rs = (struct ng_bridge_link_stats *)resp->data; | ||||
resp->data, sizeof(link->stats)); | #define FETCH(x) rs->x = counter_u64_fetch(link->stats.x) | ||||
FETCH(recvOctets); | |||||
FETCH(recvPackets); | |||||
FETCH(recvMulticasts); | |||||
FETCH(recvBroadcasts); | |||||
FETCH(recvUnknown); | |||||
FETCH(recvRunts); | |||||
FETCH(recvInvalid); | |||||
FETCH(xmitOctets); | |||||
FETCH(xmitPackets); | |||||
FETCH(xmitMulticasts); | |||||
FETCH(xmitBroadcasts); | |||||
FETCH(loopDrops); | |||||
FETCH(loopDetects); | |||||
FETCH(memoryFailures); | |||||
#undef FETCH | |||||
} | } | ||||
if (msg->header.cmd != NGM_BRIDGE_GET_STATS) | if (msg->header.cmd != NGM_BRIDGE_GET_STATS) | ||||
bzero(&link->stats, sizeof(link->stats)); | ng_bridge_clear_link_stats(&link->stats); | ||||
break; | break; | ||||
} | } | ||||
case NGM_BRIDGE_GET_TABLE: | case NGM_BRIDGE_GET_TABLE: | ||||
{ | { | ||||
struct ng_bridge_host_ary *ary; | struct ng_bridge_host_ary *ary; | ||||
struct ng_bridge_hent *hent; | struct ng_bridge_hent *hent; | ||||
int i = 0, bucket; | int i = 0, bucket; | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | ng_bridge_send_ctx(hook_p dst, void *arg) | ||||
} | } | ||||
/* | /* | ||||
* It's usable link but not the reserved (first) one. | * It's usable link but not the reserved (first) one. | ||||
* Copy mbuf info for sending. | * Copy mbuf info for sending. | ||||
*/ | */ | ||||
m2 = m_dup(ctx->m, M_NOWAIT); /* XXX m_copypacket() */ | m2 = m_dup(ctx->m, M_NOWAIT); /* XXX m_copypacket() */ | ||||
if (m2 == NULL) { | if (m2 == NULL) { | ||||
ctx->incoming->stats.memoryFailures++; | counter_u64_add(ctx->incoming->stats.memoryFailures, 1); | ||||
ctx->error = ENOBUFS; | ctx->error = ENOBUFS; | ||||
return (0); /* abort loop */ | return (0); /* abort loop */ | ||||
} | } | ||||
/* Update stats */ | /* Update stats */ | ||||
destLink->stats.xmitPackets++; | counter_u64_add(destLink->stats.xmitPackets, 1); | ||||
destLink->stats.xmitOctets += m2->m_pkthdr.len; | counter_u64_add(destLink->stats.xmitOctets, m2->m_pkthdr.len); | ||||
switch (ctx->manycast) { | switch (ctx->manycast) { | ||||
default: /* unknown unicast */ | default: /* unknown unicast */ | ||||
break; | break; | ||||
case 1: /* multicast */ | case 1: /* multicast */ | ||||
destLink->stats.xmitMulticasts++; | counter_u64_add(destLink->stats.xmitMulticasts, 1); | ||||
break; | break; | ||||
case 2: /* broadcast */ | case 2: /* broadcast */ | ||||
destLink->stats.xmitBroadcasts++; | counter_u64_add(destLink->stats.xmitBroadcasts, 1); | ||||
break; | break; | ||||
} | } | ||||
/* Send packet */ | /* Send packet */ | ||||
NG_SEND_DATA_ONLY(error, destLink->hook, m2); | NG_SEND_DATA_ONLY(error, destLink->hook, m2); | ||||
if(error) | if(error) | ||||
ctx->error = error; | ctx->error = error; | ||||
return (1); | return (1); | ||||
Show All 9 Lines | ng_bridge_rcvdata(hook_p hook, item_p item) | ||||
struct ng_bridge_send_ctx ctx = { 0 }; | struct ng_bridge_send_ctx ctx = { 0 }; | ||||
hook_p ret; | hook_p ret; | ||||
NGI_GET_M(item, ctx.m); | NGI_GET_M(item, ctx.m); | ||||
ctx.incoming = NG_HOOK_PRIVATE(hook); | ctx.incoming = NG_HOOK_PRIVATE(hook); | ||||
/* Sanity check packet and pull up header */ | /* Sanity check packet and pull up header */ | ||||
if (ctx.m->m_pkthdr.len < ETHER_HDR_LEN) { | if (ctx.m->m_pkthdr.len < ETHER_HDR_LEN) { | ||||
ctx.incoming->stats.recvRunts++; | counter_u64_add(ctx.incoming->stats.recvRunts, 1); | ||||
NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
NG_FREE_M(ctx.m); | NG_FREE_M(ctx.m); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
if (ctx.m->m_len < ETHER_HDR_LEN && !(ctx.m = m_pullup(ctx.m, ETHER_HDR_LEN))) { | if (ctx.m->m_len < ETHER_HDR_LEN && !(ctx.m = m_pullup(ctx.m, ETHER_HDR_LEN))) { | ||||
ctx.incoming->stats.memoryFailures++; | counter_u64_add(ctx.incoming->stats.memoryFailures, 1); | ||||
NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
return (ENOBUFS); | return (ENOBUFS); | ||||
} | } | ||||
eh = mtod(ctx.m, struct ether_header *); | eh = mtod(ctx.m, struct ether_header *); | ||||
if ((eh->ether_shost[0] & 1) != 0) { | if ((eh->ether_shost[0] & 1) != 0) { | ||||
ctx.incoming->stats.recvInvalid++; | counter_u64_add(ctx.incoming->stats.recvInvalid, 1); | ||||
NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
NG_FREE_M(ctx.m); | NG_FREE_M(ctx.m); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
/* Is link disabled due to a loopback condition? */ | /* Is link disabled due to a loopback condition? */ | ||||
if (ctx.incoming->loopCount != 0) { | if (ctx.incoming->loopCount != 0) { | ||||
ctx.incoming->stats.loopDrops++; | counter_u64_add(ctx.incoming->stats.loopDrops, 1); | ||||
NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
NG_FREE_M(ctx.m); | NG_FREE_M(ctx.m); | ||||
return (ELOOP); /* XXX is this an appropriate error? */ | return (ELOOP); /* XXX is this an appropriate error? */ | ||||
} | } | ||||
/* Update stats */ | /* Update stats */ | ||||
ctx.incoming->stats.recvPackets++; | counter_u64_add(ctx.incoming->stats.recvPackets, 1); | ||||
ctx.incoming->stats.recvOctets += ctx.m->m_pkthdr.len; | counter_u64_add(ctx.incoming->stats.recvOctets, ctx.m->m_pkthdr.len); | ||||
if ((ctx.manycast = (eh->ether_dhost[0] & 1)) != 0) { | if ((ctx.manycast = (eh->ether_dhost[0] & 1)) != 0) { | ||||
if (ETHER_EQUAL(eh->ether_dhost, ng_bridge_bcast_addr)) { | if (ETHER_EQUAL(eh->ether_dhost, ng_bridge_bcast_addr)) { | ||||
ctx.incoming->stats.recvBroadcasts++; | counter_u64_add(ctx.incoming->stats.recvBroadcasts, 1); | ||||
ctx.manycast = 2; | ctx.manycast = 2; | ||||
} else | } else | ||||
ctx.incoming->stats.recvMulticasts++; | counter_u64_add(ctx.incoming->stats.recvMulticasts, 1); | ||||
} | } | ||||
/* Look up packet's source Ethernet address in hashtable */ | /* Look up packet's source Ethernet address in hashtable */ | ||||
if ((host = ng_bridge_get(priv, eh->ether_shost)) != NULL) { | if ((host = ng_bridge_get(priv, eh->ether_shost)) != NULL) { | ||||
/* Update time since last heard from this host */ | /* Update time since last heard from this host */ | ||||
host->staleness = 0; | host->staleness = 0; | ||||
/* Did host jump to a different link? */ | /* Did host jump to a different link? */ | ||||
Show All 17 Lines | if (host->link != ctx.incoming) { | ||||
log(LOG_WARNING, "ng_bridge: %s:" | log(LOG_WARNING, "ng_bridge: %s:" | ||||
" loopback detected on %s%s\n", | " loopback detected on %s%s\n", | ||||
ng_bridge_nodename(node), | ng_bridge_nodename(node), | ||||
NG_HOOK_NAME(hook), suffix); | NG_HOOK_NAME(hook), suffix); | ||||
} | } | ||||
/* Mark link as linka non grata */ | /* Mark link as linka non grata */ | ||||
ctx.incoming->loopCount = priv->conf.loopTimeout; | ctx.incoming->loopCount = priv->conf.loopTimeout; | ||||
ctx.incoming->stats.loopDetects++; | counter_u64_add(ctx.incoming->stats.loopDetects, 1); | ||||
/* Forget all hosts on this link */ | /* Forget all hosts on this link */ | ||||
ng_bridge_remove_hosts(priv, ctx.incoming); | ng_bridge_remove_hosts(priv, ctx.incoming); | ||||
/* Drop packet */ | /* Drop packet */ | ||||
ctx.incoming->stats.loopDrops++; | counter_u64_add(ctx.incoming->stats.loopDrops, 1); | ||||
NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
NG_FREE_M(ctx.m); | NG_FREE_M(ctx.m); | ||||
return (ELOOP); /* XXX appropriate? */ | return (ELOOP); /* XXX appropriate? */ | ||||
} | } | ||||
/* Move host over to new link */ | /* Move host over to new link */ | ||||
host->link = ctx.incoming; | host->link = ctx.incoming; | ||||
host->age = 0; | host->age = 0; | ||||
} | } | ||||
} else { | } else { | ||||
if (!ng_bridge_put(priv, eh->ether_shost, ctx.incoming)) { | if (!ng_bridge_put(priv, eh->ether_shost, ctx.incoming)) { | ||||
ctx.incoming->stats.memoryFailures++; | counter_u64_add(ctx.incoming->stats.memoryFailures, 1); | ||||
NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
NG_FREE_M(ctx.m); | NG_FREE_M(ctx.m); | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} | } | ||||
} | } | ||||
/* Run packet through ipfw processing, if enabled */ | /* Run packet through ipfw processing, if enabled */ | ||||
#if 0 | #if 0 | ||||
Show All 14 Lines | if ((host = ng_bridge_get(priv, eh->ether_dhost)) != NULL) { | ||||
/* If destination same as incoming link, do nothing */ | /* If destination same as incoming link, do nothing */ | ||||
if (destLink == ctx.incoming) { | if (destLink == ctx.incoming) { | ||||
NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
NG_FREE_M(ctx.m); | NG_FREE_M(ctx.m); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* Deliver packet out the destination link */ | /* Deliver packet out the destination link */ | ||||
destLink->stats.xmitPackets++; | counter_u64_add(destLink->stats.xmitPackets, 1); | ||||
destLink->stats.xmitOctets += ctx.m->m_pkthdr.len; | counter_u64_add(destLink->stats.xmitOctets, ctx.m->m_pkthdr.len); | ||||
NG_FWD_NEW_DATA(ctx.error, item, destLink->hook, ctx.m); | NG_FWD_NEW_DATA(ctx.error, item, destLink->hook, ctx.m); | ||||
return (ctx.error); | return (ctx.error); | ||||
} | } | ||||
/* Destination host is not known */ | /* Destination host is not known */ | ||||
ctx.incoming->stats.recvUnknown++; | counter_u64_add(ctx.incoming->stats.recvUnknown, 1); | ||||
} | } | ||||
/* Distribute unknown, multicast, broadcast pkts to all other links */ | /* Distribute unknown, multicast, broadcast pkts to all other links */ | ||||
NG_NODE_FOREACH_HOOK(node, ng_bridge_send_ctx, &ctx, ret); | NG_NODE_FOREACH_HOOK(node, ng_bridge_send_ctx, &ctx, ret); | ||||
/* If we never saw a good link, leave. */ | /* If we never saw a good link, leave. */ | ||||
if (ctx.foundFirst == NULL || ctx.error != 0) { | if (ctx.foundFirst == NULL || ctx.error != 0) { | ||||
NG_FREE_ITEM(item); | NG_FREE_ITEM(item); | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); | const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); | ||||
link_p link = NG_HOOK_PRIVATE(hook); | link_p link = NG_HOOK_PRIVATE(hook); | ||||
/* Remove all hosts associated with this link */ | /* Remove all hosts associated with this link */ | ||||
ng_bridge_remove_hosts(priv, link); | ng_bridge_remove_hosts(priv, link); | ||||
/* Free associated link information */ | /* Free associated link information */ | ||||
counter_u64_free(link->stats.recvOctets); | |||||
counter_u64_free(link->stats.recvPackets); | |||||
counter_u64_free(link->stats.recvMulticasts); | |||||
counter_u64_free(link->stats.recvBroadcasts); | |||||
counter_u64_free(link->stats.recvUnknown); | |||||
counter_u64_free(link->stats.recvRunts); | |||||
counter_u64_free(link->stats.recvInvalid); | |||||
counter_u64_free(link->stats.xmitOctets); | |||||
counter_u64_free(link->stats.xmitPackets); | |||||
counter_u64_free(link->stats.xmitMulticasts); | |||||
counter_u64_free(link->stats.xmitBroadcasts); | |||||
counter_u64_free(link->stats.loopDrops); | |||||
counter_u64_free(link->stats.loopDetects); | |||||
counter_u64_free(link->stats.memoryFailures); | |||||
free(link, M_NETGRAPH_BRIDGE); | free(link, M_NETGRAPH_BRIDGE); | ||||
priv->numLinks--; | priv->numLinks--; | ||||
/* If no more hooks, go away */ | /* If no more hooks, go away */ | ||||
if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) | if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) | ||||
&& (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) | && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook))) | ||||
&& !priv->persistent) { | && !priv->persistent) { | ||||
ng_rmnode_self(NG_HOOK_NODE(hook)); | ng_rmnode_self(NG_HOOK_NODE(hook)); | ||||
▲ Show 20 Lines • Show All 240 Lines • Show Last 20 Lines |
Maybe _kstats?