Skip to content

Add FelixIPIPOnly cluster routing mode - #5150

Open
nelljerram wants to merge 1 commit into
tigera:masterfrom
nelljerram:felix-ipip-cluster-routing-mode
Open

Add FelixIPIPOnly cluster routing mode#5150
nelljerram wants to merge 1 commit into
tigera:masterfrom
nelljerram:felix-ipip-cluster-routing-mode

Conversation

@nelljerram

Copy link
Copy Markdown
Member

Description

Type: new feature. Depends on projectcalico/calico#13470 — see "Merge order" below.

Calico is moving ownership of IPIP cluster routes from confd/BIRD to Felix, and
deprecating BIRD's ability to program them at all. Calico expresses that per
encapsulation type: FelixConfiguration.programClusterRoutes and
BGPConfiguration.programClusterRoutes each now take Disabled,
EnabledIPIPOnly, EnabledNoEncapOnly or Enabled, and their defaults move to
the complementary pair that puts IPIP with Felix and unencapsulated pools with
BIRD.

clusterRoutingMode was a single BIRD / Felix choice and could not express
that split. This adds a third value, FelixIPIPOnly, and maps the three modes
onto the two Calico fields:

clusterRoutingMode FelixConfiguration BGPConfiguration
BIRD Disabled Enabled
Felix Enabled Disabled
FelixIPIPOnly EnabledIPIPOnly EnabledNoEncapOnly

Unset clusterRoutingMode — no change in operator behaviour

Unset continues to mean "write neither field", so Calico's own defaults decide.
Worth being explicit about, because it means operator-installed clusters that
have not set clusterRoutingMode do pick up Calico's new defaults on upgrade
,
without any operator change — IPIP cluster routes move from BIRD to Felix. This
PR is what lets a user pin or opt into that split explicitly; it is not what
enables it.

The field's doc comment previously said [Default: BIRD]. That was only ever an
observation about what Calico defaulted to when the operator wrote nothing, and
it is now wrong, so the comment says what actually happens instead.

Validation

Validation asked one "does Felix program the cluster routes" question and applied
the answer to both IPIP and unencapsulated pools. That is no longer a single
question, so it is split in two: an IPIP pool requires BGP unless Felix owns the
IPIP routes, and an unencapsulated pool requires BGP unless Felix owns those.

So FelixIPIPOnly allows an IPIP pool with BGP disabled — new, and the point of
the value — but still rejects an unencapsulated pool with BGP disabled, correctly,
because in that mode BIRD is the component programming them.

Both predicates deliberately return false when clusterRoutingMode is unset,
so nothing that was rejected before becomes allowed by default. The alternative —
treating unset as equivalent to Calico's default — would mean encoding which
Calico version defaults which way, and that coupling would go stale silently.
The cost is that unset and FelixIPIPOnly behave identically at runtime but
differ in validation, with unset the stricter of the two. Reviewers: this is
the judgement call in this PR most worth a second opinion.

Merge order

The operator writes EnabledIPIPOnly / EnabledNoEncapOnly as plain strings, so
this compiles and its unit tests pass today. But a real cluster's
FelixConfiguration and BGPConfiguration CRDs only accept those values once
projectcalico/calico#13470 has merged and pkg/imports/crds/calico/ has been
re-imported from Calico master. Until both have happened, selecting
FelixIPIPOnly on a live cluster will be rejected by the apiserver. Please hold
this until then; the CRD re-import is not part of this PR.

Testing

  • pkg/controller/installation: 310 of 324 specs pass. The 14 failures are the
    pre-existing cel_validation_test.go BeforeEach failures, which need envtest
    assets — the same 14 fail on an unmodified master (306 of 320 there, so all
    four new specs pass and nothing regressed).
  • New specs: the FelixIPIPOnly reconcile mapping, plus validation cases for
    IPIP, IPIP-cross-subnet and unencapsulated pools with BGP disabled under
    FelixIPIPOnly.
  • golangci-lint run: 0 issues.
  • make gen-files for the regenerated Installation CRD.
  • Not yet exercised on a live cluster — that depends on the merge order above.

Also worth a reviewer's eye: FelixIPIPOnly with BGP disabled is now an allowed
combination that has not been run end-to-end. It is structurally the same shape
as VXLAN with BGP disabled (Felix owns the routes, no BIRD), but if you would
rather this PR did not widen validation at all, say so and I will drop that part
and keep the mode purely as a mapping.

Release Note

Added a FelixIPIPOnly value to Installation clusterRoutingMode, selecting Felix for the cluster routes of IPIP IP pools and confd/BIRD for those of unencapsulated IP pools.

For PR author

  • Tests for change.
  • If changing pkg/apis/, run make gen-files
  • If changing versions, run make gen-versions

🤖 Generated with Claude Code

Calico is moving the ownership of IPIP cluster routes from confd/BIRD to Felix,
and deprecating BIRD's ability to program them at all
(projectcalico/calico#13470). Calico expresses this per encapsulation type:
FelixConfiguration.programClusterRoutes and BGPConfiguration.programClusterRoutes
each now take Disabled, EnabledIPIPOnly, EnabledNoEncapOnly or Enabled, and the
new defaults put IPIP with Felix and unencapsulated pools with BIRD.

clusterRoutingMode was a single BIRD/Felix choice and so could not express that
split. Add a third value, FelixIPIPOnly, and map the three modes onto the
Calico fields:

  BIRD          -> Felix Disabled,        BIRD Enabled
  Felix         -> Felix Enabled,         BIRD Disabled
  FelixIPIPOnly -> Felix EnabledIPIPOnly, BIRD EnabledNoEncapOnly

An unset clusterRoutingMode continues to mean "write neither field", so Calico's
own defaults decide -- which from Calico v3.33 is the FelixIPIPOnly split. The
field's doc comment said "[Default: BIRD]", which was only ever an observation
about what Calico defaulted to; it now says what actually happens.

Validation asked a single "does Felix program the cluster routes" question and
applied the answer to both IPIP and unencapsulated pools. Split it: an IPIP pool
needs BGP unless Felix owns the IPIP routes, and an unencapsulated pool needs BGP
unless Felix owns those. So FelixIPIPOnly allows an IPIP pool with BGP disabled,
but still requires BGP for an unencapsulated one -- correctly, since in that mode
BIRD is the one programming them.

Both predicates deliberately return false when the mode is unset. The operator
would otherwise have to encode which Calico version defaults which way, and that
coupling would go stale silently; a user who wants IPIP without BGP can say
FelixIPIPOnly explicitly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nelljerram
nelljerram requested review from a team and marvin-tigera as code owners August 7, 2026 19:07
@marvin-tigera marvin-tigera added this to the v1.44.0 milestone Aug 7, 2026
nelljerram added a commit to nelljerram/calico that referenced this pull request Aug 7, 2026
The doc claimed tigera/operator always writes both programClusterRoutes fields,
and so that changing the defaults here has no effect on operator-installed
clusters. That is wrong. The operator only writes them when
Installation.spec.calicoNetwork.clusterRoutingMode is set; when it is unset --
the common case -- it writes neither, and these defaults are what the cluster
gets. So an operator-installed cluster does pick up the change on upgrade.

Point at tigera/operator#5150, which adds the FelixIPIPOnly value that maps onto
the new complementary pair.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants