Browse Source

Deduplicate common code parts of ARP from platform specific parts

Douglas Thrift 1 year ago
parent
commit
75b7fb852e
3 changed files with 81 additions and 123 deletions
  1. 73 0
      neighbors/arp.go
  2. 5 60
      neighbors/arp_freebsd.go
  3. 3 63
      neighbors/arp_linux.go

+ 73 - 0
neighbors/arp.go

@@ -2,6 +2,10 @@ package neighbors
 
 import (
 	"context"
+	"net"
+	"os/exec"
+
+	"goa.design/clue/log"
 )
 
 type (
@@ -12,4 +16,73 @@ type (
 		Present(ctx context.Context, ifs Interfaces, state State, addrStates HardwareAddrStates) error
 		Count(count uint)
 	}
+
+	arp struct {
+		cmd    string
+		arping ARPing
+	}
 )
+
+func NewARP(count uint) (ARP, error) {
+	cmd, err := exec.LookPath("ip")
+	if err != nil {
+		return nil, err
+	}
+
+	arping, err := NewARPing(count)
+	if err != nil {
+		return nil, err
+	}
+
+	return &arp{
+		cmd:    cmd,
+		arping: arping,
+	}, nil
+}
+
+func (a *arp) Present(ctx context.Context, ifs Interfaces, state State, addrStates HardwareAddrStates) (err error) {
+	as := make(map[string]bool, len(addrStates))
+	for hw := range addrStates {
+		as[hw] = false
+	}
+
+	es, err := a.entries(ctx, ifs)
+	if err != nil {
+		return
+	}
+
+	for _, e := range es {
+		log.Debug(ctx, log.KV{K: "IP address", V: e.IPAddress}, log.KV{K: "MAC address", V: e.MACAddress}, log.KV{K: "interface", V: e.Interface})
+		if ifs[e.Interface] {
+			var hwa net.HardwareAddr
+			hwa, err = net.ParseMAC(e.MACAddress)
+			if err != nil {
+				return
+			}
+			hw := hwa.String()
+
+			if _, ok := as[hw]; ok {
+				ok, err = a.arping.Ping(ctx, e.Interface, hw, e.IPAddress)
+				if err != nil {
+					return
+				}
+				as[hw] = ok
+			}
+		}
+	}
+
+	present := false
+	for hw, ok := range as {
+		addrStates[hw].Set(ok)
+		if ok {
+			present = true
+		}
+	}
+	state.Set(present)
+
+	return
+}
+
+func (a *arp) Count(count uint) {
+	a.arping.Count(count)
+}

+ 5 - 60
neighbors/arp_freebsd.go

