diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index 08ea15bac75..e1a39539610 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -606,7 +606,7 @@ func (i *Initializer) setupGatewayInterface() error { externalIDs := map[string]interface{}{ interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaGateway, } - gwPortUUID, err := i.ovsBridgeClient.CreateInternalPort(i.hostGateway, config.HostGatewayOFPort, externalIDs) + gwPortUUID, err := i.ovsBridgeClient.CreateInternalPort(i.hostGateway, config.HostGatewayOFPort, "", externalIDs) if err != nil { klog.ErrorS(err, "Failed to create gateway port on OVS bridge", "port", i.hostGateway) return err @@ -1144,8 +1144,11 @@ func (i *Initializer) getNodeInterfaceFromIP(nodeIPs *utilip.DualStackIPs) (v4IP // getFreeOFPort returns an OpenFlow port number which is not used by any existing OVS port. Note that, the returned port // is not saved in OVSDB yet before the real port is created, so it might introduce an issue for the same return value // if it is called multiple times before OVS port creation. -func (i *Initializer) getFreeOFPort(startPort int) (int32, error) { +func (i *Initializer) getFreeOFPort(startPort int, reservedPorts []int32) (int32, error) { existingOFPorts := sets.NewInt32() + for _, reservedPort := range reservedPorts { + existingOFPorts.Insert(reservedPort) + } ports, err := i.ovsBridgeClient.GetPortList() if err != nil { return 0, err diff --git a/pkg/agent/agent_linux.go b/pkg/agent/agent_linux.go index 1a65b91125e..7c30760e62d 100644 --- a/pkg/agent/agent_linux.go +++ b/pkg/agent/agent_linux.go @@ -30,7 +30,6 @@ import ( "antrea.io/antrea/pkg/agent/config" "antrea.io/antrea/pkg/agent/interfacestore" "antrea.io/antrea/pkg/agent/util" - "antrea.io/antrea/pkg/ovs/ovsconfig" utilip "antrea.io/antrea/pkg/util/ip" ) @@ -78,63 +77,39 @@ func (i *Initializer) prepareOVSBridge() error { return fmt.Errorf("failed to set datapath_id %s: err=%w", datapathID, err) } - // Create local port. - brName := i.ovsBridgeClient.GetBridgeName() - if _, err = i.ovsBridgeClient.GetOFPort(brName, false); err == nil { - klog.Infof("OVS bridge local port %s already exists, skip the configuration", brName) - // If uplink is internal port, get the real uplink interface. + if hostOFPort, err := i.ovsBridgeClient.GetOFPort(uplinkNetConfig.Name, false); err == nil { + klog.Infof("OVS bridge local port %s already exists", uplinkNetConfig.Name) + i.nodeConfig.HostInterfaceOFPort = uint32(hostOFPort) + // If local port exists, get the real uplink interface. // This branch is used when antrea-agent get a hard restart (e.g. SIGKILL) - if uplinkNetConfig.Name == brName { - ports, err := i.ovsBridgeClient.GetPortList() - if err != nil { - return err - } - klog.V(2).Infof("Found ports from OVS bridge: %+v", ports) - var uplinkPort *ovsconfig.OVSPortData - for index := range ports { - antreaIfaceType, _ := ports[index].ExternalIDs[interfacestore.AntreaInterfaceTypeKey] - if antreaIfaceType == interfacestore.AntreaUplink { - uplinkPort = &ports[index] - break - } - } - if uplinkPort == nil { - return fmt.Errorf("cannot find uplink port from OVS bridge %s", brName) - } - adapter, err2 := net.InterfaceByName(uplinkPort.Name) - if err2 != nil { - return fmt.Errorf("cannot find uplink port %s: err=%w", uplinkPort.Name, err2) - } - klog.Infof("Found uplink device %s", adapter.Name) - uplinkNetConfig.OFPort = uint32(uplinkPort.OFPort) - uplinkNetConfig.Name = adapter.Name + bridgedUplinkName := util.GenerateUplinkInterfaceName(uplinkNetConfig.Name) + if uplinkOFPort, err := i.ovsBridgeClient.GetOFPort(bridgedUplinkName, false); err != nil { + return fmt.Errorf("cannot find uplink port %s: err=%w", bridgedUplinkName, err) + } else { + uplinkNetConfig.OFPort = uint32(uplinkOFPort) + } + if adapter, err := net.InterfaceByName(bridgedUplinkName); err != nil { + return fmt.Errorf("cannot find uplink port %s: err=%w", bridgedUplinkName, err) + } else { uplinkNetConfig.Index = adapter.Index - uplinkInterface := interfacestore.NewUplinkInterface(uplinkPort.Name) - uplinkInterface.OVSPortConfig = &interfacestore.OVSPortConfig{uplinkPort.UUID, uplinkPort.OFPort} //nolint: govet - i.ifaceStore.AddInterface(uplinkInterface) } + klog.InfoS("Found uplink", "Name", adapter.Name, "Index", uplinkNetConfig.Index, "OFPort", uplinkNetConfig.OFPort) } else { - // OVS does not receive "ofport_request" param when creating local port, so here use config.AutoAssignedOFPort=0 - // to ignore this param. - externalIDs := map[string]interface{}{ - interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaHost, - } - if _, err = i.ovsBridgeClient.CreateInternalPort(brName, config.AutoAssignedOFPort, externalIDs); err != nil { + freePort, err := i.getFreeOFPort(config.UplinkOFPort, nil) + if err != nil { + klog.ErrorS(err, "Failed to find a free port on OVS") return err } - } - - i.nodeConfig.HostInterfaceOFPort = config.BridgeOFPort - if uplinkNetConfig.OFPort == 0 { - freePort, err := i.getFreeOFPort(config.UplinkOFPort) + uplinkNetConfig.OFPort = uint32(freePort) + klog.InfoS("Set OpenFlow port in UplinkNetConfig", "ofport", uplinkNetConfig.OFPort) + freePort, err = i.getFreeOFPort(config.UplinkOFPort, []int32{freePort}) if err != nil { klog.ErrorS(err, "Failed to find a free port on OVS") return err } - uplinkNetConfig.OFPort = uint32(freePort) - klog.InfoS("Set OpenFlow port in UplinkNetConfig", "ofport", freePort) + i.nodeConfig.HostInterfaceOFPort = uint32(freePort) + klog.InfoS("Set host interface", "ofport", i.nodeConfig.HostInterfaceOFPort) } - return nil } @@ -179,7 +154,7 @@ func (i *Initializer) saveHostRoutes() error { // the antrea network initialize stage. // The backup routes are restored after the IP configuration change. func (i *Initializer) restoreHostRoutes() error { - return i.restoreHostRoutesToInterface(i.ovsBridge) + return i.restoreHostRoutesToInterface(i.nodeConfig.UplinkNetConfig.Name) } func (i *Initializer) restoreHostRoutesToInterface(ifaceName string) error { @@ -206,53 +181,65 @@ func (i *Initializer) ConnectUplinkToOVSBridge() error { klog.Infof("Bridging uplink to OVS bridge") var err error uplinkNetConfig := i.nodeConfig.UplinkNetConfig - brName := i.ovsBridgeClient.GetBridgeName() + uplinkName := uplinkNetConfig.Name + bridgedUplinkName := util.GenerateUplinkInterfaceName(uplinkNetConfig.Name) // If uplink is already exists, return. - uplink := uplinkNetConfig.Name - if uplinkOFPort, err := i.ovsBridgeClient.GetOFPort(uplink, false); err == nil { - klog.InfoS("Uplink already exists, skip the configuration", "uplink", uplink, "port", uplinkOFPort) + if uplinkOFPort, err := i.ovsBridgeClient.GetOFPort(bridgedUplinkName, false); err == nil { + klog.InfoS("Uplink already exists, skip the configuration", "uplink", bridgedUplinkName, "port", uplinkOFPort) return nil } + uplinkIPs, err := getTransportIPNetByNameWithExcludedList(uplinkName, nil) + if err != nil { + return fmt.Errorf("failed to get uplink IPs: err=%w", err) + } + if err := util.RenameInterface(uplinkName, bridgedUplinkName); err != nil { + return fmt.Errorf("failed to change uplink interface name: err=%w", err) + } + // Create uplink port. - uplinkPortUUID, err := i.ovsBridgeClient.CreateUplinkPort(uplink, int32(i.nodeConfig.UplinkNetConfig.OFPort), map[string]interface{}{interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUplink}) + uplinkPortUUID, err := i.ovsBridgeClient.CreateUplinkPort(bridgedUplinkName, int32(uplinkNetConfig.OFPort), map[string]interface{}{interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUplink}) if err != nil { - return fmt.Errorf("failed to add uplink port %s: err=%w", uplink, err) + return fmt.Errorf("failed to add uplink port %s: err=%w", bridgedUplinkName, err) } - // Add newly created uplinkInterface to interface cache. This will be overwritten by initInterfaceStore. - uplinkInterface := interfacestore.NewUplinkInterface(uplink) - uplinkOFPort, err := i.ovsBridgeClient.GetOFPort(uplink, false) + // Add newly created uplinkInterface to interface cache. + uplinkInterface := interfacestore.NewUplinkInterface(bridgedUplinkName) + uplinkOFPort, err := i.ovsBridgeClient.GetOFPort(bridgedUplinkName, false) if err != nil { - return fmt.Errorf("failed to get uplink ofport %s: err=%w", uplink, err) + return fmt.Errorf("failed to get uplink ofport %s: err=%w", bridgedUplinkName, err) } - klog.InfoS("Allocated OpenFlow port for uplink interface", "port", uplink, "ofPort", uplinkOFPort) + klog.InfoS("Allocated OpenFlow port for uplink interface", "port", bridgedUplinkName, "ofPort", uplinkOFPort) uplinkInterface.OVSPortConfig = &interfacestore.OVSPortConfig{uplinkPortUUID, uplinkOFPort} //nolint: govet i.ifaceStore.AddInterface(uplinkInterface) + // Create local port. + externalIDs := map[string]interface{}{ + interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaHost, + } + if _, err = i.ovsBridgeClient.CreateInternalPort(uplinkName, int32(i.nodeConfig.HostInterfaceOFPort), uplinkNetConfig.MAC.String(), externalIDs); err != nil { + return fmt.Errorf("cannot create host interface port %s: err=%w", uplinkName, err) + } + // Move network configuration of uplink interface to OVS bridge local interface. // The net configuration of uplink will be restored by RestoreOVSBridge when shutting down. wait.PollImmediate(100*time.Millisecond, 10000*time.Millisecond, func() (bool, error) { // Wait a few seconds for OVS bridge local port. - link, err := netlink.LinkByName(brName) + link, err := netlink.LinkByName(uplinkName) if err != nil { - klog.V(4).InfoS("OVS bridge local port is not ready", "port", brName, "err", err) + klog.V(4).InfoS("OVS bridge local port is not ready", "port", uplinkName, "err", err) return false, nil } klog.InfoS("OVS bridge local port is ready", "type", link.Type(), "attrs", link.Attrs()) return true, nil }) - brLink, err := netlink.LinkByName(brName) + localLink, err := netlink.LinkByName(uplinkName) if err != nil { return err } - if _, _, err = util.SetLinkUp(brName); err != nil { - return err - } - if err = util.SetAdapterMACAddress(brName, &uplinkNetConfig.MAC); err != nil { + if _, _, err = util.SetLinkUp(uplinkName); err != nil { return err } - // TODO(gran): support IPv6 - if err = util.ConfigureLinkAddresses(brLink.Attrs().Index, []*net.IPNet{uplinkNetConfig.IP}); err != nil { + if err = util.ConfigureLinkAddresses(localLink.Attrs().Index, uplinkIPs); err != nil { return err } if err = util.ConfigureLinkAddresses(uplinkNetConfig.Index, nil); err != nil { @@ -274,36 +261,33 @@ func (i *Initializer) RestoreOVSBridge() { } klog.Infof("Restoring bridge config to uplink...") uplinkNetConfig := i.nodeConfig.UplinkNetConfig - uplink := "" + uplinkName := "" + bridgedUplinkName := "" if uplinkNetConfig != nil { - uplink = uplinkNetConfig.Name + uplinkName = uplinkNetConfig.Name + bridgedUplinkName = util.GenerateUplinkInterfaceName(uplinkName) } + brName := i.ovsBridge - brName := i.ovsBridgeClient.GetBridgeName() - brLink, err := netlink.LinkByName(brName) + uplinkIPs, err := getTransportIPNetByNameWithExcludedList(uplinkName, nil) if err != nil { - klog.Warningf("OVS bridge local port not found: %+v", err) + klog.ErrorS(err, "Failed to get uplink IPs") } - - if uplink != "" { - if err := util.DeleteOVSPort(brName, uplink); err != nil { - klog.ErrorS(err, "Removing uplink port from bridge failed", "uplink", uplink, "bridge", brName) + if uplinkName != "" { + if err := util.DeleteOVSPort(brName, uplinkName); err != nil { + klog.ErrorS(err, "Delete OVS port failed", "port", uplinkName) } - if err := util.ConfigureLinkAddresses(uplinkNetConfig.Index, []*net.IPNet{uplinkNetConfig.IP}); err != nil { - klog.ErrorS(err, "Configure IP to uplink failed", "uplink", uplink) + if err := util.DeleteOVSPort(brName, bridgedUplinkName); err != nil { + klog.ErrorS(err, "Delete OVS port failed", "port", bridgedUplinkName) } - } - if brLink != nil { - if err := util.ConfigureLinkAddresses(brLink.Attrs().Index, nil); err != nil { - klog.ErrorS(err, "Remove IP from bridge interface failed", "interface", brName) + if err := util.RenameInterface(bridgedUplinkName, uplinkName); err != nil { + klog.ErrorS(err, "Restore uplink name failed", "uplink", bridgedUplinkName) } - if err := netlink.LinkSetDown(brLink); err != nil { - klog.ErrorS(err, "Disable bridge interface failed", "interface", brName) + if err := util.ConfigureLinkAddresses(uplinkNetConfig.Index, uplinkIPs); err != nil { + klog.ErrorS(err, "Configure IP to uplink failed", "uplink", uplinkName) } - } - if uplink != "" { - if err := i.restoreHostRoutesToInterface(uplink); err != nil { - klog.ErrorS(err, "Configure route to uplink interface failed", "interface", uplink) + if err := i.restoreHostRoutesToInterface(uplinkName); err != nil { + klog.ErrorS(err, "Configure route to uplink interface failed", "uplink", uplinkName) } } klog.Infof("Finished to restore bridge config to uplink...") @@ -312,3 +296,32 @@ func (i *Initializer) RestoreOVSBridge() { func (i *Initializer) setInterfaceMTU(iface string, mtu int) error { return i.ovsBridgeClient.SetInterfaceMTU(iface, mtu) } + +func getTransportIPNetByNameWithExcludedList(interfaceName string, excludedIPs []*net.IPNet) ([]*net.IPNet, error) { + IPs := []*net.IPNet{} + _, _, adapter, err := getTransportIPNetDeviceByName(interfaceName, "") + if err != nil { + return nil, err + } + addrs, _ := adapter.Addrs() + for _, addr := range addrs { + if ip, ipNet, err := net.ParseCIDR(addr.String()); err != nil { + klog.Warningf("Unable to parse addr %+v, err=%+v", addr, err) + } else if !ip.IsLinkLocalUnicast() { + ipNet.IP = ip + ipNetString := ipNet.String() + isExcludedIP := false + for _, excludedIP := range excludedIPs { + if ipNetString == excludedIP.String() { + isExcludedIP = true + break + } + } + if !isExcludedIP { + IPs = append(IPs, ipNet) + } + } + } + klog.InfoS("Found IPs on interface", "IPs", IPs, "interface", interfaceName) + return IPs, nil +} diff --git a/pkg/agent/agent_windows.go b/pkg/agent/agent_windows.go index d980f9f7c54..f3b9eeea198 100644 --- a/pkg/agent/agent_windows.go +++ b/pkg/agent/agent_windows.go @@ -150,7 +150,7 @@ func (i *Initializer) prepareOVSBridge() error { externalIDs := map[string]interface{}{ interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaHost, } - if _, err = i.ovsBridgeClient.CreateInternalPort(brName, config.AutoAssignedOFPort, externalIDs); err != nil { + if _, err = i.ovsBridgeClient.CreateInternalPort(brName, config.AutoAssignedOFPort, "", externalIDs); err != nil { return err } } @@ -165,7 +165,7 @@ func (i *Initializer) prepareOVSBridge() error { return nil } // Create uplink port. - freePort, err := i.getFreeOFPort(config.UplinkOFPort) + freePort, err := i.getFreeOFPort(config.UplinkOFPort, nil) if err != nil { klog.ErrorS(err, "Failed to find a free port on OVS") return err diff --git a/pkg/agent/cniserver/pod_configuration.go b/pkg/agent/cniserver/pod_configuration.go index f33d20c4717..89b023ab48d 100644 --- a/pkg/agent/cniserver/pod_configuration.go +++ b/pkg/agent/cniserver/pod_configuration.go @@ -271,7 +271,7 @@ func (pc *podConfigurator) createOVSPort(ovsPortName string, ovsAttachInfo map[s var err error switch pc.ifConfigurator.getOVSInterfaceType(ovsPortName) { case internalOVSInterfaceType: - portUUID, err = pc.ovsBridgeClient.CreateInternalPort(ovsPortName, 0, ovsAttachInfo) + portUUID, err = pc.ovsBridgeClient.CreateInternalPort(ovsPortName, 0, "", ovsAttachInfo) default: if vlanID == 0 { portUUID, err = pc.ovsBridgeClient.CreatePort(ovsPortName, ovsPortName, ovsAttachInfo) diff --git a/pkg/agent/controller/trafficcontrol/controller.go b/pkg/agent/controller/trafficcontrol/controller.go index 0b94482e6cf..3ed0675184e 100644 --- a/pkg/agent/controller/trafficcontrol/controller.go +++ b/pkg/agent/controller/trafficcontrol/controller.go @@ -585,7 +585,7 @@ func ParseTrafficControlInterfaceConfig(portData *ovsconfig.OVSPortData, portCon // createOVSInternalPort creates an OVS internal port on OVS and corresponding interface on host. Note that, host interface // might not be available immediately after creating OVS internal port. func (c *Controller) createOVSInternalPort(portName string) (string, error) { - portUUID, err := c.ovsBridgeClient.CreateInternalPort(portName, 0, trafficControlPortExternalIDs) + portUUID, err := c.ovsBridgeClient.CreateInternalPort(portName, 0, "", trafficControlPortExternalIDs) if err != nil { return "", err } diff --git a/pkg/agent/util/net.go b/pkg/agent/util/net.go index 3b3304c9ded..74d234e6abf 100644 --- a/pkg/agent/util/net.go +++ b/pkg/agent/util/net.go @@ -38,6 +38,8 @@ const ( FamilyIPv4 uint8 = 4 FamilyIPv6 uint8 = 6 + + BridgedUplinkSuffix = "~" ) func generateInterfaceName(key string, name string, useHead bool) string { @@ -378,3 +380,8 @@ func PortToUint16(port int) uint16 { klog.Errorf("Port value %d out-of-bounds", port) return 0 } + +// GenerateUplinkInterfaceName generates the uplink interface name after bridged to OVS +func GenerateUplinkInterfaceName(name string) string { + return name + BridgedUplinkSuffix +} diff --git a/pkg/agent/util/net_linux.go b/pkg/agent/util/net_linux.go index eb25c5b737f..a77004d245f 100644 --- a/pkg/agent/util/net_linux.go +++ b/pkg/agent/util/net_linux.go @@ -23,10 +23,12 @@ import ( "os" "os/exec" "path/filepath" + "time" "github.com/containernetworking/plugins/pkg/ip" "github.com/containernetworking/plugins/pkg/ns" "github.com/vishvananda/netlink" + "k8s.io/apimachinery/pkg/util/wait" "k8s.io/klog/v2" ) @@ -237,3 +239,37 @@ func DeleteOVSPort(brName, portName string) error { cmd := exec.Command("ovs-vsctl", "--if-exists", "del-port", brName, portName) return cmd.Run() } + +func RenameInterface(from, to string) error { + klog.InfoS("Rename interface", "oldName", from, "newName", to) + var renameErr error + pollErr := wait.Poll(time.Millisecond*100, time.Second, func() (done bool, err error) { + renameErr = renameHostInterface(from, to) + if renameErr != nil { + klog.InfoS("Unable to rename host interface name with error, retrying", "oldName", from, "newName", to, "err", renameErr) + return false, nil + } + return true, nil + }) + if pollErr != nil { + return fmt.Errorf("failed to rename host interface name %s to %s", from, to) + } + return nil +} + +func renameHostInterface(oriName string, newName string) error { + link, err := netlink.LinkByName(oriName) + if err != nil { + return err + } + if err := netlink.LinkSetDown(link); err != nil { + return err + } + defer func() { + netlink.LinkSetUp(link) + }() + if err := netlink.LinkSetName(link, newName); err != nil { + return err + } + return nil +} diff --git a/pkg/ovs/ovsconfig/interfaces.go b/pkg/ovs/ovsconfig/interfaces.go index 2bea4390d00..b479c009a47 100644 --- a/pkg/ovs/ovsconfig/interfaces.go +++ b/pkg/ovs/ovsconfig/interfaces.go @@ -39,7 +39,7 @@ type OVSBridgeClient interface { SetInterfaceOptions(name string, options map[string]interface{}) Error CreatePort(name, ifDev string, externalIDs map[string]interface{}) (string, Error) CreateAccessPort(name, ifDev string, externalIDs map[string]interface{}, vlanID uint16) (string, Error) - CreateInternalPort(name string, ofPortRequest int32, externalIDs map[string]interface{}) (string, Error) + CreateInternalPort(name string, ofPortRequest int32, mac string, externalIDs map[string]interface{}) (string, Error) CreateTunnelPort(name string, tunnelType TunnelType, ofPortRequest int32) (string, Error) CreateTunnelPortExt(name string, tunnelType TunnelType, ofPortRequest int32, csum bool, localIP string, remoteIP string, remoteName string, psk string, extraOptions, externalIDs map[string]interface{}) (string, Error) CreateUplinkPort(name string, ofPortRequest int32, externalIDs map[string]interface{}) (string, Error) diff --git a/pkg/ovs/ovsconfig/ovs_client.go b/pkg/ovs/ovsconfig/ovs_client.go index fafc55fed4d..69d0faeebc5 100644 --- a/pkg/ovs/ovsconfig/ovs_client.go +++ b/pkg/ovs/ovsconfig/ovs_client.go @@ -362,11 +362,11 @@ func (br *OVSBridge) DeletePort(portUUID string) Error { // If externalIDs is not empty, the map key/value pairs will be set to the // port's external_ids. // If ofPortRequest is not zero, it will be passed to the OVS port creation. -func (br *OVSBridge) CreateInternalPort(name string, ofPortRequest int32, externalIDs map[string]interface{}) (string, Error) { +func (br *OVSBridge) CreateInternalPort(name string, ofPortRequest int32, mac string, externalIDs map[string]interface{}) (string, Error) { if ofPortRequest < 0 || ofPortRequest > ofPortRequestMax { return "", newInvalidArgumentsError(fmt.Sprint("invalid ofPortRequest value: ", ofPortRequest)) } - return br.createPort(name, name, "internal", ofPortRequest, 0, externalIDs, nil) + return br.createPort(name, name, "internal", ofPortRequest, 0, mac, externalIDs, nil) } // CreateTunnelPort creates a tunnel port with the specified name and type on @@ -454,7 +454,7 @@ func (br *OVSBridge) createTunnelPort( options["csum"] = "true" } - return br.createPort(name, name, string(tunnelType), ofPortRequest, 0, externalIDs, options) + return br.createPort(name, name, string(tunnelType), ofPortRequest, 0, "", externalIDs, options) } // GetInterfaceOptions returns the options of the provided interface. @@ -526,7 +526,7 @@ func ParseTunnelInterfaceOptions(portData *OVSPortData) (net.IP, net.IP, string, // CreateUplinkPort creates uplink port. func (br *OVSBridge) CreateUplinkPort(name string, ofPortRequest int32, externalIDs map[string]interface{}) (string, Error) { - return br.createPort(name, name, "", ofPortRequest, 0, externalIDs, nil) + return br.createPort(name, name, "", ofPortRequest, 0, "", externalIDs, nil) } // CreatePort creates a port with the specified name on the bridge, and connects @@ -534,7 +534,7 @@ func (br *OVSBridge) CreateUplinkPort(name string, ofPortRequest int32, external // If externalIDs is not empty, the map key/value pairs will be set to the // port's external_ids. func (br *OVSBridge) CreatePort(name, ifDev string, externalIDs map[string]interface{}) (string, Error) { - return br.createPort(name, ifDev, "", 0, 0, externalIDs, nil) + return br.createPort(name, ifDev, "", 0, 0, "", externalIDs, nil) } // CreateAccessPort creates a port with the specified name and VLAN ID on the bridge, and connects @@ -543,10 +543,10 @@ func (br *OVSBridge) CreatePort(name, ifDev string, externalIDs map[string]inter // port's external_ids. // vlanID=0 will perform same behavior as CreatePort. func (br *OVSBridge) CreateAccessPort(name, ifDev string, externalIDs map[string]interface{}, vlanID uint16) (string, Error) { - return br.createPort(name, ifDev, "", 0, vlanID, externalIDs, nil) + return br.createPort(name, ifDev, "", 0, vlanID, "", externalIDs, nil) } -func (br *OVSBridge) createPort(name, ifName, ifType string, ofPortRequest int32, vlanID uint16, externalIDs, options map[string]interface{}) (string, Error) { +func (br *OVSBridge) createPort(name, ifName, ifType string, ofPortRequest int32, vlanID uint16, mac string, externalIDs, options map[string]interface{}) (string, Error) { var externalIDMap []interface{} var optionMap []interface{} @@ -564,6 +564,7 @@ func (br *OVSBridge) createPort(name, ifName, ifType string, ofPortRequest int32 Type: ifType, OFPortRequest: ofPortRequest, Options: optionMap, + MAC: mac, } ifNamedUUID := tx.Insert(dbtransaction.Insert{ Table: "Interface", diff --git a/pkg/ovs/ovsconfig/ovs_schema.go b/pkg/ovs/ovsconfig/ovs_schema.go index efc6ae2e512..81c8784c030 100644 --- a/pkg/ovs/ovsconfig/ovs_schema.go +++ b/pkg/ovs/ovsconfig/ovs_schema.go @@ -36,4 +36,5 @@ type Interface struct { Type string `json:"type,omitempty"` OFPortRequest int32 `json:"ofport_request,omitempty"` Options []interface{} `json:"options,omitempty"` + MAC string `json:"mac,omitempty"` } diff --git a/pkg/ovs/ovsconfig/testing/mock_ovsconfig.go b/pkg/ovs/ovsconfig/testing/mock_ovsconfig.go index fe0ae94fe16..0050086fe56 100644 --- a/pkg/ovs/ovsconfig/testing/mock_ovsconfig.go +++ b/pkg/ovs/ovsconfig/testing/mock_ovsconfig.go @@ -106,18 +106,18 @@ func (mr *MockOVSBridgeClientMockRecorder) CreateAccessPort(arg0, arg1, arg2, ar } // CreateInternalPort mocks base method -func (m *MockOVSBridgeClient) CreateInternalPort(arg0 string, arg1 int32, arg2 map[string]interface{}) (string, ovsconfig.Error) { +func (m *MockOVSBridgeClient) CreateInternalPort(arg0 string, arg1 int32, arg2 string, arg3 map[string]interface{}) (string, ovsconfig.Error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateInternalPort", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "CreateInternalPort", arg0, arg1, arg2, arg3) ret0, _ := ret[0].(string) ret1, _ := ret[1].(ovsconfig.Error) return ret0, ret1 } // CreateInternalPort indicates an expected call of CreateInternalPort -func (mr *MockOVSBridgeClientMockRecorder) CreateInternalPort(arg0, arg1, arg2 interface{}) *gomock.Call { +func (mr *MockOVSBridgeClientMockRecorder) CreateInternalPort(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateInternalPort", reflect.TypeOf((*MockOVSBridgeClient)(nil).CreateInternalPort), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateInternalPort", reflect.TypeOf((*MockOVSBridgeClient)(nil).CreateInternalPort), arg0, arg1, arg2, arg3) } // CreatePort mocks base method diff --git a/test/integration/ovs/ovs_client_test.go b/test/integration/ovs/ovs_client_test.go index d3e86f87801..74a4162ff14 100644 --- a/test/integration/ovs/ovs_client_test.go +++ b/test/integration/ovs/ovs_client_test.go @@ -312,7 +312,7 @@ func testCreatePort(t *testing.T, br *ovsconfig.OVSBridge, name string, ifType s } case "internal": externalIDs = map[string]interface{}{"k1": "v1", "k2": "v2"} - uuid, err = br.CreateInternalPort(name, ofPortRequest, externalIDs) + uuid, err = br.CreateInternalPort(name, ofPortRequest, "", externalIDs) case "vxlan": externalIDs = map[string]interface{}{} uuid, err = br.CreateTunnelPort(name, ovsconfig.VXLANTunnel, ofPortRequest)