Skip to content

Commit

Permalink
set rangeStart for hostLocal cni plugin
Browse files Browse the repository at this point in the history
Change-Id: I29ed4218f0a4d8f7dc20421f0034d2d844595014
  • Loading branch information
aojea committed Jul 22, 2024
1 parent 71eda2b commit 187eb68
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 32 deletions.
70 changes: 38 additions & 32 deletions cmd/kindnetd/cni.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,40 +29,49 @@ import (
"github.com/vishvananda/netlink"

corev1 "k8s.io/api/core/v1"
utilsnet "k8s.io/utils/net"
)

/* cni config management */

// CNIConfigInputs is supplied to the CNI config template
type CNIConfigInputs struct {
PodCIDRs []string
RangeStart []string
DefaultRoutes []string
Mtu int
}

// ComputeCNIConfigInputs computes the template inputs for CNIConfigWriter
func ComputeCNIConfigInputs(node *corev1.Node) CNIConfigInputs {

defaultRoutes := []string{"0.0.0.0/0", "::/0"}
// check if is a dualstack cluster
if len(node.Spec.PodCIDRs) > 1 {
return CNIConfigInputs{
PodCIDRs: node.Spec.PodCIDRs,
DefaultRoutes: defaultRoutes,
inputs := CNIConfigInputs{}
podCIDRs, _ := utilsnet.ParseCIDRs(node.Spec.PodCIDRs) // already validated
for _, podCIDR := range podCIDRs {
inputs.PodCIDRs = append(inputs.PodCIDRs, podCIDR.String())
// define the default route
if utilsnet.IsIPv4CIDR(podCIDR) {
inputs.DefaultRoutes = append(inputs.DefaultRoutes, "0.0.0.0/0")
} else {
inputs.DefaultRoutes = append(inputs.DefaultRoutes, "::/0")
}
// reserve the first IPs of the range
size := utilsnet.RangeSize(podCIDR)
podCapacity := node.Status.Capacity.Pods().Value()
if podCapacity == 0 {
podCapacity = 110 // default to 110
}
rangeStart := ""
offset := size - podCapacity
if offset > 10 { // reserve the first 10 addresses of the Pod range if there is capacity
startAddress, err := utilsnet.GetIndexedIP(podCIDR, 10)
if err == nil {
rangeStart = startAddress.String()
}
}
inputs.RangeStart = append(inputs.RangeStart, rangeStart)

}
// the cluster is single stack
// we use the legacy node.Spec.PodCIDR for backwards compatibility
podCIDRs := []string{node.Spec.PodCIDR}
// This is a single stack cluster
defaultRoute := defaultRoutes[:1]
if isIPv6CIDRString(podCIDRs[0]) {
defaultRoute = defaultRoutes[1:]
}
return CNIConfigInputs{
PodCIDRs: podCIDRs,
DefaultRoutes: defaultRoute,
}
return inputs
}

// GetMTU returns the MTU used for the IP family
Expand Down Expand Up @@ -144,17 +153,15 @@ const cniConfigTemplate = `
"type": "host-local",
"dataDir": "/run/cni-ipam-state",
"routes": [
{{$first := true}}
{{- range $route := .DefaultRoutes}}
{{if $first}}{{$first = false}}{{else}},{{end}}
{{- range $i, $route := .DefaultRoutes}}
{{- if gt $i 0 }},{{end}}
{ "dst": "{{ $route }}" }
{{- end}}
],
"ranges": [
{{$first := true}}
{{- range $cidr := .PodCIDRs}}
{{if $first}}{{$first = false}}{{else}},{{end}}
[ { "subnet": "{{ $cidr }}" } ]
{{- range $i, $cidr := .PodCIDRs}}
{{- if gt $i 0 }},{{end}}
[ { "subnet": "{{ $cidr }}" {{ if index $.RangeStart $i }}, "rangeStart": "{{ index $.RangeStart $i }}" {{ end -}} } ]
{{- end}}
]
}
Expand Down Expand Up @@ -188,16 +195,15 @@ const cniConfigTemplateBridge = `
"type": "host-local",
"dataDir": "/run/cni-ipam-state",
"ranges": [
{{$first := true}}
{{- range $cidr := .PodCIDRs}}
{{if $first}}{{$first = false}}{{else}},{{end}}
[ { "subnet": "{{ $cidr }}" } ]
{{- range $i, $cidr := .PodCIDRs}}
{{- if gt $i 0 }},{{end}}
[ { "subnet": "{{ $cidr }}" {{ if index $.RangeStart $i }}, "rangeStart": "{{ index $.RangeStart $i }}" {{ end -}} } ]
{{- end}}
]
}
{{if .Mtu}},
{{- if .Mtu}},
"mtu": {{ .Mtu }}
{{end}}
{{- end}}
},
{
"type": "portmap",
Expand Down
127 changes: 127 additions & 0 deletions cmd/kindnetd/cni_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/*
Copyright 2019 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"bytes"
"encoding/json"
"testing"

v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func Test_writeCNIConfig(t *testing.T) {
tests := []struct {
name string
node *v1.Node
mtu int
wantW string
wantErr bool
}{
{
name: "ipv4 only and ptp plugin and start range",
mtu: 1500,
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "node0",
},
Spec: v1.NodeSpec{
PodCIDRs: []string{"192.168.0.0/24"},
},
Status: v1.NodeStatus{
Capacity: v1.ResourceList{
v1.ResourcePods: resource.MustParse("110"),
},
},
},
},
{
name: "dual stack only and ptp plugin and start range",
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "node0",
},
Spec: v1.NodeSpec{
PodCIDRs: []string{"192.168.0.0/24", "fd00:1:2:3::/96"},
},
Status: v1.NodeStatus{
Capacity: v1.ResourceList{
v1.ResourcePods: resource.MustParse("110"),
},
},
},
},
{
name: "ipv4 only and ptp plugin and no start range",
mtu: 1500,
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "node0",
},
Spec: v1.NodeSpec{
PodCIDRs: []string{"192.168.0.0/24"},
},
Status: v1.NodeStatus{
Capacity: v1.ResourceList{
v1.ResourcePods: resource.MustParse("255"),
},
},
},
},
{
name: "dual stack only and ptp plugin and no start range",
node: &v1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "node0",
},
Spec: v1.NodeSpec{
PodCIDRs: []string{"192.168.0.0/24", "fd00:1:2:3::/96"},
},
Status: v1.NodeStatus{
Capacity: v1.ResourceList{
v1.ResourcePods: resource.MustParse("255"),
},
},
},
},
}
for _, tt := range tests {
for _, cniTemplate := range []string{cniConfigTemplate, cniConfigTemplateBridge} {
t.Run(tt.name, func(t *testing.T) {
w := &bytes.Buffer{}
data := ComputeCNIConfigInputs(tt.node)
data.Mtu = tt.mtu
if err := writeCNIConfig(w, cniTemplate, data); (err != nil) != tt.wantErr {
t.Errorf("writeCNIConfig() error = %v, wantErr %v", err, tt.wantErr)
return
}
t.Logf("CNI input:\n%#v", data)
t.Logf("CNI config:\n%s", w.String())
// is valid json
if !json.Valid([]byte(w.String())) {
t.Errorf("Invalid Json: %s", w.String())
}
if gotW := w.String(); gotW != tt.wantW {
// TODO validate the content
// t.Errorf("writeCNIConfig() = %v, want %v", gotW, tt.wantW)
}
})
}
}
}

0 comments on commit 187eb68

Please sign in to comment.