From ae2cc13d141cd1385bd920b6a657e6cd8323b586 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 17 May 2019 22:29:52 +0100 Subject: [PATCH] Fix configuration reloading support --- cmd/yggdrasil/main.go | 65 ++------------------------------------ src/multicast/multicast.go | 34 ++++++++++++++++++++ src/tuntap/tun.go | 32 +++++++++++++++++++ src/yggdrasil/core.go | 6 ++-- 4 files changed, 71 insertions(+), 66 deletions(-) diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 96349835..52ddfe9c 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -280,69 +280,6 @@ func main() { defer func() { n.core.Stop() }() - // Listen for new sessions - /* - go func() { - listener, err := n.core.ListenConn() - if err != nil { - logger.Errorln("Unable to listen for sessions:", err) - return - } - for { - conn, err := listener.Accept() - if err != nil { - logger.Errorln("Accept:", err) - continue - } - logger.Println("Accepted") - for { - b := make([]byte, 100) - if n, err := conn.Read(b); err != nil { - logger.Errorln("Read failed:", err) - time.Sleep(time.Second * 2) - } else { - logger.Println("Read", n, "bytes:", b) - b = []byte{5, 5, 5} - if n, err := conn.Write(b); err != nil { - logger.Errorln("Write failed:", err) - time.Sleep(time.Second * 2) - } else { - logger.Println("Wrote", n, "bytes:", b) - } - } - } - } - }() - // Try creating new sessions - go func() { - if cfg.EncryptionPublicKey != "533574224115f835b7c7db6433986bc5aef855ff9c9568c01abeb0fbed3e8810" { - return - } - time.Sleep(time.Second * 2) - conn, err := n.core.Dial("nodeid", "9890e135604e8aa6039a909e40c629824d852042a70e51957d5b9d700195663d50552e8e869af132b4617d76f8ef00314d94cce23aa8d6b051b3b952a32a4966") - if err != nil { - logger.Errorln("Dial:", err) - return - } - go func() { - for { - time.Sleep(time.Second * 2) - b := []byte{1, 2, 3, 4, 5} - if n, err := conn.Write(b); err != nil { - logger.Errorln("Write failed:", err) - } else { - logger.Println("Wrote", n, "bytes:", b) - b = make([]byte, 100) - if n, err := conn.Read(b); err != nil { - logger.Errorln("Read failed:", err) - } else { - logger.Println("Read", n, "bytes:", b) - } - } - } - }() - }() - */ // Make some nice output that tells us what our IPv6 address and subnet are. // This is just logged to stdout for the user. address := n.core.Address() @@ -367,6 +304,8 @@ func main() { if *useconffile != "" { cfg = readConfig(useconf, useconffile, normaliseconf) n.core.UpdateConfig(cfg) + n.tuntap.UpdateConfig(cfg) + n.multicast.UpdateConfig(cfg) } else { logger.Errorln("Reloading config at runtime is only possible with -useconffile") } diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 4e5bc4b1..8d18889d 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -41,6 +41,10 @@ func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log go func() { for { e := <-m.reconfigure + // There's nothing particularly to do here because the multicast module + // already consults the config.NodeState when enumerating multicast + // interfaces on each pass. We just need to return nil so that the + // reconfiguration doesn't block indefinitely e <- nil } }() @@ -89,6 +93,36 @@ func (m *Multicast) Stop() error { return nil } +// UpdateConfig updates the multicast module with the provided config.NodeConfig +// and then signals the various module goroutines to reconfigure themselves if +// needed. +func (m *Multicast) UpdateConfig(config *config.NodeConfig) { + m.log.Debugln("Reloading multicast configuration...") + + m.config.Replace(*config) + + errors := 0 + + components := []chan chan error{ + m.reconfigure, + } + + for _, component := range components { + response := make(chan error) + component <- response + if err := <-response; err != nil { + m.log.Errorln(err) + errors++ + } + } + + if errors > 0 { + m.log.Warnln(errors, "multicast module(s) reported errors during configuration reload") + } else { + m.log.Infoln("Multicast configuration reloaded successfully") + } +} + func (m *Multicast) interfaces() map[string]net.Interface { // Get interface expressions from config current, _ := m.config.Get() diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index a73dde17..310e4211 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -148,6 +148,7 @@ func (tun *TunAdapter) Start() error { tun.mutex.Lock() tun.isOpen = true tun.send = make(chan []byte, 32) // TODO: is this a sensible value? + tun.reconfigure = make(chan chan error) tun.mutex.Unlock() if iftapmode { go func() { @@ -178,6 +179,37 @@ func (tun *TunAdapter) Start() error { return nil } +// UpdateConfig updates the TUN/TAP module with the provided config.NodeConfig +// and then signals the various module goroutines to reconfigure themselves if +// needed. +func (tun *TunAdapter) UpdateConfig(config *config.NodeConfig) { + tun.log.Debugln("Reloading TUN/TAP configuration...") + + tun.config.Replace(*config) + + errors := 0 + + components := []chan chan error{ + tun.reconfigure, + tun.ckr.reconfigure, + } + + for _, component := range components { + response := make(chan error) + component <- response + if err := <-response; err != nil { + tun.log.Errorln(err) + errors++ + } + } + + if errors > 0 { + tun.log.Warnln(errors, "TUN/TAP module(s) reported errors during configuration reload") + } else { + tun.log.Infoln("TUN/TAP configuration reloaded successfully") + } +} + func (tun *TunAdapter) handler() error { for { // Accept the incoming connection diff --git a/src/yggdrasil/core.go b/src/yggdrasil/core.go index ac2b494f..63d33d91 100644 --- a/src/yggdrasil/core.go +++ b/src/yggdrasil/core.go @@ -114,7 +114,7 @@ func (c *Core) addPeerLoop() { // config.NodeConfig and then signals the various module goroutines to // reconfigure themselves if needed. func (c *Core) UpdateConfig(config *config.NodeConfig) { - c.log.Infoln("Reloading configuration...") + c.log.Debugln("Reloading node configuration...") c.config.Replace(*config) @@ -141,9 +141,9 @@ func (c *Core) UpdateConfig(config *config.NodeConfig) { } if errors > 0 { - c.log.Warnln(errors, "modules reported errors during configuration reload") + c.log.Warnln(errors, "node module(s) reported errors during configuration reload") } else { - c.log.Infoln("Configuration reloaded successfully") + c.log.Infoln("Node configuration reloaded successfully") } }