Add FelixIPIPOnly cluster routing mode - #5150
Open
nelljerram wants to merge 1 commit into
Open
Conversation
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
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.programClusterRoutesandBGPConfiguration.programClusterRouteseach now takeDisabled,EnabledIPIPOnly,EnabledNoEncapOnlyorEnabled, and their defaults move tothe complementary pair that puts IPIP with Felix and unencapsulated pools with
BIRD.
clusterRoutingModewas a singleBIRD/Felixchoice and could not expressthat split. This adds a third value,
FelixIPIPOnly, and maps the three modesonto the two Calico fields:
clusterRoutingModeFelixConfigurationBGPConfigurationBIRDDisabledEnabledFelixEnabledDisabledFelixIPIPOnlyEnabledIPIPOnlyEnabledNoEncapOnlyUnset
clusterRoutingMode— no change in operator behaviourUnset 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
clusterRoutingModedo 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 anobservation 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
FelixIPIPOnlyallows an IPIP pool with BGP disabled — new, and the point ofthe 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
falsewhenclusterRoutingModeis 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
FelixIPIPOnlybehave identically at runtime butdiffer 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/EnabledNoEncapOnlyas plain strings, sothis 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 beenre-imported from Calico master. Until both have happened, selecting
FelixIPIPOnlyon a live cluster will be rejected by the apiserver. Please holdthis 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 thepre-existing
cel_validation_test.goBeforeEachfailures, which need envtestassets — the same 14 fail on an unmodified
master(306 of 320 there, so allfour new specs pass and nothing regressed).
FelixIPIPOnlyreconcile mapping, plus validation cases forIPIP, IPIP-cross-subnet and unencapsulated pools with BGP disabled under
FelixIPIPOnly.golangci-lint run: 0 issues.make gen-filesfor the regenerated Installation CRD.Also worth a reviewer's eye:
FelixIPIPOnlywith BGP disabled is now an allowedcombination 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
For PR author
make gen-filesmake gen-versions🤖 Generated with Claude Code