summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node/EthernetTap.cpp47
-rw-r--r--node/Network.cpp28
-rw-r--r--node/Network.hpp7
-rw-r--r--node/NodeConfig.cpp4
4 files changed, 65 insertions, 21 deletions
diff --git a/node/EthernetTap.cpp b/node/EthernetTap.cpp
index 86e96f33..d2302e3f 100644
--- a/node/EthernetTap.cpp
+++ b/node/EthernetTap.cpp
@@ -234,6 +234,7 @@ EthernetTap::EthernetTap(
_fd(0)
{
char procpath[128];
+ struct stat sbuf;
Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
if (mtu > 4096)
@@ -246,13 +247,19 @@ EthernetTap::EthernetTap(
struct ifreq ifr;
memset(&ifr,0,sizeof(ifr));
- { // pick an unused device name
+ // Try to recall our last device name, or pick an unused one if that fails.
+ bool recalledDevice = false;
+ if ((tag)&&(tag[0])) {
+ Utils::scopy(ifr.ifr_name,sizeof(ifr.ifr_name),tag);
+ Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.fr_name);
+ recalledDevice = (stat(procpath,&sbuf) != 0);
+ }
+ if (!recalledDevice) {
int devno = 0;
- struct stat sbuf;
do {
Utils::snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"zt%d",devno++);
Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
- } while (stat(procpath,&sbuf) == 0);
+ } while (stat(procpath,&sbuf) == 0); // try zt#++ until we find one that does not exist
}
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
@@ -359,17 +366,33 @@ EthernetTap::EthernetTap(
if (stat("/dev/zt0",&stattmp))
throw std::runtime_error("/dev/zt# tap devices do not exist and unable to load kernel extension");
- // Open the first available device (ones in use will fail with resource busy)
- for(int i=0;i<256;++i) {
- Utils::snprintf(devpath,sizeof(devpath),"/dev/zt%d",i);
- if (stat(devpath,&stattmp))
- throw std::runtime_error("no more TAP devices available");
- _fd = ::open(devpath,O_RDWR);
- if (_fd > 0) {
- Utils::snprintf(_dev,sizeof(_dev),"zt%d",i);
- break;
+ // Try to reopen the last device we had, if we had one and it's still unused.
+ bool recalledDevice = false;
+ if ((tag)&&(tag[0])) {
+ Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tag);
+ if (stat(devpath,&stattmp) == 0) {
+ _fd = ::open(devpath,O_RDWR);
+ if (_fd > 0) {
+ Utils::scopy(_dev,sizeof(_dev),tag);
+ recalledDevice = true;
+ }
}
}
+
+ // Open the first unused tap device if we didn't recall a previous one.
+ if (!recalledDevice) {
+ for(int i=0;i<256;++i) {
+ Utils::snprintf(devpath,sizeof(devpath),"/dev/zt%d",i);
+ if (stat(devpath,&stattmp))
+ throw std::runtime_error("no more TAP devices available");
+ _fd = ::open(devpath,O_RDWR);
+ if (_fd > 0) {
+ Utils::snprintf(_dev,sizeof(_dev),"zt%d",i);
+ break;
+ }
+ }
+ }
+
if (_fd <= 0)
throw std::runtime_error("unable to open TAP device or no more devices available");
diff --git a/node/Network.cpp b/node/Network.cpp
index db252f73..19190207 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -75,7 +75,7 @@ Network::~Network()
}
}
-SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t id)
+SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,NodeConfig *nc,uint64_t 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
@@ -85,6 +85,7 @@ SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t
SharedPtr<Network> nw(new Network());
nw->_id = id;
+ nw->_nc = nc;
nw->_mac = renv->identity.address().toMAC();
nw->_r = renv;
nw->_tap = (EthernetTap *)0;
@@ -269,12 +270,31 @@ void Network::_pushMembershipCertificate(const Address &peer,bool force,uint64_t
void Network::threadMain()
throw()
{
+ // Setup thread -- this exits when tap is constructed. It's here
+ // because opening the tap can take some time on some platforms.
+
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];
+#ifdef __WINDOWS__
+ // Windows tags interfaces by their network IDs, which are shoved into the
+ // registry to mark persistent instance of the tap device.
+ char tag[24];
Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)_id);
+#else
+ // Unix tries to get the same device name next time, if possible.
+ std::string tagstr;
+ char lcentry[128];
+ Utils::snprintf(lcentry,sizeof(lcentry),"_dev_for_%.16llx",(unsigned long long)_id);
+ tagstr = _nc->getLocalConfig(lcentry);
+ const char *tag = (tagstr.length() > 0) ? tagstr.c_str() : (const char *)0;
+#endif
+
_tap = new EthernetTap(_r,tag,_mac,ZT_IF_MTU,&_CBhandleTapData,this);
+
+#ifndef __WINDOWS__
+ std::string dn(_tap->deviceName());
+ if ((!tag)||(dn != tag))
+ _nc->putLocalConfig(lcentry,dn);
+#endif
} catch (std::exception &exc) {
LOG("network %.16llx failed to initialize: %s",_id,exc.what());
_netconfFailure = NETCONF_FAILURE_INIT_FAILED;
diff --git a/node/Network.hpp b/node/Network.hpp
index 7f07d753..d6a21c95 100644
--- a/node/Network.hpp
+++ b/node/Network.hpp
@@ -82,8 +82,7 @@ private:
// Only NodeConfig can create, only SharedPtr can delete
// Actual construction happens in newInstance()
- Network() throw() : _tap((EthernetTap *)0) {}
-
+ Network() throw() {}
~Network();
/**
@@ -96,11 +95,12 @@ private:
* cough).
*
* @param renv Runtime environment
+ * @param nc Parent NodeConfig
* @param id Network ID
* @return Reference counted pointer to new network
* @throws std::runtime_error Unable to create tap device or other fatal error
*/
- static SharedPtr<Network> newInstance(const RuntimeEnvironment *renv,uint64_t id);
+ static SharedPtr<Network> newInstance(const RuntimeEnvironment *renv,NodeConfig *nc,uint64_t id);
/**
* Causes all persistent disk presence to be erased on delete
@@ -406,6 +406,7 @@ private:
void _dumpMulticastCerts();
uint64_t _id;
+ NodeConfig *_nc;
MAC _mac;
const RuntimeEnvironment *_r;
EthernetTap *volatile _tap;
diff --git a/node/NodeConfig.cpp b/node/NodeConfig.cpp
index 64f27f29..88776a1b 100644
--- a/node/NodeConfig.cpp
+++ b/node/NodeConfig.cpp
@@ -91,7 +91,7 @@ NodeConfig::NodeConfig(const RuntimeEnvironment *renv,const char *authToken,unsi
for(std::vector<uint64_t>::iterator n(configuredNets.begin());n!=configuredNets.end();++n) {
try {
- _networks[*n] = Network::newInstance(_r,*n);
+ _networks[*n] = Network::newInstance(_r,this,*n);
} catch (std::exception &exc) {
LOG("unable to create network %.16llx: %s",(unsigned long long)*n,exc.what());
} catch ( ... ) {
@@ -246,7 +246,7 @@ std::vector<std::string> NodeConfig::execute(const char *command)
_P("409 already a member of %.16llx",(unsigned long long)nwid);
} else {
try {
- SharedPtr<Network> nw(Network::newInstance(_r,nwid));
+ SharedPtr<Network> nw(Network::newInstance(_r,this,nwid));
_networks[nwid] = nw;
_P("200 join %.16llx OK",(unsigned long long)nwid);
} catch (std::exception &exc) {