mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-23 14:52:24 +00:00
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:
parent
e0cb5caef2
commit
f80ec871f6
@ -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)) {
|
||||
|
@ -86,6 +86,7 @@ private:
|
||||
QString myAddress;
|
||||
QString myStatus;
|
||||
QString myVersion;
|
||||
bool firstTimerTick;
|
||||
int pollServiceTimerId;
|
||||
unsigned int numPeers;
|
||||
unsigned int cyclesSinceResponseFromService;
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
163
node/Network.hpp
163
node/Network.hpp
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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") {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user