From a115d18595e748dc1deddc5fd12a56bb0f747014 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 2 May 2020 22:26:41 +0100 Subject: [PATCH 1/6] Refactor the multicast code a bit --- src/multicast/multicast.go | 275 ++++++++++++++++++------------------- 1 file changed, 134 insertions(+), 141 deletions(-) diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 93bf94b..6ceef0a 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -15,40 +15,57 @@ import ( "golang.org/x/net/ipv6" ) +const ( + // GroupAddr contains the multicast group and port used for multicast packets. + GroupAddr = "[ff02::114]:9001" +) + // Multicast represents the multicast advertisement and discovery mechanism used // by Yggdrasil to find peers on the same subnet. When a beacon is received on a // configured multicast interface, Yggdrasil will attempt to peer with that node // automatically. type Multicast struct { phony.Inbox - core *yggdrasil.Core - config *config.NodeState - log *log.Logger - sock *ipv6.PacketConn - groupAddr string - listeners map[string]*listenerInfo - listenPort uint16 - isOpen bool - announcer *time.Timer - platformhandler *time.Timer + core *yggdrasil.Core + config *config.NodeState + log *log.Logger + sock *ipv6.PacketConn + groupAddr *net.UDPAddr + listeners map[string]*multicastInterface + listenPort uint16 + isOpen bool + interfaceMonitor *time.Timer + announcer *time.Timer + platformhandler *time.Timer } -type listenerInfo struct { +type multicastInterface struct { + phony.Inbox + sock *ipv6.PacketConn + destAddr net.UDPAddr listener *yggdrasil.TcpListener - time time.Time + zone string + timer *time.Timer interval time.Duration + send chan<- beacon + stop chan interface{} +} + +type beacon struct { + llAddr string + zone string } // Init prepares the multicast interface for use. -func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log.Logger, options interface{}) error { +func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log.Logger, options interface{}) (err error) { m.core = core m.config = state m.log = log - m.listeners = make(map[string]*listenerInfo) + m.listeners = make(map[string]*multicastInterface) current := m.config.GetCurrent() m.listenPort = current.LinkLocalTCPPort - m.groupAddr = "[ff02::114]:9001" - return nil + m.groupAddr, err = net.ResolveUDPAddr("udp6", GroupAddr) + return } // Start starts the multicast interface. This launches goroutines which will @@ -71,7 +88,7 @@ func (m *Multicast) _start() error { return nil } m.log.Infoln("Starting multicast module") - addr, err := net.ResolveUDPAddr("udp", m.groupAddr) + addr, err := net.ResolveUDPAddr("udp", GroupAddr) if err != nil { return err } @@ -91,7 +108,7 @@ func (m *Multicast) _start() error { m.isOpen = true go m.listen() m.Act(m, m.multicastStarted) - m.Act(m, m.announce) + m.Act(m, m.monitorInterfaceChanges) return nil } @@ -118,9 +135,14 @@ func (m *Multicast) Stop() error { func (m *Multicast) _stop() error { m.log.Infoln("Stopping multicast module") m.isOpen = false - if m.announcer != nil { - m.announcer.Stop() - } + /* + if m.monitorInterfaceChanges != nil { + m.monitorInterfaceChanges.Stop() + } + if m.sendBeacons != nil { + m.sendBeacons.Stop() + } + */ if m.platformhandler != nil { m.platformhandler.Stop() } @@ -156,6 +178,83 @@ func (m *Multicast) _updateConfig(config *config.NodeConfig) { m.log.Debugln("Reloaded multicast configuration successfully") } +func (m *Multicast) monitorInterfaceChanges() { + interfaces := m.Interfaces() + + // Look for interfaces we don't know about yet. + for name, intf := range interfaces { + if _, ok := m.listeners[name]; !ok { + // Look up interface addresses. + addrs, err := intf.Addrs() + if err != nil { + continue + } + // Find the first link-local address. + for _, addr := range addrs { + addrIP, _, _ := net.ParseCIDR(addr.String()) + // Join the multicast group. + m.sock.JoinGroup(&intf, m.groupAddr) + // Construct a listener on this address. + listenaddr := fmt.Sprintf("[%s%%%s]:%d", addrIP, intf.Name, m.listenPort) + listener, err := m.core.ListenTCP(listenaddr) + if err != nil { + m.log.Warnln("Not multicasting on", name, "due to error:", err) + continue + } + // This is a new interface. Start an announcer for it. + multicastInterface := &multicastInterface{ + sock: m.sock, + destAddr: *m.groupAddr, + listener: listener, + stop: make(chan interface{}), + zone: name, + } + multicastInterface.Act(multicastInterface, multicastInterface.announce) + m.listeners[name] = multicastInterface + m.log.Infoln("Started multicasting on", name) + break + } + } + } + // Look for interfaces we knew about but are no longer there. + for name, intf := range m.listeners { + if _, ok := interfaces[name]; !ok { + // This is a disappeared interface. Stop the announcer. + close(intf.stop) + delete(m.listeners, name) + m.log.Infoln("Stopped multicasting on", name) + } + } + // Queue the next check. + m.interfaceMonitor = time.AfterFunc(time.Second, func() { + m.Act(m, m.monitorInterfaceChanges) + }) +} + +func (m *multicastInterface) announce() { + // Check if the multicast interface has been stopped. This will happen + // if it disappears from the system or goes down. + select { + case <-m.stop: + return + default: + } + // Send the beacon. + lladdr := m.listener.Listener.Addr().String() + if a, err := net.ResolveTCPAddr("tcp6", lladdr); err == nil { + a.Zone = "" + msg := []byte(a.String()) + m.sock.WriteTo(msg, nil, &m.destAddr) + } + // Queue the next beacon. + if m.interval.Seconds() < 15 { + m.interval += time.Second + } + m.timer = time.AfterFunc(m.interval, func() { + m.Act(m, m.announce) + }) +} + // GetInterfaces returns the currently known/enabled multicast interfaces. It is // expected that UpdateInterfaces has been called at least once before calling // this method. @@ -183,6 +282,19 @@ func (m *Multicast) Interfaces() map[string]net.Interface { // Ignore point-to-point interfaces continue } + addrs, _ := iface.Addrs() + hasLLAddr := false + for _, addr := range addrs { + addrIP, _, _ := net.ParseCIDR(addr.String()) + if addrIP.To4() == nil && addrIP.IsLinkLocalUnicast() { + hasLLAddr = true + break + } + } + if !hasLLAddr { + // Ignore interfaces without link-local addresses + continue + } for _, expr := range exprs { // Compile each regular expression e, err := regexp.Compile(expr) @@ -198,127 +310,8 @@ func (m *Multicast) Interfaces() map[string]net.Interface { return interfaces } -func (m *Multicast) announce() { - groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr) - if err != nil { - panic(err) - } - destAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr) - if err != nil { - panic(err) - } - interfaces := m.Interfaces() - // There might be interfaces that we configured listeners for but are no - // longer up - if that's the case then we should stop the listeners - for name, info := range m.listeners { - // Prepare our stop function! - stop := func() { - info.listener.Stop() - delete(m.listeners, name) - m.log.Debugln("No longer multicasting on", name) - } - // If the interface is no longer visible on the system then stop the - // listener, as another one will be started further down - if _, ok := interfaces[name]; !ok { - stop() - continue - } - // It's possible that the link-local listener address has changed so if - // that is the case then we should clean up the interface listener - found := false - listenaddr, err := net.ResolveTCPAddr("tcp6", info.listener.Listener.Addr().String()) - if err != nil { - stop() - continue - } - // Find the interface that matches the listener - if intf, err := net.InterfaceByName(name); err == nil { - if addrs, err := intf.Addrs(); err == nil { - // Loop through the addresses attached to that listener and see if any - // of them match the current address of the listener - for _, addr := range addrs { - if ip, _, err := net.ParseCIDR(addr.String()); err == nil { - // Does the interface address match our listener address? - if ip.Equal(listenaddr.IP) { - found = true - break - } - } - } - } - } - // If the address has not been found on the adapter then we should stop - // and clean up the TCP listener. A new one will be created below if a - // suitable link-local address is found - if !found { - stop() - } - } - // Now that we have a list of valid interfaces from the operating system, - // we can start checking if we can send multicasts on them - for _, iface := range interfaces { - // Find interface addresses - addrs, err := iface.Addrs() - if err != nil { - panic(err) - } - for _, addr := range addrs { - addrIP, _, _ := net.ParseCIDR(addr.String()) - // Ignore IPv4 addresses - if addrIP.To4() != nil { - continue - } - // Ignore non-link-local addresses - if !addrIP.IsLinkLocalUnicast() { - continue - } - // Join the multicast group - m.sock.JoinGroup(&iface, groupAddr) - // Try and see if we already have a TCP listener for this interface - var info *listenerInfo - if nfo, ok := m.listeners[iface.Name]; !ok || nfo.listener.Listener == nil { - // No listener was found - let's create one - listenaddr := fmt.Sprintf("[%s%%%s]:%d", addrIP, iface.Name, m.listenPort) - if li, err := m.core.ListenTCP(listenaddr); err == nil { - m.log.Debugln("Started multicasting on", iface.Name) - // Store the listener so that we can stop it later if needed - info = &listenerInfo{listener: li, time: time.Now()} - m.listeners[iface.Name] = info - } else { - m.log.Warnln("Not multicasting on", iface.Name, "due to error:", err) - } - } else { - // An existing listener was found - info = m.listeners[iface.Name] - } - // Make sure nothing above failed for some reason - if info == nil { - continue - } - if time.Since(info.time) < info.interval { - continue - } - // Get the listener details and construct the multicast beacon - lladdr := info.listener.Listener.Addr().String() - if a, err := net.ResolveTCPAddr("tcp6", lladdr); err == nil { - a.Zone = "" - destAddr.Zone = iface.Name - msg := []byte(a.String()) - m.sock.WriteTo(msg, nil, destAddr) - } - if info.interval.Seconds() < 15 { - info.interval += time.Second - } - break - } - } - m.announcer = time.AfterFunc(time.Second, func() { - m.Act(m, m.announce) - }) -} - func (m *Multicast) listen() { - groupAddr, err := net.ResolveUDPAddr("udp6", m.groupAddr) + groupAddr, err := net.ResolveUDPAddr("udp6", GroupAddr) if err != nil { panic(err) } From 0c7cf65d27fe734bda4d9bc334e95c8a9fea2e13 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 2 May 2020 22:33:25 +0100 Subject: [PATCH 2/6] Move some logging back to debug --- src/multicast/multicast.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 6ceef0a..d944b7f 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -211,7 +211,7 @@ func (m *Multicast) monitorInterfaceChanges() { } multicastInterface.Act(multicastInterface, multicastInterface.announce) m.listeners[name] = multicastInterface - m.log.Infoln("Started multicasting on", name) + m.log.Debugln("Started multicasting on", name) break } } @@ -222,7 +222,7 @@ func (m *Multicast) monitorInterfaceChanges() { // This is a disappeared interface. Stop the announcer. close(intf.stop) delete(m.listeners, name) - m.log.Infoln("Stopped multicasting on", name) + m.log.Debugln("Stopped multicasting on", name) } } // Queue the next check. From 127b7e311c737fb23142941d16a1b7e8cdb1cf5f Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Sat, 2 May 2020 22:37:12 +0100 Subject: [PATCH 3/6] Clean up a bit --- src/multicast/multicast.go | 41 ++++++++++++++------------------------ 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index d944b7f..28c9b4e 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -26,17 +26,16 @@ const ( // automatically. type Multicast struct { phony.Inbox - core *yggdrasil.Core - config *config.NodeState - log *log.Logger - sock *ipv6.PacketConn - groupAddr *net.UDPAddr - listeners map[string]*multicastInterface - listenPort uint16 - isOpen bool - interfaceMonitor *time.Timer - announcer *time.Timer - platformhandler *time.Timer + core *yggdrasil.Core + config *config.NodeState + log *log.Logger + sock *ipv6.PacketConn + groupAddr *net.UDPAddr + listeners map[string]*multicastInterface + listenPort uint16 + isOpen bool + monitor *time.Timer + platformhandler *time.Timer } type multicastInterface struct { @@ -47,15 +46,9 @@ type multicastInterface struct { zone string timer *time.Timer interval time.Duration - send chan<- beacon stop chan interface{} } -type beacon struct { - llAddr string - zone string -} - // Init prepares the multicast interface for use. func (m *Multicast) Init(core *yggdrasil.Core, state *config.NodeState, log *log.Logger, options interface{}) (err error) { m.core = core @@ -135,14 +128,10 @@ func (m *Multicast) Stop() error { func (m *Multicast) _stop() error { m.log.Infoln("Stopping multicast module") m.isOpen = false - /* - if m.monitorInterfaceChanges != nil { - m.monitorInterfaceChanges.Stop() - } - if m.sendBeacons != nil { - m.sendBeacons.Stop() - } - */ + for name := range m.listeners { + close(m.listeners[name].stop) + delete(m.listeners, name) + } if m.platformhandler != nil { m.platformhandler.Stop() } @@ -226,7 +215,7 @@ func (m *Multicast) monitorInterfaceChanges() { } } // Queue the next check. - m.interfaceMonitor = time.AfterFunc(time.Second, func() { + m.monitor = time.AfterFunc(time.Second, func() { m.Act(m, m.monitorInterfaceChanges) }) } From 02e1cb180d046e2a9d120de00556456f5c6887ad Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sat, 2 May 2020 17:23:20 -0500 Subject: [PATCH 4/6] possibly reduce multicast cpu usage even more --- src/multicast/multicast.go | 43 +++++++++++++++++++----------- src/multicast/multicast_darwin.go | 4 +-- src/multicast/multicast_other.go | 2 +- src/multicast/multicast_unix.go | 2 +- src/multicast/multicast_windows.go | 2 +- 5 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 28c9b4e..4f0a3ff 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -36,6 +36,8 @@ type Multicast struct { isOpen bool monitor *time.Timer platformhandler *time.Timer + _interfaces map[string]net.Interface + _interfaceAddrs map[string][]net.Addr } type multicastInterface struct { @@ -100,8 +102,8 @@ func (m *Multicast) _start() error { m.isOpen = true go m.listen() - m.Act(m, m.multicastStarted) - m.Act(m, m.monitorInterfaceChanges) + m.Act(nil, m._multicastStarted) + m.Act(nil, m._monitorInterfaceChanges) return nil } @@ -145,7 +147,7 @@ func (m *Multicast) _stop() error { // and then signals the various module goroutines to reconfigure themselves if // needed. func (m *Multicast) UpdateConfig(config *config.NodeConfig) { - m.Act(m, func() { m._updateConfig(config) }) + m.Act(nil, func() { m._updateConfig(config) }) } func (m *Multicast) _updateConfig(config *config.NodeConfig) { @@ -167,17 +169,14 @@ func (m *Multicast) _updateConfig(config *config.NodeConfig) { m.log.Debugln("Reloaded multicast configuration successfully") } -func (m *Multicast) monitorInterfaceChanges() { - interfaces := m.Interfaces() +func (m *Multicast) _monitorInterfaceChanges() { + m._updateInterfaces() // update interfaces and interfaceAddrs // Look for interfaces we don't know about yet. - for name, intf := range interfaces { + for name, intf := range m._interfaces { if _, ok := m.listeners[name]; !ok { // Look up interface addresses. - addrs, err := intf.Addrs() - if err != nil { - continue - } + addrs := m._interfaceAddrs[intf.Name] // Find the first link-local address. for _, addr := range addrs { addrIP, _, _ := net.ParseCIDR(addr.String()) @@ -198,7 +197,7 @@ func (m *Multicast) monitorInterfaceChanges() { stop: make(chan interface{}), zone: name, } - multicastInterface.Act(multicastInterface, multicastInterface.announce) + multicastInterface.Act(m, multicastInterface._announce) m.listeners[name] = multicastInterface m.log.Debugln("Started multicasting on", name) break @@ -207,7 +206,7 @@ func (m *Multicast) monitorInterfaceChanges() { } // Look for interfaces we knew about but are no longer there. for name, intf := range m.listeners { - if _, ok := interfaces[name]; !ok { + if _, ok := m._interfaces[name]; !ok { // This is a disappeared interface. Stop the announcer. close(intf.stop) delete(m.listeners, name) @@ -216,11 +215,11 @@ func (m *Multicast) monitorInterfaceChanges() { } // Queue the next check. m.monitor = time.AfterFunc(time.Second, func() { - m.Act(m, m.monitorInterfaceChanges) + m.Act(nil, m._monitorInterfaceChanges) }) } -func (m *multicastInterface) announce() { +func (m *multicastInterface) _announce() { // Check if the multicast interface has been stopped. This will happen // if it disappears from the system or goes down. select { @@ -240,7 +239,7 @@ func (m *multicastInterface) announce() { m.interval += time.Second } m.timer = time.AfterFunc(m.interval, func() { - m.Act(m, m.announce) + m.Act(nil, m._announce) }) } @@ -248,6 +247,14 @@ func (m *multicastInterface) announce() { // expected that UpdateInterfaces has been called at least once before calling // this method. func (m *Multicast) Interfaces() map[string]net.Interface { + var interfaces map[string]net.Interface + phony.Block(m, func() { + interfaces = m._interfaces + }) + return interfaces +} + +func (m *Multicast) _updateInterfaces() { interfaces := make(map[string]net.Interface) // Get interface expressions from config current := m.config.GetCurrent() @@ -258,6 +265,7 @@ func (m *Multicast) Interfaces() map[string]net.Interface { panic(err) } // Work out which interfaces to announce on + interfaceAddrs := make(map[string][]net.Addr) for _, iface := range allifaces { if iface.Flags&net.FlagUp == 0 { // Ignore interfaces that are down @@ -293,10 +301,12 @@ func (m *Multicast) Interfaces() map[string]net.Interface { // Does the interface match the regular expression? Store it if so if e.MatchString(iface.Name) { interfaces[iface.Name] = iface + interfaceAddrs[iface.Name] = addrs } } } - return interfaces + m._interfaces = interfaces + m._interfaceAddrs = interfaceAddrs } func (m *Multicast) listen() { @@ -333,6 +343,7 @@ func (m *Multicast) listen() { if addr.IP.String() != from.IP.String() { continue } + // Note that m.Interfaces would block if it was being run by the actor itself if _, ok := m.Interfaces()[from.Zone]; ok { addr.Zone = "" if err := m.core.CallPeer("tcp://"+addr.String(), from.Zone); err != nil { diff --git a/src/multicast/multicast_darwin.go b/src/multicast/multicast_darwin.go index 4cfef9e..e020106 100644 --- a/src/multicast/multicast_darwin.go +++ b/src/multicast/multicast_darwin.go @@ -31,7 +31,7 @@ import ( var awdlGoroutineStarted bool -func (m *Multicast) multicastStarted() { +func (m *Multicast) _multicastStarted() { C.StopAWDLBrowsing() for intf := range m.Interfaces() { if intf == "awdl0" { @@ -40,7 +40,7 @@ func (m *Multicast) multicastStarted() { } } m.platformhandler = time.AfterFunc(time.Minute, func() { - m.Act(m, m.multicastStarted) + m.Act(m, m._multicastStarted) }) } diff --git a/src/multicast/multicast_other.go b/src/multicast/multicast_other.go index 16ea15d..dfcf625 100644 --- a/src/multicast/multicast_other.go +++ b/src/multicast/multicast_other.go @@ -4,7 +4,7 @@ package multicast import "syscall" -func (m *Multicast) multicastStarted() { +func (m *Multicast) _multicastStarted() { } diff --git a/src/multicast/multicast_unix.go b/src/multicast/multicast_unix.go index 9d6a01a..1ff48b1 100644 --- a/src/multicast/multicast_unix.go +++ b/src/multicast/multicast_unix.go @@ -5,7 +5,7 @@ package multicast import "syscall" import "golang.org/x/sys/unix" -func (m *Multicast) multicastStarted() { +func (m *Multicast) _multicastStarted() { } diff --git a/src/multicast/multicast_windows.go b/src/multicast/multicast_windows.go index 7a846b1..3666faa 100644 --- a/src/multicast/multicast_windows.go +++ b/src/multicast/multicast_windows.go @@ -5,7 +5,7 @@ package multicast import "syscall" import "golang.org/x/sys/windows" -func (m *Multicast) multicastStarted() { +func (m *Multicast) _multicastStarted() { } From de79401bb228695a78b6244f9e85037ef46c5062 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 3 May 2020 02:50:04 -0500 Subject: [PATCH 5/6] only call (net.Interface).Addrs() once per minute per interface --- src/multicast/multicast.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index 4f0a3ff..aaa2115 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -37,7 +37,12 @@ type Multicast struct { monitor *time.Timer platformhandler *time.Timer _interfaces map[string]net.Interface - _interfaceAddrs map[string][]net.Addr + _interfaceAddrs map[string]addrInfo +} + +type addrInfo struct { + addrs []net.Addr + time time.Time } type multicastInterface struct { @@ -176,7 +181,7 @@ func (m *Multicast) _monitorInterfaceChanges() { for name, intf := range m._interfaces { if _, ok := m.listeners[name]; !ok { // Look up interface addresses. - addrs := m._interfaceAddrs[intf.Name] + addrs := m._interfaceAddrs[intf.Name].addrs // Find the first link-local address. for _, addr := range addrs { addrIP, _, _ := net.ParseCIDR(addr.String()) @@ -265,7 +270,7 @@ func (m *Multicast) _updateInterfaces() { panic(err) } // Work out which interfaces to announce on - interfaceAddrs := make(map[string][]net.Addr) + interfaceAddrs := make(map[string]addrInfo) for _, iface := range allifaces { if iface.Flags&net.FlagUp == 0 { // Ignore interfaces that are down @@ -279,9 +284,16 @@ func (m *Multicast) _updateInterfaces() { // Ignore point-to-point interfaces continue } - addrs, _ := iface.Addrs() + var aInfo addrInfo + var isIn bool + if aInfo, isIn = m._interfaceAddrs[iface.Name]; isIn && time.Since(aInfo.time) < time.Minute { + // don't call iface.Addrs, it's unlikely things have changed + } else { + aInfo.addrs, _ = iface.Addrs() + aInfo.time = time.Now() + } hasLLAddr := false - for _, addr := range addrs { + for _, addr := range aInfo.addrs { addrIP, _, _ := net.ParseCIDR(addr.String()) if addrIP.To4() == nil && addrIP.IsLinkLocalUnicast() { hasLLAddr = true @@ -301,7 +313,7 @@ func (m *Multicast) _updateInterfaces() { // Does the interface match the regular expression? Store it if so if e.MatchString(iface.Name) { interfaces[iface.Name] = iface - interfaceAddrs[iface.Name] = addrs + interfaceAddrs[iface.Name] = aInfo } } } From 95f4ec52a40ad1e8d3d1c72d80dd50dbbb8553ce Mon Sep 17 00:00:00 2001 From: Arceliar Date: Sun, 3 May 2020 05:06:59 -0500 Subject: [PATCH 6/6] save only the link-local addresses for multicast --- src/multicast/multicast.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index aaa2115..fc7b137 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -292,15 +292,15 @@ func (m *Multicast) _updateInterfaces() { aInfo.addrs, _ = iface.Addrs() aInfo.time = time.Now() } - hasLLAddr := false + lladdrs := aInfo.addrs[:0] for _, addr := range aInfo.addrs { addrIP, _, _ := net.ParseCIDR(addr.String()) if addrIP.To4() == nil && addrIP.IsLinkLocalUnicast() { - hasLLAddr = true - break + lladdrs = append(lladdrs, addr) } } - if !hasLLAddr { + aInfo.addrs = lladdrs + if len(lladdrs) == 0 { // Ignore interfaces without link-local addresses continue }