59#include <sys/kernel.h>
61#include <sys/malloc.h>
64#include <sys/rwlock.h>
65#include <sys/syslog.h>
66#include <sys/socket.h>
69#include <sys/counter.h>
72#include <net/if_var.h>
73#include <net/ethernet.h>
76#include <netinet/in.h>
78#include <netinet/ip_fw.h>
85#ifdef NG_SEPARATE_MALLOC
87 "netgraph bridge node");
89#define M_NETGRAPH_BRIDGE M_NETGRAPH
122 struct ng_bridge_bucket *
tab;
167 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
170#define ETHER_EQUAL(a,b) (((const u_int32_t *)(a))[0] \
171 == ((const u_int32_t *)(b))[0] \
172 && ((const u_int16_t *)(a))[2] \
173 == ((const u_int16_t *)(b))[2])
176#define MIN_BUCKETS (1 << 5)
177#define MAX_BUCKETS (1 << 14)
180#define DEFAULT_LOOP_TIMEOUT 60
181#define DEFAULT_MAX_STALENESS (15 * 60)
182#define DEFAULT_MIN_STABLE_AGE 1
193 const u_char *start,
const u_char *buf)
349 priv->conf.debugLevel = 1;
353 priv->sendUnknown = 1;
379 if (strlen(
name) <= strlen(prefix))
382 isUplink = (
name[0] ==
'u');
387 linkNum = strtoul(
name + strlen(prefix), NULL, 10);
389 snprintf(linkName,
sizeof(linkName),
"%s%u", prefix, linkNum);
390 if (strcmp(linkName,
name) != 0)
393 if (linkNum == 0 && isUplink)
403#define NG_BRIDGE_COUNTER_ALLOC(f) do { \
404 link->stats.f = counter_u64_alloc(M_NOWAIT); \
405 if (link->stats.f == NULL) \
421#undef NG_BRIDGE_COUNTER_ALLOC
427 if (
priv->numLinks == 0)
428 priv->sendUnknown = 0;
559 linkNum = *((int32_t *)msg->
data);
561 snprintf(linkName,
sizeof(linkName),
564 snprintf(linkName,
sizeof(linkName),
567 if ((hook =
ng_findhook(node, linkName)) == NULL) {
578 sizeof(link->
stats), M_NOWAIT);
584#define
FETCH(x) rs->x = counter_u64_fetch(link->
stats.x)
612 + (
priv->numHosts *
sizeof(*ary->
hosts)), M_NOWAIT);
619 for (bucket = 0; bucket <
priv->numBuckets; bucket++) {
620 SLIST_FOREACH(host, &
priv->tab[bucket], next) {
636 priv->persistent = 1;
690 size_t len = m->m_pkthdr.len;
699 counter_u64_add(dst->stats.memoryFailures, 1);
708 counter_u64_add(dst->stats.xmitPackets, 1);
709 counter_u64_add(dst->stats.xmitOctets, len);
714 counter_u64_add(dst->stats.xmitMulticasts, 1);
717 counter_u64_add(dst->stats.xmitBroadcasts, 1);
732 struct mbuf *m2 = NULL;
758 m2 = m_dup(ctx->
m, M_NOWAIT);
761 ctx->
error = ENOBUFS;
778 struct ether_header *eh;
786 if (ctx.
m->m_pkthdr.len < ETHER_HDR_LEN) {
792 if (ctx.
m->m_len < ETHER_HDR_LEN && !(ctx.
m = m_pullup(ctx.
m, ETHER_HDR_LEN))) {
797 eh = mtod(ctx.
m,
struct ether_header *);
798 if ((eh->ether_shost[0] & 1) != 0) {
816 if ((ctx.
manycast = (eh->ether_dhost[0] & 1)) != 0) {
830 if (__predict_false(host->
staleness > 0))
840 sizeof(*mh), M_NOWAIT);
850 memcpy(mh->
addr, eh->ether_shost,
sizeof(mh->
addr));
858 if (host->
age <
priv->conf.minStableAge) {
869 if (
priv->conf.ipfw[linkNum] && V_fw_enable && V_ip_fw_chk_ptr != NULL) {
929 KASSERT(
priv->numLinks == 0 &&
priv->numHosts == 0,
930 (
"%s: numLinks=%d numHosts=%d",
931 __func__,
priv->numLinks,
priv->numHosts));
959 && !
priv->persistent) {
972#define HASH(addr,mask) ( (((const u_int16_t *)(addr))[0] \
973 ^ ((const u_int16_t *)(addr))[1] \
974 ^ ((const u_int16_t *)(addr))[2]) & (mask) )
985 SLIST_FOREACH(host, &
priv->tab[bucket], next) {
1008 if (host->
age >=
priv->conf.minStableAge) {
1018 if (
priv->conf.debugLevel >= 2)
1019 log(LOG_WARNING,
"ng_bridge: %s:"
1020 " loopback detected on %s\n",
1037 bcopy(
addr, host->
addr, ETHER_ADDR_LEN);
1043 SLIST_INSERT_HEAD(&
priv->tab[bucket], host, next);
1061 struct ng_bridge_bucket *newTab;
1062 int oldBucket, newBucket;
1067 if (
priv->numHosts >
priv->numBuckets
1069 newNumBuckets =
priv->numBuckets << 1;
1070 else if (
priv->numHosts < (
priv->numBuckets >> 2)
1072 newNumBuckets =
priv->numBuckets >> 2;
1075 newMask = newNumBuckets - 1;
1078 newTab = malloc(newNumBuckets *
sizeof(*newTab),
1084 for (oldBucket = 0; oldBucket <
priv->numBuckets; oldBucket++) {
1085 struct ng_bridge_bucket *
const oldList = &
priv->tab[oldBucket];
1087 while (!SLIST_EMPTY(oldList)) {
1089 = SLIST_FIRST(oldList);
1091 SLIST_REMOVE_HEAD(oldList, next);
1092 newBucket =
HASH(host->
addr, newMask);
1093 SLIST_INSERT_HEAD(&newTab[newBucket], host, next);
1098 if (
priv->conf.debugLevel >= 3) {
1099 log(LOG_INFO,
"ng_bridge: %s: table size %d -> %d\n",
1101 priv->numBuckets, newNumBuckets);
1104 priv->numBuckets = newNumBuckets;
1105 priv->hashMask = newMask;
1123 for (bucket = 0; bucket <
priv->numBuckets; bucket++) {
1126 while (*hptr != NULL) {
1130 *hptr = SLIST_NEXT(host, next);
1134 hptr = &SLIST_NEXT(host, next);
1156 log(LOG_INFO,
"ng_bridge: %s:"
1157 " restoring looped back %s\n",
1174 for (bucket = 0; bucket <
priv->numBuckets; bucket++) {
1177 while (*hptr != NULL) {
1182 *hptr = SLIST_NEXT(host, next);
1186 if (host->
age < 0xffff)
1188 hptr = &SLIST_NEXT(host, next);
1193 KASSERT(
priv->numHosts == counter,
1194 (
"%s: hosts: %d != %d", __func__,
priv->numHosts, counter));
1202 KASSERT(
priv->numLinks == counter,
1203 (
"%s: links: %d != %d", __func__,
priv->numLinks, counter));
#define NG_HOOK_NODE(hook)
#define NG_PEER_NODE(hook)
#define NG_NODE_FOREACH_HOOK(node, fn, arg, rethook)
int ng_rcvmsg_t(node_p node, item_p item, hook_p lasthook)
int ng_disconnect_t(hook_p hook)
#define NG_NODE_SET_PRIVATE(node, val)
#define NG_RESPOND_MSG(error, here, item, resp)
#define NG_NODE_IS_VALID(node)
struct ng_node const * node_cp
#define NG_NODE_HAS_NAME(node)
#define NG_NODE_UNREF(node)
#define NG_NODE_NAME(node)
#define NG_HOOK_SET_PRIVATE(hook, val)
int ng_rmnode_self(node_p here)
#define ng_callout_init(c)
#define NG_FWD_NEW_DATA(error, item, hook, m)
#define NG_SEND_DATA_ONLY(error, hook, m)
#define NG_SEND_MSG_ID(error, here, msg, ID, retaddr)
int ng_rcvdata_t(hook_p hook, item_p item)
int ng_shutdown_t(node_p node)
int ng_uncallout(struct callout *c, node_p node)
#define NG_HOOK_NAME(hook)
#define NG_FREE_ITEM(item)
int ng_constructor_t(node_p node)
ng_ID_t ng_node2ID(node_cp node)
#define NG_NODE_NUMHOOKS(node)
#define NGI_GET_MSG(i, m)
#define NG_NODE_PRIVATE(node)
int ng_callout(struct callout *c, node_p node, hook_p hook, int ticks, ng_item_fn *fn, void *arg1, int arg2)
int ng_newhook_t(node_p node, hook_p hook, const char *name)
hook_p ng_findhook(node_p node, const char *name)
#define NG_HOOK_PRIVATE(hook)
static int ng_bridge_send_ctx(hook_p dst, void *arg)
NETGRAPH_INIT(bridge, &ng_bridge_typestruct)
static void ng_bridge_remove_hosts(priv_p priv, link_p link)
static const struct ng_parse_type ng_bridge_hary_type
static const struct ng_parse_type ng_bridge_stats_type
#define ETHER_EQUAL(a, b)
static int ng_bridge_getTableLength(const struct ng_parse_type *type, const u_char *start, const u_char *buf)
struct ng_bridge_link const * link_cp
struct ng_bridge_private const * priv_cp
static const struct ng_parse_type ng_bridge_host_ary_type
static int ng_bridge_reset_link(hook_p hook, void *arg __unused)
static const struct ng_parse_struct_field ng_bridge_move_host_type_fields[]
static int ng_bridge_unmute(hook_p hook, void *arg)
static ng_shutdown_t ng_bridge_shutdown
static const struct ng_parse_struct_field ng_bridge_host_type_fields[]
static ng_constructor_t ng_bridge_constructor
static const struct ng_parse_struct_field ng_bridge_host_ary_type_fields[]
static ng_newhook_t ng_bridge_newhook
static const struct ng_parse_type ng_bridge_move_host_type
static ng_disconnect_t ng_bridge_disconnect
static const struct ng_parse_struct_field ng_bridge_stats_type_fields[]
static ng_rcvdata_t ng_bridge_rcvdata
static void ng_bridge_free_link(link_p link)
static int ng_bridge_send_data(link_cp dst, int manycast, struct mbuf *m, item_p item)
static void ng_bridge_clear_link_stats(struct ng_bridge_link_kernel_stats *p)
static void ng_bridge_rehash(priv_p priv)
static struct ng_bridge_host * ng_bridge_get(priv_cp priv, const u_char *addr)
static ng_rcvmsg_t ng_bridge_rcvmsg
static const struct ng_parse_struct_field ng_bridge_config_type_fields[]
#define M_NETGRAPH_BRIDGE
#define DEFAULT_MAX_STALENESS
static const struct ng_parse_type ng_bridge_host_type
#define DEFAULT_MIN_STABLE_AGE
static const char * ng_bridge_nodename(node_cp node)
static int ng_bridge_put(priv_p priv, const u_char *addr, link_p link)
static const struct ng_cmdlist ng_bridge_cmdlist[]
SLIST_HEAD(ng_bridge_bucket, ng_bridge_host)
static struct ng_type ng_bridge_typestruct
#define DEFAULT_LOOP_TIMEOUT
static const struct ng_parse_array_info ng_bridge_hary_type_info
static const struct ng_parse_type ng_bridge_config_type
static const u_char ng_bridge_bcast_addr[ETHER_ADDR_LEN]
struct ng_bridge_private * priv_p
static void ng_bridge_timeout(node_p node, hook_p hook, void *arg1, int arg2)
#define NG_BRIDGE_COUNTER_ALLOC(f)
#define NG_BRIDGE_STATS_TYPE_INFO
#define NG_BRIDGE_NODE_TYPE
#define NG_BRIDGE_HOST_ARY_TYPE_INFO(harytype)
#define NG_BRIDGE_CONFIG_TYPE_INFO
#define NG_BRIDGE_HOOK_UPLINK_PREFIX
@ NGM_BRIDGE_SET_PERSISTENT
@ NGM_BRIDGE_GETCLR_STATS
#define NG_BRIDGE_MOVE_HOST_TYPE_INFO(entype)
#define NGM_BRIDGE_COOKIE
#define NG_BRIDGE_HOOK_LINK_PREFIX
#define NG_BRIDGE_HOST_TYPE_INFO(entype)
MALLOC_DEFINE(M_NG_CCATM, "ng_ccatm", "netgraph uni api node")
#define NG_MKRESPONSE(rsp, msg, len, how)
#define NG_MKMESSAGE(msg, cookie, cmdid, len, how)
const struct ng_parse_type ng_parse_enaddr_type
const struct ng_parse_type ng_parse_array_type
const struct ng_parse_type ng_parse_struct_type
const struct ng_parse_type ng_parse_uint32_type
struct ng_bridge_hostent hosts[]
counter_u64_t xmitPackets
counter_u64_t recvMulticasts
counter_u64_t xmitMulticasts
counter_u64_t recvBroadcasts
counter_u64_t xmitBroadcasts
counter_u64_t recvPackets
counter_u64_t recvInvalid
counter_u64_t recvUnknown
counter_u64_t memoryFailures
struct ng_bridge_link_kernel_stats stats
u_char addr[ETHER_ADDR_LEN]
struct ng_bridge_bucket * tab
struct ng_bridge_config conf
struct ng_mesg::ng_msghdr header