66265764df
The agent now collects the device's reachable prefixes from the kernel FIB
(including FRR-installed routes) via 'ip route show' / 'ip -6 route show' and
reports them to the control plane (POST /devices/{name}/routes) alongside its
status. tomswallapi uses these to scope which routers enforce a rule. Route
parsing (default routes, ECMP nexthop lines, route-type keywords, host routes,
v4/v6) is unit-tested; collection degrades to nil without iproute2.
56 lines
1.5 KiB
Go
56 lines
1.5 KiB
Go
package agent
|
|
|
|
import (
|
|
"reflect"
|
|
"sort"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseRoutesV4(t *testing.T) {
|
|
// Representative `ip route show` output, including a default route, an ECMP
|
|
// route with nexthop continuation lines, a connected route, and a host route.
|
|
out := `default via 10.0.0.1 dev eth0 proto dhcp
|
|
10.1.0.0/24 dev eth1 proto kernel scope link src 10.1.0.5
|
|
10.4.0.0/24 proto bgp metric 20
|
|
nexthop via 10.0.0.2 dev eth0 weight 1
|
|
nexthop via 10.0.0.3 dev eth0 weight 1
|
|
192.0.2.7 dev eth2 scope link
|
|
blackhole 172.16.0.0/12
|
|
`
|
|
got := parseRoutes(out, "0.0.0.0/0")
|
|
sort.Strings(got)
|
|
want := []string{"0.0.0.0/0", "10.1.0.0/24", "10.4.0.0/24", "172.16.0.0/12", "192.0.2.7/32"}
|
|
sort.Strings(want)
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Errorf("parseRoutes v4 = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestParseRoutesV6(t *testing.T) {
|
|
out := `default via fe80::1 dev eth0 metric 1024
|
|
2001:db8:1::/64 dev eth1 proto kernel metric 256
|
|
2001:db8:4::5 dev eth2
|
|
`
|
|
got := parseRoutes(out, "::/0")
|
|
sort.Strings(got)
|
|
want := []string{"2001:db8:1::/64", "2001:db8:4::5/128", "::/0"}
|
|
sort.Strings(want)
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Errorf("parseRoutes v6 = %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestNormalizePrefix(t *testing.T) {
|
|
cases := map[string]string{
|
|
"10.1.0.0/24": "10.1.0.0/24",
|
|
"10.1.0.5": "10.1.0.5/32",
|
|
"2001:db8::1": "2001:db8::1/128",
|
|
"2001:db8::/32": "2001:db8::/32",
|
|
}
|
|
for in, want := range cases {
|
|
if got := normalizePrefix(in); got != want {
|
|
t.Errorf("normalizePrefix(%q) = %q, want %q", in, got, want)
|
|
}
|
|
}
|
|
}
|