mirror of
https://github.com/KusakabeShi/EtherGuard-VPN.git
synced 2024-11-07 16:04:00 +01:00
Negative cycle detection and removal
This commit is contained in:
parent
f689aadccf
commit
9054ee126a
@ -143,6 +143,7 @@ type GraphRecalculateSetting struct {
|
||||
JitterTolerance float64
|
||||
JitterToleranceMultiplier float64
|
||||
NodeReportTimeout float64
|
||||
TimeoutCheckInterval float64
|
||||
RecalculateCoolDown float64
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
30
main_edge.go
30
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)
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
14
path/ntp.go
14
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{
|
||||
|
201
path/path.go
201
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,
|
||||
|
Loading…
Reference in New Issue
Block a user