From a9c710211b8871b66e59f12a0bb3481a85bb26df Mon Sep 17 00:00:00 2001 From: David Wragg Date: Mon, 8 Jun 2015 18:01:00 +0100 Subject: [PATCH] Notify the InterHost when routes change --- router/interhost.go | 10 +++++- router/peer.go | 2 +- router/routes.go | 83 +++++++++++++++++++++++++++++++++++++++------ router/sleeve.go | 4 +++ 4 files changed, 86 insertions(+), 13 deletions(-) diff --git a/router/interhost.go b/router/interhost.go index 3862605b..2f3e9bd1 100644 --- a/router/interhost.go +++ b/router/interhost.go @@ -9,6 +9,10 @@ type InterHost interface { // Start consuming forwarded packets. ConsumePackets(*Peer, *Peers, InterHostConsumer) error + // The routes have changed, so any cached information should + // be discarded. + InvalidateRoutes() + // Form a packet-forwarding connection. The remote UDPAddr // can be nil if unknown (in which case the implementation // needs to discover it). @@ -53,10 +57,14 @@ type InterHostForwarderListener interface { type NullInterHost struct{} -func (NullInterHost) ConsumePackets(*Peer, *Peers, InterHostConsumer) error { +func (NullInterHost) ConsumeInterHostPackets(*Peer, *Peers, + InterHostConsumer) error { return nil } +func (NullInterHost) InvalidateRoutes() { +} + func (NullInterHost) MakeForwarder(*Peer, net.IP, *net.UDPAddr, uint64, InterHostCrypto, func([]byte) error) (InterHostForwarder, error) { return NullInterHost{}, nil diff --git a/router/peer.go b/router/peer.go index afab53b6..43f3f07d 100644 --- a/router/peer.go +++ b/router/peer.go @@ -70,7 +70,7 @@ func (peer *Peer) Info() string { // NB: This function should generally be invoked while holding a read // lock on Peers and LocalPeer. func (peer *Peer) Routes(stopAt *Peer, establishedAndSymmetric bool) (bool, map[PeerName]PeerName) { - routes := make(map[PeerName]PeerName) + routes := make(unicastRoutes) routes[peer.Name] = UnknownPeerName nextWorklist := []*Peer{peer} for len(nextWorklist) > 0 { diff --git a/router/routes.go b/router/routes.go index 1f73833d..2611291f 100644 --- a/router/routes.go +++ b/router/routes.go @@ -7,14 +7,17 @@ import ( "sync" ) +type unicastRoutes map[PeerName]PeerName +type broadcastRoutes map[PeerName][]PeerName + type Routes struct { sync.RWMutex ourself *LocalPeer peers *Peers - unicast map[PeerName]PeerName - unicastAll map[PeerName]PeerName // [1] - broadcast map[PeerName][]PeerName - broadcastAll map[PeerName][]PeerName // [1] + unicast unicastRoutes + unicastAll unicastRoutes // [1] + broadcast broadcastRoutes + broadcastAll broadcastRoutes // [1] recalculate chan<- *struct{} wait chan<- chan struct{} // [1] based on *all* connections, not just established & @@ -27,10 +30,10 @@ func NewRoutes(ourself *LocalPeer, peers *Peers) *Routes { routes := &Routes{ ourself: ourself, peers: peers, - unicast: make(map[PeerName]PeerName), - unicastAll: make(map[PeerName]PeerName), - broadcast: make(map[PeerName][]PeerName), - broadcastAll: make(map[PeerName][]PeerName), + unicast: make(unicastRoutes), + unicastAll: make(unicastRoutes), + broadcast: make(broadcastRoutes), + broadcastAll: make(broadcastRoutes), recalculate: recalculate, wait: wait} routes.unicast[ourself.Name] = UnknownPeerName @@ -166,6 +169,8 @@ func (routes *Routes) calculate() { routes.peers.RLock() routes.ourself.RLock() var ( + oldUnicast = routes.unicast + oldBroadcast = routes.broadcast unicast = routes.calculateUnicast(true) unicastAll = routes.calculateUnicast(false) broadcast = routes.calculateBroadcast(true) @@ -180,6 +185,10 @@ func (routes *Routes) calculate() { routes.broadcast = broadcast routes.broadcastAll = broadcastAll routes.Unlock() + + if !unicast.equals(oldUnicast) || !broadcast.equals(oldBroadcast) { + routes.ourself.router.InterHost.InvalidateRoutes() + } } // Calculate all the routes for the question: if *we* want to send a @@ -191,7 +200,7 @@ func (routes *Routes) calculate() { // any knowledge of the MAC address at all. Thus there's no need // to exchange knowledge of MAC addresses, nor any constraints on // the routes that we construct. -func (routes *Routes) calculateUnicast(establishedAndSymmetric bool) map[PeerName]PeerName { +func (routes *Routes) calculateUnicast(establishedAndSymmetric bool) unicastRoutes { _, unicast := routes.ourself.Routes(nil, establishedAndSymmetric) return unicast } @@ -214,8 +223,8 @@ func (routes *Routes) calculateUnicast(establishedAndSymmetric bool) map[PeerNam // Y =/= Z /\ X.Routes(Y) <= X.Routes(Z) => // X.Routes(Y) u [P | Y.HasSymmetricConnectionTo(P)] <= X.Routes(Z) // where <= is the subset relationship on keys of the returned map. -func (routes *Routes) calculateBroadcast(establishedAndSymmetric bool) map[PeerName][]PeerName { - broadcast := make(map[PeerName][]PeerName) +func (routes *Routes) calculateBroadcast(establishedAndSymmetric bool) broadcastRoutes { + broadcast := make(broadcastRoutes) for _, peer := range routes.peers.table { hops := []PeerName{} if found, reached := peer.Routes(routes.ourself.Peer, establishedAndSymmetric); found { @@ -226,3 +235,55 @@ func (routes *Routes) calculateBroadcast(establishedAndSymmetric bool) map[PeerN } return broadcast } + +func (a unicastRoutes) equals(b unicastRoutes) bool { + for key, aval := range a { + if bval, ok := b[key]; !ok || bval != aval { + return false + } + } + + for key := range b { + if _, ok := a[key]; !ok { + return false + } + } + + return true +} + +func (a broadcastRoutes) equals(b broadcastRoutes) bool { + set := make(map[PeerName]struct{}) + + for key, aval := range a { + bval, ok := b[key] + if !ok { + return false + } + + for _, peer := range aval { + set[peer] = struct{}{} + } + + for _, peer := range bval { + if _, ok := set[peer]; !ok { + return false + } + + delete(set, peer) + } + + if len(set) != 0 { + return false + } + + } + + for key := range b { + if _, ok := a[key]; !ok { + return false + } + } + + return true +} diff --git a/router/sleeve.go b/router/sleeve.go index c8cf7fe7..0f0a28c6 100644 --- a/router/sleeve.go +++ b/router/sleeve.go @@ -86,6 +86,10 @@ func (sleeve *SleeveInterHost) ConsumePackets(localPeer *Peer, peers *Peers, return nil } +func (*SleeveInterHost) InvalidateRoutes() { + // no cached information, so nothing to do +} + func (sleeve *SleeveInterHost) logFrame(string, []byte, *layers.Ethernet) { // XXX }