mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-10 05:10:26 +00:00
when we detect we're blocked, only drop packets often enough to make sure the existing queue's size is non-increasing, and always drop the worst packet from a random flow with odds based on the total size of packets queued for that flow
This commit is contained in:
parent
6e92af1cd2
commit
7720e169f2
@ -1,6 +1,7 @@
|
|||||||
package yggdrasil
|
package yggdrasil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/rand"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -28,32 +29,19 @@ func (q *packetQueue) drop() bool {
|
|||||||
if q.size == 0 {
|
if q.size == 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// TODO? drop from a random stream
|
// select a random stream, odds based on stream size
|
||||||
// odds proportional to size? bandwidth?
|
offset := rand.Uint64() % q.size
|
||||||
// always using the worst is exploitable -> flood 1 packet per random stream
|
|
||||||
// find the stream that's using the most bandwidth
|
|
||||||
now := time.Now()
|
|
||||||
var worst pqStreamID
|
var worst pqStreamID
|
||||||
for id := range q.streams {
|
var size uint64
|
||||||
worst = id
|
|
||||||
break // get a random ID to start
|
|
||||||
}
|
|
||||||
worstStream := q.streams[worst]
|
|
||||||
worstSize := float64(worstStream.size)
|
|
||||||
worstAge := now.Sub(worstStream.infos[0].time).Seconds()
|
|
||||||
for id, stream := range q.streams {
|
for id, stream := range q.streams {
|
||||||
thisSize := float64(stream.size)
|
worst = id
|
||||||
thisAge := now.Sub(stream.infos[0].time).Seconds()
|
size += stream.size
|
||||||
// cross multiply to avoid division by zero issues
|
if size >= offset {
|
||||||
if worstSize*thisAge < thisSize*worstAge {
|
break
|
||||||
// worstSize/worstAge < thisSize/thisAge -> this uses more bandwidth
|
|
||||||
worst = id
|
|
||||||
worstStream = stream
|
|
||||||
worstSize = thisSize
|
|
||||||
worstAge = thisAge
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Drop the oldest packet from the worst stream
|
// drop the oldest packet from the stream
|
||||||
|
worstStream := q.streams[worst]
|
||||||
packet := worstStream.infos[0].packet
|
packet := worstStream.infos[0].packet
|
||||||
worstStream.infos = worstStream.infos[1:]
|
worstStream.infos = worstStream.infos[1:]
|
||||||
worstStream.size -= uint64(len(packet))
|
worstStream.size -= uint64(len(packet))
|
||||||
|
@ -110,6 +110,7 @@ type peer struct {
|
|||||||
queue packetQueue
|
queue packetQueue
|
||||||
seq uint64 // this and idle are used to detect when to drop packets from queue
|
seq uint64 // this and idle are used to detect when to drop packets from queue
|
||||||
idle bool
|
idle bool
|
||||||
|
drop bool // set to true if we're dropping packets from the queue
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *peers) updateTables(from phony.Actor, table *lookupTable) {
|
func (ps *peers) updateTables(from phony.Actor, table *lookupTable) {
|
||||||
@ -275,13 +276,19 @@ func (p *peer) sendPacketsFrom(from phony.Actor, packets [][]byte) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) _sendPackets(packets [][]byte) {
|
func (p *peer) _sendPackets(packets [][]byte) {
|
||||||
|
size := p.queue.size
|
||||||
for _, packet := range packets {
|
for _, packet := range packets {
|
||||||
p.queue.push(packet)
|
p.queue.push(packet)
|
||||||
}
|
}
|
||||||
if p.idle {
|
switch {
|
||||||
|
case p.idle:
|
||||||
p.idle = false
|
p.idle = false
|
||||||
p._handleIdle()
|
p._handleIdle()
|
||||||
} else {
|
case p.drop:
|
||||||
|
for p.queue.size > size {
|
||||||
|
p.queue.drop()
|
||||||
|
}
|
||||||
|
default:
|
||||||
p.intf.notifyQueued(p.seq)
|
p.intf.notifyQueued(p.seq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -303,17 +310,14 @@ func (p *peer) _handleIdle() {
|
|||||||
p.intf.out(packets)
|
p.intf.out(packets)
|
||||||
} else {
|
} else {
|
||||||
p.idle = true
|
p.idle = true
|
||||||
|
p.drop = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *peer) dropFromQueue(from phony.Actor, seq uint64) {
|
func (p *peer) dropFromQueue(from phony.Actor, seq uint64) {
|
||||||
p.Act(from, func() {
|
p.Act(from, func() {
|
||||||
switch {
|
if seq == p.seq {
|
||||||
case seq != p.seq:
|
p.drop = true
|
||||||
case p.queue.size < streamMsgSize:
|
|
||||||
case p.queue.drop():
|
|
||||||
p.core.log.Debugln("DEBUG dropped:", p.port, p.queue.size)
|
|
||||||
p.intf.notifyQueued(p.seq)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user