@@ -4,7 +4,6 @@ import (
 	"context"
 	"encoding/json"
 	"fmt"
-	"net"
 	"os/exec"
 
 	"goa.design/clue/log"
@@ -15,11 +14,6 @@ const (
 )
 
 type (
-	arp struct {
-		cmd    string
-		arping ARPing
-	}
-
 	arpOutput struct {
 		Version string `json:"__version"`
 		ARP     struct {
@@ -34,29 +28,7 @@ type (
 	}
 )
 
-func NewARP(count uint) (ARP, error) {
-	cmd, err := exec.LookPath("arp")
-	if err != nil {
-		return nil, err
-	}
-
-	arping, err := NewARPing(count)
-	if err != nil {
-		return nil, err
-	}
-
-	return &arp{
-		cmd:    cmd,
-		arping: arping,
-	}, nil
-}
-
-func (a *arp) Present(ctx context.Context, ifs Interfaces, state State, addrStates HardwareAddrStates) (err error) {
-	as := make(map[string]bool, len(addrStates))
-	for hw := range addrStates {
-		as[hw] = false
-	}
-
+func (a *arp) entries(ctx context.Context, ifs Interfaces) (entries []arpEntry, err error) {
 	cmd := exec.CommandContext(ctx, a.cmd, "--libxo=json", "-an")
 	if len(ifs) == 1 {
 		for ifi := range ifs {
@@ -70,8 +42,7 @@ func (a *arp) Present(ctx context.Context, ifs Interfaces, state State, addrStat
 	}
 
 	o := &arpOutput{}
-	err = json.Unmarshal(b, o)
-	if err != nil {
+	if err = json.Unmarshal(b, o); err != nil {
 		return
 	}
 
@@ -80,38 +51,12 @@ func (a *arp) Present(ctx context.Context, ifs Interfaces, state State, addrStat
 		return
 	}
 
+	entries = make([]arpEntry, 0, len(o.ARP.Cache))
 	for _, e := range o.ARP.Cache {
-		log.Debug(ctx, log.KV{K: "IP address", V: e.IPAddress}, log.KV{K: "MAC address", V: e.MACAddress}, log.KV{K: "interface", V: e.Interface})
-		if ifs[e.Interface] {
-			var hwa net.HardwareAddr
-			hwa, err = net.ParseMAC(e.MACAddress)
-			if err != nil {
-				return
-			}
-			hw := hwa.String()
-
-			if _, ok := as[hw]; ok {
-				ok, err = a.arping.Ping(ctx, e.Interface, hw, e.IPAddress)
-				if err != nil {
-					return
-				}
-				as[hw] = ok
-			}
+		if e.IPAddress != "" {
+			entries = append(entries, e)
 		}
 	}
 
-	present := false
-	for hw, ok := range as {
-		addrStates[hw].Set(ok)
-		if ok {
-			present = true
-		}
-	}
-	state.Set(present)
-
 	return
 }
-
-func (a *arp) Count(count uint) {
-	a.arping.Count(count)
-}

+ 3 - 63
neighbors/arp_linux.go

@@ -3,18 +3,12 @@ package neighbors
 import (
 	"context"
 	"encoding/json"
-	"net"
 	"os/exec"
 
 	"goa.design/clue/log"
 )
 
 type (
-	arp struct {
-		cmd    string
-		arping ARPing
-	}
-
 	arpEntry struct {
 		IPAddress  string `json:"dst"`
 		MACAddress string `json:"lladdr"`
@@ -22,29 +16,7 @@ type (
 	}
 )
 
-func NewARP(count uint) (ARP, error) {
-	cmd, err := exec.LookPath("ip")
-	if err != nil {
-		return nil, err
-	}
-
-	arping, err := NewARPing(count)
-	if err != nil {
-		return nil, err
-	}
-
-	return &arp{
-		cmd:    cmd,
-		arping: arping,
-	}, nil
-}
-
-func (a *arp) Present(ctx context.Context, ifs Interfaces, state State, addrStates HardwareAddrStates) (err error) {
-	as := make(map[string]bool, len(addrStates))
-	for hw := range addrStates {
-		as[hw] = false
-	}
-
+func (a *arp) entries(ctx context.Context, ifs Interfaces) (entries []arpEntry, err error) {
 	cmd := exec.CommandContext(ctx, a.cmd, "-family", "inet", "-json", "neighbor", "show", "nud", "reachable")
 	if len(ifs) == 1 {
 		for ifi := range ifs {
@@ -57,41 +29,9 @@ func (a *arp) Present(ctx context.Context, ifs Interfaces, state State, addrStat
 		return
 	}
 
-	var es []arpEntry
-	err = json.Unmarshal(b, &es)
-
-	for _, e := range es {
-		log.Debug(ctx, log.KV{K: "IP address", V: e.IPAddress}, log.KV{K: "MAC address", V: e.MACAddress}, log.KV{K: "interface", V: e.Interface})
-		if ifs[e.Interface] {
-			var hwa net.HardwareAddr
-			hwa, err = net.ParseMAC(e.MACAddress)
-			if err != nil {
-				return
-			}
-			hw := hwa.String()
-
-			if _, ok := as[hw]; ok {
-				ok, err = a.arping.Ping(ctx, e.Interface, hw, e.IPAddress)
-				if err != nil {
-					return
-				}
-				as[hw] = ok
-			}
-		}
-	}
-
-	present := false
-	for hw, ok := range as {
-		addrStates[hw].Set(ok)
-		if ok {
-			present = true
-		}
+	if err = json.Unmarshal(b, &entries); err != nil {
+		return
 	}
-	state.Set(present)
 
 	return
 }
-
-func (a *arp) Count(count uint) {
-	a.arping.Count(count)
-}