9.3 KiB
Windows Network Traffic Stats Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Fix Windows network traffic statistics showing zero when the active adapter is named like Ethernet0 and uses a private IPv4 address.
Architecture: Keep the fix inside internal/analytic/network.go. Extract the interface selection rule into a small testable helper, then let GetNetworkStat() aggregate any up, non-loopback, non-virtual interface with a hardware address and at least one usable unicast IP address, including private IPv4 ranges. Continue excluding disconnected, loopback, link-local-only, TAP, tunnel, VPN, Docker, and similar virtual interfaces.
Tech Stack: Go, net, github.com/shirou/gopsutil/v4/net, existing go test workflow.
File Structure
- Modify:
internal/analytic/network.go- Keep
GetNetworkStat()as the public entry point. - Add a lightweight
networkInterfaceInfostruct so selection logic can be unit-tested without depending on host NICs. - Replace the current public-IP-only gate with
hasUsableUnicastIP().
- Keep
- Create:
internal/analytic/network_test.go- Unit tests for Windows-style adapter names and private IPs.
- Regression tests for virtual, loopback, down, and link-local-only interfaces.
Task 1: Add Failing Network Interface Selection Tests
Files:
-
Create:
internal/analytic/network_test.go -
Step 1: Create tests for the Windows regression and exclusions
Create internal/analytic/network_test.go:
package analytic
import (
stdnet "net"
"testing"
)
func mustCIDR(t *testing.T, value string) stdnet.Addr {
t.Helper()
ip, ipNet, err := stdnet.ParseCIDR(value)
if err != nil {
t.Fatalf("failed to parse CIDR %q: %v", value, err)
}
ipNet.IP = ip
return ipNet
}
func TestShouldCountNetworkInterfaceAcceptsWindowsEthernetPrivateIPv4(t *testing.T) {
iface := networkInterfaceInfo{
Name: "Ethernet0",
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
HardwareAddr: stdnet.HardwareAddr{0x00, 0x50, 0x56, 0xba, 0x25, 0x01},
Addrs: []stdnet.Addr{mustCIDR(t, "10.100.1.10/28")},
}
if !shouldCountNetworkInterface(iface) {
t.Fatalf("expected Windows Ethernet interface with private IPv4 to be counted")
}
}
func TestShouldCountNetworkInterfaceRejectsTapAdapter(t *testing.T) {
iface := networkInterfaceInfo{
Name: "TAP-Windows Adapter V9",
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
HardwareAddr: stdnet.HardwareAddr{0x00, 0xff, 0x55, 0x61, 0x3a, 0xd2},
Addrs: []stdnet.Addr{mustCIDR(t, "10.8.0.2/24")},
}
if shouldCountNetworkInterface(iface) {
t.Fatalf("expected TAP adapter to be excluded")
}
}
func TestShouldCountNetworkInterfaceRejectsLinkLocalOnly(t *testing.T) {
iface := networkInterfaceInfo{
Name: "Ethernet0",
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
HardwareAddr: stdnet.HardwareAddr{0x00, 0x50, 0x56, 0xba, 0x25, 0x01},
Addrs: []stdnet.Addr{mustCIDR(t, "fe80::c562:f8dc:9cd4:18eb/64")},
}
if shouldCountNetworkInterface(iface) {
t.Fatalf("expected link-local-only interface to be excluded")
}
}
func TestShouldCountNetworkInterfaceRejectsLoopback(t *testing.T) {
iface := networkInterfaceInfo{
Name: "Loopback Pseudo-Interface 1",
Flags: stdnet.FlagUp | stdnet.FlagLoopback,
Addrs: []stdnet.Addr{mustCIDR(t, "127.0.0.1/8")},
}
if shouldCountNetworkInterface(iface) {
t.Fatalf("expected loopback interface to be excluded")
}
}
- Step 2: Run tests and verify they fail because the helper does not exist
Run:
go test ./internal/analytic
Expected: FAIL with compile errors containing undefined: networkInterfaceInfo and undefined: shouldCountNetworkInterface.
Task 2: Implement Testable Interface Classification
Files:
-
Modify:
internal/analytic/network.go -
Step 1: Add testable interface metadata and selection helpers
Add this near the top of internal/analytic/network.go, after imports and before GetNetworkStat():
type networkInterfaceInfo struct {
Name string
Flags stdnet.Flags
HardwareAddr stdnet.HardwareAddr
Addrs []stdnet.Addr
}
func shouldCountNetworkInterface(iface networkInterfaceInfo) bool {
if iface.Flags&stdnet.FlagUp == 0 || iface.Flags&stdnet.FlagLoopback != 0 {
return false
}
if isVirtualInterface(iface.Name) {
return false
}
if len(iface.HardwareAddr) == 0 {
return false
}
return hasUsableUnicastIP(iface.Addrs)
}
func buildCountedInterfaceSet(interfaces []networkInterfaceInfo) map[string]bool {
countedInterfaces := make(map[string]bool)
for _, iface := range interfaces {
if shouldCountNetworkInterface(iface) {
countedInterfaces[iface.Name] = true
}
}
return countedInterfaces
}
func hasUsableUnicastIP(addrs []stdnet.Addr) bool {
for _, addr := range addrs {
ip, _, err := stdnet.ParseCIDR(addr.String())
if err != nil {
continue
}
if !ip.IsGlobalUnicast() {
continue
}
if ip.IsLinkLocalUnicast() || ip.IsLoopback() || ip.IsMulticast() || ip.IsUnspecified() {
continue
}
if isReservedIP(ip) {
continue
}
return true
}
return false
}
- Step 2: Run tests and verify helper behavior passes but
GetNetworkStat()still uses old selection
Run:
go test ./internal/analytic
Expected: PASS for the new helper tests if they are the only changed tests; the runtime path has not been updated yet.
Task 3: Wire GetNetworkStat() to the New Selection Rule
Files:
-
Modify:
internal/analytic/network.go -
Step 1: Replace the existing external-interface discovery loop
In GetNetworkStat(), replace the current logic that checks isPhysicalInterface() and isRealExternalIP() with this loop:
interfaceInfos := make([]networkInterfaceInfo, 0, len(interfaces))
for _, iface := range interfaces {
addrs, err := iface.Addrs()
if err != nil {
logger.Error(err)
continue
}
interfaceInfos = append(interfaceInfos, networkInterfaceInfo{
Name: iface.Name,
Flags: iface.Flags,
HardwareAddr: iface.HardwareAddr,
Addrs: addrs,
})
}
countedInterfaces := buildCountedInterfaceSet(interfaceInfos)
Then update the aggregation condition from:
if externalInterfaces[stat.Name] {
to:
if countedInterfaces[stat.Name] {
- Step 2: Remove now-unused physical/public-IP selection helpers
Remove these functions if they are no longer referenced:
func isPhysicalInterface(name string) bool
func isNumericSuffix(s string) bool
func isRealExternalIP(ip stdnet.IP, ipNet *stdnet.IPNet) bool
Keep isReservedIP() because hasUsableUnicastIP() still uses it.
- Step 3: Run gofmt
Run:
gofmt -w internal/analytic/network.go internal/analytic/network_test.go
Expected: no output.
- Step 4: Run analytic package tests
Run:
go test ./internal/analytic
Expected: PASS.
Task 4: Add Regression Coverage for Aggregation Name Matching
Files:
-
Modify:
internal/analytic/network_test.go -
Step 1: Add a test for building the counted interface map
Add this test:
func TestBuildCountedInterfaceSetIncludesOnlyEligibleNames(t *testing.T) {
interfaces := []networkInterfaceInfo{
{
Name: "Ethernet0",
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
HardwareAddr: stdnet.HardwareAddr{0x00, 0x50, 0x56, 0xba, 0x25, 0x01},
Addrs: []stdnet.Addr{mustCIDR(t, "10.100.1.10/28")},
},
{
Name: "TAP-Windows Adapter V9",
Flags: stdnet.FlagUp | stdnet.FlagBroadcast | stdnet.FlagMulticast,
HardwareAddr: stdnet.HardwareAddr{0x00, 0xff, 0x55, 0x61, 0x3a, 0xd2},
Addrs: []stdnet.Addr{mustCIDR(t, "10.8.0.2/24")},
},
}
counted := buildCountedInterfaceSet(interfaces)
if !counted["Ethernet0"] {
t.Fatalf("expected Ethernet0 to be counted")
}
if counted["TAP-Windows Adapter V9"] {
t.Fatalf("expected TAP adapter to be excluded")
}
}
- Step 2: Run tests
Run:
go test ./internal/analytic
Expected: PASS.
Task 5: Final Verification
Files:
-
Verify only; no edits.
-
Step 1: Check the changed file list
Run:
git diff --stat -- internal/analytic/network.go internal/analytic/network_test.go
Expected: only the network stat implementation and its tests are listed.
- Step 2: Run package tests
Run:
go test ./internal/analytic
Expected: PASS.
- Step 3: Optional broader backend smoke test
Run:
go test ./api/analytic ./internal/analytic
Expected: PASS.
Self-Review
- Spec coverage: The plan addresses the observed Windows Server 2012 R2 output where
Ethernet0has a private10.100.x.xaddress and traffic is currently filtered to zero. - Risk control: The plan keeps virtual/tunnel exclusions and avoids switching blindly to
net.IOCounters(false), which could count loopback and virtual adapters. - Test coverage: The plan adds regression tests for the Windows physical adapter case and for the exclusion cases that the old filter tried to protect.