Negative cycle detection and removal

This commit is contained in:
KusakabeSi 2021-10-12 08:05:23 +00:00
parent f689aadccf
commit 9054ee126a
9 changed files with 206 additions and 91 deletions

View File

@ -143,6 +143,7 @@ type GraphRecalculateSetting struct {
JitterTolerance float64
JitterToleranceMultiplier float64
NodeReportTimeout float64
TimeoutCheckInterval float64
RecalculateCoolDown float64
}

View File

@ -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()

View File

@ -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)
}
}
}

View File

@ -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

View File

@ -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)

View File

@ -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()

View File

@ -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)

View File

@ -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{

View File

@ -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,