implement node sync handler, tho needs bug fixes, testing
This commit is contained in:
parent
428aa2a11e
commit
431314292e
3 changed files with 119 additions and 1 deletions
|
|
@ -21,6 +21,8 @@ type LuxNode struct {
|
||||||
|
|
||||||
state LuxNodeState
|
state LuxNodeState
|
||||||
stateLock sync.RWMutex
|
stateLock sync.RWMutex
|
||||||
|
|
||||||
|
genlist net.LuxNonceList
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewLuxNode(nodeKey crypto.LuxKey, ks crypto.LuxKeyStore) LuxNode {
|
func NewLuxNode(nodeKey crypto.LuxKey, ks crypto.LuxKeyStore) LuxNode {
|
||||||
|
|
@ -30,6 +32,7 @@ func NewLuxNode(nodeKey crypto.LuxKey, ks crypto.LuxKeyStore) LuxNode {
|
||||||
running: false,
|
running: false,
|
||||||
neighbors: make(map[proto.LuxID]*ipnet.UDPAddr),
|
neighbors: make(map[proto.LuxID]*ipnet.UDPAddr),
|
||||||
state: NewNodeState(),
|
state: NewNodeState(),
|
||||||
|
genlist: net.NewLuxNonceList(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -51,7 +54,7 @@ func (node *LuxNode) AddExterior(udpAddr string) error {
|
||||||
|
|
||||||
func (node *LuxNode) AddNeighbor(id proto.LuxID, udpAddr string) error {
|
func (node *LuxNode) AddNeighbor(id proto.LuxID, udpAddr string) error {
|
||||||
if bytes.Equal(id.UUID[:], node.nodeId.UUID[:]) {
|
if bytes.Equal(id.UUID[:], node.nodeId.UUID[:]) {
|
||||||
log.Debug("skipping neighbor pointing to this node %s", node.nodeId.String())
|
log.Debugf("skipping neighbor pointing to this node %s", node.nodeId.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -121,7 +124,66 @@ func (node *LuxNode) handleSync(packet *net.LuxPacket) {
|
||||||
log.Errorf("failed to parse sync packet: %v", err)
|
log.Errorf("failed to parse sync packet: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we're already synced, discard
|
||||||
|
if _, ok := sync.Synced[*node.nodeId]; ok {
|
||||||
|
log.Debugf("already synced to %d, discarding", sync.SyncState.generation)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// check generation
|
// check generation
|
||||||
|
if !node.genlist.RotateOrFail(sync.SyncState.generation) {
|
||||||
|
// as additional measure to prevent packet looping, we
|
||||||
|
// check generation against nonce list
|
||||||
|
log.Warningf("already seen %d generation", sync.SyncState.generation)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// populate our neighbor list
|
||||||
|
// (we dont lock neighborLock here)
|
||||||
|
for id, udpAddr := range sync.Neighbors {
|
||||||
|
if _, ok := node.neighbors[id]; !ok {
|
||||||
|
// add new neighbor
|
||||||
|
node.AddNeighbor(id, udpAddr.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// merge sync neighbor list
|
||||||
|
node.neighborLock.Lock()
|
||||||
|
for id, udpAddr := range node.neighbors {
|
||||||
|
sync.Neighbors[id] = udpAddr
|
||||||
|
}
|
||||||
|
node.neighborLock.Unlock()
|
||||||
|
|
||||||
|
// merge our node state table
|
||||||
|
node.stateLock.Lock()
|
||||||
|
node.state.Merge(&sync.SyncState)
|
||||||
|
|
||||||
|
// after merging, we issue new generation
|
||||||
|
oldGeneration := node.state.generation
|
||||||
|
node.state.IssueNewGeneration()
|
||||||
|
|
||||||
|
log.Debugf("new generation %d -> %d", oldGeneration, node.state.generation)
|
||||||
|
node.stateLock.Unlock()
|
||||||
|
|
||||||
|
// add our node to synced list
|
||||||
|
sync.Synced[*node.nodeId] = struct{}{}
|
||||||
|
|
||||||
|
// serialize sync state packet
|
||||||
|
newSyncPacket := net.LuxPacket{
|
||||||
|
Type: net.LuxPacketTypeSync,
|
||||||
|
Buffer: proto.NewLuxBuffer(),
|
||||||
|
}
|
||||||
|
sync.Write(&newSyncPacket.Buffer)
|
||||||
|
|
||||||
|
// finish sender's multicast by sending to all nodes
|
||||||
|
// that aren't in synced list
|
||||||
|
for _, route := range node.router.GetRoutes() {
|
||||||
|
key, _ := node.router.GetRouteKey(route)
|
||||||
|
if _, ok := sync.Synced[key.Id]; !ok {
|
||||||
|
// not in synced list - sending!
|
||||||
|
newSyncPacket.Target = key.Id
|
||||||
|
node.router.Send(newSyncPacket)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func nodeLoop(node *LuxNode) {
|
func nodeLoop(node *LuxNode) {
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ func (ns *LuxNodeState) Merge(new *LuxNodeState) {
|
||||||
} else {
|
} else {
|
||||||
// add new host state
|
// add new host state
|
||||||
ns.hosts[id] = newState
|
ns.hosts[id] = newState
|
||||||
|
log.Debugf("registering %s new host %s", id.String(), newState.State.Hostname)
|
||||||
}
|
}
|
||||||
// let channel receivers know about new merged states
|
// let channel receivers know about new merged states
|
||||||
ns.stateChan <- *ns.hosts[id]
|
ns.stateChan <- *ns.hosts[id]
|
||||||
|
|
|
||||||
|
|
@ -44,3 +44,58 @@ func TestNodeHeartbeat(t *testing.T) {
|
||||||
t.Log(hostState)
|
t.Log(hostState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNodeSync(t *testing.T) {
|
||||||
|
/*
|
||||||
|
NODE A has neighbor NODE B
|
||||||
|
|
||||||
|
NODE A <-- interior 127.0.0.1:9980 --> NODE B
|
||||||
|
^
|
||||||
|
|
|
||||||
|
| <- exterior 127.0.0.1:9979
|
||||||
|
|
|
||||||
|
HOST heartbeats to NODE A
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
ks := crypto.NewLuxKeyStore("/tmp/keystore.dat")
|
||||||
|
|
||||||
|
keyNodeA, _ := crypto.NewLuxKey(proto.LuxTypeNode)
|
||||||
|
ks.Put(keyNodeA)
|
||||||
|
keyNodeB, _ := crypto.NewLuxKey(proto.LuxTypeNode)
|
||||||
|
ks.Put(keyNodeB)
|
||||||
|
keyHost, _ := crypto.NewLuxKey(proto.LuxTypeHost)
|
||||||
|
ks.Put(keyHost)
|
||||||
|
|
||||||
|
nodeA := node.NewLuxNode(keyNodeA, ks)
|
||||||
|
nodeA.AddExterior("127.0.0.1:9979")
|
||||||
|
nodeA.AddNeighbor(keyNodeB.Id, "127.0.0.1:9980")
|
||||||
|
nodeA.Start()
|
||||||
|
defer nodeA.Stop()
|
||||||
|
|
||||||
|
nodeB := node.NewLuxNode(keyNodeB, ks)
|
||||||
|
nodeB.AddInterior("127.0.0.1:9980")
|
||||||
|
nodeB.Start()
|
||||||
|
defer nodeB.Stop()
|
||||||
|
|
||||||
|
host := host.NewLuxHost("test-host", keyHost, ks)
|
||||||
|
host.AddNode(keyNodeA.Id, "127.0.0.1:9979")
|
||||||
|
host.AddOptionProvider(&DummyWANProvider2{})
|
||||||
|
host.Start()
|
||||||
|
defer host.Stop()
|
||||||
|
|
||||||
|
// register some host state into node
|
||||||
|
if err := host.Heartbeat(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// issue node sync
|
||||||
|
if err := nodeA.MulticastSync(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// now we wait and catch option update from node B,
|
||||||
|
// that should be merged from node A sync multicast
|
||||||
|
hostState := <-nodeB.GetHostStateChannel()
|
||||||
|
t.Log(hostState)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue