Browse Source

Implement cross cluster sharing of network configs to make clusters able to actually join networks.

Adam Ierymenko 8 years ago
parent
commit
eebd271bb1
3 changed files with 38 additions and 5 deletions
  1. 19 0
      node/Cluster.cpp
  2. 11 4
      node/Cluster.hpp
  3. 8 1
      node/IncomingPacket.cpp

+ 19 - 0
node/Cluster.cpp

@@ -44,6 +44,7 @@
 #include "Packet.hpp"
 #include "Switch.hpp"
 #include "Node.hpp"
+#include "Network.hpp"
 #include "Array.hpp"
 
 namespace ZeroTier {
@@ -469,6 +470,15 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len)
 						RR->sw->send(outp,true);
 						//TRACE("[%u] proxy send %s to %s length %u",(unsigned int)fromMemberId,Packet::verbString(verb),rcpt.toString().c_str(),len);
 					}	break;
+
+					case CLUSTER_MESSAGE_NETWORK_CONFIG: {
+						const SharedPtr<Network> network(RR->node->network(dmsg.at<uint64_t>(ptr)));
+						if (network) {
+							// Copy into a Packet just to conform to Network API. Eventually
+							// will want to refactor.
+							network->handleConfigChunk(Packet(dmsg),ptr);
+						}
+					}	break;
 				}
 			} catch ( ... ) {
 				TRACE("invalid message of size %u type %d (inner decode), discarding",mlen,mtype);
@@ -494,6 +504,15 @@ void Cluster::broadcastHavePeer(const Identity &id)
 	}
 }
 
+void Cluster::broadcastNetworkConfigChunk(const void *chunk,unsigned int len)
+{
+	Mutex::Lock _l(_memberIds_m);
+	for(std::vector<uint16_t>::const_iterator mid(_memberIds.begin());mid!=_memberIds.end();++mid) {
+		Mutex::Lock _l2(_members[*mid].lock);
+		_send(*mid,CLUSTER_MESSAGE_NETWORK_CONFIG,chunk,len);
+	}
+}
+
 void Cluster::sendViaCluster(const Address &fromPeerAddress,const Address &toPeerAddress,const void *data,unsigned int len,bool unite)
 {
 	if (len > ZT_PROTO_MAX_PACKET_LENGTH) // sanity check

+ 11 - 4
node/Cluster.hpp

@@ -216,14 +216,13 @@ public:
 
 		/**
 		 * Replicate a network config for a network we belong to:
-		 *   <[8] 64-bit network ID>
-		 *   <[2] 16-bit length of network config>
-		 *   <[...] serialized network config>
+		 *   <[...] network config chunk>
 		 *
 		 * This is used by clusters to avoid every member having to query
 		 * for the same netconf for networks all members belong to.
 		 *
-		 * TODO: not implemented yet!
+		 * The first field of a network config chunk is the network ID,
+		 * so this can be checked to look up the network on receipt.
 		 */
 		CLUSTER_MESSAGE_NETWORK_CONFIG = 7
 	};
@@ -267,6 +266,14 @@ public:
 	 */
 	void broadcastHavePeer(const Identity &id);
 
+	/**
+	 * Broadcast a network config chunk to other members of cluster
+	 *
+	 * @param chunk Chunk data
+	 * @param len Length of chunk
+	 */
+	void broadcastNetworkConfigChunk(const void *chunk,unsigned int len);
+
 	/**
 	 * Send this packet via another node in this cluster if another node has this peer
 	 *

+ 8 - 1
node/IncomingPacket.cpp

@@ -461,8 +461,12 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
 
 			case Packet::VERB_NETWORK_CONFIG_REQUEST: {
 				const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_OK_IDX_PAYLOAD)));
-				if (network)
+				if (network) {
+#ifdef ZT_ENABLE_CLUSTER
+					RR->cluster->broadcastNetworkConfigChunk(field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PROTO_VERB_OK_IDX_PAYLOAD),size() - ZT_PROTO_VERB_OK_IDX_PAYLOAD);
+#endif
 					network->handleConfigChunk(*this,ZT_PROTO_VERB_OK_IDX_PAYLOAD);
+				}
 			}	break;
 
 			case Packet::VERB_MULTICAST_GATHER: {
@@ -922,6 +926,9 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const Shared
 	try {
 		const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PACKET_IDX_PAYLOAD)));
 		if (network) {
+#ifdef ZT_ENABLE_CLUSTER
+			RR->cluster->broadcastNetworkConfigChunk(field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD),size() - ZT_PACKET_IDX_PAYLOAD);
+#endif
 			const uint64_t configUpdateId = network->handleConfigChunk(*this,ZT_PACKET_IDX_PAYLOAD);
 			if (configUpdateId) {
 				Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);