Make EthernetTap creation occur in a background thread in Network since it's a time consuming operation on Windows. This fixes one of the last remaining Windows problems.

This commit is contained in:
Adam Ierymenko 2014-01-27 23:13:36 -08:00
parent e0cb5caef2
commit f80ec871f6
12 changed files with 239 additions and 105 deletions

View File

@ -121,7 +121,8 @@ MainWindow::MainWindow(QWidget *parent) :
ui->bottomContainerWidget->setVisible(false);
ui->networkListWidget->setVisible(false);
this->pollServiceTimerId = this->startTimer(1000);
this->firstTimerTick = true;
this->pollServiceTimerId = this->startTimer(200);
this->cyclesSinceResponseFromService = 0;
}
@ -133,15 +134,19 @@ MainWindow::~MainWindow()
mainWindow = (MainWindow *)0;
}
void MainWindow::timerEvent(QTimerEvent *event)
void MainWindow::timerEvent(QTimerEvent *event) // event can be null since code also calls this directly
{
event->accept();
if (this->isHidden())
return;
if (pollServiceTimerId < 0)
if (this->pollServiceTimerId < 0)
return;
if (this->firstTimerTick) {
this->firstTimerTick = false;
this->killTimer(this->pollServiceTimerId);
this->pollServiceTimerId = this->startTimer(1500);
}
if (!zeroTierClient) {
std::string authToken;
if (!ZeroTier::Utils::readFile(ZeroTier::Node::LocalClient::authTokenDefaultUserPath().c_str(),authToken)) {

View File

@ -86,6 +86,7 @@ private:
QString myAddress;
QString myStatus;
QString myVersion;
bool firstTimerTick;
int pollServiceTimerId;
unsigned int numPeers;
unsigned int cyclesSinceResponseFromService;

View File

@ -64,6 +64,9 @@ QListWidget.ipAddressList::item {
}
QListWidget.ipAddressList::item:selected {
background: transparent;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid transparent;
}
QListWidget.ipAddressList::item:hover {

View File

@ -336,8 +336,6 @@ EthernetTap::EthernetTap(
}
}
whack(); // turns on IPv6 on OSX
::pipe(_shutdownSignalPipe);
_thread = Thread::start(this);
@ -378,7 +376,7 @@ EthernetTap::~EthernetTap()
#endif // __APPLE__
}
#ifdef __APPLE__
/*
void EthernetTap::whack()
{
const char *ipconfig = UNIX_COMMANDS[ZT_MAC_IPCONFIG_COMMAND];
@ -393,9 +391,7 @@ void EthernetTap::whack()
}
}
}
#else
void EthernetTap::whack() {}
#endif // __APPLE__ / !__APPLE__
*/
void EthernetTap::setDisplayName(const char *dn)
{
@ -979,7 +975,8 @@ EthernetTap::EthernetTap(
_arg(arg),
_tap(INVALID_HANDLE_VALUE),
_injectSemaphore(INVALID_HANDLE_VALUE),
_run(true)
_run(true),
_initialized(false)
{
char subkeyName[4096];
char subkeyClass[4096];
@ -1203,11 +1200,15 @@ EthernetTap::EthernetTap(
// Start background thread that actually performs I/O
_injectSemaphore = CreateSemaphore(NULL,0,1,NULL);
_thread = Thread::start(this);
// Certain functions can now work (e.g. ips())
_initialized = true;
}
EthernetTap::~EthernetTap()
{
_run = false;
ReleaseSemaphore(_injectSemaphore,1,NULL);
Thread::join(_thread);
CloseHandle(_tap);
@ -1237,12 +1238,10 @@ EthernetTap::~EthernetTap()
}
}
void EthernetTap::whack()
{
}
void EthernetTap::setDisplayName(const char *dn)
{
if (!_initialized)
return;
HKEY ifp;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE,(std::string("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}\\") + _myDeviceInstanceId).c_str(),0,KEY_READ|KEY_WRITE,&ifp) == ERROR_SUCCESS) {
RegSetKeyValueA(ifp,"Connection","Name",REG_SZ,(LPCVOID)dn,(DWORD)(strlen(dn)+1));
@ -1252,6 +1251,8 @@ void EthernetTap::setDisplayName(const char *dn)
bool EthernetTap::addIP(const InetAddress &ip)
{
if (!_initialized)
return false;
if (!ip.netmaskBits()) // sanity check... netmask of 0.0.0.0 is WUT?
return false;
@ -1299,6 +1300,8 @@ bool EthernetTap::addIP(const InetAddress &ip)
bool EthernetTap::removeIP(const InetAddress &ip)
{
if (!_initialized)
return false;
try {
MIB_UNICASTIPADDRESS_TABLE *ipt = (MIB_UNICASTIPADDRESS_TABLE *)0;
std::pair<NET_LUID,NET_IFINDEX> ifidx = _findAdapterByGuid(_deviceGuid);
@ -1339,6 +1342,9 @@ std::set<InetAddress> EthernetTap::ips() const
static const InetAddress linkLocalLoopback("fe80::1",64); // what is this and why does Windows assign it?
std::set<InetAddress> addrs;
if (!_initialized)
return addrs;
try {
MIB_UNICASTIPADDRESS_TABLE *ipt = (MIB_UNICASTIPADDRESS_TABLE *)0;
std::pair<NET_LUID,NET_IFINDEX> ifidx = _findAdapterByGuid(_deviceGuid);
@ -1369,6 +1375,8 @@ std::set<InetAddress> EthernetTap::ips() const
void EthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{
if (!_initialized)
return;
if (len > (ZT_IF_MTU))
return;
@ -1398,6 +1406,9 @@ std::string EthernetTap::persistentId() const
bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
{
if (!_initialized)
return false;
std::set<MulticastGroup> newGroups;
// Ensure that groups are added for each IP... this handles the MAC:ADI
@ -1456,7 +1467,7 @@ void EthernetTap::threadMain()
HANDLE wait4[3];
wait4[0] = _injectSemaphore;
wait4[1] = _tapOvlRead.hEvent;
wait4[2] = _tapOvlWrite.hEvent;
wait4[2] = _tapOvlWrite.hEvent; // only included if writeInProgress is true
ReadFile(_tap,_tapReadBuf,sizeof(_tapReadBuf),NULL,&_tapOvlRead);
bool writeInProgress = false;

View File

@ -94,11 +94,6 @@ public:
*/
~EthernetTap();
/**
* Perform OS dependent actions on network configuration change detection
*/
void whack();
/**
* Set the user display name for this connection
*
@ -245,6 +240,7 @@ private:
std::queue< std::pair< Array<char,ZT_IF_MTU + 32>,unsigned int > > _injectPending;
Mutex _injectPending_m;
volatile bool _run;
volatile bool _initialized;
#endif
};

View File

@ -46,6 +46,7 @@ const char *Network::statusString(const Status s)
throw()
{
switch(s) {
case NETWORK_INITIALIZING: return "INITIALIZING";
case NETWORK_WAITING_FOR_FIRST_AUTOCONF: return "WAITING_FOR_FIRST_AUTOCONF";
case NETWORK_OK: return "OK";
case NETWORK_ACCESS_DENIED: return "ACCESS_DENIED";
@ -56,6 +57,8 @@ const char *Network::statusString(const Status s)
Network::~Network()
{
Thread::join(_setupThread);
std::string devPersistentId(_tap->persistentId());
delete _tap;
@ -73,46 +76,50 @@ Network::~Network()
SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t id)
{
// Tag to identify tap device -- used on some OSes like Windows
char tag[32];
Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)id);
/* We construct Network via a static method to ensure that it is immediately
* wrapped in a SharedPtr<>. Otherwise if there is traffic on the Ethernet
* tap device, a SharedPtr<> wrap can occur in the Ethernet frame handler
* that then causes the Network instance to be deleted before it is finished
* being constructed. C++ edge cases, how I love thee. */
// We construct Network via a static method to ensure that it is immediately
// wrapped in a SharedPtr<>. Otherwise if there is traffic on the Ethernet
// tap device, a SharedPtr<> wrap can occur in the Ethernet frame handler
// that then causes the Network instance to be deleted before it is finished
// being constructed. C++ edge cases, how I love thee.
SharedPtr<Network> nw(new Network());
nw->_id = id;
nw->_ready = false; // disable handling of Ethernet frames during construct
nw->_mac = renv->identity.address().toMAC();
nw->_r = renv;
nw->_tap = new EthernetTap(renv,tag,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,nw.ptr());
nw->_tap = (EthernetTap *)0;
nw->_lastConfigUpdate = 0;
nw->_status = NETWORK_WAITING_FOR_FIRST_AUTOCONF;
nw->_destroyOnDelete = false;
nw->_netconfFailure = NETCONF_FAILURE_NONE;
if (nw->controller() == renv->identity.address()) // netconf masters can't really join networks
throw std::runtime_error("cannot join a network for which I am the netconf master");
nw->_restoreState();
nw->_ready = true; // enable handling of Ethernet frames
nw->requestConfiguration();
nw->_setupThread = Thread::start<Network>(nw.ptr());
return nw;
}
void Network::setConfiguration(const Dictionary &conf,bool saveToDisk)
bool Network::setConfiguration(const Dictionary &conf,bool saveToDisk)
{
Mutex::Lock _l(_lock);
EthernetTap *t = _tap;
if (!t) {
TRACE("BUG: setConfiguration() called while tap is null!");
return false; // can't accept config in initialization state
}
try {
SharedPtr<NetworkConfig> newConfig(new NetworkConfig(conf));
if ((newConfig->networkId() == _id)&&(newConfig->issuedTo() == _r->identity.address())) {
Mutex::Lock _l(_lock);
_config = newConfig;
if (newConfig->staticIps().size())
_tap->setIps(newConfig->staticIps());
_tap->setDisplayName((std::string("ZeroTier One [") + newConfig->name() + "]").c_str());
t->setIps(newConfig->staticIps());
t->setDisplayName((std::string("ZeroTier One [") + newConfig->name() + "]").c_str());
_lastConfigUpdate = Utils::now();
_status = NETWORK_OK;
_netconfFailure = NETCONF_FAILURE_NONE;
if (saveToDisk) {
std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".conf");
@ -122,6 +129,8 @@ void Network::setConfiguration(const Dictionary &conf,bool saveToDisk)
Utils::lockDownFile(confPath.c_str(),false);
}
}
return true;
} else {
LOG("ignored invalid configuration for network %.16llx (configuration contains mismatched network ID or issued-to address)",(unsigned long long)_id);
}
@ -130,10 +139,15 @@ void Network::setConfiguration(const Dictionary &conf,bool saveToDisk)
} catch ( ... ) {
LOG("ignored invalid configuration for network %.16llx (unknown exception)",(unsigned long long)_id);
}
return false;
}
void Network::requestConfiguration()
{
if (!_tap)
return; // don't bother requesting until we are initialized
if (controller() == _r->identity.address()) {
// netconf master cannot be a member of its own nets
LOG("unable to request network configuration for network %.16llx: I am the network master, cannot query self",(unsigned long long)_id);
@ -190,6 +204,7 @@ bool Network::isAllowed(const Address &peer) const
void Network::clean()
{
Mutex::Lock _l(_lock);
if ((_config)&&(_config->isOpen())) {
// Open (public) networks do not track certs or cert pushes at all.
_membershipCertificates.clear();
@ -215,7 +230,7 @@ void Network::clean()
void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data)
{
if (!((Network *)arg)->isUp())
if (((Network *)arg)->status() != NETWORK_OK)
return;
const RuntimeEnvironment *_r = ((Network *)arg)->_r;
@ -250,6 +265,31 @@ void Network::_pushMembershipCertificate(const Address &peer,bool force,uint64_t
}
}
void Network::threadMain()
{
try {
// Setup thread -- this exits when tap is constructed. It's here
// because opening the tap can take some time on some platforms.
char tag[32];
Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)_id);
_tap = new EthernetTap(_r,tag,_mac,ZT_IF_MTU,&_CBhandleTapData,this);
} catch (std::exception &exc) {
LOG("network %.16llx failed to initialize: %s",_id,exc.what());
_netconfFailure = NETCONF_FAILURE_INIT_FAILED;
} catch ( ... ) {
LOG("network %.16llx failed to initialize: unknown error",_id);
_netconfFailure = NETCONF_FAILURE_INIT_FAILED;
}
try {
_restoreState();
requestConfiguration();
} catch ( ... ) {
TRACE("BUG: exception in network setup thread in _restoreState() or requestConfiguration()!");
_lastConfigUpdate = 0; // call requestConfiguration() again
}
}
void Network::_restoreState()
{
if (!_id)

View File

@ -53,6 +53,7 @@
#include "BandwidthAccount.hpp"
#include "NetworkConfig.hpp"
#include "CertificateOfMembership.hpp"
#include "Thread.hpp"
namespace ZeroTier {
@ -91,6 +92,9 @@ private:
* If there is no saved state, a dummy .conf is created on disk to remember
* this network across restarts.
*
* This can be a time consuming operation on some platforms (cough Windows
* cough).
*
* @param renv Runtime environment
* @param id Network ID
* @return Reference counted pointer to new network
@ -109,10 +113,12 @@ public:
*/
enum Status
{
NETWORK_INITIALIZING,
NETWORK_WAITING_FOR_FIRST_AUTOCONF,
NETWORK_OK,
NETWORK_ACCESS_DENIED,
NETWORK_NOT_FOUND
NETWORK_NOT_FOUND,
NETWORK_INITIALIZATION_FAILED
};
/**
@ -127,11 +133,6 @@ public:
*/
inline uint64_t id() const throw() { return _id; }
/**
* @return Ethernet tap
*/
inline EthernetTap &tap() throw() { return *_tap; }
/**
* @return Address of network's controlling node
*/
@ -155,7 +156,10 @@ public:
inline bool updateMulticastGroups()
{
Mutex::Lock _l(_lock);
return _tap->updateMulticastGroups(_multicastGroups);
EthernetTap *t = _tap;
if (t)
return _tap->updateMulticastGroups(_multicastGroups);
return false;
}
/**
@ -173,10 +177,34 @@ public:
* This is called by PacketDecoder when an update comes over the wire, or
* internally when an old config is reloaded from disk.
*
* This also cancels any netconf failure flags.
*
* The network can't accept configuration when in INITIALIZATION state,
* and so in that state this will just return false.
*
* @param conf Configuration in key/value dictionary form
* @param saveToDisk IF true (default), write config to disk
* @return True if configuration was accepted
*/
void setConfiguration(const Dictionary &conf,bool saveToDisk = true);
bool setConfiguration(const Dictionary &conf,bool saveToDisk = true);
/**
* Set netconf failure to 'access denied'.
*/
inline void setAccessDenied()
{
Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_ACCESS_DENIED;
}
/**
* Set netconf failure to 'not found'.
*/
inline void setNotFound()
{
Mutex::Lock _l(_lock);
_netconfFailure = NETCONF_FAILURE_NOT_FOUND;
}
/**
* Causes this network to request an updated configuration from its master node now
@ -223,16 +251,6 @@ public:
*/
inline uint64_t lastConfigUpdate() const throw() { return _lastConfigUpdate; }
/**
* Force this network's status to a particular state based on config reply
*/
inline void forceStatusTo(const Status s)
throw()
{
Mutex::Lock _l(_lock);
_status = s;
}
/**
* @return Status of this network
*/
@ -240,17 +258,20 @@ public:
throw()
{
Mutex::Lock _l(_lock);
return _status;
}
/**
* @return True if this network is in "OK" status and can accept traffic from us
*/
inline bool isUp() const
throw()
{
Mutex::Lock _l(_lock);
return ((_config)&&(_status == NETWORK_OK)&&(_ready));
if (_tap) {
switch(_netconfFailure) {
case NETCONF_FAILURE_ACCESS_DENIED:
return NETWORK_ACCESS_DENIED;
case NETCONF_FAILURE_NOT_FOUND:
return NETWORK_NOT_FOUND;
case NETCONF_FAILURE_NONE:
if (_lastConfigUpdate > 0)
return NETWORK_OK;
else return NETWORK_WAITING_FOR_FIRST_AUTOCONF;
}
} else if (_netconfFailure == NETCONF_FAILURE_INIT_FAILED)
return NETWORK_INITIALIZATION_FAILED;
else return NETWORK_INITIALIZING;
}
/**
@ -307,6 +328,73 @@ public:
return _config;
}
/**
* Thread main method; do not call elsewhere
*/
void threadMain()
throw();
/**
* Inject a frame into tap (if it's created)
*
* @param from Origin MAC
* @param to Destination MC
* @param etherType Ethernet frame type
* @param data Frame data
* @param len Frame length
*/
inline void tapPut(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{
EthernetTap *t = _tap;
if (t)
t->put(from,to,etherType,data,len);
}
/**
* Inject a frame into tap with local MAC as destination MAC (if it's created)
*
* @param from Origin MAC
* @param etherType Ethernet frame type
* @param data Frame data
* @param len Frame length
*/
inline void tapPut(const MAC &from,unsigned int etherType,const void *data,unsigned int len)
{
EthernetTap *t = _tap;
if (t)
t->put(from,t->mac(),etherType,data,len);
}
/**
* @return Tap device name or empty string if still initializing
*/
inline std::string tapDeviceName() const
{
EthernetTap *t = _tap;
if (t)
return t->deviceName();
else return std::string();
}
/**
* @return Ethernet MAC address for this network's local interface
*/
inline const MAC &mac() const
{
return _mac;
}
/**
* @return Set of currently assigned IP addresses
*/
inline std::set<InetAddress> ips() const
{
EthernetTap *t = _tap;
if (t)
return t->ips();
return std::set<InetAddress>();
}
private:
static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data);
@ -315,22 +403,23 @@ private:
void _dumpMulticastCerts();
uint64_t _id;
MAC _mac;
const RuntimeEnvironment *_r;
EthernetTap *_tap;
EthernetTap *volatile _tap;
std::set<MulticastGroup> _multicastGroups;
std::map< std::pair<Address,MulticastGroup>,BandwidthAccount > _multicastRateAccounts;
std::map<Address,CertificateOfMembership> _membershipCertificates;
std::map<Address,uint64_t> _lastPushedMembershipCertificate;
SharedPtr<NetworkConfig> _config;
volatile uint64_t _lastConfigUpdate;
volatile Status _status;
volatile bool _destroyOnDelete;
volatile bool _ready;
volatile enum {
NETCONF_FAILURE_NONE,
NETCONF_FAILURE_ACCESS_DENIED,
NETCONF_FAILURE_NOT_FOUND,
NETCONF_FAILURE_INIT_FAILED
} _netconfFailure;
Thread _setupThread;
Mutex _lock;
AtomicCounter __refCount;

View File

@ -545,7 +545,6 @@ Node::ReasonForTermination Node::run()
LOG("netconf fingerprint change: %.16llx != %.16llx, resyncing with network",networkConfigurationFingerprint,fp);
networkConfigurationFingerprint = fp;
resynchronize = true;
_r->nc->whackAllTaps(); // call whack() on all tap devices -- hack, might go away
}
}

View File

@ -115,14 +115,6 @@ NodeConfig::~NodeConfig()
{
}
void NodeConfig::whackAllTaps()
{
std::vector< SharedPtr<Network> > nwlist;
Mutex::Lock _l(_networks_m);
for(std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n)
n->second->tap().whack();
}
void NodeConfig::clean()
{
Mutex::Lock _l(_networks_m);
@ -205,7 +197,7 @@ std::vector<std::string> NodeConfig::execute(const char *command)
_P("200 listnetworks <nwid> <name> <status> <config age> <type> <dev> <ips>");
for(std::map< uint64_t,SharedPtr<Network> >::const_iterator nw(_networks.begin());nw!=_networks.end();++nw) {
std::string tmp;
std::set<InetAddress> ips(nw->second->tap().ips());
std::set<InetAddress> ips(nw->second->ips());
for(std::set<InetAddress>::iterator i(ips.begin());i!=ips.end();++i) {
if (tmp.length())
tmp.push_back(',');
@ -219,13 +211,14 @@ std::vector<std::string> NodeConfig::execute(const char *command)
age = 0;
age /= 1000;
std::string dn(nw->second->tapDeviceName());
_P("200 listnetworks %.16llx %s %s %lld %s %s %s",
(unsigned long long)nw->first,
((nconf) ? nconf->name().c_str() : "?"),
Network::statusString(nw->second->status()),
age,
((nconf) ? (nconf->isOpen() ? "public" : "private") : "?"),
nw->second->tap().deviceName().c_str(),
(dn.length() > 0) ? dn.c_str() : "?",
((tmp.length() > 0) ? tmp.c_str() : "-"));
}
} else if (cmd[0] == "join") {

View File

@ -90,11 +90,6 @@ public:
return nwlist;
}
/**
* Call whack() on all networks' tap devices
*/
void whackAllTaps();
/**
* Perform cleanup and possibly update saved state
*/
@ -117,8 +112,11 @@ public:
{
std::set<std::string> tapDevs;
Mutex::Lock _l(_networks_m);
for(std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n)
tapDevs.insert(n->second->tap().deviceName());
for(std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
std::string dn(n->second->tapDeviceName());
if (dn.length())
tapDevs.insert(dn);
}
return tapDevs;
}

View File

@ -139,7 +139,7 @@ bool PacketDecoder::_doERROR(const RuntimeEnvironment *_r,const SharedPtr<Peer>
} else if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
SharedPtr<Network> network(_r->nc->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
if ((network)&&(network->controller() == source()))
network->forceStatusTo(Network::NETWORK_NOT_FOUND);
network->setNotFound();
}
break;
case Packet::ERROR_IDENTITY_COLLISION:
@ -154,7 +154,7 @@ bool PacketDecoder::_doERROR(const RuntimeEnvironment *_r,const SharedPtr<Peer>
case Packet::ERROR_NETWORK_ACCESS_DENIED_: {
SharedPtr<Network> network(_r->nc->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
if ((network)&&(network->controller() == source()))
network->forceStatusTo(Network::NETWORK_ACCESS_DENIED);
network->setAccessDenied();
} break;
default:
break;
@ -416,7 +416,7 @@ bool PacketDecoder::_doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer>
unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE);
if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) {
if (network->config()->permitsEtherType(etherType)) {
network->tap().put(source().toMAC(),network->tap().mac(),etherType,data() + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD);
network->tapPut(source().toMAC(),etherType,data() + ZT_PROTO_VERB_FRAME_IDX_PAYLOAD,size() - ZT_PROTO_VERB_FRAME_IDX_PAYLOAD);
} else {
TRACE("dropped FRAME from %s: ethernet type %u not allowed on network %.16llx",source().toString().c_str(),etherType,(unsigned long long)network->id());
return true;
@ -677,7 +677,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
TRACE("dropped MULTICAST_FRAME from %s(%s): rate limits exceeded for sender %s",source().toString().c_str(),_remoteAddress.toString().c_str(),origin.toString().c_str());
return true;
} else {
network->tap().put(sourceMac,dest.mac(),etherType,frame,frameLen);
network->tapPut(sourceMac,dest.mac(),etherType,frame,frameLen);
}
}
}

View File

@ -86,12 +86,11 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
if (!nconf)
return;
if (to == network->tap().mac()) {
LOG("%s: frame received from self, ignoring (bridge loop? OS bug?)",network->tap().deviceName().c_str());
if (to == network->mac()) {
LOG("%s: frame received from self, ignoring (bridge loop? OS bug?)",network->tapDeviceName().c_str());
return;
}
if (from != network->tap().mac()) {
if (from != network->mac()) {
LOG("ignored tap: %s -> %s %s (bridging not supported)",from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType));
return;
}