From f7019d9e80efa81e31ee7fa303be4f0e0a85c0fc Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 26 Jan 2018 22:14:10 -0500 Subject: Tie up the rest of hub and spoke designated replicator multicast mode. --- RELEASE-NOTES.md | 1 + controller/EmbeddedNetworkController.cpp | 2 -- controller/README.md | 1 - node/IncomingPacket.cpp | 6 +++++- node/Multicaster.cpp | 10 +++++++--- node/Network.cpp | 2 +- node/NetworkConfig.cpp | 3 --- node/NetworkConfig.hpp | 32 ++++++++++++++++++-------------- node/Packet.hpp | 1 + 9 files changed, 33 insertions(+), 25 deletions(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 243ccde4..c7185792 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -6,6 +6,7 @@ ZeroTier Release Notes * Features and Core Improvements * Path selection has been overhauled to improve path stability, simplify code, and prepare for multi-path and trunking in the next major release. * This version introduces remote tracing for remote diagnostics. Network controllers can set a node (usually the controller itself) to receive remote tracing events from all members of the network or from select members. Events are only sent if they pertain to a given network for security reasons. These can be used to help remotely diagnose problems. In the future we'll be refining and enhancing this feature. + * Multicast replication can now be done by designated multicast replicators on a network (flagged as such at the controller) rather than by the sender. This offers a hub-and-spoke multicast replication topology that may be faster or more bandwidth efficient in certain cases. It's also attractive for use on networks with low powered devices that need to send multicast or where there are very large numbers of multicast recipients. * Documentation fixes in network controller. * Performance improvements in crypto and memory operations. * Multithreaded performance improvements throughout the code base, including the use of an inline lightweight spinlock for low-contention resources. diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 3945c8c7..f88f8cff 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -782,7 +782,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( if (b.count("name")) network["name"] = OSUtils::jsonString(b["name"],""); if (b.count("private")) network["private"] = OSUtils::jsonBool(b["private"],true); if (b.count("enableBroadcast")) network["enableBroadcast"] = OSUtils::jsonBool(b["enableBroadcast"],false); - if (b.count("allowPassiveBridging")) network["allowPassiveBridging"] = OSUtils::jsonBool(b["allowPassiveBridging"],false); if (b.count("multicastLimit")) network["multicastLimit"] = OSUtils::jsonInt(b["multicastLimit"],32ULL); if (b.count("mtu")) network["mtu"] = std::max(std::min((unsigned int)OSUtils::jsonInt(b["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); @@ -1338,7 +1337,6 @@ void EmbeddedNetworkController::_request( nc->revision = OSUtils::jsonInt(network["revision"],0ULL); nc->issuedTo = identity.address(); if (OSUtils::jsonBool(network["enableBroadcast"],true)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; - if (OSUtils::jsonBool(network["allowPassiveBridging"],false)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING; Utils::scopy(nc->name,sizeof(nc->name),OSUtils::jsonString(network["name"],"").c_str()); nc->mtu = std::max(std::min((unsigned int)OSUtils::jsonInt(network["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); nc->multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL); diff --git a/controller/README.md b/controller/README.md index 09eab834..23bd931d 100644 --- a/controller/README.md +++ b/controller/README.md @@ -88,7 +88,6 @@ Example: | creationTime | integer | Time network record was created (ms since epoch) | no | | private | boolean | Is access control enabled? | YES | | enableBroadcast | boolean | Ethernet ff:ff:ff:ff:ff:ff allowed? | YES | -| allowPassiveBridging | boolean | Allow any member to bridge (very experimental) | YES | | v4AssignMode | object | IPv4 management and assign options (see below) | YES | | v6AssignMode | object | IPv6 management and assign options (see below) | YES | | mtu | integer | Network MTU (default: 2800) | YES | diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 8a6f4bc5..ff4fc94b 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -1019,6 +1019,11 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, return true; } + const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); + + if ((flags & 0x08)&&(network->config().isMulticastReplicator(RR->identity.address()))) + RR->mc->send(tPtr,RR->node->now(),network,peer->address(),to,from,etherType,frameData,frameLen); + if (from != MAC(peer->address(),nwid)) { if (network->config().permitsBridging(peer->address())) { network->learnBridgeRoute(from,peer->address()); @@ -1029,7 +1034,6 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, } } - const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); if (network->filterIncomingPacket(tPtr,peer,RR->identity.address(),from,to.mac(),frameData,frameLen,etherType,0) > 0) RR->node->putFrame(tPtr,nwid,network->userPtr(),from,to.mac(),etherType,0,(const void *)frameData,frameLen); } diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 9845c6cd..753e4ee0 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -174,8 +174,12 @@ void Multicaster::send( // If we're in hub-and-spoke designated multicast replication mode, see if we // have a multicast replicator active. If so, pick the best and send it // there. If we are a multicast replicator or if none are alive, fall back - // to sender replication. - { + // to sender replication. Note that bridges do not do this since this would + // break bridge route learning. This is sort of an edge case limitation of + // the current protocol and could be fixed, but fixing it would add more + // complexity than the fix is probably worth. Bridges are generally high + // bandwidth nodes. + if (!network->config().isActiveBridge(RR->identity.address())) { Address multicastReplicators[ZT_MAX_NETWORK_SPECIALISTS]; const unsigned int multicastReplicatorCount = network->config().multicastReplicators(multicastReplicators); if (multicastReplicatorCount) { @@ -197,7 +201,7 @@ void Multicaster::send( if (bestMulticastReplicator) { Packet outp(bestMulticastReplicator->address(),RR->identity.address(),Packet::VERB_MULTICAST_FRAME); outp.append((uint64_t)network->id()); - outp.append((uint8_t)0x04); // includes source MAC + outp.append((uint8_t)0x0c); // includes source MAC | please replicate ((src) ? src : MAC(RR->identity.address(),network->id())).appendTo(outp); mg.mac().appendTo(outp); outp.append((uint32_t)mg.adi()); diff --git a/node/Network.cpp b/node/Network.cpp index 6a96b3fc..c12df6c1 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1379,7 +1379,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const ec->mtu = (_config) ? _config.mtu : ZT_DEFAULT_MTU; ec->dhcp = 0; std::vector
ab(_config.activeBridges()); - ec->bridge = ((_config.allowPassiveBridging())||(std::find(ab.begin(),ab.end(),RR->identity.address()) != ab.end())) ? 1 : 0; + ec->bridge = (std::find(ab.begin(),ab.end(),RR->identity.address()) != ab.end()) ? 1 : 0; ec->broadcastEnabled = (_config) ? (_config.enableBroadcast() ? 1 : 0) : 0; ec->portError = _portError; ec->netconfRevision = (_config) ? (unsigned long)_config.revision : 0; diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index f9b16cc5..db051699 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -58,7 +58,6 @@ bool NetworkConfig::toDictionary(Dictionary &d,b #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF if (includeLegacy) { - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING_OLD,this->allowPassiveBridging())) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD,this->enableBroadcast())) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_PRIVATE_OLD,this->isPrivate())) return false; @@ -236,8 +235,6 @@ bool NetworkConfig::fromDictionary(const Dictionaryflags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING; if (d.getB(ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD)) this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; this->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; // always enable for old-style netconf diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp index 30b8d0f3..44066c86 100644 --- a/node/NetworkConfig.hpp +++ b/node/NetworkConfig.hpp @@ -68,11 +68,6 @@ */ #define ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA 185000ULL -/** - * Flag: allow passive bridging (experimental) - */ -#define ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING 0x0000000000000001ULL - /** * Flag: enable broadcast */ @@ -196,8 +191,6 @@ namespace ZeroTier { // Legacy fields -- these are obsoleted but are included when older clients query -// boolean (now a flag) -#define ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING_OLD "pb" // boolean (now a flag) #define ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST_OLD "eb" // IP/bits[,IP/bits,...] @@ -249,11 +242,6 @@ public: */ bool fromDictionary(const Dictionary &d); - /** - * @return True if passive bridging is allowed (experimental) - */ - inline bool allowPassiveBridging() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING) != 0); } - /** * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network */ @@ -302,6 +290,15 @@ public: return c; } + inline bool isActiveBridge(const Address &a) const + { + for(unsigned int i=0;i anchors() const { std::vector
r; @@ -332,6 +329,15 @@ public: return c; } + inline bool isMulticastReplicator(const Address &a) const + { + for(unsigned int i=0;i alwaysContactAddresses() const { std::vector
r; @@ -367,8 +373,6 @@ public: */ inline bool permitsBridging(const Address &fromPeer) const { - if ((flags & ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING) != 0) - return true; for(unsigned int i=0;i