diff --git a/config/config.go b/config/config.go index 3ed9d79..0bdd7a9 100644 --- a/config/config.go +++ b/config/config.go @@ -143,6 +143,7 @@ type GraphRecalculateSetting struct { JitterTolerance float64 JitterToleranceMultiplier float64 NodeReportTimeout float64 + TimeoutCheckInterval float64 RecalculateCoolDown float64 } diff --git a/device/device.go b/device/device.go index 1fc8d31..4725ac9 100644 --- a/device/device.go +++ b/device/device.go @@ -347,11 +347,9 @@ func NewDevice(tapDevice tap.Device, id config.Vertex, bind conn.Bind, logger *L if IsSuperNode { device.Event_server_pong = superevents.Event_server_pong device.Event_server_register = superevents.Event_server_register - device.Event_server_NhTable_changed = superevents.Event_server_NhTable_changed device.LogLevel = sconfig.LogLevel device.SuperConfig = sconfig device.SuperConfigPath = configpath - go device.RoutineRecalculateNhTable() } else { device.EdgeConfigPath = configpath device.EdgeConfig = econfig @@ -367,11 +365,11 @@ func NewDevice(tapDevice tap.Device, id config.Vertex, bind conn.Bind, logger *L go device.RoutineSetEndpoint() go device.RoutineRegister() go device.RoutineSendPing() - go device.RoutineRecalculateNhTable() go device.RoutineSpreadAllMyNeighbor() go device.RoutineResetConn() go device.RoutineClearL2FIB() } + go device.RoutineRecalculateNhTable() // create queues device.queue.handshake = newHandshakeQueue() diff --git a/device/receivesendproc.go b/device/receivesendproc.go index 88a48f4..e053c8d 100644 --- a/device/receivesendproc.go +++ b/device/receivesendproc.go @@ -327,7 +327,7 @@ func (device *Device) process_ping(peer *Peer, content path.PingMsg) error { Timediff: device.graph.GetCurrentTime().Sub(content.Time), } if device.DRoute.P2P.UseP2P && time.Now().After(device.graph.NhTableExpire) { - device.graph.UpdateLentancy(content.Src_nodeID, device.ID, PongMSG.Timediff, true, false) + device.graph.UpdateLatency(content.Src_nodeID, device.ID, PongMSG.Timediff, true, false) } body, err := path.GetByte(&PongMSG) if err != nil { @@ -354,7 +354,7 @@ func (device *Device) process_ping(peer *Peer, content path.PingMsg) error { func (device *Device) process_pong(peer *Peer, content path.PongMsg) error { if device.DRoute.P2P.UseP2P { if time.Now().After(device.graph.NhTableExpire) { - device.graph.UpdateLentancy(content.Src_nodeID, content.Dst_nodeID, content.Timediff, true, false) + device.graph.UpdateLatency(content.Src_nodeID, content.Dst_nodeID, content.Timediff, true, false) } if !peer.AskedForNeighbor { QueryPeerMsg := path.QueryPeerMsg{ @@ -458,10 +458,10 @@ func (device *Device) process_UpdatePeerMsg(peer *Peer, content path.UpdatePeerM fmt.Println("Control: Add new peer to local ID:" + peerinfo.NodeID.ToString() + " PubKey:" + PubKey) } if device.graph.Weight(device.ID, peerinfo.NodeID) == path.Infinity { // add node to graph - device.graph.UpdateLentancy(device.ID, peerinfo.NodeID, path.S2TD(path.Infinity), true, false) + device.graph.UpdateLatency(device.ID, peerinfo.NodeID, path.S2TD(path.Infinity), true, false) } if device.graph.Weight(peerinfo.NodeID, device.ID) == path.Infinity { // add node to graph - device.graph.UpdateLentancy(peerinfo.NodeID, device.ID, path.S2TD(path.Infinity), true, false) + device.graph.UpdateLatency(peerinfo.NodeID, device.ID, path.S2TD(path.Infinity), true, false) } device.NewPeer(sk, peerinfo.NodeID, false) thepeer = device.LookupPeer(sk) @@ -615,10 +615,10 @@ func (device *Device) process_BoardcastPeerMsg(peer *Peer, content path.Boardcas fmt.Println("Control: Add new peer to local ID:" + content.NodeID.ToString() + " PubKey:" + pk.ToString()) } if device.graph.Weight(device.ID, content.NodeID) == path.Infinity { // add node to graph - device.graph.UpdateLentancy(device.ID, content.NodeID, path.S2TD(path.Infinity), true, false) + device.graph.UpdateLatency(device.ID, content.NodeID, path.S2TD(path.Infinity), true, false) } if device.graph.Weight(content.NodeID, device.ID) == path.Infinity { // add node to graph - device.graph.UpdateLentancy(content.NodeID, device.ID, path.S2TD(path.Infinity), true, false) + device.graph.UpdateLatency(content.NodeID, device.ID, path.S2TD(path.Infinity), true, false) } device.NewPeer(pk, content.NodeID, false) } @@ -748,13 +748,16 @@ func (device *Device) RoutineRegister() { } func (device *Device) RoutineRecalculateNhTable() { + if device.graph.TimeoutCheckInterval == 0 { + return + } if device.IsSuperNode { for { changed := device.graph.RecalculateNhTable(true) if changed { device.Event_server_NhTable_changed <- struct{}{} } - time.Sleep(device.graph.NodeReportTimeout) + time.Sleep(device.graph.TimeoutCheckInterval) } } else { if !device.DRoute.P2P.UseP2P { @@ -764,7 +767,7 @@ func (device *Device) RoutineRecalculateNhTable() { if time.Now().After(device.graph.NhTableExpire) { device.graph.RecalculateNhTable(false) } - time.Sleep(device.graph.NodeReportTimeout) + time.Sleep(device.graph.TimeoutCheckInterval) } } } diff --git a/example_config/super_mode/s1.yaml b/example_config/super_mode/s1.yaml index 84a7d89..3ead458 100644 --- a/example_config/super_mode/s1.yaml +++ b/example_config/super_mode/s1.yaml @@ -17,8 +17,9 @@ graphrecalculatesetting: staticmode: false jittertolerance: 5 jittertolerancemultiplier: 1.01 - nodereporttimeout: 50 - recalculatecooldown: 5 + nodereporttimeout: 20 + timeoutcheckinterval: 5 + recalculatecooldown: 1 nexthoptable: 1: 2: 2 diff --git a/main_edge.go b/main_edge.go index 3801545..d8aedab 100644 --- a/main_edge.go +++ b/main_edge.go @@ -120,21 +120,21 @@ func printExampleEdgeConf() { }, }, } - g := path.NewGraph(3, false, tconfig.DynamicRoute.P2P.GraphRecalculateSetting, tconfig.DynamicRoute.NTPconfig, false) + g := path.NewGraph(3, false, tconfig.DynamicRoute.P2P.GraphRecalculateSetting, tconfig.DynamicRoute.NTPconfig, tconfig.LogLevel) - g.UpdateLentancy(1, 2, path.S2TD(0.5), false, false) - g.UpdateLentancy(2, 1, path.S2TD(0.5), false, false) - g.UpdateLentancy(2, 3, path.S2TD(0.5), false, false) - g.UpdateLentancy(3, 2, path.S2TD(0.5), false, false) - g.UpdateLentancy(2, 4, path.S2TD(0.5), false, false) - g.UpdateLentancy(4, 2, path.S2TD(0.5), false, false) - g.UpdateLentancy(3, 4, path.S2TD(0.5), false, false) - g.UpdateLentancy(4, 3, path.S2TD(0.5), false, false) - g.UpdateLentancy(5, 3, path.S2TD(0.5), false, false) - g.UpdateLentancy(3, 5, path.S2TD(0.5), false, false) - g.UpdateLentancy(6, 4, path.S2TD(0.5), false, false) - g.UpdateLentancy(4, 6, path.S2TD(0.5), false, false) - _, next := path.FloydWarshall(g) + g.UpdateLatency(1, 2, path.S2TD(0.5), false, false) + g.UpdateLatency(2, 1, path.S2TD(0.5), false, false) + g.UpdateLatency(2, 3, path.S2TD(0.5), false, false) + g.UpdateLatency(3, 2, path.S2TD(0.5), false, false) + g.UpdateLatency(2, 4, path.S2TD(0.5), false, false) + g.UpdateLatency(4, 2, path.S2TD(0.5), false, false) + g.UpdateLatency(3, 4, path.S2TD(0.5), false, false) + g.UpdateLatency(4, 3, path.S2TD(0.5), false, false) + g.UpdateLatency(5, 3, path.S2TD(0.5), false, false) + g.UpdateLatency(3, 5, path.S2TD(0.5), false, false) + g.UpdateLatency(6, 4, path.S2TD(0.5), false, false) + g.UpdateLatency(4, 6, path.S2TD(0.5), false, false) + _, next, _ := g.FloydWarshall(false) tconfig.NextHopTable = next toprint, _ := yaml.Marshal(tconfig) fmt.Print(string(toprint)) @@ -222,7 +222,7 @@ func Edge(configPath string, useUAPI bool, printExample bool, bindmode string) ( if econfig.DynamicRoute.P2P.UseP2P == false && econfig.DynamicRoute.SuperNode.UseSuperNode == false { econfig.LogLevel.LogNTP = false // NTP in static mode is useless } - graph := path.NewGraph(3, false, econfig.DynamicRoute.P2P.GraphRecalculateSetting, econfig.DynamicRoute.NTPconfig, econfig.LogLevel.LogNTP) + graph := path.NewGraph(3, false, econfig.DynamicRoute.P2P.GraphRecalculateSetting, econfig.DynamicRoute.NTPconfig, econfig.LogLevel) graph.SetNHTable(econfig.NextHopTable, [32]byte{}) the_device := device.NewDevice(thetap, econfig.NodeID, conn.NewDefaultBind(true, true, bindmode), logger, graph, false, configPath, &econfig, nil, nil, Version) diff --git a/main_httpserver.go b/main_httpserver.go index eac249a..9623715 100644 --- a/main_httpserver.go +++ b/main_httpserver.go @@ -56,6 +56,7 @@ type HttpState struct { PeerInfo map[config.Vertex]HttpPeerInfo Infinity float64 Edges map[config.Vertex]map[config.Vertex]float64 + Edges_Nh map[config.Vertex]map[config.Vertex]float64 NhTable config.NextHopTable Dist config.DistTable } @@ -263,9 +264,10 @@ func get_info(w http.ResponseWriter, r *http.Request) { if time.Now().After(http_StateExpire) { hs := HttpState{ PeerInfo: make(map[config.Vertex]HttpPeerInfo), - NhTable: http_graph.GetNHTable(), + NhTable: http_graph.GetNHTable(false), Infinity: path.Infinity, - Edges: http_graph.GetEdges(), + Edges: http_graph.GetEdges(false), + Edges_Nh: http_graph.GetEdges(true), Dist: http_graph.GetDtst(), } http_maps_lock.RLock() diff --git a/main_super.go b/main_super.go index 78e7ee8..bfe845a 100644 --- a/main_super.go +++ b/main_super.go @@ -174,7 +174,7 @@ func Super(configPath string, useUAPI bool, printExample bool, bindmode string) Event_server_register: make(chan path.RegisterMsg, 1<<5), Event_server_NhTable_changed: make(chan struct{}, 1<<4), } - http_graph = path.NewGraph(3, true, sconfig.GraphRecalculateSetting, config.NTPinfo{}, sconfig.LogLevel.LogNTP) + http_graph = path.NewGraph(3, true, sconfig.GraphRecalculateSetting, config.NTPinfo{}, sconfig.LogLevel) http_graph.SetNHTable(http_sconfig.NextHopTable, [32]byte{}) if sconfig.GraphRecalculateSetting.StaticMode { err = checkNhTable(http_sconfig.NextHopTable, sconfig.Peers) @@ -364,7 +364,7 @@ func Event_server_event_hendler(graph *path.IG, events path.SUPER_Events) { PushNhTable(false) } case <-events.Event_server_NhTable_changed: - NhTable := graph.GetNHTable() + NhTable := graph.GetNHTable(true) NhTablestr, _ := json.Marshal(NhTable) md5_hash_raw := md5.Sum(http_NhTableStr) new_hash_str := hex.EncodeToString(md5_hash_raw[:]) @@ -373,9 +373,9 @@ func Event_server_event_hendler(graph *path.IG, events path.SUPER_Events) { http_NhTableStr = NhTablestr PushNhTable(false) case pong_msg := <-events.Event_server_pong: - changed := graph.UpdateLentancy(pong_msg.Src_nodeID, pong_msg.Dst_nodeID, pong_msg.Timediff, true, true) + changed := graph.UpdateLatency(pong_msg.Src_nodeID, pong_msg.Dst_nodeID, pong_msg.Timediff, true, true) if changed { - NhTable := graph.GetNHTable() + NhTable := graph.GetNHTable(true) NhTablestr, _ := json.Marshal(NhTable) md5_hash_raw := md5.Sum(append(http_NhTableStr, http_HashSalt...)) new_hash_str := hex.EncodeToString(md5_hash_raw[:]) @@ -423,7 +423,10 @@ func PushNhTable(force bool) { http_maps_lock.RLock() for pkstr, peerstate := range http_PeerState { isAlive := peerstate.LastSeen.Add(path.S2TD(http_sconfig.GraphRecalculateSetting.NodeReportTimeout)).After(time.Now()) - if (force && isAlive) || peerstate.NhTableState != http_NhTable_Hash { + if !isAlive { + continue + } + if force || peerstate.NhTableState != http_NhTable_Hash { if peer := http_device4.LookupPeerByStr(pkstr); peer != nil && peer.GetEndpointDstStr() != "" { http_device4.SendPacket(peer, path.UpdateNhTable, buf, device.MessageTransportOffsetContent) } @@ -452,6 +455,10 @@ func PushPeerinfo(force bool) { copy(buf[path.EgHeaderLen:], body) http_maps_lock.RLock() for pkstr, peerstate := range http_PeerState { + isAlive := peerstate.LastSeen.Add(path.S2TD(http_sconfig.GraphRecalculateSetting.NodeReportTimeout)).After(time.Now()) + if !isAlive { + continue + } if force || peerstate.PeerInfoState != http_PeerInfo_hash { if peer := http_device4.LookupPeerByStr(pkstr); peer != nil { http_device4.SendPacket(peer, path.UpdatePeer, buf, device.MessageTransportOffsetContent) diff --git a/path/ntp.go b/path/ntp.go index b396b74..b8fdb71 100644 --- a/path/ntp.go +++ b/path/ntp.go @@ -26,8 +26,8 @@ func (g *IG) InitNTP() { g.SyncTimeMultiple(-1) go g.RoutineSyncTime() } else { - if g.ntp_log { - fmt.Println("NTP sync disabled") + if g.loglevel.LogNTP { + fmt.Println("NTP: NTP sync disabled") } } } @@ -87,7 +87,7 @@ func (g *IG) SyncTimeMultiple(count int) { results = append(results, result.ClockOffset) } } - if g.ntp_log { + if g.loglevel.LogNTP { fmt.Println("NTP: All done") } sort.Sort(ByDuration(results)) @@ -99,25 +99,25 @@ func (g *IG) SyncTimeMultiple(count int) { totaltime += result } avgtime := totaltime / time.Duration(len(results)) - if g.ntp_log { + if g.loglevel.LogNTP { fmt.Println("NTP: Arvage offset: " + avgtime.String()) } g.ntp_offset = avgtime } func (g *IG) SyncTime(url string, timeout time.Duration) { - if g.ntp_log { + if g.loglevel.LogNTP { fmt.Println("NTP: Starting syncing with NTP server :" + url) } options := ntp.QueryOptions{Timeout: timeout} response, err := ntp.QueryWithOptions(url, options) if err == nil { - if g.ntp_log { + if g.loglevel.LogNTP { fmt.Println("NTP: NTP server :" + url + "\tResult:" + response.ClockOffset.String() + " RTT:" + response.RTT.String()) } g.ntp_servers.Set(url, *response) } else { - if g.ntp_log { + if g.loglevel.LogNTP { fmt.Println("NTP: NTP server :" + url + "\tFailed :" + err.Error()) } g.ntp_servers.Set(url, ntp.Response{ diff --git a/path/path.go b/path/path.go index f9e8864..4e00f24 100644 --- a/path/path.go +++ b/path/path.go @@ -2,6 +2,7 @@ package path import ( "bytes" + "errors" "fmt" "io/ioutil" "math" @@ -21,17 +22,10 @@ func (g *IG) GetCurrentTime() time.Time { return time.Now().Add(g.ntp_offset).Round(0) } -// A Graph is the interface implemented by graphs that -// this algorithm can run on. -type Graph interface { - Vertices() map[config.Vertex]bool - Neighbors(v config.Vertex) []config.Vertex - Weight(u, v config.Vertex) float64 -} - type Latency struct { - ping float64 - time time.Time + ping float64 + ping_old float64 + time time.Time } type Fullroute struct { @@ -42,7 +36,7 @@ type Fullroute struct { // IG is a graph of integers that satisfies the Graph interface. type IG struct { Vert map[config.Vertex]bool - edges map[config.Vertex]map[config.Vertex]Latency + edges map[config.Vertex]map[config.Vertex]*Latency edgelock *sync.RWMutex StaticMode bool JitterTolerance float64 @@ -50,15 +44,16 @@ type IG struct { NodeReportTimeout time.Duration SuperNodeInfoTimeout time.Duration RecalculateCoolDown time.Duration + TimeoutCheckInterval time.Duration recalculateTime time.Time dlTable config.DistTable nhTable config.NextHopTable NhTableHash [32]byte NhTableExpire time.Time IsSuperMode bool + loglevel config.LoggerInfo ntp_wg sync.WaitGroup - ntp_log bool ntp_info config.NTPinfo ntp_offset time.Duration ntp_servers orderedmap.OrderedMap // serverurl:lentancy @@ -68,7 +63,7 @@ func S2TD(secs float64) time.Duration { return time.Duration(secs * float64(time.Second)) } -func NewGraph(num_node int, IsSuperMode bool, theconfig config.GraphRecalculateSetting, ntpinfo config.NTPinfo, logntp bool) *IG { +func NewGraph(num_node int, IsSuperMode bool, theconfig config.GraphRecalculateSetting, ntpinfo config.NTPinfo, loglevel config.LoggerInfo) *IG { g := IG{ edgelock: &sync.RWMutex{}, StaticMode: theconfig.StaticMode, @@ -76,12 +71,13 @@ func NewGraph(num_node int, IsSuperMode bool, theconfig config.GraphRecalculateS JitterToleranceMultiplier: theconfig.JitterToleranceMultiplier, NodeReportTimeout: S2TD(theconfig.NodeReportTimeout), RecalculateCoolDown: S2TD(theconfig.RecalculateCoolDown), + TimeoutCheckInterval: S2TD(theconfig.TimeoutCheckInterval), ntp_info: ntpinfo, } g.Vert = make(map[config.Vertex]bool, num_node) - g.edges = make(map[config.Vertex]map[config.Vertex]Latency, num_node) + g.edges = make(map[config.Vertex]map[config.Vertex]*Latency, num_node) g.IsSuperMode = IsSuperMode - g.ntp_log = logntp + g.loglevel = loglevel g.InitNTP() return &g } @@ -98,7 +94,7 @@ func (g *IG) GetWeightType(x float64) (y float64) { } func (g *IG) ShouldUpdate(u config.Vertex, v config.Vertex, newval float64) bool { - oldval := math.Abs(g.Weight(u, v) * 1000) + oldval := math.Abs(g.OldWeight(u, v) * 1000) newval = math.Abs(newval * 1000) if g.IsSuperMode { if g.JitterTolerance > 0.001 && g.JitterToleranceMultiplier >= 1 { @@ -121,8 +117,11 @@ func (g *IG) RecalculateNhTable(checkchange bool) (changed bool) { } return } + if !g.ShouldCalculate() { + return + } if g.recalculateTime.Add(g.RecalculateCoolDown).Before(time.Now()) { - dist, next := FloydWarshall(g) + dist, next, _ := g.FloydWarshall(false) changed = false if checkchange { CheckLoop: @@ -144,16 +143,10 @@ func (g *IG) RecalculateNhTable(checkchange bool) (changed bool) { func (g *IG) RemoveVirt(v config.Vertex, recalculate bool, checkchange bool) (changed bool) { //Waiting for test g.edgelock.Lock() - if _, ok := g.Vert[v]; ok { - delete(g.Vert, v) - } - if _, ok := g.edges[v]; ok { - delete(g.edges, v) - } - for u, vv := range g.edges { - if _, ok := vv[v]; ok { - delete(g.edges[u], v) - } + delete(g.Vert, v) + delete(g.edges, v) + for u, _ := range g.edges { + delete(g.edges[u], v) } g.edgelock.Unlock() g.NhTableHash = [32]byte{} @@ -163,21 +156,27 @@ func (g *IG) RemoveVirt(v config.Vertex, recalculate bool, checkchange bool) (ch return } -func (g *IG) UpdateLentancy(u, v config.Vertex, dt time.Duration, recalculate bool, checkchange bool) (changed bool) { +func (g *IG) UpdateLatency(u, v config.Vertex, dt time.Duration, recalculate bool, checkchange bool) (changed bool) { g.edgelock.Lock() g.Vert[u] = true g.Vert[v] = true w := float64(dt) / float64(time.Second) if _, ok := g.edges[u]; !ok { g.recalculateTime = time.Time{} - g.edges[u] = make(map[config.Vertex]Latency) + g.edges[u] = make(map[config.Vertex]*Latency) } g.edgelock.Unlock() should_update := g.ShouldUpdate(u, v, w) g.edgelock.Lock() - g.edges[u][v] = Latency{ - ping: w, - time: time.Now(), + if _, ok := g.edges[u][v]; ok { + g.edges[u][v].ping = w + g.edges[u][v].time = time.Now() + } else { + g.edges[u][v] = &Latency{ + ping: w, + ping_old: Infinity, + time: time.Now(), + } } g.edgelock.Unlock() if should_update && recalculate { @@ -185,7 +184,7 @@ func (g *IG) UpdateLentancy(u, v config.Vertex, dt time.Duration, recalculate bo } return } -func (g IG) Vertices() map[config.Vertex]bool { +func (g *IG) Vertices() map[config.Vertex]bool { vr := make(map[config.Vertex]bool) g.edgelock.RLock() defer g.edgelock.RUnlock() @@ -203,7 +202,7 @@ func (g IG) Neighbors(v config.Vertex) (vs []config.Vertex) { return vs } -func (g IG) Next(u, v config.Vertex) *config.Vertex { +func (g *IG) Next(u, v config.Vertex) *config.Vertex { if _, ok := g.nhTable[u]; !ok { return nil } @@ -213,15 +212,14 @@ func (g IG) Next(u, v config.Vertex) *config.Vertex { return g.nhTable[u][v] } -func (g IG) Weight(u, v config.Vertex) float64 { +func (g *IG) Weight(u, v config.Vertex) (ret float64) { g.edgelock.RLock() defer g.edgelock.RUnlock() + //defer func() { fmt.Println(u, v, ret) }() + if u == v { + return 0 + } if _, ok := g.edges[u]; !ok { - g.edgelock.RUnlock() - g.edgelock.Lock() - g.edges[u] = make(map[config.Vertex]Latency) - g.edgelock.Unlock() - g.edgelock.RLock() return Infinity } if _, ok := g.edges[u][v]; !ok { @@ -233,7 +231,83 @@ func (g IG) Weight(u, v config.Vertex) float64 { return g.edges[u][v].ping } -func FloydWarshall(g Graph) (dist config.DistTable, next config.NextHopTable) { +func (g *IG) OldWeight(u, v config.Vertex) (ret float64) { + g.edgelock.RLock() + defer g.edgelock.RUnlock() + if u == v { + return 0 + } + if _, ok := g.edges[u]; !ok { + return Infinity + } + if _, ok := g.edges[u][v]; !ok { + return Infinity + } + return g.edges[u][v].ping_old +} + +func (g *IG) ShouldCalculate() bool { + vert := g.Vertices() + for u, _ := range vert { + for v, _ := range vert { + if u != v { + w := g.Weight(u, v) + if g.ShouldUpdate(u, v, w) { + return true + } + } + } + } + return false +} + +func (g *IG) SetWeight(u, v config.Vertex, weight float64) { + g.edgelock.Lock() + defer g.edgelock.Unlock() + if _, ok := g.edges[u]; !ok { + return + } + if _, ok := g.edges[u][v]; !ok { + return + } + g.edges[u][v].ping = weight +} + +func (g *IG) SetOldWeight(u, v config.Vertex, weight float64) { + g.edgelock.Lock() + defer g.edgelock.Unlock() + if _, ok := g.edges[u]; !ok { + return + } + if _, ok := g.edges[u][v]; !ok { + return + } + g.edges[u][v].ping_old = weight +} + +func (g *IG) RemoveAllNegativeValue() { + vert := g.Vertices() + for u, _ := range vert { + for v, _ := range vert { + if g.Weight(u, v) < 0 { + if g.loglevel.LogInternal { + fmt.Printf("Internal: Remove negative value : edge[%v][%v] = 0\n", u, v) + } + g.SetWeight(u, v, 0) + } + } + } +} + +func (g *IG) FloydWarshall(again bool) (dist config.DistTable, next config.NextHopTable, err error) { + if g.loglevel.LogInternal { + if !again { + fmt.Println("Internal: Start Floyd Warshall algorithm") + } else { + fmt.Println("Internal: Start Floyd Warshall algorithm again") + + } + } vert := g.Vertices() dist = make(config.DistTable) next = make(config.NextHopTable) @@ -251,6 +325,7 @@ func FloydWarshall(g Graph) (dist config.DistTable, next config.NextHopTable) { dist[u][v] = w next[u][v] = &v } + g.SetOldWeight(u, v, w) } } for k, _ := range vert { @@ -265,7 +340,28 @@ func FloydWarshall(g Graph) (dist config.DistTable, next config.NextHopTable) { } } } - return dist, next + for i := range dist { + if dist[i][i] < 0 { + if !again { + if g.loglevel.LogInternal { + fmt.Println("Internal: Error: Negative cycle detected") + } + g.RemoveAllNegativeValue() + err = errors.New("negative cycle detected") + dist, next, _ = g.FloydWarshall(true) + return + } else { + dist = make(config.DistTable) + next = make(config.NextHopTable) + err = errors.New("negative cycle detected again!") + if g.loglevel.LogInternal { + fmt.Println("Internal: Error: Negative cycle detected again") + } + return + } + } + } + return } func Path(u, v config.Vertex, next config.NextHopTable) (path []config.Vertex) { @@ -286,8 +382,8 @@ func (g *IG) SetNHTable(nh config.NextHopTable, table_hash [32]byte) { // set nh g.NhTableExpire = time.Now().Add(g.SuperNodeInfoTimeout) } -func (g *IG) GetNHTable() config.NextHopTable { - if time.Now().After(g.NhTableExpire) { +func (g *IG) GetNHTable(recalculate bool) config.NextHopTable { + if recalculate && time.Now().After(g.NhTableExpire) { g.RecalculateNhTable(false) } return g.nhTable @@ -297,14 +393,18 @@ func (g *IG) GetDtst() config.DistTable { return g.dlTable } -func (g *IG) GetEdges() (edges map[config.Vertex]map[config.Vertex]float64) { +func (g *IG) GetEdges(isOld bool) (edges map[config.Vertex]map[config.Vertex]float64) { vert := g.Vertices() edges = make(map[config.Vertex]map[config.Vertex]float64, len(vert)) for src, _ := range vert { edges[src] = make(map[config.Vertex]float64, len(vert)) for dst, _ := range vert { if src != dst { - edges[src][dst] = g.Weight(src, dst) + if isOld { + edges[src][dst] = g.OldWeight(src, dst) + } else { + edges[src][dst] = g.Weight(src, dst) + } } } } @@ -369,7 +469,7 @@ func Solve(filePath string, pe bool) error { g := NewGraph(3, false, config.GraphRecalculateSetting{ NodeReportTimeout: 9999, - }, config.NTPinfo{}, false) + }, config.NTPinfo{}, config.LoggerInfo{LogInternal: true}) inputb, err := ioutil.ReadFile(filePath) if err != nil { return err @@ -385,11 +485,14 @@ func Solve(filePath string, pe bool) error { val := a2n(sval) dst := a2v(verts[index+1]) if src != dst && val != Infinity { - g.UpdateLentancy(src, dst, S2TD(val), false, false) + g.UpdateLatency(src, dst, S2TD(val), false, false) } } } - dist, next := FloydWarshall(g) + dist, next, err := g.FloydWarshall(false) + if err != nil { + fmt.Println("Error:", err) + } rr, _ := yaml.Marshal(Fullroute{ Dist: dist,