Skip to content

Commit 284ca5a

Browse files
Manifest -> operator migration for nftables mode (tigera#3994)
1 parent 4ebda7b commit 284ca5a

4 files changed

Lines changed: 179 additions & 3 deletions

File tree

pkg/controller/migration/convert/bpf.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2022-2024 Tigera, Inc. All rights reserved.
1+
// Copyright (c) 2022-2025 Tigera, Inc. All rights reserved.
22

33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -48,7 +48,8 @@ func copyK8sServicesEPConfigMap(c *components) error {
4848
Name: cmName,
4949
Namespace: common.OperatorNamespace(),
5050
},
51-
Data: map[string]string{"KUBERNETES_SERVICE_HOST": host,
51+
Data: map[string]string{
52+
"KUBERNETES_SERVICE_HOST": host,
5253
"KUBERNETES_SERVICE_PORT": port,
5354
},
5455
})
@@ -83,6 +84,13 @@ func handleBPF(c *components, install *operatorv1.Installation) error {
8384
install.Spec.CalicoNetwork = &operatorv1.CalicoNetworkSpec{}
8485
}
8586

87+
// Make sure dataplane mode isn't already set by another handler.
88+
// If we hit this, it means that either there was conflicting configuration in the
89+
// manifest, or that a dataplane combination exists that is not supported by the operator.
90+
if install.Spec.CalicoNetwork.LinuxDataplane != nil {
91+
return fmt.Errorf("cannot enable bpf, already set to %s", *install.Spec.CalicoNetwork.LinuxDataplane)
92+
}
93+
8694
install.Spec.CalicoNetwork.LinuxDataplane = &bpf
8795
install.Spec.CalicoNetwork.HostPorts = nil
8896
}

pkg/controller/migration/convert/handler.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2019,2022 Tigera, Inc. All rights reserved.
1+
// Copyright (c) 2019,2025 Tigera, Inc. All rights reserved.
22

