From 86da073226b27c976f99d22c5b32ba8ed673b9ef Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 2 Dec 2018 22:49:27 +0000 Subject: [PATCH 1/4] Add SwitchOptions and MaxTotalQueueSize --- src/yggdrasil/admin.go | 2 +- src/yggdrasil/config/config.go | 6 +++++ src/yggdrasil/core.go | 4 ++++ src/yggdrasil/switch.go | 41 +++++++++++++++++----------------- yggdrasil.go | 1 + yggdrasilctl.go | 2 +- 6 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 86ca657..7784ea4 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -638,7 +638,7 @@ func (a *admin) getData_getSwitchQueues() admin_nodeInfo { {"queues_size", switchTable.queues.size}, {"highest_queues_count", switchTable.queues.maxbufs}, {"highest_queues_size", switchTable.queues.maxsize}, - {"maximum_queues_size", switch_buffer_maxSize}, + {"maximum_queues_size", switchTable.queuetotalmaxsize}, } } a.core.switchTable.doAdmin(getSwitchQueues) diff --git a/src/yggdrasil/config/config.go b/src/yggdrasil/config/config.go index a14ece9..855eb92 100644 --- a/src/yggdrasil/config/config.go +++ b/src/yggdrasil/config/config.go @@ -18,6 +18,7 @@ type NodeConfig struct { IfMTU int `comment:"Maximux Transmission Unit (MTU) size for your local TUN/TAP interface.\nDefault is the largest supported size for your platform. The lowest\npossible value is 1280."` SessionFirewall SessionFirewall `comment:"The session firewall controls who can send/receive network traffic\nto/from. This is useful if you want to protect this node without\nresorting to using a real firewall. This does not affect traffic\nbeing routed via this node to somewhere else. Rules are prioritised as\nfollows: blacklist, whitelist, always allow outgoing, direct, remote."` TunnelRouting TunnelRouting `comment:"Allow tunneling non-Yggdrasil traffic over Yggdrasil. This effectively\nallows you to use Yggdrasil to route to, or to bridge other networks,\nsimilar to a VPN tunnel. Tunnelling works between any two nodes and\ndoes not require them to be directly peered."` + SwitchOptions SwitchOptions `comment:"Advanced options for tuning the switch. Normally you will not need\nto edit these options."` //Net NetConfig `comment:"Extended options for connecting to peers over other networks."` } @@ -45,3 +46,8 @@ type TunnelRouting struct { IPv4Destinations map[string]string `comment:"IPv4 CIDR subnets, mapped to the EncryptionPublicKey to which they\nshould be routed, e.g. { \"a.b.c.d/e\": \"boxpubkey\", ... }"` IPv4Sources []string `comment:"IPv4 source subnets which are allowed to be tunnelled. Unlike for\nIPv6, this option is required for bridging IPv4 traffic. Only\ntraffic with a source matching these subnets will be tunnelled."` } + +// SwitchOptions contains tuning options for the switch +type SwitchOptions struct { + MaxTotalQueueSize uint64 `comment:"Maximum size of all switch queues combined."` +} diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 9b9bcc1..67a50c9 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -105,6 +105,10 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { return err } + c.switchTable.doAdmin(func() { + c.switchTable.queuetotalmaxsize = nc.SwitchOptions.MaxTotalQueueSize + }) + c.sessions.setSessionFirewallState(nc.SessionFirewall.Enable) c.sessions.setSessionFirewallDefaults( nc.SessionFirewall.AllowFromDirect, diff --git a/src/yggdrasil/switch.go b/src/yggdrasil/switch.go index 28f8312..5dede5b 100644 --- a/src/yggdrasil/switch.go +++ b/src/yggdrasil/switch.go @@ -156,19 +156,20 @@ type switchData struct { // All the information stored by the switch. type switchTable struct { - core *Core - key sigPubKey // Our own key - time time.Time // Time when locator.tstamp was last updated - drop map[sigPubKey]int64 // Tstamp associated with a dropped root - mutex sync.RWMutex // Lock for reads/writes of switchData - parent switchPort // Port of whatever peer is our parent, or self if we're root - data switchData // - updater atomic.Value // *sync.Once - table atomic.Value // lookupTable - packetIn chan []byte // Incoming packets for the worker to handle - idleIn chan switchPort // Incoming idle notifications from peer links - admin chan func() // Pass a lambda for the admin socket to query stuff - queues switch_buffers // Queues - not atomic so ONLY use through admin chan + core *Core + key sigPubKey // Our own key + time time.Time // Time when locator.tstamp was last updated + drop map[sigPubKey]int64 // Tstamp associated with a dropped root + mutex sync.RWMutex // Lock for reads/writes of switchData + parent switchPort // Port of whatever peer is our parent, or self if we're root + data switchData // + updater atomic.Value // *sync.Once + table atomic.Value // lookupTable + packetIn chan []byte // Incoming packets for the worker to handle + idleIn chan switchPort // Incoming idle notifications from peer links + admin chan func() // Pass a lambda for the admin socket to query stuff + queues switch_buffers // Queues - not atomic so ONLY use through admin chan + queuetotalmaxsize uint64 // Maximum combined size of queues } // Initializes the switchTable struct. @@ -620,8 +621,6 @@ type switch_packetInfo struct { time time.Time // Timestamp of when the packet arrived } -const switch_buffer_maxSize = 4 * 1048576 // Maximum 4 MB - // Used to keep track of buffered packets type switch_buffer struct { packets []switch_packetInfo // Currently buffered packets, which may be dropped if it grows too large @@ -629,10 +628,11 @@ type switch_buffer struct { } type switch_buffers struct { - bufs map[string]switch_buffer // Buffers indexed by StreamID - size uint64 // Total size of all buffers, in bytes - maxbufs int - maxsize uint64 + switchTable *switchTable + bufs map[string]switch_buffer // Buffers indexed by StreamID + size uint64 // Total size of all buffers, in bytes + maxbufs int + maxsize uint64 } func (b *switch_buffers) cleanup(t *switchTable) { @@ -649,7 +649,7 @@ func (b *switch_buffers) cleanup(t *switchTable) { } } - for b.size > switch_buffer_maxSize { + for b.size > b.switchTable.queuetotalmaxsize { // Drop a random queue target := rand.Uint64() % b.size var size uint64 // running total @@ -719,6 +719,7 @@ func (t *switchTable) handleIdle(port switchPort) bool { // The switch worker does routing lookups and sends packets to where they need to be func (t *switchTable) doWorker() { + t.queues.switchTable = t t.queues.bufs = make(map[string]switch_buffer) // Packets per PacketStreamID (string) idle := make(map[switchPort]struct{}) // this is to deduplicate things for { diff --git a/yggdrasil.go b/yggdrasil.go index 447bb3e..c3df805 100644 --- a/yggdrasil.go +++ b/yggdrasil.go @@ -69,6 +69,7 @@ func generateConfig(isAutoconf bool) *nodeConfig { cfg.SessionFirewall.Enable = false cfg.SessionFirewall.AllowFromDirect = true cfg.SessionFirewall.AllowFromRemote = true + cfg.SwitchOptions.MaxTotalQueueSize = 4 * 1048576 return &cfg } diff --git a/yggdrasilctl.go b/yggdrasilctl.go index ac25efd..79b5f86 100644 --- a/yggdrasilctl.go +++ b/yggdrasilctl.go @@ -216,8 +216,8 @@ func main() { fmt.Printf("Highest queue size: %d bytes\n", uint(highestqueuesize)) } if m, ok := v["maximum_queues_size"].(float64); ok { - fmt.Printf("Maximum queue size: %d bytes\n", uint(maximumqueuesize)) maximumqueuesize = m + fmt.Printf("Maximum queue size: %d bytes\n", uint(maximumqueuesize)) } if queues, ok := v["queues"].([]interface{}); ok { if len(queues) != 0 { From 319457ae2747bf926577c242d4c5f338f25accd2 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 2 Dec 2018 23:03:10 +0000 Subject: [PATCH 2/4] Update comment for MaxTotalQueueSize --- src/yggdrasil/config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yggdrasil/config/config.go b/src/yggdrasil/config/config.go index 855eb92..904907b 100644 --- a/src/yggdrasil/config/config.go +++ b/src/yggdrasil/config/config.go @@ -49,5 +49,5 @@ type TunnelRouting struct { // SwitchOptions contains tuning options for the switch type SwitchOptions struct { - MaxTotalQueueSize uint64 `comment:"Maximum size of all switch queues combined."` + MaxTotalQueueSize uint64 `comment:"Maximum size of all switch queues combined (in bytes)."` } From b5f4637b5cceac4630fda0ad4df53be2059c6253 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 2 Dec 2018 23:20:11 +0000 Subject: [PATCH 3/4] Enforce min 4MB switch queue total size --- src/yggdrasil/admin.go | 2 +- src/yggdrasil/core.go | 8 +++++--- src/yggdrasil/switch.go | 8 ++++++-- yggdrasil.go | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/yggdrasil/admin.go b/src/yggdrasil/admin.go index 7784ea4..2b5bc64 100644 --- a/src/yggdrasil/admin.go +++ b/src/yggdrasil/admin.go @@ -638,7 +638,7 @@ func (a *admin) getData_getSwitchQueues() admin_nodeInfo { {"queues_size", switchTable.queues.size}, {"highest_queues_count", switchTable.queues.maxbufs}, {"highest_queues_size", switchTable.queues.maxsize}, - {"maximum_queues_size", switchTable.queuetotalmaxsize}, + {"maximum_queues_size", switchTable.queueTotalMaxSize}, } } a.core.switchTable.doAdmin(getSwitchQueues) diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 67a50c9..224945e 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -105,9 +105,11 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { return err } - c.switchTable.doAdmin(func() { - c.switchTable.queuetotalmaxsize = nc.SwitchOptions.MaxTotalQueueSize - }) + if nc.SwitchOptions.MaxTotalQueueSize >= SwitchQueueTotalMinSize { + c.switchTable.doAdmin(func() { + c.switchTable.queueTotalMaxSize = nc.SwitchOptions.MaxTotalQueueSize + }) + } c.sessions.setSessionFirewallState(nc.SessionFirewall.Enable) c.sessions.setSessionFirewallDefaults( diff --git a/src/yggdrasil/switch.go b/src/yggdrasil/switch.go index 5dede5b..adb624a 100644 --- a/src/yggdrasil/switch.go +++ b/src/yggdrasil/switch.go @@ -169,9 +169,12 @@ type switchTable struct { idleIn chan switchPort // Incoming idle notifications from peer links admin chan func() // Pass a lambda for the admin socket to query stuff queues switch_buffers // Queues - not atomic so ONLY use through admin chan - queuetotalmaxsize uint64 // Maximum combined size of queues + queueTotalMaxSize uint64 // Maximum combined size of queues } +// Minimum allowed total size of switch queues. +const SwitchQueueTotalMinSize = 4 * 1024 * 1024 + // Initializes the switchTable struct. func (t *switchTable) init(core *Core, key sigPubKey) { now := time.Now() @@ -186,6 +189,7 @@ func (t *switchTable) init(core *Core, key sigPubKey) { t.packetIn = make(chan []byte, 1024) t.idleIn = make(chan switchPort, 1024) t.admin = make(chan func()) + t.queueTotalMaxSize = SwitchQueueTotalMinSize } // Safely gets a copy of this node's locator. @@ -649,7 +653,7 @@ func (b *switch_buffers) cleanup(t *switchTable) { } } - for b.size > b.switchTable.queuetotalmaxsize { + for b.size > b.switchTable.queueTotalMaxSize { // Drop a random queue target := rand.Uint64() % b.size var size uint64 // running total diff --git a/yggdrasil.go b/yggdrasil.go index c3df805..8536fa1 100644 --- a/yggdrasil.go +++ b/yggdrasil.go @@ -69,7 +69,7 @@ func generateConfig(isAutoconf bool) *nodeConfig { cfg.SessionFirewall.Enable = false cfg.SessionFirewall.AllowFromDirect = true cfg.SessionFirewall.AllowFromRemote = true - cfg.SwitchOptions.MaxTotalQueueSize = 4 * 1048576 + cfg.SwitchOptions.MaxTotalQueueSize = yggdrasil.SwitchQueueTotalMinSize return &cfg } From 5a89a869be1f94a16c5dd558d5150d1f8af1ff2d Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sun, 2 Dec 2018 23:24:54 +0000 Subject: [PATCH 4/4] Set queueTotalMaxSize before switch worker starts --- src/yggdrasil/core.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index 224945e..706b8aa 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -100,17 +100,15 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error { return err } + if nc.SwitchOptions.MaxTotalQueueSize >= SwitchQueueTotalMinSize { + c.switchTable.queueTotalMaxSize = nc.SwitchOptions.MaxTotalQueueSize + } + if err := c.switchTable.start(); err != nil { c.log.Println("Failed to start switch") return err } - if nc.SwitchOptions.MaxTotalQueueSize >= SwitchQueueTotalMinSize { - c.switchTable.doAdmin(func() { - c.switchTable.queueTotalMaxSize = nc.SwitchOptions.MaxTotalQueueSize - }) - } - c.sessions.setSessionFirewallState(nc.SessionFirewall.Enable) c.sessions.setSessionFirewallDefaults( nc.SessionFirewall.AllowFromDirect,