Index: sys/netgraph/ng_bridge.c =================================================================== --- sys/netgraph/ng_bridge.c +++ sys/netgraph/ng_bridge.c @@ -793,56 +793,15 @@ } /* 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. * This is safe without locking, because it's * the only operation during shared access. */ host->staleness = 0; - /* Did host jump to a different link? */ - if (host->link != ctx.incoming) { - /* - * If the host's old link was recently established - * on the old link and it's already jumped to a new - * link, declare a loopback condition. - */ - if (host->age < priv->conf.minStableAge) { - /* Log the problem */ - if (priv->conf.debugLevel >= 2) { - struct ifnet *ifp = ctx.m->m_pkthdr.rcvif; - char suffix[32]; - - if (ifp != NULL) - snprintf(suffix, sizeof(suffix), - " (%s)", ifp->if_xname); - else - *suffix = '\0'; - log(LOG_WARNING, "ng_bridge: %s:" - " loopback detected on %s%s\n", - ng_bridge_nodename(node), - NG_HOOK_NAME(hook), suffix); - } - - /* Mark link as linka non grata */ - ctx.incoming->loopCount = priv->conf.loopTimeout; - counter_u64_add(ctx.incoming->stats.loopDetects, 1); - - /* Forget all hosts on this link */ - ng_bridge_remove_hosts(priv, ctx.incoming); - - /* Drop packet */ - counter_u64_add(ctx.incoming->stats.loopDrops, 1); - NG_FREE_ITEM(item); - NG_FREE_M(ctx.m); - return (ELOOP); /* XXX appropriate? */ - } - - /* Move host over to new link */ - host->link = ctx.incoming; - host->age = 0; - } - } else if (ctx.incoming->learnMac) { + if ((host == NULL && ctx.incoming->learnMac) || + (host != NULL && host->link != ctx.incoming)) { struct ng_mesg *msg; struct ng_bridge_move_host *mh; int error = 0; @@ -865,6 +824,16 @@ counter_u64_add(ctx.incoming->stats.memoryFailures, 1); } + if (host != NULL && host->link != ctx.incoming) { + if (host->age < priv->conf.minStableAge) { + /* Drop packet on instable links */ + counter_u64_add(ctx.incoming->stats.loopDrops, 1); + NG_FREE_ITEM(item); + NG_FREE_M(ctx.m); + return (ELOOP); /* XXX appropriate? */ + } + } + /* Run packet through ipfw processing, if enabled */ #if 0 if (priv->conf.ipfw[linkNum] && V_fw_enable && V_ip_fw_chk_ptr != NULL) { @@ -1016,6 +985,36 @@ const int bucket = HASH(addr, priv->hashMask); struct ng_bridge_host *host; + if ((host = ng_bridge_get(priv, addr)) != NULL) { + /* Did host jump to a different link? */ + if (host->link != link) { + /* + * If the host's old link was recently established + * on the old link and it's already jumped to a new + * link, declare a loopback condition. + */ + if (host->age < priv->conf.minStableAge) { + /* Log the problem */ + if (priv->conf.debugLevel >= 2) + log(LOG_WARNING, "ng_bridge: %s:" + " loopback detected on %s\n", + ng_bridge_nodename(priv->node), + NG_HOOK_NAME(link->hook)); + + /* Mark link as linka non grata */ + link->loopCount += priv->conf.loopTimeout; + counter_u64_add(link->stats.loopDetects, 1); + + /* Forget all hosts on this link */ + ng_bridge_remove_hosts(priv, link); + } + + /* Move host over to new link */ + host->link = link; + host->age = 0; + } + } + #ifdef INVARIANTS /* Assert that entry does not already exist in hashtable */ SLIST_FOREACH(host, &priv->tab[bucket], next) {