Browse Source

Pull logic to always send new multicasts to supernode since we need to do that differently, re-add support for active bridges, and remove some gratuitous use of std::set where not needed.

Adam Ierymenko 10 years ago
parent
commit
2c8321be1f
6 changed files with 64 additions and 61 deletions
  1. 18 32
      node/Multicaster.cpp
  2. 4 2
      node/Multicaster.hpp
  3. 6 6
      node/Network.cpp
  4. 21 13
      node/NetworkConfig.cpp
  5. 12 7
      node/NetworkConfig.hpp
  6. 3 1
      node/Switch.cpp

+ 18 - 32
node/Multicaster.cpp

@@ -115,6 +115,7 @@ void Multicaster::send(
 	unsigned int limit,
 	unsigned int limit,
 	uint64_t now,
 	uint64_t now,
 	uint64_t nwid,
 	uint64_t nwid,
+	const std::vector<Address> &alwaysSendTo,
 	const MulticastGroup &mg,
 	const MulticastGroup &mg,
 	const MAC &src,
 	const MAC &src,
 	unsigned int etherType,
 	unsigned int etherType,
@@ -124,16 +125,10 @@ void Multicaster::send(
 	Mutex::Lock _l(_groups_m);
 	Mutex::Lock _l(_groups_m);
 	MulticastGroupStatus &gs = _groups[std::pair<uint64_t,MulticastGroup>(nwid,mg)];
 	MulticastGroupStatus &gs = _groups[std::pair<uint64_t,MulticastGroup>(nwid,mg)];
 
 
-	// TODO / DEPRECATED:
-	// Right now we also send all multicasts to at least one supernode.
-	// This supernode then relays them via the old multicast message
-	// type to pre 1.0.0 peers. We'll keep doing this until there aren't
-	// any of these on the network. Costs a bit of bandwidth, but maintains
-	// backward compability while people upgrade. Then this code can die.
-	bool gotASupernode = false;
-
 	if (gs.members.size() >= limit) {
 	if (gs.members.size() >= limit) {
-		// If we already have enough members, just send and we're done -- no need for TX queue
+		// If we already have enough members, just send and we're done. We can
+		// skip the TX queue and skip the overhead of maintaining a send log by
+		// using sendOnly().
 		OutboundMulticast out;
 		OutboundMulticast out;
 
 
 		out.init(
 		out.init(
@@ -150,18 +145,18 @@ void Multicaster::send(
 			len);
 			len);
 
 
 		unsigned int count = 0;
 		unsigned int count = 0;
-		for(std::vector<MulticastGroupMember>::const_reverse_iterator m(gs.members.rbegin());m!=gs.members.rend();++m) {
-			out.sendOnly(*(RR->sw),m->address); // sendOnly() avoids overhead of creating sent log since we're going to discard this immediately
-			if (RR->topology->isSupernode(m->address))
-				gotASupernode = true;
-			if (++count >= limit)
+
+		for(std::vector<Address>::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast) {
+			if (count++ >= limit)
 				break;
 				break;
+			out.sendOnly(*(RR->sw),*ast);
 		}
 		}
 
 
-		if (!gotASupernode) {
-			SharedPtr<Peer> sn(RR->topology->getBestSupernode());
-			if (sn)
-				out.sendOnly(*(RR->sw),sn->address());
+		for(std::vector<MulticastGroupMember>::const_reverse_iterator m(gs.members.rbegin());m!=gs.members.rend();++m) {
+			if (count++ >= limit)
+				break;
+			if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),m->address) == alwaysSendTo.end())
+				out.sendOnly(*(RR->sw),m->address);
 		}
 		}
 	} else {
 	} else {
 		unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1;
 		unsigned int gatherLimit = (limit - (unsigned int)gs.members.size()) + 1;
@@ -169,11 +164,6 @@ void Multicaster::send(
 		if ((now - gs.lastExplicitGather) >= ZT_MULTICAST_EXPLICIT_GATHER_DELAY) {
 		if ((now - gs.lastExplicitGather) >= ZT_MULTICAST_EXPLICIT_GATHER_DELAY) {
 			gs.lastExplicitGather = now;
 			gs.lastExplicitGather = now;
 
 
-			// TODO / INPROGRESS: right now supernodes track multicast LIKEs, a relic
-			// from the old algorithm. The next step will be to devolve this duty
-			// somewhere else, such as node(s) nominated by netconf masters. But
-			// we'll keep announcing LIKEs to supernodes for the near future to
-			// gradually migrate from old multicast to new without losing old nodes.
 			SharedPtr<Peer> sn(RR->topology->getBestSupernode());
 			SharedPtr<Peer> sn(RR->topology->getBestSupernode());
 			if (sn) {
 			if (sn) {
 				Packet outp(sn->address(),RR->identity.address(),Packet::VERB_MULTICAST_GATHER);
 				Packet outp(sn->address(),RR->identity.address(),Packet::VERB_MULTICAST_GATHER);
@@ -209,16 +199,12 @@ void Multicaster::send(
 			data,
 			data,
 			len);
 			len);
 
 
-		for(std::vector<MulticastGroupMember>::const_reverse_iterator m(gs.members.rbegin());m!=gs.members.rend();++m) {
-			out.sendAndLog(*(RR->sw),m->address);
-			if (RR->topology->isSupernode(m->address))
-				gotASupernode = true;
-		}
+		for(std::vector<Address>::const_iterator ast(alwaysSendTo.begin());ast!=alwaysSendTo.end();++ast)
+			out.sendAndLog(*(RR->sw),*ast);
 
 
-		if (!gotASupernode) {
-			SharedPtr<Peer> sn(RR->topology->getBestSupernode());
-			if (sn)
-				out.sendAndLog(*(RR->sw),sn->address());
+		for(std::vector<MulticastGroupMember>::const_reverse_iterator m(gs.members.rbegin());m!=gs.members.rend();++m) {
+			if (std::find(alwaysSendTo.begin(),alwaysSendTo.end(),m->address) == alwaysSendTo.end())
+				out.sendAndLog(*(RR->sw),m->address);
 		}
 		}
 	}
 	}
 }
 }

+ 4 - 2
node/Multicaster.hpp

@@ -123,12 +123,13 @@ public:
 	/**
 	/**
 	 * Send a multicast
 	 * Send a multicast
 	 *
 	 *
-	 * @param nwid Network ID
 	 * @param com Certificate of membership to include or NULL for none
 	 * @param com Certificate of membership to include or NULL for none
 	 * @param limit Multicast limit
 	 * @param limit Multicast limit
 	 * @param now Current time
 	 * @param now Current time
+	 * @param nwid Network ID
+	 * @param alwaysSendTo Send to these peers first and even if not included in subscriber list
 	 * @param mg Multicast group
 	 * @param mg Multicast group
-	 * @param from Source Ethernet MAC address
+	 * @param src Source Ethernet MAC address
 	 * @param etherType Ethernet frame type
 	 * @param etherType Ethernet frame type
 	 * @param data Packet data
 	 * @param data Packet data
 	 * @param len Length of packet data
 	 * @param len Length of packet data
@@ -138,6 +139,7 @@ public:
 		unsigned int limit,
 		unsigned int limit,
 		uint64_t now,
 		uint64_t now,
 		uint64_t nwid,
 		uint64_t nwid,
+		const std::vector<Address> &alwaysSendTo,
 		const MulticastGroup &mg,
 		const MulticastGroup &mg,
 		const MAC &src,
 		const MAC &src,
 		unsigned int etherType,
 		unsigned int etherType,

+ 6 - 6
node/Network.cpp

@@ -200,7 +200,7 @@ bool Network::applyConfiguration(const SharedPtr<NetworkConfig> &conf)
 
 
 	try {
 	try {
 		if ((conf->networkId() == _id)&&(conf->issuedTo() == RR->identity.address())) {
 		if ((conf->networkId() == _id)&&(conf->issuedTo() == RR->identity.address())) {
-			std::set<InetAddress> oldStaticIps;
+			std::vector<InetAddress> oldStaticIps;
 			if (_config)
 			if (_config)
 				oldStaticIps = _config->staticIps();
 				oldStaticIps = _config->staticIps();
 
 
@@ -216,14 +216,14 @@ bool Network::applyConfiguration(const SharedPtr<NetworkConfig> &conf)
 				t->setFriendlyName(fname);
 				t->setFriendlyName(fname);
 
 
 				// Remove previously configured static IPs that are gone
 				// Remove previously configured static IPs that are gone
-				for(std::set<InetAddress>::const_iterator oldip(oldStaticIps.begin());oldip!=oldStaticIps.end();++oldip) {
-					if (!_config->staticIps().count(*oldip))
+				for(std::vector<InetAddress>::const_iterator oldip(oldStaticIps.begin());oldip!=oldStaticIps.end();++oldip) {
+					if (std::find(_config->staticIps().begin(),_config->staticIps().end(),*oldip) == _config->staticIps().end())
 						t->removeIP(*oldip);
 						t->removeIP(*oldip);
 				}
 				}
 
 
 				// Add new static IPs that were not in previous config
 				// Add new static IPs that were not in previous config
-				for(std::set<InetAddress>::const_iterator newip(_config->staticIps().begin());newip!=_config->staticIps().end();++newip) {
-					if (!oldStaticIps.count(*newip))
+				for(std::vector<InetAddress>::const_iterator newip(_config->staticIps().begin());newip!=_config->staticIps().end();++newip) {
+					if (std::find(oldStaticIps.begin(),oldStaticIps.end(),*newip) == oldStaticIps.end())
 						t->addIP(*newip);
 						t->addIP(*newip);
 				}
 				}
 
 
@@ -494,7 +494,7 @@ void Network::threadMain()
 		_tap = t;
 		_tap = t;
 		if (t) {
 		if (t) {
 			if (_config) {
 			if (_config) {
-				for(std::set<InetAddress>::const_iterator newip(_config->staticIps().begin());newip!=_config->staticIps().end();++newip)
+				for(std::vector<InetAddress>::const_iterator newip(_config->staticIps().begin());newip!=_config->staticIps().end();++newip)
 					t->addIP(*newip);
 					t->addIP(*newip);
 			}
 			}
 			t->setEnabled(_enabled);
 			t->setEnabled(_enabled);

+ 21 - 13
node/NetworkConfig.cpp

@@ -54,18 +54,22 @@ SharedPtr<NetworkConfig> NetworkConfig::createTestNetworkConfig(const Address &s
 	return nc;
 	return nc;
 }
 }
 
 
-std::set<unsigned int> NetworkConfig::allowedEtherTypes() const
+std::vector<unsigned int> NetworkConfig::allowedEtherTypes() const
 {
 {
-	std::set<unsigned int> ets;
-	for(unsigned int i=0;i<sizeof(_etWhitelist);++i) {
-		if (_etWhitelist[i]) {
-			unsigned char b = _etWhitelist[i];
-			unsigned int et = i * 8;
-			while (b) {
-				if ((b & 1))
-					ets.insert(et);
-				b >>= 1;
-				++et;
+	std::vector<unsigned int> ets;
+	if ((_etWhitelist[0] & 1) != 0) {
+		ets.push_back(0);
+	} else {
+		for(unsigned int i=0;i<sizeof(_etWhitelist);++i) {
+			if (_etWhitelist[i]) {
+				unsigned char b = _etWhitelist[i];
+				unsigned int et = i * 8;
+				while (b) {
+					if ((b & 1))
+						ets.push_back(et);
+					b >>= 1;
+					++et;
+				}
 			}
 			}
 		}
 		}
 	}
 	}
@@ -139,17 +143,21 @@ void NetworkConfig::_fromDictionary(const Dictionary &d)
 			default: // ignore unrecognized address types or junk/empty fields
 			default: // ignore unrecognized address types or junk/empty fields
 				continue;
 				continue;
 		}
 		}
-		_staticIps.insert(addr);
+		_staticIps.push_back(addr);
 	}
 	}
+	std::sort(_staticIps.begin(),_staticIps.end());
+	std::unique(_staticIps.begin(),_staticIps.end());
 
 
 	std::vector<std::string> activeBridgesSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES,"").c_str(),",","",""));
 	std::vector<std::string> activeBridgesSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES,"").c_str(),",","",""));
 	for(std::vector<std::string>::const_iterator a(activeBridgesSplit.begin());a!=activeBridgesSplit.end();++a) {
 	for(std::vector<std::string>::const_iterator a(activeBridgesSplit.begin());a!=activeBridgesSplit.end();++a) {
 		if (a->length() == ZT_ADDRESS_LENGTH_HEX) { // ignore empty or garbage fields
 		if (a->length() == ZT_ADDRESS_LENGTH_HEX) { // ignore empty or garbage fields
 			Address tmp(*a);
 			Address tmp(*a);
 			if (!tmp.isReserved())
 			if (!tmp.isReserved())
-				_activeBridges.insert(tmp);
+				_activeBridges.push_back(tmp);
 		}
 		}
 	}
 	}
+	std::sort(_activeBridges.begin(),_activeBridges.end());
+	std::unique(_activeBridges.begin(),_activeBridges.end());
 
 
 	Dictionary multicastRateEntries(d.get(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_RATES,std::string()));
 	Dictionary multicastRateEntries(d.get(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_RATES,std::string()));
 	for(Dictionary::const_iterator i(multicastRateEntries.begin());i!=multicastRateEntries.end();++i) {
 	for(Dictionary::const_iterator i(multicastRateEntries.begin());i!=multicastRateEntries.end();++i) {

+ 12 - 7
node/NetworkConfig.hpp

@@ -31,9 +31,10 @@
 #include <stdint.h>
 #include <stdint.h>
 
 
 #include <map>
 #include <map>
-#include <set>
+#include <vector>
 #include <string>
 #include <string>
 #include <stdexcept>
 #include <stdexcept>
+#include <algorithm>
 
 
 #include "Constants.hpp"
 #include "Constants.hpp"
 #include "Dictionary.hpp"
 #include "Dictionary.hpp"
@@ -122,7 +123,11 @@ public:
 		return ((_etWhitelist[etherType >> 3] & (1 << (etherType & 7))) != 0);
 		return ((_etWhitelist[etherType >> 3] & (1 << (etherType & 7))) != 0);
 	}
 	}
 
 
-	std::set<unsigned int> allowedEtherTypes() const;
+	/**
+	 * @return Allowed ethernet types or a vector containing only 0 if "all"
+	 */
+	std::vector<unsigned int> allowedEtherTypes() const;
+
 	inline uint64_t networkId() const throw() { return _nwid; }
 	inline uint64_t networkId() const throw() { return _nwid; }
 	inline uint64_t timestamp() const throw() { return _timestamp; }
 	inline uint64_t timestamp() const throw() { return _timestamp; }
 	inline const Address &issuedTo() const throw() { return _issuedTo; }
 	inline const Address &issuedTo() const throw() { return _issuedTo; }
@@ -133,8 +138,8 @@ public:
 	inline bool isPrivate() const throw() { return _private; }
 	inline bool isPrivate() const throw() { return _private; }
 	inline const std::string &name() const throw() { return _name; }
 	inline const std::string &name() const throw() { return _name; }
 	inline const std::string &description() const throw() { return _description; }
 	inline const std::string &description() const throw() { return _description; }
-	inline const std::set<InetAddress> &staticIps() const throw() { return _staticIps; }
-	inline const std::set<Address> &activeBridges() const throw() { return _activeBridges; }
+	inline const std::vector<InetAddress> &staticIps() const throw() { return _staticIps; }
+	inline const std::vector<Address> &activeBridges() const throw() { return _activeBridges; }
 	inline const CertificateOfMembership &com() const throw() { return _com; }
 	inline const CertificateOfMembership &com() const throw() { return _com; }
 	inline bool enableBroadcast() const throw() { return _enableBroadcast; }
 	inline bool enableBroadcast() const throw() { return _enableBroadcast; }
 
 
@@ -144,7 +149,7 @@ public:
 	 */
 	 */
 	inline bool permitsBridging(const Address &fromPeer) const
 	inline bool permitsBridging(const Address &fromPeer) const
 	{
 	{
-		return ((_allowPassiveBridging) ? true : (_activeBridges.count(fromPeer) > 0));
+		return ( (_allowPassiveBridging) || (std::find(_activeBridges.begin(),_activeBridges.end(),fromPeer) != _activeBridges.end()) );
 	}
 	}
 
 
 	/**
 	/**
@@ -170,8 +175,8 @@ private:
 	bool _enableBroadcast;
 	bool _enableBroadcast;
 	std::string _name;
 	std::string _name;
 	std::string _description;
 	std::string _description;
-	std::set<InetAddress> _staticIps;
-	std::set<Address> _activeBridges;
+	std::vector<InetAddress> _staticIps;
+	std::vector<Address> _activeBridges;
 	std::map<MulticastGroup,MulticastRate> _multicastRates;
 	std::map<MulticastGroup,MulticastRate> _multicastRates;
 	CertificateOfMembership _com;
 	CertificateOfMembership _com;
 
 

+ 3 - 1
node/Switch.cpp

@@ -155,6 +155,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
 			nconf->multicastLimit(),
 			nconf->multicastLimit(),
 			now,
 			now,
 			network->id(),
 			network->id(),
+			nconf->activeBridges(),
 			mg,
 			mg,
 			from,
 			from,
 			etherType,
 			etherType,
@@ -169,6 +170,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
 
 
 		Address toZT(to.toAddress(network->id()));
 		Address toZT(to.toAddress(network->id()));
 		if (network->isAllowed(toZT)) {
 		if (network->isAllowed(toZT)) {
+			// TODO: we can refactor this to push certificates with EXT_FRAME
 			network->pushMembershipCertificate(toZT,false,Utils::now());
 			network->pushMembershipCertificate(toZT,false,Utils::now());
 
 
 			if (fromBridged) {
 			if (fromBridged) {
@@ -214,7 +216,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
 			 * know which port corresponds to a MAC, they send it to all ports. If
 			 * know which port corresponds to a MAC, they send it to all ports. If
 			 * there aren't any active bridges, numBridges will stay 0 and packet
 			 * there aren't any active bridges, numBridges will stay 0 and packet
 			 * is dropped. */
 			 * is dropped. */
-			std::set<Address>::const_iterator ab(nconf->activeBridges().begin());
+			std::vector<Address>::const_iterator ab(nconf->activeBridges().begin());
 			if (nconf->activeBridges().size() <= ZT_MAX_BRIDGE_SPAM) {
 			if (nconf->activeBridges().size() <= ZT_MAX_BRIDGE_SPAM) {
 				// If there are <= ZT_MAX_BRIDGE_SPAM active bridges, spam them all
 				// If there are <= ZT_MAX_BRIDGE_SPAM active bridges, spam them all
 				while (ab != nconf->activeBridges().end()) {
 				while (ab != nconf->activeBridges().end()) {