mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-07 13:03:45 +02:00
Add RENDEZVOUS to high throughput root
This commit is contained in:
parent
86762d2b40
commit
6e3e09bed4
1 changed files with 113 additions and 26 deletions
139
root/root.cpp
139
root/root.cpp
|
@ -74,7 +74,25 @@ struct AddressHasher { ZT_ALWAYS_INLINE std::size_t operator()(const Address &a)
|
||||||
struct InetAddressHasher { ZT_ALWAYS_INLINE std::size_t operator()(const InetAddress &ip) const { return (std::size_t)ip.hashCode(); } };
|
struct InetAddressHasher { ZT_ALWAYS_INLINE std::size_t operator()(const InetAddress &ip) const { return (std::size_t)ip.hashCode(); } };
|
||||||
struct MulticastGroupHasher { ZT_ALWAYS_INLINE std::size_t operator()(const MulticastGroup &mg) const { return (std::size_t)mg.hashCode(); } };
|
struct MulticastGroupHasher { ZT_ALWAYS_INLINE std::size_t operator()(const MulticastGroup &mg) const { return (std::size_t)mg.hashCode(); } };
|
||||||
|
|
||||||
struct PeerInfo
|
struct RendezvousKey
|
||||||
|
{
|
||||||
|
RendezvousKey(const Address aa,const Address bb)
|
||||||
|
{
|
||||||
|
if (aa > bb) {
|
||||||
|
a = aa;
|
||||||
|
b = bb;
|
||||||
|
} else {
|
||||||
|
a = bb;
|
||||||
|
b = aa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Address a,b;
|
||||||
|
ZT_ALWAYS_INLINE bool operator==(const RendezvousKey &k) const { return ((a == k.a)&&(b == k.b)); }
|
||||||
|
ZT_ALWAYS_INLINE bool operator!=(const RendezvousKey &k) const { return ((a != k.a)||(b != k.b)); }
|
||||||
|
struct Hasher { ZT_ALWAYS_INLINE std::size_t operator()(const RendezvousKey &k) const { return (std::size_t)(k.a.toInt() ^ k.b.toInt()); } };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RootPeer
|
||||||
{
|
{
|
||||||
Identity id;
|
Identity id;
|
||||||
uint8_t key[32];
|
uint8_t key[32];
|
||||||
|
@ -84,31 +102,36 @@ struct PeerInfo
|
||||||
|
|
||||||
AtomicCounter __refCount;
|
AtomicCounter __refCount;
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE ~PeerInfo() { Utils::burn(key,sizeof(key)); }
|
ZT_ALWAYS_INLINE ~RootPeer() { Utils::burn(key,sizeof(key)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
static Identity self;
|
static Identity self;
|
||||||
static std::atomic_bool run;
|
static std::atomic_bool run;
|
||||||
|
|
||||||
static std::unordered_map< uint64_t,std::unordered_map< MulticastGroup,std::unordered_map< Address,int64_t,AddressHasher >,MulticastGroupHasher > > multicastSubscriptions;
|
static std::unordered_map< uint64_t,std::unordered_map< MulticastGroup,std::unordered_map< Address,int64_t,AddressHasher >,MulticastGroupHasher > > multicastSubscriptions;
|
||||||
static std::unordered_map< Identity,SharedPtr<PeerInfo>,IdentityHasher > peersByIdentity;
|
static std::unordered_map< Identity,SharedPtr<RootPeer>,IdentityHasher > peersByIdentity;
|
||||||
static std::unordered_map< Address,std::set< SharedPtr<PeerInfo> >,AddressHasher > peersByVirtAddr;
|
static std::unordered_map< Address,std::set< SharedPtr<RootPeer> >,AddressHasher > peersByVirtAddr;
|
||||||
static std::unordered_map< InetAddress,std::set< SharedPtr<PeerInfo> >,InetAddressHasher > peersByPhysAddr;
|
static std::unordered_map< InetAddress,std::set< SharedPtr<RootPeer> >,InetAddressHasher > peersByPhysAddr;
|
||||||
|
static std::unordered_map< RendezvousKey,int64_t,RendezvousKey::Hasher > lastRendezvous;
|
||||||
|
|
||||||
static std::mutex multicastSubscriptions_l;
|
static std::mutex multicastSubscriptions_l;
|
||||||
static std::mutex peersByIdentity_l;
|
static std::mutex peersByIdentity_l;
|
||||||
static std::mutex peersByVirtAddr_l;
|
static std::mutex peersByVirtAddr_l;
|
||||||
static std::mutex peersByPhysAddr_l;
|
static std::mutex peersByPhysAddr_l;
|
||||||
|
static std::mutex lastRendezvous_l;
|
||||||
|
|
||||||
static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
|
static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
|
||||||
{
|
{
|
||||||
char ipstr[128],ipstr2[128],astr[32],tmpstr[256];
|
char ipstr[128],ipstr2[128],astr[32],astr2[32],tmpstr[256];
|
||||||
const bool fragment = pkt[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR;
|
const bool fragment = pkt[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR;
|
||||||
|
const Address source(pkt.source());
|
||||||
|
const Address dest(pkt.destination());
|
||||||
|
const int64_t now = OSUtils::now();
|
||||||
|
|
||||||
// See if this is destined for us and isn't a fragment / fragmented. (No packets
|
// See if this is destined for us and isn't a fragment / fragmented. (No packets
|
||||||
// understood by the root are fragments/fragmented.)
|
// understood by the root are fragments/fragmented.)
|
||||||
if ((!fragment)&&(!pkt.fragmented())&&(pkt.destination() == self.address())) {
|
if ((!fragment)&&(!pkt.fragmented())&&(dest == self.address())) {
|
||||||
SharedPtr<PeerInfo> peer;
|
SharedPtr<RootPeer> peer;
|
||||||
|
|
||||||
// If this is an un-encrypted HELLO, either learn a new peer or verify
|
// If this is an un-encrypted HELLO, either learn a new peer or verify
|
||||||
// that this is a peer we already know.
|
// that this is a peer we already know.
|
||||||
|
@ -120,7 +143,7 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
|
||||||
auto pById = peersByIdentity.find(id);
|
auto pById = peersByIdentity.find(id);
|
||||||
if (pById != peersByIdentity.end()) {
|
if (pById != peersByIdentity.end()) {
|
||||||
peer = pById->second;
|
peer = pById->second;
|
||||||
//printf("%s has %s (known (1))" ZT_EOL_S,ip->toString(ipstr),pkt.source().toString(astr));
|
//printf("%s has %s (known (1))" ZT_EOL_S,ip->toString(ipstr),source().toString(astr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (peer) {
|
if (peer) {
|
||||||
|
@ -129,7 +152,7 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
peer.set(new PeerInfo);
|
peer.set(new RootPeer);
|
||||||
if (self.agree(id,peer->key)) {
|
if (self.agree(id,peer->key)) {
|
||||||
if (pkt.dearmor(peer->key)) {
|
if (pkt.dearmor(peer->key)) {
|
||||||
peer->id = id;
|
peer->id = id;
|
||||||
|
@ -158,12 +181,12 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
|
||||||
// short ZT address successfully decrypt the packet.
|
// short ZT address successfully decrypt the packet.
|
||||||
if (!peer) {
|
if (!peer) {
|
||||||
std::lock_guard<std::mutex> pbv_l(peersByVirtAddr_l);
|
std::lock_guard<std::mutex> pbv_l(peersByVirtAddr_l);
|
||||||
auto peers = peersByVirtAddr.find(pkt.source());
|
auto peers = peersByVirtAddr.find(source);
|
||||||
if (peers != peersByVirtAddr.end()) {
|
if (peers != peersByVirtAddr.end()) {
|
||||||
for(auto p=peers->second.begin();p!=peers->second.end();++p) {
|
for(auto p=peers->second.begin();p!=peers->second.end();++p) {
|
||||||
if (pkt.dearmor((*p)->key)) {
|
if (pkt.dearmor((*p)->key)) {
|
||||||
peer = (*p);
|
peer = (*p);
|
||||||
//printf("%s has %s (known (2))" ZT_EOL_S,ip->toString(ipstr),pkt.source().toString(astr));
|
//printf("%s has %s (known (2))" ZT_EOL_S,ip->toString(ipstr),source().toString(astr));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,7 +218,7 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
|
||||||
try {
|
try {
|
||||||
const uint64_t origId = pkt.packetId();
|
const uint64_t origId = pkt.packetId();
|
||||||
const uint64_t ts = pkt.template at<uint64_t>(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP);
|
const uint64_t ts = pkt.template at<uint64_t>(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP);
|
||||||
pkt.reset(pkt.source(),self.address(),Packet::VERB_OK);
|
pkt.reset(source,self.address(),Packet::VERB_OK);
|
||||||
pkt.append((uint8_t)Packet::VERB_HELLO);
|
pkt.append((uint8_t)Packet::VERB_HELLO);
|
||||||
pkt.append(origId);
|
pkt.append(origId);
|
||||||
pkt.append(ts);
|
pkt.append(ts);
|
||||||
|
@ -236,7 +259,7 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
|
||||||
gatherLimit = 255;
|
gatherLimit = 255;
|
||||||
|
|
||||||
const uint64_t origId = pkt.packetId();
|
const uint64_t origId = pkt.packetId();
|
||||||
pkt.reset(pkt.source(),self.address(),Packet::VERB_OK);
|
pkt.reset(source,self.address(),Packet::VERB_OK);
|
||||||
pkt.append((uint8_t)Packet::VERB_MULTICAST_GATHER);
|
pkt.append((uint8_t)Packet::VERB_MULTICAST_GATHER);
|
||||||
pkt.append(origId);
|
pkt.append(origId);
|
||||||
pkt.append(nwid);
|
pkt.append(nwid);
|
||||||
|
@ -275,42 +298,106 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<InetAddress> toAddrs;
|
// If we made it here, we are forwarding this packet to someone else and also possibly
|
||||||
|
// sending a RENDEZVOUS message.
|
||||||
|
|
||||||
|
bool introduce = false;
|
||||||
|
{
|
||||||
|
RendezvousKey rk(source,dest);
|
||||||
|
std::lock_guard<std::mutex> l(lastRendezvous_l);
|
||||||
|
int64_t &lr = lastRendezvous[rk];
|
||||||
|
if ((now - lr) >= 45000) {
|
||||||
|
lr = now;
|
||||||
|
introduce = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector< std::pair< InetAddress *,SharedPtr<RootPeer> > > toAddrs;
|
||||||
{
|
{
|
||||||
const int64_t now = OSUtils::now();
|
|
||||||
std::lock_guard<std::mutex> pbv_l(peersByVirtAddr_l);
|
std::lock_guard<std::mutex> pbv_l(peersByVirtAddr_l);
|
||||||
auto peers = peersByVirtAddr.find(pkt.destination());
|
auto peers = peersByVirtAddr.find(dest);
|
||||||
if (peers != peersByVirtAddr.end()) {
|
if (peers != peersByVirtAddr.end()) {
|
||||||
for(auto p=peers->second.begin();p!=peers->second.end();++p) {
|
for(auto p=peers->second.begin();p!=peers->second.end();++p) {
|
||||||
if ((now - (*p)->lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT) {
|
if ((now - (*p)->lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT) {
|
||||||
if ((*p)->ip6)
|
if ((*p)->ip6) {
|
||||||
toAddrs.push_back((*p)->ip6);
|
toAddrs.push_back(std::pair< InetAddress *,SharedPtr<RootPeer> >(&((*p)->ip6),*p));
|
||||||
else if ((*p)->ip4)
|
} else if ((*p)->ip4) {
|
||||||
toAddrs.push_back((*p)->ip4);
|
toAddrs.push_back(std::pair< InetAddress *,SharedPtr<RootPeer> >(&((*p)->ip4),*p));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (toAddrs.empty()) {
|
if (toAddrs.empty()) {
|
||||||
//printf("%s not forwarding to %s: no destinations found" ZT_EOL_S,ip->toString(ipstr),pkt.destination().toString(astr));
|
//printf("%s not forwarding to %s: no destinations found" ZT_EOL_S,ip->toString(ipstr),dest().toString(astr));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (introduce) {
|
||||||
|
std::lock_guard<std::mutex> l(peersByVirtAddr_l);
|
||||||
|
auto sources = peersByVirtAddr.find(source);
|
||||||
|
for(auto a=sources->second.begin();a!=sources->second.end();++a) {
|
||||||
|
for(auto b=toAddrs.begin();b!=toAddrs.end();++b) {
|
||||||
|
if (((*a)->ip6 == *ip)&&(b->second->ip6)) {
|
||||||
|
printf("* introducing %s(%s) to %s(%s)" ZT_EOL_S,ip->toString(ipstr),source.toString(astr),b->second->ip6.toString(ipstr2),dest.toString(astr2));
|
||||||
|
|
||||||
|
Packet outp(source,self.address(),Packet::VERB_RENDEZVOUS);
|
||||||
|
outp.append((uint8_t)0);
|
||||||
|
dest.appendTo(outp);
|
||||||
|
outp.append((uint16_t)b->second->ip6.port());
|
||||||
|
outp.append((uint8_t)16);
|
||||||
|
outp.append((const uint8_t *)b->second->ip6.rawIpData(),16);
|
||||||
|
outp.armor((*a)->key,true);
|
||||||
|
sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)ip,(socklen_t)sizeof(struct sockaddr_in6));
|
||||||
|
|
||||||
|
outp.reset(dest,self.address(),Packet::VERB_RENDEZVOUS);
|
||||||
|
outp.append((uint8_t)0);
|
||||||
|
source.appendTo(outp);
|
||||||
|
outp.append((uint16_t)ip->port());
|
||||||
|
outp.append((uint8_t)16);
|
||||||
|
outp.append((const uint8_t *)ip->rawIpData(),16);
|
||||||
|
outp.armor(b->second->key,true);
|
||||||
|
sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)&(b->second->ip6),(socklen_t)sizeof(struct sockaddr_in6));
|
||||||
|
} else if (((*a)->ip4 == *ip)&&(b->second->ip4)) {
|
||||||
|
printf("* introducing %s(%s) to %s(%s)" ZT_EOL_S,ip->toString(ipstr),source.toString(astr),b->second->ip4.toString(ipstr2),dest.toString(astr2));
|
||||||
|
|
||||||
|
Packet outp(source,self.address(),Packet::VERB_RENDEZVOUS);
|
||||||
|
outp.append((uint8_t)0);
|
||||||
|
dest.appendTo(outp);
|
||||||
|
outp.append((uint16_t)b->second->ip4.port());
|
||||||
|
outp.append((uint8_t)4);
|
||||||
|
outp.append((const uint8_t *)b->second->ip4.rawIpData(),4);
|
||||||
|
outp.armor((*a)->key,true);
|
||||||
|
sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)ip,(socklen_t)sizeof(struct sockaddr_in));
|
||||||
|
|
||||||
|
outp.reset(dest,self.address(),Packet::VERB_RENDEZVOUS);
|
||||||
|
outp.append((uint8_t)0);
|
||||||
|
source.appendTo(outp);
|
||||||
|
outp.append((uint16_t)ip->port());
|
||||||
|
outp.append((uint8_t)4);
|
||||||
|
outp.append((const uint8_t *)ip->rawIpData(),4);
|
||||||
|
outp.armor(b->second->key,true);
|
||||||
|
sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)&(b->second->ip4),(socklen_t)sizeof(struct sockaddr_in));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (fragment) {
|
if (fragment) {
|
||||||
if (reinterpret_cast<Packet::Fragment *>(&pkt)->incrementHops() >= ZT_PROTO_MAX_HOPS) {
|
if (reinterpret_cast<Packet::Fragment *>(&pkt)->incrementHops() >= ZT_PROTO_MAX_HOPS) {
|
||||||
printf("%s refused to forward to %s: max hop count exceeded" ZT_EOL_S,ip->toString(ipstr),pkt.destination().toString(astr));
|
printf("%s refused to forward to %s: max hop count exceeded" ZT_EOL_S,ip->toString(ipstr),dest.toString(astr));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (pkt.incrementHops() >= ZT_PROTO_MAX_HOPS) {
|
if (pkt.incrementHops() >= ZT_PROTO_MAX_HOPS) {
|
||||||
printf("%s refused to forward to %s: max hop count exceeded" ZT_EOL_S,ip->toString(ipstr),pkt.destination().toString(astr));
|
printf("%s refused to forward to %s: max hop count exceeded" ZT_EOL_S,ip->toString(ipstr),dest.toString(astr));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(auto i=toAddrs.begin();i!=toAddrs.end();++i) {
|
for(auto i=toAddrs.begin();i!=toAddrs.end();++i) {
|
||||||
//printf("%s -> %s for %s" ZT_EOL_S,ip->toString(ipstr),i->toString(ipstr2),pkt.destination().toString(astr));
|
//printf("%s -> %s for %s" ZT_EOL_S,ip->toString(ipstr),i->toString(ipstr2),dest().toString(astr));
|
||||||
sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)&(*i),(socklen_t)((i->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)));
|
sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)i->first,(socklen_t)((i->first->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue