Skip to content

Commit

Permalink
CNI tuning plugin configuration added to Installation CRD
Browse files Browse the repository at this point in the history
  • Loading branch information
Tamas-Biro1 authored and Tamas Biro committed Oct 4, 2023
1 parent e48f3d3 commit ba4234c
Show file tree
Hide file tree
Showing 11 changed files with 342 additions and 0 deletions.
4 changes: 4 additions & 0 deletions api/v1/installation_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,10 @@ type CalicoNetworkSpec struct {
// +optional
// +kubebuilder:validation:Enum=Enabled;Disabled
ContainerIPForwarding *ContainerIPForwardingType `json:"containerIPForwarding,omitempty"`

// SysctlTuning configures sysctl parameters for tuning plugin
// +optional
SysctlTuning *map[string]string `json:"sysctlTuning,omitempty"`
}

// NodeAddressAutodetection provides configuration options for auto-detecting node addresses. At most one option
Expand Down
11 changes: 11 additions & 0 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions pkg/controller/installation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,30 @@ func validateCustomResource(instance *operatorv1.Installation) error {
return fmt.Errorf("spec.calicoNetwork.containerIPForwarding is supported only for Calico CNI")
}
}

type TuningSpec struct {
Sysctl *map[string]string `json:"sysctl,omitempty"`
Type string `json:"type"`
}

if instance.Spec.CalicoNetwork.SysctlTuning != nil {
// CNI tuning plugin
pluginData := instance.Spec.CalicoNetwork.SysctlTuning

// sysctl settings
allowedKeys := map[string]struct{}{
"net.ipv4.tcp_keepalive_intvl": {},
"net.ipv4.tcp_keepalive_probes": {},
"net.ipv4.tcp_keepalive_time": {},
}

for key, value := range *pluginData {
if _, allowed := allowedKeys[key]; !allowed {
return fmt.Errorf("value %s not allowed in spec.calicoNetwork.sysctlTuning", value)
}
}

}
}

// Verify that the flexvolume path is valid - either "None" (to disable) or a valid absolute path.
Expand Down
10 changes: 10 additions & 0 deletions pkg/controller/installation/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,16 @@ var _ = Describe("Installation validation tests", func() {
Expect(err).To(HaveOccurred())
})

It("should error on not-allowed CNI sysctl tuning plugin config", func() {
instance.Spec.CalicoNetwork.SysctlTuning = &map[string]string{
"net.ipv4.not_allowed_setting": "15",
"net.ipv4.tcp_keepalive_probes": "6",
"net.ipv4.tcp_keepalive_time": "40",
}
err := validateCustomResource(instance)
Expect(err).To(HaveOccurred())
})

Describe("validate Calico CNI plugin Type", func() {
DescribeTable("test invalid IPAM",
func(ipam operator.IPAMPluginType) {
Expand Down
37 changes: 37 additions & 0 deletions pkg/controller/migration/convert/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package convert

import (
"encoding/json"
"fmt"
"strings"

Expand Down Expand Up @@ -198,6 +199,42 @@ func handleCalicoCNI(c *components, install *operatorv1.Installation) error {
install.Spec.CalicoNetwork.HostPorts = &hp
}

type TuningSpec struct {
Sysctl *map[string]string `json:"sysctl,omitempty"`
Type string `json:"type"`
}

// CNI tuning plugin
if pluginData, ok := c.cni.Plugins["tuning"]; ok {
// parse JSON data
var tuningSpecData TuningSpec
if err := json.Unmarshal([]byte(pluginData.Bytes), &tuningSpecData); err != nil {

return ErrIncompatibleCluster{
err: "error parsing CNI config plugin type 'tuning'",
component: ComponentCNIConfig,
fix: "fix CNI config",
}
}

// sysctl settings
allowedKeys := map[string]struct{}{
"net.ipv4.tcp_keepalive_intvl": {},
"net.ipv4.tcp_keepalive_probes": {},
"net.ipv4.tcp_keepalive_time": {},
}
sysctlTuning := make(map[string]string)
for key, value := range *tuningSpecData.Sysctl {
if _, allowed := allowedKeys[key]; allowed {
sysctlTuning[key] = value
}
}

if len(sysctlTuning) > 0 {
install.Spec.CalicoNetwork.SysctlTuning = &sysctlTuning
}
}

if c.cni.ConfigName != "k8s-pod-network" {
return ErrIncompatibleCluster{
err: fmt.Sprintf("only 'k8s-pod-network' is supported as CNI name, found %s", c.cni.ConfigName),
Expand Down
123 changes: 123 additions & 0 deletions pkg/controller/migration/convert/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -755,6 +755,129 @@ var _ = Describe("Convert network tests", func() {
})

Context("Calico CNI config flags", func() {
Describe("migrate tuning setting", func() {
It("sysctl tuning in config", func() {
ds := emptyNodeSpec()
ds.Spec.Template.Spec.InitContainers[0].Env = []corev1.EnvVar{{
Name: "CNI_NETWORK_CONFIG",
Value: `{
"name": "k8s-pod-network",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "calico",
"log_level": "info",
"datastore_type": "kubernetes",
"nodename": "__KUBERNETES_NODE_NAME__",
"mtu": __CNI_MTU__,
"ipam": {
"type": "host-local"
},
"policy": {
"type": "k8s"
},
"kubernetes": {
"kubeconfig": "__KUBECONFIG_FILEPATH__"
}
},
{
"type": "tuning",
"sysctl": {
"net.ipv4.tcp_keepalive_intvl": "15",
"net.ipv4.tcp_keepalive_probes": "6",
"net.ipv4.tcp_keepalive_time": "40"
}
}
]
}`,
}}
c := fake.NewClientBuilder().WithScheme(scheme).WithObjects(ds, emptyKubeControllerSpec(), v4pool, emptyFelixConfig()).Build()
cfg, err := Convert(ctx, c)
Expect(err).ToNot(HaveOccurred())
Expect(cfg).ToNot(BeNil())
Expect(cfg.Spec.CalicoNetwork.SysctlTuning).ToNot(BeNil())
Expect(*cfg.Spec.CalicoNetwork.SysctlTuning).To(Equal(map[string]string{
"net.ipv4.tcp_keepalive_time": "40",
"net.ipv4.tcp_keepalive_intvl": "15",
"net.ipv4.tcp_keepalive_probes": "6",
}))
})

It("no sysctl tuning in config, cfg must be nil", func() {
ds := emptyNodeSpec()
ds.Spec.Template.Spec.InitContainers[0].Env = []corev1.EnvVar{{
Name: "CNI_NETWORK_CONFIG",
Value: `{
"name": "k8s-pod-network",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "calico",
"log_level": "info",
"datastore_type": "kubernetes",
"nodename": "__KUBERNETES_NODE_NAME__",
"mtu": __CNI_MTU__,
"ipam": {
"type": "host-local"
},
"policy": {
"type": "k8s"
},
"kubernetes": {
"kubeconfig": "__KUBECONFIG_FILEPATH__"
}
},
{
"type": "tuning",
"sysctl": {
"net.ipv4.not_allowed": "40"
}
}
]
}`,
}}
c := fake.NewClientBuilder().WithScheme(scheme).WithObjects(ds, emptyKubeControllerSpec(), v4pool, emptyFelixConfig()).Build()
cfg, err := Convert(ctx, c)
Expect(err).ToNot(HaveOccurred())
Expect(cfg).ToNot(BeNil())
Expect(cfg.Spec.CalicoNetwork.SysctlTuning).To(BeNil())
})

It("not allowed sysctl tuning in config", func() {
ds := emptyNodeSpec()
ds.Spec.Template.Spec.InitContainers[0].Env = []corev1.EnvVar{{
Name: "CNI_NETWORK_CONFIG",
Value: `{
"name": "k8s-pod-network",
"cniVersion": "0.3.1",
"plugins": [
{
"type": "calico",
"log_level": "info",
"datastore_type": "kubernetes",
"nodename": "__KUBERNETES_NODE_NAME__",
"mtu": __CNI_MTU__,
"ipam": {
"type": "host-local"
},
"policy": {
"type": "k8s"
},
"kubernetes": {
"kubeconfig": "__KUBECONFIG_FILEPATH__"
}
}
]
}`,
}}
c := fake.NewClientBuilder().WithScheme(scheme).WithObjects(ds, emptyKubeControllerSpec(), v4pool, emptyFelixConfig()).Build()
cfg, err := Convert(ctx, c)
Expect(err).ToNot(HaveOccurred())
Expect(cfg).ToNot(BeNil())
Expect(cfg.Spec.CalicoNetwork.SysctlTuning).To(BeNil())
})
})

Describe("migrate portmap setting", func() {
It("no portmap in config", func() {
ds := emptyNodeSpec()
Expand Down
5 changes: 5 additions & 0 deletions pkg/controller/utils/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,11 @@ func mergeCalicoNetwork(cfg, override *operatorv1.CalicoNetworkSpec) *operatorv1
case BOnlySet, Different:
out.ContainerIPForwarding = override.ContainerIPForwarding
}

switch compareFields(out.SysctlTuning, override.SysctlTuning) {
case BOnlySet, Different:
out.SysctlTuning = override.SysctlTuning
}
return out
}

Expand Down
30 changes: 30 additions & 0 deletions pkg/controller/utils/merge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,36 @@ var _ = Describe("Installation merge tests", func() {
HostPorts: &_hpe,
}),
)

_sysctlTuningA := map[string]string{
"net.ipv4.tcp_keepalive_time": "40",
"net.ipv4.tcp_keepalive_intvl": "15",
"net.ipv4.tcp_keepalive_probes": "6",
}
_sysctlTuningB := map[string]string{}
DescribeTable("merge CNI Tuning", func(main, second, expect *map[string]string) {
m := opv1.InstallationSpec{}
s := opv1.InstallationSpec{}
if main != nil {
m.CalicoNetwork = &opv1.CalicoNetworkSpec{SysctlTuning: main}
}
if second != nil {
s.CalicoNetwork = &opv1.CalicoNetworkSpec{SysctlTuning: second}
}
inst := OverrideInstallationSpec(m, s)
if expect == nil {
Expect(inst.CalicoNetwork).To(BeNil())
} else {
Expect(*inst.CalicoNetwork.SysctlTuning).To(Equal(*expect))
}
},
Entry("Both unset", nil, nil, nil),
Entry("Main only set", &_sysctlTuningA, nil, &_sysctlTuningA),
Entry("Second only set", nil, &_sysctlTuningB, &_sysctlTuningB),
Entry("Both set equal", &_sysctlTuningA, &_sysctlTuningA, &_sysctlTuningA),
Entry("Both set not matching", &_sysctlTuningA, &_sysctlTuningB, &_sysctlTuningB),
)

})

DescribeTable("merge NodeMetricsPort", func(main, second, expect *int32) {
Expand Down
12 changes: 12 additions & 0 deletions pkg/crds/operator/operator.tigera.io_installations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1483,6 +1483,12 @@ spec:
on interfaces that do not match the given regex.
type: string
type: object
sysctlTuning:
additionalProperties:
type: string
description: SysctlTuning configures sysctl parameters for tuning
plugin
type: object
windowsDataplane:
description: 'WindowsDataplane is used to select the dataplane
used for Windows nodes. In particular, it causes the operator
Expand Down Expand Up @@ -10585,6 +10591,12 @@ spec:
on interfaces that do not match the given regex.
type: string
type: object
sysctlTuning:
additionalProperties:
type: string
description: SysctlTuning configures sysctl parameters for
tuning plugin
type: object
windowsDataplane:
description: 'WindowsDataplane is used to select the dataplane
used for Windows nodes. In particular, it causes the operator
Expand Down
16 changes: 16 additions & 0 deletions pkg/render/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,17 @@ func (c *nodeComponent) createPortmapPlugin() map[string]interface{} {
return portmapPlugin
}

func (c *nodeComponent) createTuningPlugin() map[string]interface{} {
// tuning plugin (sysctl)
tuningPlugin := map[string]interface{}{
"type": "tuning",
"sysctl": map[string]string{},
}
tuningPlugin["sysctl"] = *c.cfg.Installation.CalicoNetwork.SysctlTuning

return tuningPlugin
}

// nodeCNIConfigMap returns a config map containing the CNI network config to be installed on each node.
// Returns nil if no configmap is needed.
func (c *nodeComponent) nodeCNIConfigMap() *corev1.ConfigMap {
Expand All @@ -730,6 +741,11 @@ func (c *nodeComponent) nodeCNIConfigMap() *corev1.ConfigMap {
plugins = append(plugins, c.createPortmapPlugin())
}

// optional tuning plugin
if c.cfg.Installation.CalicoNetwork.SysctlTuning != nil {
plugins = append(plugins, c.createTuningPlugin())
}

pluginsArray, _ := json.Marshal(plugins)

config := fmt.Sprintf(`{
Expand Down
Loading

0 comments on commit ba4234c

Please sign in to comment.