From ebb876e1b07721d731081cbfa9a212548173a8b5 Mon Sep 17 00:00:00 2001 From: Nick Rogers Date: Tue, 27 Sep 2022 09:30:12 -0400 Subject: [PATCH] Add support to specify ofport_request in the network configuration (#239) (#239) Signed-off-by: Nick Rogers Signed-off-by: Nick Rogers Co-authored-by: Nick Rogers --- docs/cni-plugin.md | 1 + pkg/ovsdb/ovsdb.go | 11 ++++++++--- pkg/plugin/plugin.go | 6 +++--- pkg/plugin/plugin_test.go | 32 ++++++++++++++++++++++++++++++++ pkg/types/types.go | 3 ++- 5 files changed, 46 insertions(+), 7 deletions(-) diff --git a/docs/cni-plugin.md b/docs/cni-plugin.md index 233c87c41..cd21d9120 100644 --- a/docs/cni-plugin.md +++ b/docs/cni-plugin.md @@ -45,6 +45,7 @@ Another example with a trunk port and jumbo frames: * `mtu` (integer, optional): MTU. * `trunk` (optional): List of VLAN ID's and/or ranges of accepted VLAN ID's. +* `ofport_request` (integer, optional): request a static OpenFlow port number in range 1 to 65,279 * `configuration_path` (optional): configuration file containing ovsdb socket file path, etc. diff --git a/pkg/ovsdb/ovsdb.go b/pkg/ovsdb/ovsdb.go index 972ca255e..9c8857f01 100644 --- a/pkg/ovsdb/ovsdb.go +++ b/pkg/ovsdb/ovsdb.go @@ -150,8 +150,8 @@ func (ovsd *OvsDriver) ovsdbTransact(ops []ovsdb.Operation) ([]ovsdb.OperationRe // **************** OVS driver API ******************** // CreatePort Create an internal port in OVS -func (ovsd *OvsBridgeDriver) CreatePort(intfName, contNetnsPath, contIfaceName, ovnPortName string, vlanTag uint, trunks []uint, portType string) error { - intfUUID, intfOp, err := createInterfaceOperation(intfName, ovnPortName) +func (ovsd *OvsBridgeDriver) CreatePort(intfName, contNetnsPath, contIfaceName, ovnPortName string, ofportRequest uint, vlanTag uint, trunks []uint, portType string) error { + intfUUID, intfOp, err := createInterfaceOperation(intfName, ofportRequest, ovnPortName) if err != nil { return err } @@ -782,7 +782,7 @@ func (ovsd *OvsDriver) isMirrorExistsByConditions(conditions []ovsdb.Condition) return true, nil } -func createInterfaceOperation(intfName, ovnPortName string) (ovsdb.UUID, *ovsdb.Operation, error) { +func createInterfaceOperation(intfName string, ofportRequest uint, ovnPortName string) (ovsdb.UUID, *ovsdb.Operation, error) { intfUUIDStr := fmt.Sprintf("Intf%s", intfName) intfUUID := ovsdb.UUID{GoUUID: intfUUIDStr} @@ -798,6 +798,11 @@ func createInterfaceOperation(intfName, ovnPortName string) (ovsdb.UUID, *ovsdb. intf["external_ids"] = oMap } + // Requested OpenFlow port number for this interface + if ofportRequest != 0 { + intf["ofport_request"] = ofportRequest + } + // Add an entry in Interface table intfOp := ovsdb.Operation{ Op: "insert", diff --git a/pkg/plugin/plugin.go b/pkg/plugin/plugin.go index 609b809fe..96a6f3e51 100644 --- a/pkg/plugin/plugin.go +++ b/pkg/plugin/plugin.go @@ -154,8 +154,8 @@ func getBridgeName(bridgeName, ovnPort string) (string, error) { return "", fmt.Errorf("failed to get bridge name") } -func attachIfaceToBridge(ovsDriver *ovsdb.OvsBridgeDriver, hostIfaceName string, contIfaceName string, vlanTag uint, trunks []uint, portType string, contNetnsPath string, ovnPortName string) error { - err := ovsDriver.CreatePort(hostIfaceName, contNetnsPath, contIfaceName, ovnPortName, vlanTag, trunks, portType) +func attachIfaceToBridge(ovsDriver *ovsdb.OvsBridgeDriver, hostIfaceName string, contIfaceName string, ofportRequest uint, vlanTag uint, trunks []uint, portType string, contNetnsPath string, ovnPortName string) error { + err := ovsDriver.CreatePort(hostIfaceName, contNetnsPath, contIfaceName, ovnPortName, ofportRequest, vlanTag, trunks, portType) if err != nil { return err } @@ -307,7 +307,7 @@ func CmdAdd(args *skel.CmdArgs) error { } } - if err = attachIfaceToBridge(ovsDriver, hostIface.Name, contIface.Name, vlanTagNum, trunks, portType, args.Netns, ovnPort); err != nil { + if err = attachIfaceToBridge(ovsDriver, hostIface.Name, contIface.Name, netconf.OfportRequest, vlanTagNum, trunks, portType, args.Netns, ovnPort); err != nil { return err } diff --git a/pkg/plugin/plugin_test.go b/pkg/plugin/plugin_test.go index dd73cde93..ed7843f04 100644 --- a/pkg/plugin/plugin_test.go +++ b/pkg/plugin/plugin_test.go @@ -19,6 +19,7 @@ import ( "encoding/json" "errors" "fmt" + "math/rand" "net" "os/exec" "strconv" @@ -663,6 +664,37 @@ var testFunc = func(version string) { Expect(string(output[:len(output)-1])).To(Equal(ovsOutput)) }) }) + Context("specified OfportRequest", func() { + It("should configure an ovs interface with a specific ofport", func() { + // Pick a random ofport 5000-6000 + ofportRequest := rand.Intn(1000) + 5000 + ovsOutput := fmt.Sprintf("ofport : %d", ofportRequest) + + conf := fmt.Sprintf(`{ + "cniVersion": "%s", + "name": "mynet", + "type": "ovs", + "ofport_request": %d, + "bridge": "%s"}`, version, ofportRequest, bridgeName) + + targetNs := newNS() + defer func() { + closeNS(targetNs) + }() + + result := attach(targetNs, conf, IFNAME, "", "") + hostIface := result.Interfaces[0] + + // Wait for OVS to actually assign the port, even when the add returns + // successfully, ofport can still be blank ("[]") for a short period of + // time. + Eventually(func() bool { + output, err := exec.Command("ovs-vsctl", "--column=ofport", "find", "Interface", fmt.Sprintf("name=%s", hostIface.Name)).CombinedOutput() + Expect(err).NotTo(HaveOccurred()) + return (string(output[:len(output)-1]) == ovsOutput) + }, time.Minute, 100*time.Millisecond).Should(Equal(true)) + }) + }) Context("specify trunk with multiple ranges", func() { trunks := `[ {"minID": 10, "maxID": 12}, {"minID": 19, "maxID": 20} ]` It("testSplitVlanIds method should return with specifed values in the range", func() { diff --git a/pkg/types/types.go b/pkg/types/types.go index 29b71aef1..0989699c8 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -33,7 +33,8 @@ type NetConf struct { VlanTag *uint `json:"vlan"` MTU int `json:"mtu"` Trunk []*Trunk `json:"trunk,omitempty"` - DeviceID string `json:"deviceID"` // PCI address of a VF in valid sysfs format + DeviceID string `json:"deviceID"` // PCI address of a VF in valid sysfs format + OfportRequest uint `json:"ofport_request"` // OpenFlow port number in range 1 to 65,279 ConfigurationPath string `json:"configuration_path"` SocketFile string `json:"socket_file"` LinkStateCheckRetries int `json:"link_state_check_retries"`