fix goroutine leak and reduce code duplication
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -45,7 +45,7 @@ func (t *Tendrils) parseARPTable() []arpEntry {
|
|||||||
macStr = normalizeMACAddress(macStr)
|
macStr = normalizeMACAddress(macStr)
|
||||||
mac, err := net.ParseMAC(macStr)
|
mac, err := net.ParseMAC(macStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("[arp] failed to parse MAC %q for IP %s: %v", macStr, ipStr, err)
|
log.Printf("[ERROR] [arp] failed to parse MAC %q for IP %s: %v", macStr, ipStr, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
31
artnet.go
31
artnet.go
@@ -30,18 +30,7 @@ type ArtNetNode struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tendrils) listenArtNet(ctx context.Context, iface net.Interface) {
|
func (t *Tendrils) listenArtNet(ctx context.Context, iface net.Interface) {
|
||||||
addrs, err := iface.Addrs()
|
srcIP, _ := getInterfaceIPv4(iface)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var srcIP net.IP
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.To4() != nil {
|
|
||||||
srcIP = ipnet.IP.To4()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if srcIP == nil {
|
if srcIP == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -157,23 +146,7 @@ func (t *Tendrils) handleArtPollReply(ifaceName string, srcIP net.IP, data []byt
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tendrils) runArtNetPoller(ctx context.Context, iface net.Interface, conn *net.UDPConn) {
|
func (t *Tendrils) runArtNetPoller(ctx context.Context, iface net.Interface, conn *net.UDPConn) {
|
||||||
addrs, err := iface.Addrs()
|
_, broadcast := getInterfaceIPv4(iface)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var broadcast net.IP
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.To4() != nil {
|
|
||||||
ip := ipnet.IP.To4()
|
|
||||||
mask := ipnet.Mask
|
|
||||||
broadcast = make(net.IP, 4)
|
|
||||||
for i := 0; i < 4; i++ {
|
|
||||||
broadcast[i] = ip[i] | ^mask[i]
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if broadcast == nil {
|
if broadcast == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
19
bmd.go
19
bmd.go
@@ -14,24 +14,7 @@ func (t *Tendrils) listenBMD(ctx context.Context, iface net.Interface) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tendrils) discoverATEMs(ctx context.Context, iface net.Interface) {
|
func (t *Tendrils) discoverATEMs(ctx context.Context, iface net.Interface) {
|
||||||
addrs, err := iface.Addrs()
|
srcIP, broadcast := getInterfaceIPv4(iface)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var srcIP net.IP
|
|
||||||
var broadcast net.IP
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.To4() != nil {
|
|
||||||
srcIP = ipnet.IP.To4()
|
|
||||||
mask := ipnet.Mask
|
|
||||||
broadcast = make(net.IP, 4)
|
|
||||||
for i := 0; i < 4; i++ {
|
|
||||||
broadcast[i] = srcIP[i] | ^mask[i]
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if srcIP == nil {
|
if srcIP == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
42
dante.go
42
dante.go
@@ -140,6 +140,15 @@ func NewDanteFlows() *DanteFlows {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func containsString(slice []string, val string) bool {
|
||||||
|
for _, s := range slice {
|
||||||
|
if s == val {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (d *DanteFlows) Update(source, subscriber *Node, channelInfo string) {
|
func (d *DanteFlows) Update(source, subscriber *Node, channelInfo string) {
|
||||||
d.mu.Lock()
|
d.mu.Lock()
|
||||||
defer d.mu.Unlock()
|
defer d.mu.Unlock()
|
||||||
@@ -161,18 +170,9 @@ func (d *DanteFlows) Update(source, subscriber *Node, channelInfo string) {
|
|||||||
flow.Subscribers[subscriber] = sub
|
flow.Subscribers[subscriber] = sub
|
||||||
}
|
}
|
||||||
|
|
||||||
if channelInfo != "" {
|
if channelInfo != "" && !containsString(sub.Channels, channelInfo) {
|
||||||
hasChannel := false
|
sub.Channels = append(sub.Channels, channelInfo)
|
||||||
for _, ch := range sub.Channels {
|
sort.Strings(sub.Channels)
|
||||||
if ch == channelInfo {
|
|
||||||
hasChannel = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !hasChannel {
|
|
||||||
sub.Channels = append(sub.Channels, channelInfo)
|
|
||||||
sort.Strings(sub.Channels)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub.LastSeen = time.Now()
|
sub.LastSeen = time.Now()
|
||||||
@@ -188,14 +188,7 @@ func (d *DanteFlows) ReplaceNode(oldNode, newNode *Node) {
|
|||||||
for subNode, sub := range flow.Subscribers {
|
for subNode, sub := range flow.Subscribers {
|
||||||
if existingSub, hasSub := existingFlow.Subscribers[subNode]; hasSub {
|
if existingSub, hasSub := existingFlow.Subscribers[subNode]; hasSub {
|
||||||
for _, ch := range sub.Channels {
|
for _, ch := range sub.Channels {
|
||||||
hasChannel := false
|
if !containsString(existingSub.Channels, ch) {
|
||||||
for _, existingCh := range existingSub.Channels {
|
|
||||||
if existingCh == ch {
|
|
||||||
hasChannel = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !hasChannel {
|
|
||||||
existingSub.Channels = append(existingSub.Channels, ch)
|
existingSub.Channels = append(existingSub.Channels, ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,14 +207,7 @@ func (d *DanteFlows) ReplaceNode(oldNode, newNode *Node) {
|
|||||||
delete(flow.Subscribers, oldNode)
|
delete(flow.Subscribers, oldNode)
|
||||||
if existingSub, hasNew := flow.Subscribers[newNode]; hasNew {
|
if existingSub, hasNew := flow.Subscribers[newNode]; hasNew {
|
||||||
for _, ch := range sub.Channels {
|
for _, ch := range sub.Channels {
|
||||||
hasChannel := false
|
if !containsString(existingSub.Channels, ch) {
|
||||||
for _, existingCh := range existingSub.Channels {
|
|
||||||
if existingCh == ch {
|
|
||||||
hasChannel = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !hasChannel {
|
|
||||||
existingSub.Channels = append(existingSub.Channels, ch)
|
existingSub.Channels = append(existingSub.Channels, ch)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
igmp.go
13
igmp.go
@@ -111,18 +111,7 @@ func (t *Tendrils) handleIGMPv3(ifaceName string, sourceIP net.IP, igmp *layers.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tendrils) runIGMPQuerier(ctx context.Context, iface net.Interface) {
|
func (t *Tendrils) runIGMPQuerier(ctx context.Context, iface net.Interface) {
|
||||||
addrs, err := iface.Addrs()
|
srcIP, _ := getInterfaceIPv4(iface)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var srcIP net.IP
|
|
||||||
for _, addr := range addrs {
|
|
||||||
if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.To4() != nil {
|
|
||||||
srcIP = ipnet.IP.To4()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if srcIP == nil {
|
if srcIP == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
35
nodes.go
35
nodes.go
@@ -83,18 +83,7 @@ func (s *InterfaceStats) String() string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "[" + fmt.Sprintf("%s", joinParts(parts)) + "]"
|
return "[" + strings.Join(parts, " ") + "]"
|
||||||
}
|
|
||||||
|
|
||||||
func joinParts(parts []string) string {
|
|
||||||
result := ""
|
|
||||||
for i, p := range parts {
|
|
||||||
if i > 0 {
|
|
||||||
result += " "
|
|
||||||
}
|
|
||||||
result += p
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PoEBudget struct {
|
type PoEBudget struct {
|
||||||
@@ -133,7 +122,7 @@ func (n *Node) String() string {
|
|||||||
|
|
||||||
parts = append(parts, fmt.Sprintf("{%v}", ifaces))
|
parts = append(parts, fmt.Sprintf("{%v}", ifaces))
|
||||||
|
|
||||||
return joinParts(parts)
|
return strings.Join(parts, " ")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) DisplayName() string {
|
func (n *Node) DisplayName() string {
|
||||||
@@ -541,8 +530,10 @@ func (n *Nodes) mergeNodes(keepID, mergeID int) {
|
|||||||
for _, ip := range iface.IPs {
|
for _, ip := range iface.IPs {
|
||||||
ips = append(ips, ip)
|
ips = append(ips, ip)
|
||||||
}
|
}
|
||||||
n.updateNodeInterface(keep, keepID, iface.MAC, ips, iface.Name)
|
if iface.MAC != nil {
|
||||||
n.macIndex[iface.MAC.String()] = keepID
|
n.updateNodeInterface(keep, keepID, iface.MAC, ips, iface.Name)
|
||||||
|
n.macIndex[iface.MAC.String()] = keepID
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for peerMAC, ifaceName := range merge.MACTable {
|
for peerMAC, ifaceName := range merge.MACTable {
|
||||||
@@ -563,6 +554,11 @@ func (n *Nodes) mergeNodes(keepID, mergeID int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cancel, exists := n.nodeCancel[mergeID]; exists {
|
||||||
|
cancel()
|
||||||
|
delete(n.nodeCancel, mergeID)
|
||||||
|
}
|
||||||
|
|
||||||
delete(n.nodes, mergeID)
|
delete(n.nodes, mergeID)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -747,7 +743,7 @@ func (n *Nodes) logNode(node *Node) {
|
|||||||
tags = append(tags, "dante-clock-master")
|
tags = append(tags, "dante-clock-master")
|
||||||
}
|
}
|
||||||
if len(tags) > 0 {
|
if len(tags) > 0 {
|
||||||
log.Printf("[node] %s [%s]", name, joinParts(tags))
|
log.Printf("[node] %s [%s]", name, strings.Join(tags, " "))
|
||||||
} else {
|
} else {
|
||||||
log.Printf("[node] %s", name)
|
log.Printf("[node] %s", name)
|
||||||
}
|
}
|
||||||
@@ -911,7 +907,9 @@ func (n *Nodes) getDirectLinks() []*Link {
|
|||||||
macToNode := map[string]*Node{}
|
macToNode := map[string]*Node{}
|
||||||
for _, node := range n.nodes {
|
for _, node := range n.nodes {
|
||||||
for _, iface := range node.Interfaces {
|
for _, iface := range node.Interfaces {
|
||||||
macToNode[iface.MAC.String()] = node
|
if iface.MAC != nil {
|
||||||
|
macToNode[iface.MAC.String()] = node
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -921,6 +919,9 @@ func (n *Nodes) getDirectLinks() []*Link {
|
|||||||
for _, target := range n.nodes {
|
for _, target := range n.nodes {
|
||||||
seenMACs := map[string]bool{}
|
seenMACs := map[string]bool{}
|
||||||
for _, iface := range target.Interfaces {
|
for _, iface := range target.Interfaces {
|
||||||
|
if iface.MAC == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
mac := iface.MAC.String()
|
mac := iface.MAC.String()
|
||||||
if seenMACs[mac] {
|
if seenMACs[mac] {
|
||||||
continue
|
continue
|
||||||
|
|||||||
89
snmp.go
89
snmp.go
@@ -51,6 +51,21 @@ func defaultSNMPConfig() *snmpConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func snmpToInt(val interface{}) (int, bool) {
|
||||||
|
switch v := val.(type) {
|
||||||
|
case int:
|
||||||
|
return v, true
|
||||||
|
case uint:
|
||||||
|
return int(v), true
|
||||||
|
case int64:
|
||||||
|
return int(v), true
|
||||||
|
case uint64:
|
||||||
|
return int(v), true
|
||||||
|
default:
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (t *Tendrils) connectSNMP(ip net.IP) (*gosnmp.GoSNMP, error) {
|
func (t *Tendrils) connectSNMP(ip net.IP) (*gosnmp.GoSNMP, error) {
|
||||||
cfg := defaultSNMPConfig()
|
cfg := defaultSNMPConfig()
|
||||||
|
|
||||||
@@ -89,11 +104,13 @@ func (t *Tendrils) querySNMPDevice(node *Node, ip net.IP) {
|
|||||||
}
|
}
|
||||||
defer snmp.Conn.Close()
|
defer snmp.Conn.Close()
|
||||||
|
|
||||||
|
ifNames := t.getInterfaceNames(snmp)
|
||||||
|
|
||||||
t.querySysName(snmp, node)
|
t.querySysName(snmp, node)
|
||||||
t.queryInterfaceMACs(snmp, node)
|
t.queryInterfaceMACs(snmp, node, ifNames)
|
||||||
t.queryInterfaceStats(snmp, node)
|
t.queryInterfaceStats(snmp, node, ifNames)
|
||||||
t.queryPoEBudget(snmp, node)
|
t.queryPoEBudget(snmp, node)
|
||||||
t.queryBridgeMIB(snmp, node)
|
t.queryBridgeMIB(snmp, node, ifNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tendrils) querySysName(snmp *gosnmp.GoSNMP, node *Node) {
|
func (t *Tendrils) querySysName(snmp *gosnmp.GoSNMP, node *Node) {
|
||||||
@@ -121,7 +138,7 @@ func (t *Tendrils) querySysName(snmp *gosnmp.GoSNMP, node *Node) {
|
|||||||
t.nodes.Update(node, nil, nil, "", sysName, "snmp-sysname")
|
t.nodes.Update(node, nil, nil, "", sysName, "snmp-sysname")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tendrils) queryInterfaceMACs(snmp *gosnmp.GoSNMP, node *Node) {
|
func (t *Tendrils) queryInterfaceMACs(snmp *gosnmp.GoSNMP, node *Node, ifNames map[int]string) {
|
||||||
oid := "1.3.6.1.2.1.2.2.1.6"
|
oid := "1.3.6.1.2.1.2.2.1.6"
|
||||||
|
|
||||||
results, err := snmp.BulkWalkAll(oid)
|
results, err := snmp.BulkWalkAll(oid)
|
||||||
@@ -129,8 +146,6 @@ func (t *Tendrils) queryInterfaceMACs(snmp *gosnmp.GoSNMP, node *Node) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ifNames := t.getInterfaceNames(snmp)
|
|
||||||
|
|
||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
if result.Type != gosnmp.OctetString {
|
if result.Type != gosnmp.OctetString {
|
||||||
continue
|
continue
|
||||||
@@ -161,9 +176,7 @@ func (t *Tendrils) queryInterfaceMACs(snmp *gosnmp.GoSNMP, node *Node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tendrils) queryInterfaceStats(snmp *gosnmp.GoSNMP, node *Node) {
|
func (t *Tendrils) queryInterfaceStats(snmp *gosnmp.GoSNMP, node *Node, ifNames map[int]string) {
|
||||||
ifNames := t.getInterfaceNames(snmp)
|
|
||||||
|
|
||||||
ifOperStatus := t.getInterfaceTable(snmp, "1.3.6.1.2.1.2.2.1.8")
|
ifOperStatus := t.getInterfaceTable(snmp, "1.3.6.1.2.1.2.2.1.8")
|
||||||
ifHighSpeed := t.getInterfaceTable(snmp, "1.3.6.1.2.1.31.1.1.1.15")
|
ifHighSpeed := t.getInterfaceTable(snmp, "1.3.6.1.2.1.31.1.1.1.15")
|
||||||
ifInErrors := t.getInterfaceTable(snmp, "1.3.6.1.2.1.2.2.1.14")
|
ifInErrors := t.getInterfaceTable(snmp, "1.3.6.1.2.1.2.2.1.14")
|
||||||
@@ -221,20 +234,10 @@ func (t *Tendrils) queryPoEBudget(snmp *gosnmp.GoSNMP, node *Node) {
|
|||||||
|
|
||||||
var power, maxPower float64
|
var power, maxPower float64
|
||||||
for _, v := range result.Variables {
|
for _, v := range result.Variables {
|
||||||
var val int
|
val, ok := snmpToInt(v.Value)
|
||||||
switch x := v.Value.(type) {
|
if !ok {
|
||||||
case int:
|
|
||||||
val = x
|
|
||||||
case uint:
|
|
||||||
val = int(x)
|
|
||||||
case int64:
|
|
||||||
val = int(x)
|
|
||||||
case uint64:
|
|
||||||
val = int(x)
|
|
||||||
default:
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.Name == "."+powerOID {
|
if v.Name == "."+powerOID {
|
||||||
power = float64(val)
|
power = float64(val)
|
||||||
} else if v.Name == "."+maxPowerOID {
|
} else if v.Name == "."+maxPowerOID {
|
||||||
@@ -263,20 +266,10 @@ func (t *Tendrils) getInterfaceTable(snmp *gosnmp.GoSNMP, oid string) map[int]in
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var value int
|
value, ok := snmpToInt(result.Value)
|
||||||
switch v := result.Value.(type) {
|
if !ok {
|
||||||
case int:
|
|
||||||
value = v
|
|
||||||
case uint:
|
|
||||||
value = int(v)
|
|
||||||
case int64:
|
|
||||||
value = int(v)
|
|
||||||
case uint64:
|
|
||||||
value = int(v)
|
|
||||||
default:
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
table[ifIndex] = value
|
table[ifIndex] = value
|
||||||
}
|
}
|
||||||
return table
|
return table
|
||||||
@@ -306,17 +299,8 @@ func (t *Tendrils) getPoEStats(snmp *gosnmp.GoSNMP, ifNames map[int]string) map[
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var status int
|
status, ok := snmpToInt(result.Value)
|
||||||
switch v := result.Value.(type) {
|
if !ok {
|
||||||
case int:
|
|
||||||
status = v
|
|
||||||
case uint:
|
|
||||||
status = int(v)
|
|
||||||
case int64:
|
|
||||||
status = int(v)
|
|
||||||
case uint64:
|
|
||||||
status = int(v)
|
|
||||||
default:
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,26 +351,16 @@ func (t *Tendrils) getPoETable(snmp *gosnmp.GoSNMP, oid string) map[int]int {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var value int
|
value, ok := snmpToInt(result.Value)
|
||||||
switch v := result.Value.(type) {
|
if !ok {
|
||||||
case int:
|
|
||||||
value = v
|
|
||||||
case uint:
|
|
||||||
value = int(v)
|
|
||||||
case int64:
|
|
||||||
value = int(v)
|
|
||||||
case uint64:
|
|
||||||
value = int(v)
|
|
||||||
default:
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
table[portIndex] = value
|
table[portIndex] = value
|
||||||
}
|
}
|
||||||
return table
|
return table
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tendrils) queryBridgeMIB(snmp *gosnmp.GoSNMP, node *Node) {
|
func (t *Tendrils) queryBridgeMIB(snmp *gosnmp.GoSNMP, node *Node, ifNames map[int]string) {
|
||||||
portOID := "1.3.6.1.2.1.17.7.1.2.2.1.2"
|
portOID := "1.3.6.1.2.1.17.7.1.2.2.1.2"
|
||||||
|
|
||||||
portResults, err := snmp.BulkWalkAll(portOID)
|
portResults, err := snmp.BulkWalkAll(portOID)
|
||||||
@@ -423,7 +397,6 @@ func (t *Tendrils) queryBridgeMIB(snmp *gosnmp.GoSNMP, node *Node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bridgePortToIfIndex := t.getBridgePortMapping(snmp)
|
bridgePortToIfIndex := t.getBridgePortMapping(snmp)
|
||||||
ifNames := t.getInterfaceNames(snmp)
|
|
||||||
|
|
||||||
for _, entry := range macPorts {
|
for _, entry := range macPorts {
|
||||||
mac := entry.mac
|
mac := entry.mac
|
||||||
|
|||||||
19
tendrils.go
19
tendrils.go
@@ -10,6 +10,25 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func getInterfaceIPv4(iface net.Interface) (srcIP, broadcast net.IP) {
|
||||||
|
addrs, err := iface.Addrs()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
for _, addr := range addrs {
|
||||||
|
if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.To4() != nil {
|
||||||
|
srcIP = ipnet.IP.To4()
|
||||||
|
mask := ipnet.Mask
|
||||||
|
broadcast = make(net.IP, 4)
|
||||||
|
for i := 0; i < 4; i++ {
|
||||||
|
broadcast[i] = srcIP[i] | ^mask[i]
|
||||||
|
}
|
||||||
|
return srcIP, broadcast
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
type Tendrils struct {
|
type Tendrils struct {
|
||||||
activeInterfaces map[string]context.CancelFunc
|
activeInterfaces map[string]context.CancelFunc
|
||||||
nodes *Nodes
|
nodes *Nodes
|
||||||
|
|||||||
Reference in New Issue
Block a user