Skip to content

Commit

Permalink
support adding routes in underlay Pods for access to overlay Pods (#1762
Browse files Browse the repository at this point in the history
)
  • Loading branch information
zhangzujian committed Aug 19, 2022
1 parent 013549a commit 0ed5c92
Show file tree
Hide file tree
Showing 7 changed files with 228 additions and 11 deletions.
8 changes: 2 additions & 6 deletions .github/workflows/build-x86-image.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -901,14 +901,12 @@ jobs:
- name: Install Kube-OVN without LoadBalancer
uses: nick-invision/retry@v2
env:
ENABLE_LB: "false"
with:
timeout_minutes: 10
max_attempts: 3
shell: bash
command: |
sudo make kind-install
sudo ENABLE_LB=false make kind-install
- name: Set up Go 1.x
uses: actions/setup-go@v3
Expand Down Expand Up @@ -962,14 +960,12 @@ jobs:
- name: Install Kube-OVN without LoadBalancer
uses: nick-invision/retry@v2
env:
ENABLE_LB: "false"
with:
timeout_minutes: 10
max_attempts: 3
shell: bash
command: |
sudo make kind-install
sudo ENABLE_LB=false make kind-install
- name: Set up Go 1.x
uses: actions/setup-go@v3
Expand Down
2 changes: 2 additions & 0 deletions dist/images/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1237,6 +1237,8 @@ spec:
type: string
natOutgoing:
type: boolean
u2oRouting:
type: boolean
externalEgressGateway:
type: string
policyRoutingPriority:
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/kubeovn/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ type SubnetSpec struct {
GatewayType string `json:"gatewayType,omitempty"`
GatewayNode string `json:"gatewayNode,omitempty"`
NatOutgoing bool `json:"natOutgoing,omitempty"`
U2oRouting bool `json:"u2oRouting,omitempty"`

ExternalEgressGateway string `json:"externalEgressGateway,omitempty"`
PolicyRoutingPriority uint32 `json:"policyRoutingPriority,omitempty"`
Expand Down
58 changes: 53 additions & 5 deletions pkg/daemon/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,9 @@ func (csh cniServerHandler) handleAdd(req *restful.Request, resp *restful.Respon
}

var mtu int
var node *v1.Node
if providerNetwork != "" {
node, err := csh.Controller.nodesLister.Get(csh.Config.NodeName)
if err != nil {
if node, err = csh.Controller.nodesLister.Get(csh.Config.NodeName); err != nil {
errMsg := fmt.Errorf("failed to get node %s: %v", csh.Config.NodeName, err)
klog.Error(errMsg)
if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
Expand All @@ -245,14 +245,62 @@ func (csh cniServerHandler) handleAdd(req *restful.Request, resp *restful.Respon
mtu = csh.Config.MTU
}

klog.Infof("create container interface %s mac %s, ip %s, cidr %s, gw %s, custom routes %v", ifName, macAddr, ipAddr, cidr, gw, podRequest.Routes)
// routes used for access from underlay to overlay
var u2oRoutes []request.Route
if podSubnet.Spec.U2oRouting && podSubnet.Spec.Vlan != "" &&
!podSubnet.Spec.LogicalGateway && podSubnet.Spec.Vpc == util.DefaultVpc {
subnets, err := csh.Controller.subnetsLister.List(labels.Everything())
if err != nil {
errMsg := fmt.Errorf("failed to list subnets: %v", err)
klog.Error(errMsg)
if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
klog.Errorf("failed to write response: %v", err)
}
return
}

if node == nil {
if node, err = csh.Controller.nodesLister.Get(csh.Config.NodeName); err != nil {
errMsg := fmt.Errorf("failed to get node %s: %v", csh.Config.NodeName, err)
klog.Error(errMsg)
if err = resp.WriteHeaderAndEntity(http.StatusInternalServerError, request.CniResponse{Err: errMsg.Error()}); err != nil {
klog.Errorf("failed to write response: %v", err)
}
return
}
}

podCidrV4, podCidrV6 := util.SplitStringIP(cidr)
nodeIPv4, nodeIPv6 := util.GetNodeInternalIP(*node)
v4Routing := util.CIDRContainIP(podCidrV4, nodeIPv4)
v6Routing := util.CIDRContainIP(podCidrV6, nodeIPv6)
for _, subnet := range subnets {
if subnet.Spec.Vpc == util.DefaultVpc && (subnet.Spec.Vlan == "" || subnet.Spec.LogicalGateway) {
if !subnet.Status.IsReady() {
klog.V(5).Infof("subnet %s is not ready, skip", subnet.Name)
continue
}

cidrV4, cidrV6 := util.SplitStringIP(subnet.Spec.CIDRBlock)
if v4Routing && cidrV4 != "" {
u2oRoutes = append(u2oRoutes, request.Route{Destination: cidrV4, Gateway: nodeIPv4})
}
if v6Routing && cidrV6 != "" {
u2oRoutes = append(u2oRoutes, request.Route{Destination: cidrV6, Gateway: nodeIPv6})
}
}
}
}

klog.Infof("create container interface %s mac %s, ip %s, cidr %s, gw %s, u2o routes %v, custom routes %v", ifName, macAddr, ipAddr, cidr, gw, u2oRoutes, podRequest.Routes)
allRoutes := append(u2oRoutes, podRequest.Routes...)
if nicType == util.InternalType {
podNicName, err = csh.configureNicWithInternalPort(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, podRequest.Routes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, priority, podRequest.DeviceID, nicType, latency, limit, loss, gatewayCheckMode)
podNicName, err = csh.configureNicWithInternalPort(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, allRoutes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, priority, podRequest.DeviceID, nicType, latency, limit, loss, gatewayCheckMode)
} else if nicType == util.DpdkType {
err = csh.configureDpdkNic(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, ifName, macAddr, mtu, ipAddr, gw, ingress, egress, priority, getShortSharedDir(pod.UID, podRequest.VhostUserSocketVolumeName), podRequest.VhostUserSocketName)
} else {
podNicName = ifName
err = csh.configureNic(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, podRequest.VfDriver, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, podRequest.Routes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, priority, podRequest.DeviceID, nicType, latency, limit, loss, gatewayCheckMode)
err = csh.configureNic(podRequest.PodName, podRequest.PodNamespace, podRequest.Provider, podRequest.NetNs, podRequest.ContainerID, podRequest.VfDriver, ifName, macAddr, mtu, ipAddr, gw, isDefaultRoute, allRoutes, podRequest.DNS.Nameservers, podRequest.DNS.Search, ingress, egress, priority, podRequest.DeviceID, nicType, latency, limit, loss, gatewayCheckMode)
}
if err != nil {
errMsg := fmt.Errorf("configure nic failed %v", err)
Expand Down
1 change: 1 addition & 0 deletions test/e2e-underlay-single-nic/e2e_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
// tests to run
_ "github.com/kubeovn/kube-ovn/test/e2e-underlay-single-nic/kubectl-ko"
_ "github.com/kubeovn/kube-ovn/test/e2e-underlay-single-nic/node"
_ "github.com/kubeovn/kube-ovn/test/e2e-underlay-single-nic/overlay"
)

func TestE2e(t *testing.T) {
Expand Down
167 changes: 167 additions & 0 deletions test/e2e-underlay-single-nic/overlay/overlay.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
package overlay

import (
"context"
"fmt"
"os"
"strings"

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

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

kubeovnv1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1"
"github.com/kubeovn/kube-ovn/pkg/util"
"github.com/kubeovn/kube-ovn/test/e2e/framework"
)

const testImage = "kubeovn/pause:3.2"

var _ = Describe("[Overlay]", func() {
Context("[Connectivity]", func() {
It("u2o", func() {
f := framework.NewFramework("overlay", fmt.Sprintf("%s/.kube/config", os.Getenv("HOME")))

By("get default subnet")
cachedSubnet, err := f.OvnClientSet.KubeovnV1().Subnets().Get(context.Background(), "ovn-default", metav1.GetOptions{})
Expect(err).NotTo(HaveOccurred())
if cachedSubnet.Spec.Protocol == kubeovnv1.ProtocolIPv6 {
return
}

By("enable u2oRouting")
if !cachedSubnet.Spec.U2oRouting {
subnet := cachedSubnet.DeepCopy()
subnet.Spec.U2oRouting = true
_, err = f.OvnClientSet.KubeovnV1().Subnets().Update(context.Background(), subnet, metav1.UpdateOptions{})
Expect(err).NotTo(HaveOccurred())
}

By("create overlay namespace")
namespace := "e2e-overlay"
_, err = f.KubeClientSet.CoreV1().Namespaces().Create(context.Background(), &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
Labels: map[string]string{"e2e": "true"}}}, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())

By("create overlay subnet")
subnetName := "e2e-overlay"
s := kubeovnv1.Subnet{
ObjectMeta: metav1.ObjectMeta{
Name: subnetName,
Labels: map[string]string{"e2e": "true"},
},
Spec: kubeovnv1.SubnetSpec{
CIDRBlock: "12.10.0.0/16",
Namespaces: []string{namespace},
Protocol: util.CheckProtocol("12.10.0.0/16"),
},
}
_, err = f.OvnClientSet.KubeovnV1().Subnets().Create(context.Background(), &s, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
err = f.WaitSubnetReady(subnetName)
Expect(err).NotTo(HaveOccurred())

By("create underlay pod")
var autoMount bool
upod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: f.GetName(),
Namespace: "default",
Labels: map[string]string{"e2e": "true"},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: f.GetName(),
Image: testImage,
ImagePullPolicy: corev1.PullIfNotPresent,
},
},
AutomountServiceAccountToken: &autoMount,
},
}
_, err = f.KubeClientSet.CoreV1().Pods(upod.Namespace).Create(context.Background(), upod, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
upod, err = f.WaitPodReady(upod.Name, upod.Namespace)
Expect(err).NotTo(HaveOccurred())
Expect(upod.Spec.NodeName).NotTo(BeEmpty())

By("create overlay pod")
opod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: f.GetName(),
Namespace: namespace,
Labels: map[string]string{"e2e": "true"},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: f.GetName(),
Image: testImage,
ImagePullPolicy: corev1.PullIfNotPresent,
},
},
AutomountServiceAccountToken: &autoMount,
},
}
_, err = f.KubeClientSet.CoreV1().Pods(opod.Namespace).Create(context.Background(), opod, metav1.CreateOptions{})
Expect(err).NotTo(HaveOccurred())
opod, err = f.WaitPodReady(opod.Name, opod.Namespace)
Expect(err).NotTo(HaveOccurred())

By("get kube-ovn-cni pod")
podList, err := f.KubeClientSet.CoreV1().Pods("kube-system").List(context.Background(), metav1.ListOptions{LabelSelector: "app=kube-ovn-cni"})
Expect(err).NotTo(HaveOccurred())
Expect(podList).NotTo(BeNil())

var cniPod *corev1.Pod
for i, pod := range podList.Items {
if pod.Spec.NodeName == upod.Spec.NodeName {
cniPod = &podList.Items[i]
break
}
}
Expect(cniPod).NotTo(BeNil())

By("get underlay pod's netns")
cmd := fmt.Sprintf("ovs-vsctl --no-heading --columns=external_ids find interface external-ids:pod_name=%s external-ids:pod_namespace=%s", upod.Name, upod.Namespace)
stdout, _, err := f.ExecToPodThroughAPI(cmd, "cni-server", cniPod.Name, cniPod.Namespace, nil)
Expect(err).NotTo(HaveOccurred())
var netns string
for _, field := range strings.Fields(stdout) {
if strings.HasPrefix(field, "pod_netns=") {
netns = strings.TrimPrefix(field, "pod_netns=")
netns = strings.Trim(netns[:len(netns)-1], `"`)
break
}
}
Expect(netns).NotTo(BeEmpty())

By("ping overlay pod")
cmd = fmt.Sprintf("nsenter --net=%s ping -c1 -W1 %s", netns, opod.Status.PodIP)
stdout, _, err = f.ExecToPodThroughAPI(cmd, "cni-server", cniPod.Name, cniPod.Namespace, nil)
Expect(err).NotTo(HaveOccurred())
Expect(stdout).To(ContainSubstring(" 0% packet loss"))

By("delete underlay pod")
err = f.KubeClientSet.CoreV1().Pods(upod.Namespace).Delete(context.Background(), upod.Name, metav1.DeleteOptions{})
Expect(err).NotTo(HaveOccurred())

By("delete overlay pod")
err = f.KubeClientSet.CoreV1().Pods(opod.Namespace).Delete(context.Background(), opod.Name, metav1.DeleteOptions{})
Expect(err).NotTo(HaveOccurred())

By("delete overlay subnet")
err = f.OvnClientSet.KubeovnV1().Subnets().Delete(context.Background(), subnetName, metav1.DeleteOptions{})
Expect(err).NotTo(HaveOccurred())

By("delete overlay namespace")
err = f.KubeClientSet.CoreV1().Namespaces().Delete(context.Background(), opod.Namespace, metav1.DeleteOptions{})
Expect(err).NotTo(HaveOccurred())
})
})
})
2 changes: 2 additions & 0 deletions yamls/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,8 @@ spec:
type: string
natOutgoing:
type: boolean
u2oRouting:
type: boolean
externalEgressGateway:
type: string
policyRoutingPriority:
Expand Down

0 comments on commit 0ed5c92

Please sign in to comment.