From 8dffa72e276cd58669f589f7d2693a046f644695 Mon Sep 17 00:00:00 2001 From: Ritu Sood Date: Sun, 17 Feb 2019 05:58:57 -0800 Subject: Add Routes to Pod Based on Pod annotations list ovnNetworkRoutes routes are added to the Pod namespace Change-Id: If6b8b6375d798dcbd45e51ccd5adae4b24369c5c Signed-off-by: Ritu Sood --- cmd/ovn4nfvk8s-cni/app/helper_linux.go | 26 +++++++++++ cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go | 54 +++++++++++++++++++++++ cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go | 72 ++++++++++++++++++++++++++++++- 3 files changed, 151 insertions(+), 1 deletion(-) diff --git a/cmd/ovn4nfvk8s-cni/app/helper_linux.go b/cmd/ovn4nfvk8s-cni/app/helper_linux.go index 1a98a61..fc4fd94 100644 --- a/cmd/ovn4nfvk8s-cni/app/helper_linux.go +++ b/cmd/ovn4nfvk8s-cni/app/helper_linux.go @@ -143,6 +143,32 @@ var ConfigureInterface = func(args *skel.CmdArgs, namespace, podName, macAddress return []*current.Interface{hostIface, contIface}, nil } +func setupRoute(netns ns.NetNS, dst, gw, dev string) error { + // Add Route to the namespace + err := netns.Do(func(_ ns.NetNS) error { + dstAddr, dstAddrNet, _ := net.ParseCIDR(dst) + ipNet := net.IPNet{IP: dstAddr, Mask: dstAddrNet.Mask} + link, err := netlink.LinkByName(dev) + err = ip.AddRoute(&ipNet, net.ParseIP(gw), link) + if err != nil { + logrus.Errorf("ip.AddRoute failed %v dst %v gw %v", err, dst, gw) + } + return err + }) + return err +} + +// ConfigureRoute sets up the container routes +var ConfigureRoute = func(args *skel.CmdArgs, dst, gw, dev string) error { + netns, err := ns.GetNS(args.Netns) + if err != nil { + return fmt.Errorf("failed to open netns %q: %v", args.Netns, err) + } + defer netns.Close() + err = setupRoute(netns, dst, gw, dev) + return err +} + // PlatformSpecificCleanup deletes the OVS port func PlatformSpecificCleanup(ifaceName string) (bool, error) { done := false diff --git a/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go b/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go index 923363b..2722eaa 100644 --- a/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go +++ b/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni.go @@ -196,6 +196,53 @@ func addMultipleInterfaces(args *skel.CmdArgs, ovnAnnotation, namespace, podName return dstResult } +func addRoutes(args *skel.CmdArgs, ovnAnnotation string, dstResult types.Result) types.Result { + logrus.Infof("ovn4nfvk8s-cni: addRoutes ") + + var ovnAnnotatedMap []map[string]string + ovnAnnotatedMap, err := parseOvnNetworkObject(ovnAnnotation) + if err != nil { + logrus.Errorf("addLogicalPort : Error Parsing Ovn Route List %v", err) + return nil + } + + var result types.Result + var routes []*types.Route + for _, ovnNet := range ovnAnnotatedMap { + dst := ovnNet["dst"] + gw := ovnNet["gw"] + dev := ovnNet["dev"] + if dst == "" || gw == "" || dev == "" { + logrus.Errorf("failed in pod annotation key extract") + return nil + } + err = app.ConfigureRoute(args, dst, gw, dev) + if err != nil { + logrus.Errorf("Failed to configure interface in pod: %v", err) + return nil + } + dstAddr, dstAddrNet, _ := net.ParseCIDR(dst) + routes = append(routes, &types.Route{ + Dst: net.IPNet{IP: dstAddr, Mask: dstAddrNet.Mask}, + GW: net.ParseIP(gw), + }) + } + + result = ¤t.Result{ + Routes: routes, + } + // Build the result structure to pass back to the runtime + dstResult, err = mergeWithResult(result, dstResult) + if err != nil { + logrus.Errorf("Failed to merge results: %v", err) + return nil + } + logrus.Infof("addRoutes: %s", prettyPrint(dstResult)) + return dstResult + +} + + func cmdAdd(args *skel.CmdArgs) error { logrus.Infof("ovn4nfvk8s-cni: cmdAdd ") conf := &types.NetConf{} @@ -243,6 +290,13 @@ func cmdAdd(args *skel.CmdArgs) error { return fmt.Errorf("Error while obtaining pod annotations") } result := addMultipleInterfaces(args, ovnAnnotation, namespace, podName) + // Add Routes to the pod if annotation found for routes + ovnRouteAnnotation, ok := annotation["ovnNetworkRoutes"] + if ok { + logrus.Infof("ovn4nfvk8s-cni: ovnNetworkRoutes Annotation Found %+v", ovnRouteAnnotation) + result = addRoutes(args, ovnRouteAnnotation, result) + } + return result.Print() } diff --git a/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go b/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go index d5b7b6b..e1190ca 100644 --- a/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go +++ b/cmd/ovn4nfvk8s-cni/ovn4nfvk8s-cni_test.go @@ -3,9 +3,14 @@ package main import ( + "encoding/json" + "github.com/containernetworking/cni/pkg/skel" + "github.com/containernetworking/cni/pkg/types" "github.com/containernetworking/cni/pkg/types/current" + "net" "ovn4nfv-k8s-plugin/cmd/ovn4nfvk8s-cni/app" + "reflect" "testing" ) @@ -21,13 +26,19 @@ func TestAddMultipleInterfaces(t *testing.T) { Sandbox: "102103104", }}, nil } - args := &skel.CmdArgs{"102103104", "default", "eth0", "", "", nil} + oldConfigureRoute := app.ConfigureRoute + defer func() { app.ConfigureRoute = oldConfigureRoute }() + app.ConfigureRoute = func(args *skel.CmdArgs, dst, gw, dev string) error { + return nil + } + args := &skel.CmdArgs{"102103104", "default", "eth0", "", "", nil} ovnAnnotation := "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"interface\":\"net0\"}] " result := addMultipleInterfaces(args, ovnAnnotation, "default", "pod") if result == nil { t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) } + resultSave := result ovnAnnotation = "[{\"ip_address\":\"172.16.24.2/24\", \"mac_address\":\"0a:00:00:00:00:0c\", \"gateway_ip\": \"172.16.24.1\",\"defaultGateway\":\"true\",\"interface\":\"net0\"}] " result = addMultipleInterfaces(args, ovnAnnotation, "default", "pod") if result == nil { @@ -53,4 +64,63 @@ func TestAddMultipleInterfaces(t *testing.T) { if result == nil { t.Errorf("Failed addMultipleInterfaces %+v", ovnAnnotation) } + // Test add route feature + ovnRoutesAnnotation := "[{ \"dst\": \"172.16.29.0/24\", \"gw\": \"172.16.24.1\", \"dev\": \"eth0\" }]" + result = addRoutes(args, ovnRoutesAnnotation, resultSave) + if result == nil { + t.Errorf("Failed addRoutes %+v", ovnRoutesAnnotation) + } + + ovnRoutesAnnotation = "[{ \"dst\": \"172.16.30.0/24\", \"gw\": \"172.16.25.1\", \"dev\": \"eth0\"}, { \"dst\": \"172.16.31.0/24\", \"gw\": \"172.16.26.1\", \"dev\": \"eth1\" }]" + result = addRoutes(args, ovnRoutesAnnotation, resultSave) + if result == nil { + t.Errorf("Failed addRoutes %+v", ovnRoutesAnnotation) + } + newResult, err := current.NewResultFromResult(result) + if err != nil { + t.Errorf("Failed addMultipleInterfaces %+v", newResult) + } + addr1, addrNet1, _ := net.ParseCIDR("172.16.24.2/24") + addr2, addrNet2, _ := net.ParseCIDR("172.16.29.0/24") + addr3, addrNet3, _ := net.ParseCIDR("172.16.30.0/24") + addr4, addrNet4, _ := net.ParseCIDR("172.16.31.0/24") + expectedResult := ¤t.Result{ + CNIVersion: "0.3.1", + Interfaces: []*current.Interface{ + { + Name: "pod", + Mac: "0a:00:00:00:00:0c", + Sandbox: "102103104", + }, + }, + IPs: []*current.IPConfig{ + { + Version: "4", + Interface: current.Int(1), + Address: net.IPNet{IP: addr1, Mask: addrNet1.Mask}, + Gateway: net.ParseIP("172.16.24.1"), + }, + }, + Routes: []*types.Route{ + { + Dst: net.IPNet{IP: addr2, Mask: addrNet2.Mask}, + GW: net.ParseIP("172.16.24.1"), + }, + { + Dst: net.IPNet{IP: addr3, Mask: addrNet3.Mask}, + GW: net.ParseIP("172.16.25.1"), + }, + { + Dst: net.IPNet{IP: addr4, Mask: addrNet4.Mask}, + GW: net.ParseIP("172.16.26.1"), + }, + }, + DNS: types.DNS{}, + } + jsonBytes1, err := json.Marshal(newResult.Routes) + jsonBytes2, err := json.Marshal(expectedResult.Routes) + if !reflect.DeepEqual(jsonBytes1, jsonBytes2) { + t.Errorf("Routes are not correct") + } + } -- cgit 1.2.3-korg