mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 03:53:44 +02:00
Fix for GitHub issue #37: remember *nix device names.
This commit is contained in:
parent
f1b45f7df0
commit
3f912eb4ad
4 changed files with 65 additions and 21 deletions
|
@ -234,6 +234,7 @@ EthernetTap::EthernetTap(
|
||||||
_fd(0)
|
_fd(0)
|
||||||
{
|
{
|
||||||
char procpath[128];
|
char procpath[128];
|
||||||
|
struct stat sbuf;
|
||||||
Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
|
Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
|
||||||
|
|
||||||
if (mtu > 4096)
|
if (mtu > 4096)
|
||||||
|
@ -246,13 +247,19 @@ EthernetTap::EthernetTap(
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
memset(&ifr,0,sizeof(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;
|
int devno = 0;
|
||||||
struct stat sbuf;
|
|
||||||
do {
|
do {
|
||||||
Utils::snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"zt%d",devno++);
|
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);
|
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;
|
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||||
|
@ -359,17 +366,33 @@ EthernetTap::EthernetTap(
|
||||||
if (stat("/dev/zt0",&stattmp))
|
if (stat("/dev/zt0",&stattmp))
|
||||||
throw std::runtime_error("/dev/zt# tap devices do not exist and unable to load kernel extension");
|
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)
|
// Try to reopen the last device we had, if we had one and it's still unused.
|
||||||
for(int i=0;i<256;++i) {
|
bool recalledDevice = false;
|
||||||
Utils::snprintf(devpath,sizeof(devpath),"/dev/zt%d",i);
|
if ((tag)&&(tag[0])) {
|
||||||
if (stat(devpath,&stattmp))
|
Utils::snprintf(devpath,sizeof(devpath),"/dev/%s",tag);
|
||||||
throw std::runtime_error("no more TAP devices available");
|
if (stat(devpath,&stattmp) == 0) {
|
||||||
_fd = ::open(devpath,O_RDWR);
|
_fd = ::open(devpath,O_RDWR);
|
||||||
if (_fd > 0) {
|
if (_fd > 0) {
|
||||||
Utils::snprintf(_dev,sizeof(_dev),"zt%d",i);
|
Utils::scopy(_dev,sizeof(_dev),tag);
|
||||||
break;
|
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)
|
if (_fd <= 0)
|
||||||
throw std::runtime_error("unable to open TAP device or no more devices available");
|
throw std::runtime_error("unable to open TAP device or no more devices available");
|
||||||
|
|
||||||
|
|
|
@ -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
|
/* 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
|
* 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());
|
SharedPtr<Network> nw(new Network());
|
||||||
nw->_id = id;
|
nw->_id = id;
|
||||||
|
nw->_nc = nc;
|
||||||
nw->_mac = renv->identity.address().toMAC();
|
nw->_mac = renv->identity.address().toMAC();
|
||||||
nw->_r = renv;
|
nw->_r = renv;
|
||||||
nw->_tap = (EthernetTap *)0;
|
nw->_tap = (EthernetTap *)0;
|
||||||
|
@ -269,12 +270,31 @@ void Network::_pushMembershipCertificate(const Address &peer,bool force,uint64_t
|
||||||
void Network::threadMain()
|
void Network::threadMain()
|
||||||
throw()
|
throw()
|
||||||
{
|
{
|
||||||
|
// Setup thread -- this exits when tap is constructed. It's here
|
||||||
|
// because opening the tap can take some time on some platforms.
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Setup thread -- this exits when tap is constructed. It's here
|
#ifdef __WINDOWS__
|
||||||
// because opening the tap can take some time on some platforms.
|
// Windows tags interfaces by their network IDs, which are shoved into the
|
||||||
char tag[32];
|
// registry to mark persistent instance of the tap device.
|
||||||
|
char tag[24];
|
||||||
Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)_id);
|
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);
|
_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) {
|
} catch (std::exception &exc) {
|
||||||
LOG("network %.16llx failed to initialize: %s",_id,exc.what());
|
LOG("network %.16llx failed to initialize: %s",_id,exc.what());
|
||||||
_netconfFailure = NETCONF_FAILURE_INIT_FAILED;
|
_netconfFailure = NETCONF_FAILURE_INIT_FAILED;
|
||||||
|
|
|
@ -82,8 +82,7 @@ private:
|
||||||
// Only NodeConfig can create, only SharedPtr can delete
|
// Only NodeConfig can create, only SharedPtr can delete
|
||||||
|
|
||||||
// Actual construction happens in newInstance()
|
// Actual construction happens in newInstance()
|
||||||
Network() throw() : _tap((EthernetTap *)0) {}
|
Network() throw() {}
|
||||||
|
|
||||||
~Network();
|
~Network();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,11 +95,12 @@ private:
|
||||||
* cough).
|
* cough).
|
||||||
*
|
*
|
||||||
* @param renv Runtime environment
|
* @param renv Runtime environment
|
||||||
|
* @param nc Parent NodeConfig
|
||||||
* @param id Network ID
|
* @param id Network ID
|
||||||
* @return Reference counted pointer to new network
|
* @return Reference counted pointer to new network
|
||||||
* @throws std::runtime_error Unable to create tap device or other fatal error
|
* @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
|
* Causes all persistent disk presence to be erased on delete
|
||||||
|
@ -406,6 +406,7 @@ private:
|
||||||
void _dumpMulticastCerts();
|
void _dumpMulticastCerts();
|
||||||
|
|
||||||
uint64_t _id;
|
uint64_t _id;
|
||||||
|
NodeConfig *_nc;
|
||||||
MAC _mac;
|
MAC _mac;
|
||||||
const RuntimeEnvironment *_r;
|
const RuntimeEnvironment *_r;
|
||||||
EthernetTap *volatile _tap;
|
EthernetTap *volatile _tap;
|
||||||
|
|
|
@ -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) {
|
for(std::vector<uint64_t>::iterator n(configuredNets.begin());n!=configuredNets.end();++n) {
|
||||||
try {
|
try {
|
||||||
_networks[*n] = Network::newInstance(_r,*n);
|
_networks[*n] = Network::newInstance(_r,this,*n);
|
||||||
} catch (std::exception &exc) {
|
} catch (std::exception &exc) {
|
||||||
LOG("unable to create network %.16llx: %s",(unsigned long long)*n,exc.what());
|
LOG("unable to create network %.16llx: %s",(unsigned long long)*n,exc.what());
|
||||||
} catch ( ... ) {
|
} 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);
|
_P("409 already a member of %.16llx",(unsigned long long)nwid);
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
SharedPtr<Network> nw(Network::newInstance(_r,nwid));
|
SharedPtr<Network> nw(Network::newInstance(_r,this,nwid));
|
||||||
_networks[nwid] = nw;
|
_networks[nwid] = nw;
|
||||||
_P("200 join %.16llx OK",(unsigned long long)nwid);
|
_P("200 join %.16llx OK",(unsigned long long)nwid);
|
||||||
} catch (std::exception &exc) {
|
} catch (std::exception &exc) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue