From 29cd7c9c061f1240f63226ed005dbdd0c45ed9de Mon Sep 17 00:00:00 2001 From: Tomas Hruby Date: Thu, 16 Jul 2026 11:26:17 -0700 Subject: [PATCH] Default BPFOverlayHostSourceIP to HostAddress on fresh eBPF installs On a brand new eBPF cluster the operator now sets FelixConfiguration's bpfOverlayHostSourceIP to HostAddress, opting the cluster out of assigning an IP to the IPIP/VXLAN overlay tunnel device and sourcing host-networked overlay traffic from the node's own address instead. Felix defaults this setting to TunnelAddress. Existing and upgraded clusters keep that default (the operator only writes the field on a fresh install, detected by the absence of the calico-node DaemonSet) so their established host-networked overlay flows are not disrupted. Fresh clusters have no such flows to preserve, so they adopt the leaner HostAddress mode. The write is guarded on the field being unset, so a user-provided value is never overridden. Requires the FelixConfiguration bpfOverlayHostSourceIP field from projectcalico/calico#11919. Co-Authored-By: Claude Opus 4.8 --- .../installation/core_controller.go | 10 ++++ .../installation/core_controller_test.go | 46 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/pkg/controller/installation/core_controller.go b/pkg/controller/installation/core_controller.go index a766f061f4..9d4a4b802a 100644 --- a/pkg/controller/installation/core_controller.go +++ b/pkg/controller/installation/core_controller.go @@ -2173,6 +2173,16 @@ func (r *ReconcileInstallation) setDefaultsOnFelixConfiguration(ctx context.Cont return false, err } updated = true + + // A fresh eBPF install opts into sourcing host-networked overlay traffic from the + // node's own address instead of an IP assigned to the tunnel device. Felix defaults + // this to TunnelAddress, which existing/upgraded clusters keep so their host-networked + // flows are not disrupted; brand new clusters have no such flows to preserve. Only set + // it when unset so a user-provided value is never overridden. + if fc.Spec.BPFOverlayHostSourceIP == nil { + hostSourceIP := v3.BPFOverlayHostSourceIPHostAddress + fc.Spec.BPFOverlayHostSourceIP = &hostSourceIP + } } } else { bpfEnabledOnDaemonsetWithEnvVar, err := bpfEnabledOnDaemonsetWithEnvVar(ds) diff --git a/pkg/controller/installation/core_controller_test.go b/pkg/controller/installation/core_controller_test.go index bda4f6065b..9baf9d5ae8 100644 --- a/pkg/controller/installation/core_controller_test.go +++ b/pkg/controller/installation/core_controller_test.go @@ -1675,6 +1675,52 @@ var _ = Describe("Testing core-controller installation", func() { Expect(fc.Annotations[render.BPFOperatorAnnotation]).To(Equal("true")) Expect(fc.Spec.BPFEnabled).NotTo(BeNil()) Expect(*fc.Spec.BPFEnabled).To(BeTrue()) + + // A fresh eBPF install should opt into sourcing host-networked overlay traffic + // from the node's address rather than a tunnel device IP. + Expect(fc.Spec.BPFOverlayHostSourceIP).NotTo(BeNil()) + Expect(*fc.Spec.BPFOverlayHostSourceIP).To(Equal(v3.BPFOverlayHostSourceIPHostAddress)) + }) + + It("should not set BPFOverlayHostSourceIP on FelixConfiguration when calico-node already exists (upgrade)", func() { + createNodeDaemonSet() + + network := operator.LinuxDataplaneBPF + cr.Spec.CalicoNetwork = &operator.CalicoNetworkSpec{LinuxDataplane: &network} + Expect(c.Create(ctx, cr)).NotTo(HaveOccurred()) + _, err := r.Reconcile(ctx, reconcile.Request{}) + Expect(err).ShouldNot(HaveOccurred()) + + fc := &v3.FelixConfiguration{} + err = c.Get(ctx, types.NamespacedName{Name: "default"}, fc) + Expect(err).ShouldNot(HaveOccurred()) + + // An existing cluster keeps Felix's TunnelAddress default (field left unset) so + // its host-networked overlay flows are not disrupted. + Expect(fc.Spec.BPFOverlayHostSourceIP).To(BeNil()) + }) + + It("should not override a user-set BPFOverlayHostSourceIP on a fresh install", func() { + tunnelAddress := v3.BPFOverlayHostSourceIPTunnelAddress + existingFC := &v3.FelixConfiguration{ + ObjectMeta: metav1.ObjectMeta{Name: "default"}, + Spec: v3.FelixConfigurationSpec{BPFOverlayHostSourceIP: &tunnelAddress}, + } + Expect(c.Create(ctx, existingFC)).NotTo(HaveOccurred()) + + network := operator.LinuxDataplaneBPF + cr.Spec.CalicoNetwork = &operator.CalicoNetworkSpec{LinuxDataplane: &network} + Expect(c.Create(ctx, cr)).NotTo(HaveOccurred()) + _, err := r.Reconcile(ctx, reconcile.Request{}) + Expect(err).ShouldNot(HaveOccurred()) + + fc := &v3.FelixConfiguration{} + err = c.Get(ctx, types.NamespacedName{Name: "default"}, fc) + Expect(err).ShouldNot(HaveOccurred()) + + // The operator must not stomp a value the user already set. + Expect(fc.Spec.BPFOverlayHostSourceIP).NotTo(BeNil()) + Expect(*fc.Spec.BPFOverlayHostSourceIP).To(Equal(v3.BPFOverlayHostSourceIPTunnelAddress)) }) It("should set BPFEnabled to false on FelixConfiguration if BPF is disabled on installation", func() {