Store device FIB for observability (no rule limiting)
Devices carry a reachable_prefixes set (migration 0004) reported by their agent
from the kernel FIB, via a new agent-authed POST /devices/{name}/routes endpoint.
This is scoping/observability data, so it does not bump the config generation and
is exposed on the device resource.
It deliberately does NOT limit which rules a device enforces: the compiler still
emits every applicable rule on every enforcing device. The interface-agnostic,
address-matched rule form is correct under ECMP precisely because it does not
depend on which device is on the path, and most routers hold a default route
anyway — so reachability could not meaningfully narrow the rule set. The reported
FIB is kept for fleet visibility and future zone-origin validation.
This commit is contained in:
@@ -131,6 +131,10 @@ func Render(in Input) (*RenderedConfig, error) {
|
||||
|
||||
usedSets := map[string]model.AddressGroup{}
|
||||
|
||||
// Every enforcing device carries every applicable rule: the interface-agnostic
|
||||
// address-matched form is correct under ECMP precisely because it does not
|
||||
// depend on which device is on the path (over-approximation is safe). Reported
|
||||
// FIBs are stored for observability/validation, not to limit rules.
|
||||
if out.Enforcing {
|
||||
for _, rule := range in.Rules {
|
||||
rr, err := renderRule(in, rule, usedSets)
|
||||
|
||||
@@ -116,6 +116,31 @@ func TestRenderUnknownGroupIsError(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReportedFIBDoesNotLimitRules(t *testing.T) {
|
||||
// A router with a narrow FIB must still carry every applicable rule: reported
|
||||
// reachability is observability data, not a rule filter (over-approximation is
|
||||
// safe and intended under ECMP).
|
||||
in := Input{
|
||||
Fabric: &model.Fabric{Name: "core", EnforceOnRouters: true},
|
||||
Device: model.Device{Name: "rt1", Class: model.ClassRouter, Fabric: "core",
|
||||
ReachablePrefixes: []string{"192.168.0.0/16"}},
|
||||
Zones: map[string]model.Zone{
|
||||
"zone-a": {Name: "zone-a", Subnets: []string{"10.1.0.0/24"}},
|
||||
"zone-b": {Name: "zone-b", Subnets: []string{"10.4.0.0/24"}},
|
||||
},
|
||||
Rules: []model.Rule{
|
||||
{ID: 1, Action: "accept", Source: []string{"zone-a"}, Dest: []string{"zone-b"}, Proto: "tcp", Ports: []string{"22"}},
|
||||
},
|
||||
}
|
||||
cfg, err := Render(in)
|
||||
if err != nil {
|
||||
t.Fatalf("Render: %v", err)
|
||||
}
|
||||
if len(cfg.Rules) != 1 {
|
||||
t.Errorf("reported FIB must not limit rules, got %d", len(cfg.Rules))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEffectiveResolverPrefersDevice(t *testing.T) {
|
||||
in := baseInput()
|
||||
in.Device = model.Device{Name: "fw-a", Class: model.ClassFirewall, Resolver: []string{"10.9.9.9"}}
|
||||
|
||||
Reference in New Issue
Block a user