daemon: Preserve prefixes on config reload

copystructure cannot reflect the unexported fields in netip.Prefix and replaces configured default address pools with zero values during a daemon reload. Register an immutable-value copier, matching the existing netip.Addr handling, and cover it with a regression test.

Signed-off-by: Erick Shaffer <324667592+erishaffdev@users.noreply.github.com>
This commit is contained in:
Erick Shaffer committed 2026-09-22 16:43:35 -06:00
1 parent 0c42970c26
commit 56bed6b15a
2 files changed
+16 -4

No files matched your search

+7 -4
View File
@@ -17,16 +17,19 @@ import (
)
func init() {
// Register a custom copier for netip.Addr. The copystructure library uses
// reflection which cannot access unexported fields in netip.Addr, resulting
// in zero-value copies. Since netip.Addr is an immutable value type, we can
// safely return it as-is.
// Register custom copiers for netip values. The copystructure library uses
// reflection which cannot access unexported fields in these types, resulting
// in zero-value copies. Since netip values are immutable, we can safely return
// them as-is.
//
// Note: copystructure is archived (https://github.com/mitchellh/copystructure)
// and won't receive upstream fixes for this limitation.
copystructure.Copiers[reflect.TypeFor[netip.Addr]()] = func(v any) (any, error) {
return v.(netip.Addr), nil
}
copystructure.Copiers[reflect.TypeFor[netip.Prefix]()] = func(v any) (any, error) {
return v.(netip.Prefix), nil
}
}
// reloadTxn is used to defer side effects of a config reload.
+9
View File
@@ -35,6 +35,15 @@ func TestCopystructureNetipAddr(t *testing.T) {
assert.Check(t, is.DeepEqual(copied.([]netip.Addr), original, cmpopts.EquateComparable(netip.Addr{})))
}
func TestCopystructureNetipPrefix(t *testing.T) {
// Verify that our custom copier for netip.Prefix works correctly.
// Without it, copystructure.Copy produces zero-value (invalid) prefixes.
original := []netip.Prefix{netip.MustParsePrefix("172.30.0.0/16")}
copied, err := copystructure.Copy(original)
assert.NilError(t, err)
assert.Check(t, is.DeepEqual(copied.([]netip.Prefix), original, cmpopts.EquateComparable(netip.Prefix{})))
}
func newDaemonForReloadT(t *testing.T, cfg *config.Config) *Daemon {
t.Helper()
daemon := &Daemon{