Some cleanup, Multicaster now sends multicasts as it gets additional members.

This commit is contained in:
Adam Ierymenko 2014-10-01 14:05:25 -07:00
parent ae082c3cb8
commit e1882b614b
8 changed files with 76 additions and 27 deletions

View File

@ -40,7 +40,8 @@
namespace ZeroTier { namespace ZeroTier {
Multicaster::Multicaster() Multicaster::Multicaster(const RuntimeEnvironment *renv) :
RR(renv)
{ {
} }
@ -104,9 +105,9 @@ restart_member_scan:
} }
void Multicaster::send( void Multicaster::send(
const RuntimeEnvironment *RR,
const CertificateOfMembership *com, const CertificateOfMembership *com,
unsigned int limit, unsigned int limit,
unsigned int gatherLimit,
uint64_t now, uint64_t now,
uint64_t nwid, uint64_t nwid,
const MulticastGroup &mg, const MulticastGroup &mg,
@ -122,7 +123,19 @@ void Multicaster::send(
// 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 -- no need for TX queue
OutboundMulticast out; OutboundMulticast out;
out.init(now,RR->identity.address(),nwid,com,ZT_MULTICAST_DEFAULT_IMPLICIT_GATHER,src,mg,etherType,data,len); out.init(
now,
RR->identity.address(),
nwid,
com,
limit,
gatherLimit,
src,
mg,
etherType,
data,
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) { 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 out.sendOnly(*(RR->sw),m->address); // sendOnly() avoids overhead of creating sent log since we're going to discard this immediately
@ -134,7 +147,19 @@ void Multicaster::send(
gs.txQueue.push_back(OutboundMulticast()); gs.txQueue.push_back(OutboundMulticast());
OutboundMulticast &out = gs.txQueue.back(); OutboundMulticast &out = gs.txQueue.back();
out.init(now,RR->identity.address(),nwid,com,ZT_MULTICAST_DEFAULT_IMPLICIT_GATHER,src,mg,etherType,data,len); out.init(
now,
RR->identity.address(),
nwid,
com,
limit,
gatherLimit,
src,
mg,
etherType,
data,
len);
for(std::vector<MulticastGroupMember>::const_reverse_iterator m(gs.members.rbegin());m!=gs.members.rend();++m) for(std::vector<MulticastGroupMember>::const_reverse_iterator m(gs.members.rbegin());m!=gs.members.rend();++m)
out.sendAndLog(*(RR->sw),m->address); out.sendAndLog(*(RR->sw),m->address);
@ -161,13 +186,13 @@ void Multicaster::send(
} }
} }
void Multicaster::clean(const RuntimeEnvironment *RR,uint64_t now) void Multicaster::clean(uint64_t now)
{ {
Mutex::Lock _l(_groups_m); Mutex::Lock _l(_groups_m);
for(std::map< std::pair<uint64_t,MulticastGroup>,MulticastGroupStatus >::iterator mm(_groups.begin());mm!=_groups.end();) { for(std::map< std::pair<uint64_t,MulticastGroup>,MulticastGroupStatus >::iterator mm(_groups.begin());mm!=_groups.end();) {
// Remove expired outgoing multicasts from multicast TX queue // Remove expired outgoing multicasts from multicast TX queue
for(std::list<OutboundMulticast>::iterator tx(mm->second.txQueue.begin());tx!=mm->second.txQueue.end();) { for(std::list<OutboundMulticast>::iterator tx(mm->second.txQueue.begin());tx!=mm->second.txQueue.end();) {
if (tx->expired(now)) if ((tx->expired(now))||(tx->atLimit()))
mm->second.txQueue.erase(tx++); mm->second.txQueue.erase(tx++);
else ++tx; else ++tx;
} }
@ -218,7 +243,7 @@ void Multicaster::clean(const RuntimeEnvironment *RR,uint64_t now)
} }
} }
void Multicaster::_add(uint64_t now,MulticastGroupStatus &gs,const Address &learnedFrom,const Address &member) void Multicaster::_add(uint64_t now,uint64_t nwid,MulticastGroupStatus &gs,const Address &learnedFrom,const Address &member)
{ {
// assumes _groups_m is locked // assumes _groups_m is locked
@ -236,6 +261,14 @@ void Multicaster::_add(uint64_t now,MulticastGroupStatus &gs,const Address &lear
// be resorted on next clean(). In the future we might want to insert // be resorted on next clean(). In the future we might want to insert
// this somewhere else but we'll try this for now. // this somewhere else but we'll try this for now.
gs.members.push_back(MulticastGroupMember(member,learnedFrom,now)); gs.members.push_back(MulticastGroupMember(member,learnedFrom,now));
// Try to send to any outgoing multicasts that are waiting for more recipients
for(std::list<OutboundMulticast>::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) {
tx->sendIfNew(*(RR->sw),member);
if (tx->atLimit())
gs.txQueue.erase(tx++);
else ++tx;
}
} }
} // namespace ZeroTier } // namespace ZeroTier

View File

@ -42,6 +42,7 @@
#include "OutboundMulticast.hpp" #include "OutboundMulticast.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "Mutex.hpp" #include "Mutex.hpp"
#include "NonCopyable.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -52,7 +53,7 @@ class Packet;
/** /**
* Database of known multicast peers within a network * Database of known multicast peers within a network
*/ */
class Multicaster class Multicaster : NonCopyable
{ {
private: private:
struct MulticastGroupMember struct MulticastGroupMember
@ -79,7 +80,7 @@ private:
}; };
public: public:
Multicaster(); Multicaster(const RuntimeEnvironment *renv);
~Multicaster(); ~Multicaster();
/** /**
@ -94,7 +95,7 @@ public:
inline void subscribe(uint64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &learnedFrom,const Address &member) inline void subscribe(uint64_t now,uint64_t nwid,const MulticastGroup &mg,const Address &learnedFrom,const Address &member)
{ {
Mutex::Lock _l(_groups_m); Mutex::Lock _l(_groups_m);
_add(now,_groups[std::pair<uint64_t,MulticastGroup>(nwid,mg)],learnedFrom,member); _add(now,nwid,_groups[std::pair<uint64_t,MulticastGroup>(nwid,mg)],learnedFrom,member);
} }
/** /**
@ -120,10 +121,10 @@ public:
/** /**
* Send a multicast * Send a multicast
* *
* @param RR Runtime environment
* @param nwid Network ID * @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 gatherLimit Limit to pass for implicit gather with MULTICAST_FRAME
* @param now Current time * @param now Current time
* @param mg Multicast group * @param mg Multicast group
* @param from Source Ethernet MAC address * @param from Source Ethernet MAC address
@ -132,9 +133,9 @@ public:
* @param len Length of packet data * @param len Length of packet data
*/ */
void send( void send(
const RuntimeEnvironment *RR,
const CertificateOfMembership *com, const CertificateOfMembership *com,
unsigned int limit, unsigned int limit,
unsigned int gatherLimit,
uint64_t now, uint64_t now,
uint64_t nwid, uint64_t nwid,
const MulticastGroup &mg, const MulticastGroup &mg,
@ -149,11 +150,12 @@ public:
* @param RR Runtime environment * @param RR Runtime environment
* @param now Current time * @param now Current time
*/ */
void clean(const RuntimeEnvironment *RR,uint64_t now); void clean(uint64_t now);
private: private:
void _add(uint64_t now,MulticastGroupStatus &gs,const Address &learnedFrom,const Address &member); void _add(uint64_t now,uint64_t nwid,MulticastGroupStatus &gs,const Address &learnedFrom,const Address &member);
const RuntimeEnvironment *RR;
std::map< std::pair<uint64_t,MulticastGroup>,MulticastGroupStatus > _groups; std::map< std::pair<uint64_t,MulticastGroup>,MulticastGroupStatus > _groups;
Mutex _groups_m; Mutex _groups_m;
}; };

View File

@ -382,7 +382,7 @@ Node::ReasonForTermination Node::run()
RR->http = new HttpClient(); RR->http = new HttpClient();
RR->antiRec = new AntiRecursion(); RR->antiRec = new AntiRecursion();
RR->mc = new Multicaster(); RR->mc = new Multicaster(RR);
RR->sw = new Switch(RR); RR->sw = new Switch(RR);
RR->sm = new SocketManager(impl->udpPort,impl->tcpPort,&_CBztTraffic,RR); RR->sm = new SocketManager(impl->udpPort,impl->tcpPort,&_CBztTraffic,RR);
RR->topology = new Topology(RR,Utils::fileExists((RR->homePath + ZT_PATH_SEPARATOR_S + "iddb.d").c_str())); RR->topology = new Topology(RR,Utils::fileExists((RR->homePath + ZT_PATH_SEPARATOR_S + "iddb.d").c_str()));
@ -605,8 +605,8 @@ Node::ReasonForTermination Node::run()
// Do periodic tasks in submodules. // Do periodic tasks in submodules.
if ((now - lastClean) >= ZT_DB_CLEAN_PERIOD) { if ((now - lastClean) >= ZT_DB_CLEAN_PERIOD) {
lastClean = now; lastClean = now;
RR->topology->clean(); RR->topology->clean(now);
RR->mc->clean(RR,now); RR->mc->clean(now);
RR->nc->clean(); RR->nc->clean();
if (RR->updater) if (RR->updater)
RR->updater->checkIfMaxIntervalExceeded(now); RR->updater->checkIfMaxIntervalExceeded(now);

View File

@ -32,12 +32,24 @@
namespace ZeroTier { namespace ZeroTier {
void OutboundMulticast::init(uint64_t timestamp,const Address &self,uint64_t nwid,const CertificateOfMembership *com,unsigned int gatherLimit,const MAC &src,const MulticastGroup &dest,unsigned int etherType,const void *payload,unsigned int len) void OutboundMulticast::init(
uint64_t timestamp,
const Address &self,
uint64_t nwid,
const CertificateOfMembership *com,
unsigned int limit,
unsigned int gatherLimit,
const MAC &src,
const MulticastGroup &dest,
unsigned int etherType,
const void *payload,
unsigned int len)
{ {
_timestamp = timestamp; _timestamp = timestamp;
_nwid = nwid; _nwid = nwid;
_source = src; _source = src;
_destination = dest; _destination = dest;
_limit = limit;
_etherType = etherType; _etherType = etherType;
_packet.setSource(self); _packet.setSource(self);
@ -46,7 +58,7 @@ void OutboundMulticast::init(uint64_t timestamp,const Address &self,uint64_t nwi
self.appendTo(_packet); self.appendTo(_packet);
_packet.append((uint64_t)nwid); _packet.append((uint64_t)nwid);
_packet.append((uint8_t)((com) ? 0x01 : 0x00)); _packet.append((uint8_t)((com) ? 0x01 : 0x00));
_packet.append((uint32_t)gatherLimit); // gather limit -- set before send, start with 0 _packet.append((uint32_t)gatherLimit);
if (com) com->serialize(_packet); if (com) com->serialize(_packet);
_packet.append((uint32_t)dest.adi()); _packet.append((uint32_t)dest.adi());
dest.mac().appendTo(_packet); dest.mac().appendTo(_packet);

View File

@ -66,6 +66,7 @@ public:
* @param self My ZeroTier address * @param self My ZeroTier address
* @param nwid Network ID * @param nwid Network ID
* @param com Certificate of membership to attach or NULL to omit * @param com Certificate of membership to attach or NULL to omit
* @param limit Multicast limit for desired number of packets to send
* @param gatherLimit Number to lazily/implicitly gather with this frame or 0 for none * @param gatherLimit Number to lazily/implicitly gather with this frame or 0 for none
* @param src Source MAC address of frame * @param src Source MAC address of frame
* @param dest Destination multicast group (MAC + ADI) * @param dest Destination multicast group (MAC + ADI)
@ -79,6 +80,7 @@ public:
const Address &self, const Address &self,
uint64_t nwid, uint64_t nwid,
const CertificateOfMembership *com, const CertificateOfMembership *com,
unsigned int limit,
unsigned int gatherLimit, unsigned int gatherLimit,
const MAC &src, const MAC &src,
const MulticastGroup &dest, const MulticastGroup &dest,
@ -98,9 +100,9 @@ public:
inline bool expired(uint64_t now) const throw() { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); } inline bool expired(uint64_t now) const throw() { return ((now - _timestamp) >= ZT_MULTICAST_TRANSMIT_TIMEOUT); }
/** /**
* @return Number of unique recipients to which this packet has already been sent * @return True if this outbound multicast has been sent to enough peers
*/ */
inline unsigned int sentToCount() const throw() { return (unsigned int)_alreadySentTo.size(); } inline bool atLimit() const throw() { return (_alreadySentTo.size() > _limit); }
/** /**
* Just send without checking log * Just send without checking log
@ -144,6 +146,7 @@ private:
uint64_t _nwid; uint64_t _nwid;
MAC _source; MAC _source;
MulticastGroup _destination; MulticastGroup _destination;
unsigned int _limit;
unsigned int _etherType; unsigned int _etherType;
Packet _packet; // packet contains basic structure of MULTICAST_FRAME and payload, is re-used with new IV and addressing each time Packet _packet; // packet contains basic structure of MULTICAST_FRAME and payload, is re-used with new IV and addressing each time
std::vector<Address> _alreadySentTo; std::vector<Address> _alreadySentTo;

View File

@ -151,9 +151,9 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
TRACE("%s: MULTICAST %s -> %s %s %d",network->tapDeviceName().c_str(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),(int)data.size()); TRACE("%s: MULTICAST %s -> %s %s %d",network->tapDeviceName().c_str(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),(int)data.size());
RR->mc->send( RR->mc->send(
RR,
((!nconf->isPublic())&&(nconf->com())) ? &(nconf->com()) : (const CertificateOfMembership *)0, ((!nconf->isPublic())&&(nconf->com())) ? &(nconf->com()) : (const CertificateOfMembership *)0,
network->wantMulticastGroup(mg) ? nconf->multicastLimit() : 0, nconf->multicastLimit(),
network->wantMulticastGroup(mg) ? ZT_MULTICAST_DEFAULT_IMPLICIT_GATHER : 0,
now, now,
network->id(), network->id(),
mg, mg,

View File

@ -49,7 +49,7 @@ Topology::Topology(const RuntimeEnvironment *renv,bool enablePermanentIdCaching)
Topology::~Topology() Topology::~Topology()
{ {
clean(); clean(Utils::now());
_dumpPeers(); _dumpPeers();
} }
@ -256,9 +256,8 @@ keep_searching_for_supernodes:
return bestSupernode; return bestSupernode;
} }
void Topology::clean() void Topology::clean(uint64_t now)
{ {
uint64_t now = Utils::now();
Mutex::Lock _l(_activePeers_m); Mutex::Lock _l(_activePeers_m);
Mutex::Lock _l2(_supernodes_m); Mutex::Lock _l2(_supernodes_m);
for(std::map< Address,SharedPtr<Peer> >::iterator p(_activePeers.begin());p!=_activePeers.end();) { for(std::map< Address,SharedPtr<Peer> >::iterator p(_activePeers.begin());p!=_activePeers.end();) {

View File

@ -186,7 +186,7 @@ public:
/** /**
* Clean and flush database * Clean and flush database
*/ */
void clean(); void clean(uint64_t now);
/** /**
* Apply a function or function object to all peers * Apply a function or function object to all peers