diff --git a/network/default.go b/network/default.go index 799bc643..35d72184 100644 --- a/network/default.go +++ b/network/default.go @@ -331,10 +331,15 @@ func (n *network) processNetChan(client transport.Client, listener tunnel.Listen continue } log.Debugf("Network received close message from: %s", pbNetClose.Node.Id) - if err := n.pruneNode(pbNetClose.Node.Id); err != nil { - log.Debugf("Network failed to prune the node %s: %v", pbNetClose.Node.Id, err) - continue + n.node.Lock() + peer := &node{ + id: pbNetClose.Node.Id, + address: pbNetClose.Node.Address, } + if err := n.prunePeer(peer); err != nil { + log.Debugf("Network failed to prune node %s routes: %v", peer.id, err) + } + n.node.Unlock() } case <-n.closed: return @@ -393,20 +398,13 @@ func (n *network) announce(client transport.Client) { } } -// pruneNode removes a node with given id from the list of peers. It also removes all routes originted by this node. -func (n *network) pruneNode(id string) error { - // DeletePeer serializes access - n.node.DeletePeer(id) - // lookup all the routes originated at this node - q := router.NewQuery( - router.QueryRouter(id), - ) +// pruneRoutes prunes routes return by given query +func (n *network) pruneRoutes(q router.Query) error { routes, err := n.Router.Table().Query(q) if err != nil && err != router.ErrRouteNotFound { return err } - // delete the found routes - log.Logf("Network deleting routes originated by router: %s", id) + for _, route := range routes { if err := n.Router.Table().Delete(route); err != nil && err != router.ErrRouteNotFound { return err @@ -416,8 +414,41 @@ func (n *network) pruneNode(id string) error { return nil } -// prune the nodes that have not been seen for certain period of time defined by PruneTime -// Additionally, prune also removes all the routes originated by these nodes +// pruneNodeRoutes prunes routes that were either originated by or routable via given node +func (n *network) prunePeerRoutes(peer *node) error { + // lookup all routes originated by router + q := router.NewQuery( + router.QueryRouter(peer.id), + ) + if err := n.pruneRoutes(q); err != nil { + log.Debugf("Network failed deleting routes originated by %s: %s", peer.id, err) + return err + } + + // lookup all routes routable via gw + q = router.NewQuery( + router.QueryGateway(peer.address), + ) + if err := n.pruneRoutes(q); err != nil { + log.Debugf("Network failed deleting routes routable via gateway %s: %s", peer.address, err) + return err + } + + return nil +} + +// prunePeer prune peer from network node as well as all all the routes associated with it +func (n *network) prunePeer(peer *node) error { + delete(n.node.peers, peer.id) + if err := n.prunePeerRoutes(peer); err != nil { + log.Debugf("Network failed to prune %s routes: %v", peer.id, err) + return err + } + return nil +} + +// prune deltes node peers that have not been seen for longer than PruneTime seconds +// prune also removes all the routes either originated by or routable by the stale nodes func (n *network) prune() { prune := time.NewTicker(PruneTime) defer prune.Stop() @@ -427,20 +458,19 @@ func (n *network) prune() { case <-n.closed: return case <-prune.C: - n.Lock() - for id, node := range n.peers { + n.node.Lock() + for id, peer := range n.peers { if id == n.options.Id { continue } - if time.Since(node.lastSeen) > PruneTime { - log.Debugf("Network deleting node %s: reached prune time threshold", id) - if err := n.pruneNode(id); err != nil { - log.Debugf("Network failed to prune the node %s: %v", id, err) - continue + if time.Since(peer.lastSeen) > PruneTime { + log.Debugf("Network peer exceeded prune time: %s", id) + if err := n.prunePeer(peer); err != nil { + log.Debugf("Network failed to prune %s: %s", id, err) } } } - n.Unlock() + n.node.Unlock() } } } diff --git a/network/node.go b/network/node.go index b9c362bb..86cc83fb 100644 --- a/network/node.go +++ b/network/node.go @@ -71,12 +71,15 @@ func (n *node) UpdatePeer(peer *node) bool { return false } -// DeletePeer deletes a peer if it exists -func (n *node) DeletePeer(id string) { +// DeletePeer deletes a peer from node peers +// It returns true if the peers has been deleted +func (n *node) DeletePeer(id string) bool { n.Lock() defer n.Unlock() delete(n.peers, id) + + return true } // HasPeer returns true if node has peer with given id @@ -106,6 +109,7 @@ func (n *node) RefreshPeer(id string, now time.Time) bool { return true } +// walk walks the node graph until some condition is met func (n *node) walk(until func(peer *node) bool) map[string]*node { // track the visited nodes visited := make(map[string]*node) @@ -139,7 +143,7 @@ func (n *node) walk(until func(peer *node) bool) map[string]*node { return visited } -// Nodes returns a slice if all nodes in node topology +// Nodes returns a slice of all nodes in the whole node topology func (n *node) Nodes() []Node { // we need to freeze the network graph here // otherwise we might get inconsisten results @@ -162,8 +166,8 @@ func (n *node) Nodes() []Node { return nodes } -// GetPeerNode returns a peer from node topology i.e. up to MaxDepth -// It returns nil if the peer was not found in the node topology +// GetPeerNode returns a node from node MaxDepth topology +// It returns nil if the peer was not found func (n *node) GetPeerNode(id string) *node { n.RLock() defer n.RUnlock() @@ -185,7 +189,8 @@ func (n *node) GetPeerNode(id string) *node { return peerNode } -// Topology returns a copy of th node topology down to given depth +// Topology returns a copy of the node topology down to given depth +// NOTE: the returned node is a node graph - not a single node func (n *node) Topology(depth uint) *node { n.RLock() defer n.RUnlock()