Store device FIB for observability (no rule limiting)
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful

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:
benvin
2026-07-20 22:35:28 +10:00
committed by Ben Vincent
parent b350c8d198
commit 9dbeb62414
7 changed files with 85 additions and 3 deletions
+18
View File
@@ -350,6 +350,24 @@ func (s *Server) handleDeviceConfig(w http.ResponseWriter, r *http.Request) {
_, _ = w.Write(body)
}
func (s *Server) handleDeviceRoutes(w http.ResponseWriter, r *http.Request) {
var body struct {
Prefixes []string `json:"prefixes"`
}
if !decode(w, r, &body) {
return
}
if err := s.store.UpdateDeviceRoutes(r.Context(), chi.URLParam(r, "name"), body.Prefixes); err != nil {
if errors.Is(err, store.ErrNotFound) {
writeError(w, http.StatusNotFound, "device not found")
return
}
writeError(w, http.StatusInternalServerError, err.Error())
return
}
w.WriteHeader(http.StatusNoContent)
}
func (s *Server) handleDeviceStatus(w http.ResponseWriter, r *http.Request) {
var body struct {
Generation int64 `json:"generation"`
+1
View File
@@ -94,6 +94,7 @@ func (s *Server) routes() http.Handler {
r.Use(s.requireToken(s.agentToken))
r.Get("/devices/{name}/config", s.handleDeviceConfig)
r.Post("/devices/{name}/status", s.handleDeviceStatus)
r.Post("/devices/{name}/routes", s.handleDeviceRoutes)
})
})