diff --git a/node/Network.cpp b/node/Network.cpp index 3091638a5..994236370 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -119,6 +119,35 @@ SharedPtr Network::newInstance(const RuntimeEnvironment *renv,NodeConfi return nw; } +bool Network::updateMulticastGroups() +{ + Mutex::Lock _l(_lock); + EthernetTap *t = _tap; + if (t) { + // Grab current groups from the local tap + bool updated = _tap->updateMulticastGroups(_multicastGroups); + + // Merge in learned groups from any hosts bridged in behind us + for(std::map::const_iterator mg(_bridgedMulticastGroups.begin());mg!=_bridgedMulticastGroups.end();++mg) + _multicastGroups.insert(mg->first); + + // Add or remove BROADCAST group based on broadcast enabled netconf flag + if ((_config)&&(_config->enableBroadcast())) { + if (_multicastGroups.count(BROADCAST)) + return updated; + else { + _multicastGroups.insert(BROADCAST); + return true; + } + } else { + if (_multicastGroups.count(BROADCAST)) { + _multicastGroups.erase(BROADCAST); + return true; + } else return updated; + } + } else return false; +} + bool Network::setConfiguration(const Dictionary &conf,bool saveToDisk) { Mutex::Lock _l(_lock); @@ -224,6 +253,7 @@ bool Network::isAllowed(const Address &peer) const void Network::clean() { Mutex::Lock _l(_lock); + uint64_t now = Utils::now(); if ((_config)&&(_config->isOpen())) { // Open (public) networks do not track certs or cert pushes at all. @@ -239,13 +269,42 @@ void Network::clean() // Clean entries from the last pushed tracking map if they're so old as // to be no longer relevant. - uint64_t forgetIfBefore = Utils::now() - (_config->com().timestampMaxDelta() * 3ULL); + uint64_t forgetIfBefore = now - (_config->com().timestampMaxDelta() * 3ULL); for(std::map::iterator lp(_lastPushedMembershipCertificate.begin());lp!=_lastPushedMembershipCertificate.end();) { if (lp->second < forgetIfBefore) _lastPushedMembershipCertificate.erase(lp++); else ++lp; } } + + // Clean learned multicast groups if we haven't heard from them in a while + for(std::map::iterator mg(_bridgedMulticastGroups.begin());mg!=_bridgedMulticastGroups.end();) { + if ((now - mg->second) > (ZT_MULTICAST_LIKE_EXPIRE * 2)) + _bridgedMulticastGroups.erase(mg++); + else ++mg; + } +} + +Network::Status Network::status() const +{ + Mutex::Lock _l(_lock); + if (_tap) { + switch(_netconfFailure) { + case NETCONF_FAILURE_ACCESS_DENIED: + return NETWORK_ACCESS_DENIED; + case NETCONF_FAILURE_NOT_FOUND: + return NETWORK_NOT_FOUND; + case NETCONF_FAILURE_NONE: + if (_lastConfigUpdate > 0) + return NETWORK_OK; + else return NETWORK_WAITING_FOR_FIRST_AUTOCONF; + case NETCONF_FAILURE_INIT_FAILED: + default: + return NETWORK_INITIALIZATION_FAILED; + } + } else if (_netconfFailure == NETCONF_FAILURE_INIT_FAILED) { + return NETWORK_INITIALIZATION_FAILED; + } else return NETWORK_INITIALIZING; } void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data) diff --git a/node/Network.hpp b/node/Network.hpp index 0a89c8489..ceb2af72d 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -158,27 +158,7 @@ public: * * @return True if internal multicast group set has changed */ - inline bool updateMulticastGroups() - { - Mutex::Lock _l(_lock); - EthernetTap *t = _tap; - if (t) { - bool updated = _tap->updateMulticastGroups(_multicastGroups); - if ((_config)&&(_config->enableBroadcast())) { - if (_multicastGroups.count(BROADCAST)) - return updated; - else { - _multicastGroups.insert(BROADCAST); - return true; - } - } else { - if (_multicastGroups.count(BROADCAST)) { - _multicastGroups.erase(BROADCAST); - return true; - } else return updated; - } - } else return false; - } + bool updateMulticastGroups(); /** * @return Latest set of multicast groups for this network's tap @@ -272,28 +252,7 @@ public: /** * @return Status of this network */ - inline Status status() const - throw() - { - Mutex::Lock _l(_lock); - if (_tap) { - switch(_netconfFailure) { - case NETCONF_FAILURE_ACCESS_DENIED: - return NETWORK_ACCESS_DENIED; - case NETCONF_FAILURE_NOT_FOUND: - return NETWORK_NOT_FOUND; - case NETCONF_FAILURE_NONE: - if (_lastConfigUpdate > 0) - return NETWORK_OK; - else return NETWORK_WAITING_FOR_FIRST_AUTOCONF; - case NETCONF_FAILURE_INIT_FAILED: - default: - return NETWORK_INITIALIZATION_FAILED; - } - } else if (_netconfFailure == NETCONF_FAILURE_INIT_FAILED) { - return NETWORK_INITIALIZATION_FAILED; - } else return NETWORK_INITIALIZING; - } + Status status() const; /** * Update multicast balance for an address and multicast group, return whether packet is allowed @@ -418,7 +377,7 @@ public: /** * @param mac MAC address - * @return ZeroTier address of bridge to this MAC or null address if not found + * @return ZeroTier address of bridge to this MAC or null address if not found (also check result for self, since this can happen) */ inline Address findBridgeTo(const MAC &mac) const { @@ -437,6 +396,17 @@ public: */ void learnBridgeRoute(const MAC &mac,const Address &addr); + /** + * Learn a multicast group that is bridged to our tap device + * + * @param mg Multicast group + */ + inline void learnBridgedMulticastGroup(const MulticastGroup &mg) + { + Mutex::Lock _l(_lock); + _bridgedMulticastGroups[mg] = Utils::now(); + } + private: static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data); @@ -457,6 +427,7 @@ private: std::map _lastPushedMembershipCertificate; std::map _bridgeRoutes; + std::map _bridgedMulticastGroups; SharedPtr _config; volatile uint64_t _lastConfigUpdate;