From 62079e3b34f2f7ce7f04dc42e305c32bb719bd57 Mon Sep 17 00:00:00 2001 From: Kuralamudhan Ramakrishnan Date: Tue, 17 Mar 2020 05:32:22 +0000 Subject: adding primary network features - adding docker build bugfixes - Removing the dependence on Multus - ovn4nfv-k8s CNI will be default or cluster networking - ovn4nfv-k8s creates ovn overlay mutli-networking using pod annotations itself - remove the outdated unit test Based on the Ritu(ovn4nfv-k8s-plugin committer) patches Change-Id: Ic48bd11d746e6339075fb3ba33f12463bb3f218d Co-authored-by: Ritu Sood Signed-off-by: Kuralamudhan Ramakrishnan Change-Id: I9702bbd2d4aa23157052258ef6b363bc7b472a63 --- internal/pkg/ovn/common.go | 53 +++++++++++++ internal/pkg/ovn/ovn.go | 146 +++++++++++++++++------------------ internal/pkg/ovn/ovn_test.go | 180 ------------------------------------------- internal/pkg/ovn/utils.go | 8 ++ 4 files changed, 133 insertions(+), 254 deletions(-) delete mode 100644 internal/pkg/ovn/ovn_test.go (limited to 'internal/pkg') diff --git a/internal/pkg/ovn/common.go b/internal/pkg/ovn/common.go index a294004..e38c440 100644 --- a/internal/pkg/ovn/common.go +++ b/internal/pkg/ovn/common.go @@ -246,6 +246,59 @@ func setupDistributedRouter(name string) error { return nil } +// CreateNetwork in OVN controller +func createOvnLS(name, subnet, gatewayIP, excludeIps string) (gatewayIPMask string, err error) { + var stdout, stderr string + + output, stderr, err := RunOVNNbctl("--data=bare", "--no-heading", + "--columns=name", "find", "logical_switch", "name="+name) + if err != nil { + log.Error(err, "Error in reading logical switch", "stderr", stderr) + return + } + + if strings.Compare(name, output) == 0 { + log.V(1).Info("Logical Switch already exists, delete first to update/recreate", "name", name) + return "", fmt.Errorf("LS exists") + } + + _, cidr, err := net.ParseCIDR(subnet) + if err != nil { + log.Error(err, "ovnNetwork '%s' invalid subnet CIDR", "name", name) + return + + } + firstIP := NextIP(cidr.IP) + n, _ := cidr.Mask.Size() + + var gwIP net.IP + if gatewayIP != "" { + gwIP, _, err = net.ParseCIDR(gatewayIP) + if err != nil { + // Check if this is a valid IP address + gwIP = net.ParseIP(gatewayIP) + } + } + // If no valid Gateway use the first IP address for GatewayIP + if gwIP == nil { + gatewayIPMask = fmt.Sprintf("%s/%d", firstIP.String(), n) + } else { + gatewayIPMask = fmt.Sprintf("%s/%d", gwIP.String(), n) + } + + // Create a logical switch and set its subnet. + if excludeIps != "" { + stdout, stderr, err = RunOVNNbctl("--wait=hv", "--", "--may-exist", "ls-add", name, "--", "set", "logical_switch", name, "other-config:subnet="+subnet, "external-ids:gateway_ip="+gatewayIPMask, "other-config:exclude_ips="+excludeIps) + } else { + stdout, stderr, err = RunOVNNbctl("--wait=hv", "--", "--may-exist", "ls-add", name, "--", "set", "logical_switch", name, "other-config:subnet="+subnet, "external-ids:gateway_ip="+gatewayIPMask) + } + if err != nil { + log.Error(err, "Failed to create a logical switch", "name", name, "stdout", stdout, "stderr", stderr) + return + } + return +} + // generateMac generates mac address. func generateMac() string { prefix := "00:00:00" diff --git a/internal/pkg/ovn/ovn.go b/internal/pkg/ovn/ovn.go index 6e9cd79..6f7951a 100644 --- a/internal/pkg/ovn/ovn.go +++ b/internal/pkg/ovn/ovn.go @@ -6,7 +6,7 @@ import ( kapi "k8s.io/api/core/v1" kexec "k8s.io/utils/exec" "math/rand" - "net" + "os" k8sv1alpha1 "ovn4nfv-k8s-plugin/pkg/apis/k8s/v1alpha1" "strings" "time" @@ -16,12 +16,43 @@ type Controller struct { gatewayCache map[string]string } +type OVNNetworkConf struct { + Subnet string + GatewayIP string + ExcludeIPs string +} + const ( ovn4nfvRouterName = "ovn4nfv-master" // Ovn4nfvAnnotationTag tag on already processed Pods Ovn4nfvAnnotationTag = "k8s.plugin.opnfv.org/ovnInterfaces" + // OVN Default Network name + Ovn4nfvDefaultNw = "ovn4nfvk8s-default-nw" ) +var ovnConf *OVNNetworkConf + +func GetOvnNetConf() error { + ovnConf = &OVNNetworkConf{} + + ovnConf.Subnet = os.Getenv("OVN_SUBNET") + if ovnConf.Subnet == "" { + fmt.Errorf("OVN subnet is not set in nfn-operator configmap env") + } + + ovnConf.GatewayIP = os.Getenv("OVN_GATEWAYIP") + if ovnConf.GatewayIP == "" { + fmt.Errorf("OVN gatewayIP is not set in nfn-operator configmap env") + } + + ovnConf.ExcludeIPs = os.Getenv("OVN_EXCLUDEIPS") + if ovnConf.ExcludeIPs == "" { + fmt.Errorf("OVN excludeIPs is not set in nfn-operator configmap env") + } + + return nil +} + type netInterface struct { Name string Interface string @@ -43,10 +74,16 @@ func NewOvnController(exec kexec.Interface) (*Controller, error) { log.Error(err, "Failed to initialize exec helper") return nil, err } + + if err := GetOvnNetConf(); err != nil { + log.Error(err, "nfn-operator OVN Network configmap is not set") + return nil, err + } if err := SetupOvnUtils(); err != nil { log.Error(err, "Failed to initialize OVN State") return nil, err } + ovnCtl = &Controller{ gatewayCache: make(map[string]string), } @@ -64,10 +101,6 @@ func GetOvnController() (*Controller, error) { // AddLogicalPorts adds ports to the Pod func (oc *Controller) AddLogicalPorts(pod *kapi.Pod, ovnNetObjs []map[string]interface{}) (key, value string) { - if ovnNetObjs == nil { - return - } - if pod.Spec.HostNetwork { return } @@ -78,28 +111,38 @@ func (oc *Controller) AddLogicalPorts(pod *kapi.Pod, ovnNetObjs []map[string]int } var ovnString, outStr string + var defaultInterface bool + ovnString = "[" var ns netInterface for _, net := range ovnNetObjs { - err := mapstructure.Decode(net, &ns) if err != nil { log.Error(err, "mapstruct error", "network", net) return } - if !oc.FindLogicalSwitch(ns.Name) { log.Info("Logical Switch not found") return } - if ns.Interface == "" { + if ns.Name == Ovn4nfvDefaultNw { + defaultInterface = true + } + if ns.Interface == "" && ns.Name != Ovn4nfvDefaultNw { log.Info("Interface name must be provided") return } if ns.DefaultGateway == "" { ns.DefaultGateway = "false" } - outStr = oc.addLogicalPortWithSwitch(pod, ns.Name, ns.IPAddress, ns.MacAddress, ns.Interface, ns.NetType) + var portName string + if ns.Interface != "" { + portName = fmt.Sprintf("%s_%s_%s", pod.Namespace, pod.Name, ns.Interface) + } else { + portName = fmt.Sprintf("%s_%s", pod.Namespace, pod.Name) + ns.Interface = "*" + } + outStr = oc.addLogicalPortWithSwitch(pod, ns.Name, ns.IPAddress, ns.MacAddress, portName) if outStr == "" { return } @@ -110,7 +153,21 @@ func (oc *Controller) AddLogicalPorts(pod *kapi.Pod, ovnNetObjs []map[string]int ovnString += tmpString ovnString += "," } - last := len(ovnString) - 1 + var last int + if defaultInterface == false { + // Add Default interface + portName := fmt.Sprintf("%s_%s", pod.Namespace, pod.Name) + outStr = oc.addLogicalPortWithSwitch(pod, Ovn4nfvDefaultNw, "", "", portName) + if outStr == "" { + return + } + last := len(outStr) - 1 + tmpString := outStr[:last] + tmpString += "," + "\\\"interface\\\":" + "\\\"" + "*" + "\\\"}" + ovnString += tmpString + ovnString += "," + } + last = len(ovnString) - 1 ovnString = ovnString[:last] ovnString += "]" key = Ovn4nfvAnnotationTag @@ -121,6 +178,7 @@ func (oc *Controller) AddLogicalPorts(pod *kapi.Pod, ovnNetObjs []map[string]int // DeleteLogicalPorts deletes the OVN ports for the pod func (oc *Controller) DeleteLogicalPorts(name, namespace string) { + log.Info("DeleteLogicalPorts") logicalPort := fmt.Sprintf("%s_%s", namespace, name) // get the list of logical ports from OVN @@ -134,7 +192,7 @@ func (oc *Controller) DeleteLogicalPorts(name, namespace string) { for _, existingPort := range existingLogicalPorts { if strings.Contains(existingPort, logicalPort) { // found, delete this logical port - log.V(1).Info("Deleting", "Port", existingPort) + log.Info("Deleting", "Port", existingPort) stdout, stderr, err := RunOVNNbctl("--if-exists", "lsp-del", existingPort) if err != nil { @@ -145,59 +203,6 @@ func (oc *Controller) DeleteLogicalPorts(name, namespace string) { return } -// CreateNetwork in OVN controller -func (oc *Controller) createOvnLS(name, subnet, gatewayIP, excludeIps string) (gatewayIPMask string, err error) { - var stdout, stderr string - - output, stderr, err := RunOVNNbctl("--data=bare", "--no-heading", - "--columns=name", "find", "logical_switch", "name="+name) - if err != nil { - log.Error(err, "Error in reading logical switch", "stderr", stderr) - return - } - - if strings.Compare(name, output) == 0 { - log.V(1).Info("Logical Switch already exists, delete first to update/recreate", "name", name) - return "", fmt.Errorf("LS exists") - } - - _, cidr, err := net.ParseCIDR(subnet) - if err != nil { - log.Error(err, "ovnNetwork '%s' invalid subnet CIDR", "name", name) - return - - } - firstIP := NextIP(cidr.IP) - n, _ := cidr.Mask.Size() - - var gwIP net.IP - if gatewayIP != "" { - gwIP, _, err = net.ParseCIDR(gatewayIP) - if err != nil { - // Check if this is a valid IP address - gwIP = net.ParseIP(gatewayIP) - } - } - // If no valid Gateway use the first IP address for GatewayIP - if gwIP == nil { - gatewayIPMask = fmt.Sprintf("%s/%d", firstIP.String(), n) - } else { - gatewayIPMask = fmt.Sprintf("%s/%d", gwIP.String(), n) - } - - // Create a logical switch and set its subnet. - if excludeIps != "" { - stdout, stderr, err = RunOVNNbctl("--wait=hv", "--", "--may-exist", "ls-add", name, "--", "set", "logical_switch", name, "other-config:subnet="+subnet, "external-ids:gateway_ip="+gatewayIPMask, "other-config:exclude_ips="+excludeIps) - } else { - stdout, stderr, err = RunOVNNbctl("--wait=hv", "--", "--may-exist", "ls-add", name, "--", "set", "logical_switch", name, "other-config:subnet="+subnet, "external-ids:gateway_ip="+gatewayIPMask) - } - if err != nil { - log.Error(err, "Failed to create a logical switch", "name", name, "stdout", stdout, "stderr", stderr) - return - } - return -} - // CreateNetwork in OVN controller func (oc *Controller) CreateNetwork(cr *k8sv1alpha1.Network) error { var stdout, stderr string @@ -208,7 +213,7 @@ func (oc *Controller) CreateNetwork(cr *k8sv1alpha1.Network) error { gatewayIP := cr.Spec.Ipv4Subnets[0].Gateway excludeIps := cr.Spec.Ipv4Subnets[0].ExcludeIps - gatewayIPMask, err := oc.createOvnLS(name, subnet, gatewayIP, excludeIps) + gatewayIPMask, err := createOvnLS(name, subnet, gatewayIP, excludeIps) if err != nil { return err } @@ -266,7 +271,7 @@ func (oc *Controller) CreateProviderNetwork(cr *k8sv1alpha1.ProviderNetwork) err subnet := cr.Spec.Ipv4Subnets[0].Subnet gatewayIP := cr.Spec.Ipv4Subnets[0].Gateway excludeIps := cr.Spec.Ipv4Subnets[0].ExcludeIps - _, err := oc.createOvnLS(name, subnet, gatewayIP, excludeIps) + _, err := createOvnLS(name, subnet, gatewayIP, excludeIps) if err != nil { return err } @@ -339,7 +344,7 @@ func (oc *Controller) getGatewayFromSwitch(logicalSwitch string) (string, string return gatewayIP, mask, nil } -func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipAddress, macAddress, interfaceName, netType string) (annotation string) { +func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipAddress, macAddress, portName string) (annotation string) { var out, stderr string var err error var isStaticIP bool @@ -347,13 +352,6 @@ func (oc *Controller) addLogicalPortWithSwitch(pod *kapi.Pod, logicalSwitch, ipA return } - var portName string - if interfaceName != "" { - portName = fmt.Sprintf("%s_%s_%s", pod.Namespace, pod.Name, interfaceName) - } else { - return - } - log.V(1).Info("Creating logical port for on switch", "portName", portName, "logicalSwitch", logicalSwitch) if ipAddress != "" && macAddress != "" { diff --git a/internal/pkg/ovn/ovn_test.go b/internal/pkg/ovn/ovn_test.go deleted file mode 100644 index 5ea01d1..0000000 --- a/internal/pkg/ovn/ovn_test.go +++ /dev/null @@ -1,180 +0,0 @@ -package ovn - -import ( - "fmt" - "testing" - - "github.com/urfave/cli" - fakeexec "k8s.io/utils/exec/testing" - - "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "ovn4nfv-k8s-plugin/internal/pkg/config" - ovntest "ovn4nfv-k8s-plugin/internal/pkg/testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" -) - -func TestOvn(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "OVN/Pod Test Suite") -} - -var _ = AfterSuite(func() { -}) - -var _ = Describe("Add logical Port", func() { - var app *cli.App - - BeforeEach(func() { - app = cli.NewApp() - app.Name = "test" - app.Flags = config.Flags - - }) - - It("tests Pod", func() { - app.Action = func(ctx *cli.Context) error { - const ( - gwIP string = "10.1.1.1" - gwCIDR string = gwIP + "/24" - netName string = "ovn-prot-net" - portName string = "_ok_net0" - macIPAddress string = "0a:00:00:00:00:01 192.168.1.3" - ) - fakeCmds := ovntest.AddFakeCmd(nil, &ovntest.ExpectedCmd{ - Cmd: "ovn-nbctl --timeout=15 --data=bare --no-heading --columns=name find logical_switch " + "name=" + netName, - Output: netName, - }) - fakeCmds = ovntest.AddFakeCmdsNoOutputNoError(fakeCmds, []string{ - "ovn-nbctl --timeout=15 --wait=sb -- --may-exist lsp-add " + netName + " " + portName + " -- lsp-set-addresses " + portName + " dynamic -- set logical_switch_port " + portName + " external-ids:namespace= external-ids:logical_switch=" + netName + " external-ids:pod=true", - }) - - fakeCmds = ovntest.AddFakeCmd(fakeCmds, &ovntest.ExpectedCmd{ - Cmd: "ovn-nbctl --timeout=15 get logical_switch_port " + portName + " dynamic_addresses", - Output: macIPAddress, - }) - fakeCmds = ovntest.AddFakeCmd(fakeCmds, &ovntest.ExpectedCmd{ - Cmd: "ovn-nbctl --timeout=15 --if-exists get logical_switch " + netName + " external_ids:gateway_ip", - Output: gwCIDR, - }) - - fexec := &fakeexec.FakeExec{ - CommandScript: fakeCmds, - LookPathFunc: func(file string) (string, error) { - return fmt.Sprintf("/fake-bin/%s", file), nil - }, - } - oldSetupOvnUtils := SetupOvnUtils - // as we are exiting, revert ConfigureInterface back at end of function - defer func() { SetupOvnUtils = oldSetupOvnUtils }() - SetupOvnUtils = func() error { - return nil - } - ovnController, err := NewOvnController(fexec) - Expect(err).NotTo(HaveOccurred()) - - var ( - okPod = v1.Pod{ - TypeMeta: metav1.TypeMeta{ - Kind: "Pod", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "ok", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - { - Name: "by-name", - }, - {}, - }, - }, - } - ) - a := []map[string]interface{}{{"name": "ovn-prot-net", "interface": "net0"}} - ovnController.AddLogicalPorts(&okPod, a) - Expect(fexec.CommandCalls).To(Equal(len(fakeCmds))) - - return nil - } - - err := app.Run([]string{app.Name}) - Expect(err).NotTo(HaveOccurred()) - }) - - It("tests Pod provider", func() { - app.Action = func(ctx *cli.Context) error { - const ( - gwIP string = "10.1.1.1" - gwCIDR string = gwIP + "/24" - netName string = "ovn-prot-net" - portName string = "_ok_net0" - macIPAddress string = "0a:00:00:00:00:01 192.168.1.3/24" - ) - fakeCmds := ovntest.AddFakeCmd(nil, &ovntest.ExpectedCmd{ - Cmd: "ovn-nbctl --timeout=15 --data=bare --no-heading --columns=name find logical_switch " + "name=" + netName, - Output: netName, - }) - - fakeCmds = ovntest.AddFakeCmdsNoOutputNoError(fakeCmds, []string{ - "ovn-nbctl --timeout=15 --may-exist lsp-add " + netName + " " + portName + " -- lsp-set-addresses " + portName + " " + macIPAddress + " -- --if-exists clear logical_switch_port " + portName + " dynamic_addresses" + " -- set logical_switch_port " + portName + " external-ids:namespace= external-ids:logical_switch=" + netName + " external-ids:pod=true", - }) - - fakeCmds = ovntest.AddFakeCmd(fakeCmds, &ovntest.ExpectedCmd{ - Cmd: "ovn-nbctl --timeout=15 get logical_switch_port " + portName + " addresses", - Output: macIPAddress, - }) - - fakeCmds = ovntest.AddFakeCmd(fakeCmds, &ovntest.ExpectedCmd{ - Cmd: "ovn-nbctl --timeout=15 --if-exists get logical_switch " + netName + " external_ids:gateway_ip", - Output: gwCIDR, - }) - - fexec := &fakeexec.FakeExec{ - CommandScript: fakeCmds, - LookPathFunc: func(file string) (string, error) { - return fmt.Sprintf("/fake-bin/%s", file), nil - }, - } - oldSetupOvnUtils := SetupOvnUtils - // as we are exiting, revert ConfigureInterface back at end of function - defer func() { SetupOvnUtils = oldSetupOvnUtils }() - SetupOvnUtils = func() error { - return nil - } - ovnController, err := NewOvnController(fexec) - Expect(err).NotTo(HaveOccurred()) - var ( - okPod = v1.Pod{ - TypeMeta: metav1.TypeMeta{ - Kind: "Pod", - APIVersion: "v1", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: "ok", - }, - Spec: v1.PodSpec{ - Containers: []v1.Container{ - { - Name: "by-name", - }, - {}, - }, - }, - } - ) - a := []map[string]interface{}{{"name": "ovn-prot-net", "interface": "net0", "netType": "provider", "ipAddress": "192.168.1.3/24", "macAddress": "0a:00:00:00:00:01"}} - ovnController.AddLogicalPorts(&okPod, a) - Expect(fexec.CommandCalls).To(Equal(len(fakeCmds))) - - return nil - } - - err := app.Run([]string{app.Name}) - Expect(err).NotTo(HaveOccurred()) - }) - -}) diff --git a/internal/pkg/ovn/utils.go b/internal/pkg/ovn/utils.go index 3b3b53b..9b388b7 100644 --- a/internal/pkg/ovn/utils.go +++ b/internal/pkg/ovn/utils.go @@ -5,6 +5,7 @@ import ( "fmt" kexec "k8s.io/utils/exec" "os" + "reflect" "strings" "time" ) @@ -36,6 +37,13 @@ var SetupOvnUtils = func() error { log.Error(err, "Failed to initialize OVN Distributed Router") return err } + + log.Info("OVN Network", "OVN Default NW", Ovn4nfvDefaultNw, "OVN Subnet", ovnConf.Subnet, "OVN Gateway IP", ovnConf.GatewayIP, "OVN ExcludeIPs", ovnConf.ExcludeIPs) + _, err = createOvnLS(Ovn4nfvDefaultNw, ovnConf.Subnet, ovnConf.GatewayIP, ovnConf.ExcludeIPs) + if err != nil && !reflect.DeepEqual(err, fmt.Errorf("LS exists")) { + log.Error(err, "Failed to create ovn4nfvk8s default nw") + return err + } return nil } -- cgit 1.2.3-korg