33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -39,4 +39,5 @@ var handlers = []handler{
3939
handleMTU,
4040
handleIPPools,
4141
handleBPF,
42+
handleNftables,
4243
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (c) 2025 Tigera, Inc. All rights reserved.
2+
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package convert
15+
16+
import (
17+
"fmt"
18+
"strings"
19+
20+
operatorv1 "github.com/tigera/operator/api/v1"
21+
crdv1 "github.com/tigera/operator/pkg/apis/crd.projectcalico.org/v1"
22+
v1 "github.com/tigera/operator/pkg/apis/crd.projectcalico.org/v1"
23+
"k8s.io/apimachinery/pkg/types"
24+
)
25+
26+
// handleNftables is a migration handler which ensures nftables configuration is carried forward.
27+
func handleNftables(c *components, install *operatorv1.Installation) error {
28+
fc := &crdv1.FelixConfiguration{}
29+
err := c.client.Get(ctx, types.NamespacedName{Name: "default"}, fc)
30+
if err != nil {
31+
return fmt.Errorf("error reading felixconfiguration %w", err)
32+
}
33+
34+
envMode, err := c.node.getEnv(ctx, c.client, containerCalicoNode, "FELIX_NFTABLESMODE")
35+
if err != nil {
36+
return fmt.Errorf("error reading FELIX_NFTABLESMODE env var %w", err)
37+
}
38+
39+
inFelixConfig := fc.Spec.NFTablesMode != nil && *fc.Spec.NFTablesMode == v1.NFTablesModeEnabled
40+
enabledEnvVar := envMode != nil && strings.ToLower(*envMode) == "enabled"
41+
42+
// A disabled env var will override any other configuration. It's possible to have a feature enabled in the FelixConfiguration
43+
// but disabled via the environment variable as an override (although not recommended!)
44+
disabledEnvVar := envMode != nil && strings.ToLower(*envMode) == "disabled"
45+
46+
if !disabledEnvVar && (inFelixConfig || enabledEnvVar) {
47+
if install.Spec.CalicoNetwork == nil {
48+
install.Spec.CalicoNetwork = &operatorv1.CalicoNetworkSpec{}
49+
}
50+
51+
// Make sure dataplane mode isn't already set by another handler.
52+
// If we hit this, it means that either there was conflicting configuration in the
53+
// manifest, or that a dataplane combination exists that is not supported by the operator.
54+
if install.Spec.CalicoNetwork.LinuxDataplane != nil {
55+
return fmt.Errorf("cannot enable nftables, already set to %s", *install.Spec.CalicoNetwork.LinuxDataplane)
56+
}
57+
58+
nft := operatorv1.LinuxDataplaneNftables
59+
install.Spec.CalicoNetwork.LinuxDataplane = &nft
60+
}
61+
return nil
62+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Copyright (c) 2025 Tigera, Inc. All rights reserved.
2+
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
package convert
15+
16+
import (
17+
. "github.com/onsi/ginkgo"
18+
. "github.com/onsi/gomega"
19+
20+
operatorv1 "github.com/tigera/operator/api/v1"
21+
"github.com/tigera/operator/pkg/apis"
22+
crdv1 "github.com/tigera/operator/pkg/apis/crd.projectcalico.org/v1"
23+
pcv1 "github.com/tigera/operator/pkg/apis/crd.projectcalico.org/v1"
24+
ctrlrfake "github.com/tigera/operator/pkg/ctrlruntime/client/fake"
25+
26+
v1 "k8s.io/api/core/v1"
27+
kscheme "k8s.io/client-go/kubernetes/scheme"
28+
)
29+
30+
var _ = Describe("convert nftables mode", func() {
31+
var (
32+
comps = emptyComponents()
33+
i = &operatorv1.Installation{}
34+
f = &crdv1.FelixConfiguration{}
35+
scheme = kscheme.Scheme
36+
)
37+
38+
BeforeEach(func() {
39+
comps = emptyComponents()
40+
i = &operatorv1.Installation{}
41+
f = emptyFelixConfig()
42+
Expect(apis.AddToScheme(scheme)).ToNot(HaveOccurred())
43+
})
44+
45+
It("converts nftables mode from FelixConfiguration Enabled", func() {
46+
nftMode := pcv1.NFTablesModeEnabled
47+
f.Spec.NFTablesMode = &nftMode
48+
comps.client = ctrlrfake.DefaultFakeClientBuilder(scheme).WithObjects(endPointCM, f).Build()
49+
50+
err := handleNftables(&comps, i)
51+
Expect(err).ToNot(HaveOccurred())
52+
Expect(*i.Spec.CalicoNetwork.LinuxDataplane).To(BeEquivalentTo(operatorv1.LinuxDataplaneNftables))
53+
Expect(i.Spec.CalicoNetwork.HostPorts).To(BeNil())
54+
})
55+
56+
It("converts nftables mode from FelixConfiguration Disabled", func() {
57+
nftMode := pcv1.NFTablesModeDisabled
58+
f.Spec.NFTablesMode = &nftMode
59+
comps.client = ctrlrfake.DefaultFakeClientBuilder(scheme).WithObjects(endPointCM, f).Build()
60+
err := handleNftables(&comps, i)
61+
Expect(err).ToNot(HaveOccurred())
62+
Expect(i.Spec.CalicoNetwork).To(BeNil())
63+
})
64+
65+
It("rejects migration if another dataplane is already set", func() {
66+
nftMode := pcv1.NFTablesModeEnabled
67+
f.Spec.NFTablesMode = &nftMode
68+
comps.client = ctrlrfake.DefaultFakeClientBuilder(scheme).WithObjects(endPointCM, f).Build()
69+
70+
// Set the Installation to already have a dataplane mode set.
71+
bpf := operatorv1.LinuxDataplaneBPF
72+
i.Spec.CalicoNetwork = &operatorv1.CalicoNetworkSpec{LinuxDataplane: &bpf}
73+
74+
err := handleNftables(&comps, i)
75+
Expect(err).To(HaveOccurred())
76+
})
77+
78+
It("check with no felixconfig", func() {
79+
comps.client = ctrlrfake.DefaultFakeClientBuilder(scheme).WithObjects(endPointCM).Build()
80+
err := handleNftables(&comps, i)
81+
Expect(err).To(HaveOccurred())
82+
})
83+
84+
It("converts nftables mode from environment variable (enabled)", func() {
85+
comps.client = ctrlrfake.DefaultFakeClientBuilder(scheme).WithObjects(endPointCM, f).Build()
86+
comps.node.Spec.Template.Spec.Containers[0].Env = []v1.EnvVar{{
87+
Name: "FELIX_NFTABLESMODE",
88+
Value: "Enabled",
89+
}}
90+
err := handleNftables(&comps, i)
91+
Expect(err).ToNot(HaveOccurred())
92+
Expect(*i.Spec.CalicoNetwork.LinuxDataplane).To(BeEquivalentTo(operatorv1.LinuxDataplaneNftables))
93+
})
94+
95+
It("converts nftables mode from environment variable (disabled)", func() {
96+
comps.client = ctrlrfake.DefaultFakeClientBuilder(scheme).WithObjects(endPointCM, f).Build()
97+
comps.node.Spec.Template.Spec.Containers[0].Env = []v1.EnvVar{{
98+
Name: "FELIX_NFTABLESMODE",
99+
Value: "Disabled",
100+
}}
101+
err := handleNftables(&comps, i)
102+
Expect(err).ToNot(HaveOccurred())
103+
Expect(i.Spec.CalicoNetwork).To(BeNil())
104+
})
105+
})

0 commit comments

Comments
 (0)