Browse Source

Fix for issue #6: OSX tap device forgets it has IPv6

Adam Ierymenko 12 years ago
parent
commit
6eb77da094
4 changed files with 39 additions and 13 deletions
  1. 21 12
      node/EthernetTap.cpp
  2. 5 0
      node/EthernetTap.hpp
  3. 2 1
      node/Node.cpp
  4. 11 0
      node/NodeConfig.hpp

+ 21 - 12
node/EthernetTap.cpp

@@ -164,6 +164,11 @@ EthernetTap::~EthernetTap()
 	delete [] _putBuf;
 }
 
+void EthernetTap::whack()
+{
+	// Linux requires nothing here
+}
+
 static bool ___removeIp(const char *_dev,std::set<InetAddress> &_ips,const InetAddress &ip)
 {
 	long cpid;
@@ -461,18 +466,7 @@ EthernetTap::EthernetTap(const RuntimeEnvironment *renv,const MAC &mac,unsigned
 		}
 	}
 
-	// OSX seems to require that IPv6 be turned on on tap devices
-	if ((cpid = (int)fork()) == 0) {
-		execl(ZT_MAC_IPCONFIG,ZT_MAC_IPCONFIG,"set",_dev,"AUTOMATIC-V6",(const char *)0);
-		exit(-1);
-	} else {
-		int exitcode = -1;
-		waitpid(cpid,&exitcode,0);
-		if (exitcode) {
-			::close(_fd);
-			throw std::runtime_error("ipconfig failure enabling IPv6 link-local addressing");
-		}
-	}
+	whack(); // turns on IPv6 on OSX
 
 	_putBuf = new unsigned char[((mtu + 14) * 2)];
 	_getBuf = _putBuf + (mtu + 14);
@@ -484,6 +478,21 @@ EthernetTap::~EthernetTap()
 	delete [] _putBuf;
 }
 
+void EthernetTap::whack()
+{
+	int cpid = fork();
+	if (cpid == 0) {
+		execl(ZT_MAC_IPCONFIG,ZT_MAC_IPCONFIG,"set",_dev,"AUTOMATIC-V6",(const char *)0);
+		exit(-1);
+	} else {
+		int exitcode = -1;
+		waitpid(cpid,&exitcode,0);
+		if (exitcode) {
+			LOG("%s: ipconfig set AUTOMATIC-V6 failed",_dev);
+		}
+	}
+}
+
 // Helper function to actually remove IP from network device, execs ifconfig
 static bool ___removeIp(const char *_dev,const InetAddress &ip)
 {

+ 5 - 0
node/EthernetTap.hpp

@@ -68,6 +68,11 @@ public:
 
 	~EthernetTap();
 
+	/**
+	 * Perform OS dependent actions on network configuration change detection
+	 */
+	void whack();
+
 	/**
 	 * @return MAC address of this interface
 	 */

+ 2 - 1
node/Node.cpp

@@ -273,11 +273,12 @@ Node::ReasonForTermination Node::run()
 				lastNetworkFingerprintCheck = now;
 				uint64_t fp = _r->sysEnv->getNetworkConfigurationFingerprint();
 				if (fp != networkConfigurationFingerprint) {
-					LOG("netconf fingerprint change: %.16llx != %.16llx, pinging all peers",networkConfigurationFingerprint,fp);
+					LOG("netconf fingerprint change: %.16llx != %.16llx, resyncing with network",networkConfigurationFingerprint,fp);
 					networkConfigurationFingerprint = fp;
 					pingAll = true;
 					lastAutoconfigureCheck = 0; // check autoconf after network config change
 					lastMulticastCheck = 0; // check multicast group membership after network config change
+					_r->nc->whackAllTaps(); // call whack() on all tap devices
 				}
 			}
 

+ 11 - 0
node/NodeConfig.hpp

@@ -78,6 +78,17 @@ public:
 		return nwlist;
 	}
 
+	/**
+	 * Call whack() on all networks' tap devices
+	 */
+	inline void 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();
+	}
+
 	/**
 	 * @param nwid Network ID
 	 * @return True if this network exists