diff --git a/cmd/antrea-agent/agent.go b/cmd/antrea-agent/agent.go index 7c663f57e89..97551b82cf4 100644 --- a/cmd/antrea-agent/agent.go +++ b/cmd/antrea-agent/agent.go @@ -728,6 +728,7 @@ func run(o *Options) error { } if features.DefaultFeatureGate.Enabled(features.SecondaryNetwork) { + defer secondarynetwork.RestoreOVSBridge(&o.config.SecondaryNetwork) if err := secondarynetwork.Initialize( o.config.ClientConnection, o.config.KubeAPIServerOverride, k8sClient, localPodInformer.Get(), nodeConfig.Name, diff --git a/pkg/agent/agent_linux.go b/pkg/agent/agent_linux.go index bc0b4fbeca9..18ddc34eea6 100644 --- a/pkg/agent/agent_linux.go +++ b/pkg/agent/agent_linux.go @@ -166,30 +166,6 @@ func (i *Initializer) saveHostRoutes() error { return nil } -// restoreHostRoutes restores the host routes which are lost when moving the IP -// configuration of uplink interface to the OVS bridge interface during -// the Antrea bridge initialization stage. -// The backup routes are restored after the IP configuration changes. -func (i *Initializer) restoreHostRoutes() error { - return i.restoreHostRoutesToInterface(i.nodeConfig.UplinkNetConfig.Name) -} - -func (i *Initializer) restoreHostRoutesToInterface(ifaceName string) error { - iface, err := net.InterfaceByName(ifaceName) - if err != nil { - return nil - } - for _, routeInterface := range i.nodeConfig.UplinkNetConfig.Routes { - route := routeInterface.(netlink.Route) - newRoute := route - newRoute.LinkIndex = iface.Index - if err := netlink.RouteReplace(&newRoute); err != nil { - return err - } - } - return nil -} - func (i *Initializer) ConnectUplinkToOVSBridge() error { // Return immediately on Linux if connectUplinkToBridge is false. if !i.connectUplinkToBridge { @@ -198,18 +174,24 @@ func (i *Initializer) ConnectUplinkToOVSBridge() error { klog.InfoS("Bridging uplink to OVS bridge") var err error uplinkNetConfig := i.nodeConfig.UplinkNetConfig - uplinkName := uplinkNetConfig.Name - bridgedUplinkName := util.GenerateUplinkInterfaceName(uplinkNetConfig.Name) - uplinkIPs := uplinkNetConfig.IPs - // If the uplink port already exists, just return. - if uplinkOFPort, err := i.ovsBridgeClient.GetOFPort(bridgedUplinkName, false); err == nil { - klog.InfoS("Uplink already exists, skip the configuration", "uplink", bridgedUplinkName, "port", uplinkOFPort) - return nil + externalIDs := map[string]interface{}{ + interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaHost, } - - if err := util.RenameInterface(uplinkName, bridgedUplinkName); err != nil { - return fmt.Errorf("failed to change uplink interface name: err=%w", err) + bridgedUplinkName, exists, err := util.PrepareHostInterfaceConnection( + i.ovsBridgeClient, + uplinkNetConfig.Name, + uplinkNetConfig.Index, + int32(i.nodeConfig.HostInterfaceOFPort), + uplinkNetConfig.MAC, + uplinkNetConfig.IPs, + uplinkNetConfig.Routes, + externalIDs) + if err != nil { + return err + } + if exists { + return nil } // Create uplink port. @@ -226,64 +208,6 @@ func (i *Initializer) ConnectUplinkToOVSBridge() error { 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.PollUntilContextTimeout(context.TODO(), 100*time.Millisecond, 10000*time.Millisecond, true, - func(ctx context.Context) (bool, error) { - // Wait a few seconds for OVS bridge local port. - link, err := netlink.LinkByName(uplinkName) - if err != nil { - 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 - }) - localLink, err := netlink.LinkByName(uplinkName) - if err != nil { - return err - } - if _, _, err = util.SetLinkUp(uplinkName); err != nil { - return err - } - - // Check if uplink is configured with an IPv6 address: if it is, we need to ensure that IPv6 - // is enabled on the OVS internal port as we need to move all IP addresses over. - uplinkHasIPv6Address := false - for _, ip := range uplinkIPs { - if ip.IP.To4() == nil { - uplinkHasIPv6Address = true - break - } - } - if uplinkHasIPv6Address { - klog.InfoS("Uplink has IPv6 address, ensuring that IPv6 is enabled on bridge local port", "port", uplinkName) - if err := util.EnsureIPv6EnabledOnInterface(uplinkName); err != nil { - klog.ErrorS(err, "Failed to ensure that IPv6 is enabled on bridge local port, moving uplink IPs to bridge is likely to fail", "port", uplinkName) - } - } - - if err = util.ConfigureLinkAddresses(localLink.Attrs().Index, uplinkIPs); err != nil { - return err - } - if err = util.ConfigureLinkAddresses(uplinkNetConfig.Index, nil); err != nil { - return err - } - // Restore the host routes which are lost when moving the network configuration of the - // uplink interface to OVS bridge interface. - if err = i.restoreHostRoutes(); err != nil { - return err - } - return nil } @@ -294,33 +218,15 @@ func (i *Initializer) RestoreOVSBridge() { return } klog.InfoS("Restoring bridge config to uplink...") - uplinkNetConfig := i.nodeConfig.UplinkNetConfig - uplinkName := "" - bridgedUplinkName := "" - if uplinkNetConfig != nil { - uplinkName = uplinkNetConfig.Name - bridgedUplinkName = util.GenerateUplinkInterfaceName(uplinkName) - } - brName := i.ovsBridge - if uplinkName != "" { - uplinkIPs := uplinkNetConfig.IPs - if err := util.DeleteOVSPort(brName, uplinkName); err != nil { - klog.ErrorS(err, "Delete OVS port failed", "port", uplinkName) - } - if err := util.DeleteOVSPort(brName, bridgedUplinkName); err != nil { - klog.ErrorS(err, "Delete OVS port failed", "port", bridgedUplinkName) - } - if err := util.RenameInterface(bridgedUplinkName, uplinkName); err != nil { - klog.ErrorS(err, "Restore uplink name failed", "uplink", bridgedUplinkName) - } - if err := util.ConfigureLinkAddresses(uplinkNetConfig.Index, uplinkIPs); err != nil { - klog.ErrorS(err, "Configure IP to uplink failed", "uplink", uplinkName) - } - if err := i.restoreHostRoutesToInterface(uplinkName); err != nil { - klog.ErrorS(err, "Configure route to uplink interface failed", "uplink", uplinkName) - } + _, ifaceIPs, ifaceRoutes, err := util.GetInterfaceConfig(i.nodeConfig.UplinkNetConfig.Name) + if err != nil { + klog.ErrorS(err, "Failed to get interface config", "interface", i.nodeConfig.UplinkNetConfig.Name) + ifaceIPs = i.nodeConfig.UplinkNetConfig.IPs + ifaceRoutes = i.nodeConfig.UplinkNetConfig.Routes } + + util.RestoreHostInterfaceConfiguration(i.ovsBridge, i.nodeConfig.UplinkNetConfig.Name, ifaceIPs, ifaceRoutes) klog.InfoS("Finished to restore bridge config to uplink...") } diff --git a/pkg/agent/secondarynetwork/init.go b/pkg/agent/secondarynetwork/init.go index 7333b6e5878..dfc5edea33e 100644 --- a/pkg/agent/secondarynetwork/init.go +++ b/pkg/agent/secondarynetwork/init.go @@ -27,6 +27,7 @@ import ( "antrea.io/antrea/pkg/agent/interfacestore" "antrea.io/antrea/pkg/agent/secondarynetwork/podwatch" + "antrea.io/antrea/pkg/agent/util" agentconfig "antrea.io/antrea/pkg/config/agent" "antrea.io/antrea/pkg/ovs/ovsconfig" "antrea.io/antrea/pkg/util/channel" @@ -48,13 +49,34 @@ func Initialize( nodeName string, podUpdateSubscriber channel.Subscriber, stopCh <-chan struct{}, - config *agentconfig.SecondaryNetworkConfig, ovsdb *ovsdb.OVSDB) error { + secNetConfig *agentconfig.SecondaryNetworkConfig, ovsdb *ovsdb.OVSDB) error { - ovsBridgeClient, err := createOVSBridge(config.OVSBridges, ovsdb) + ovsBridgeClient, err := createOVSBridge(secNetConfig.OVSBridges, ovsdb) if err != nil { return err } + // We only support moving and restoring of interface configuration to OVS Bridge for the single physical interface case. + phyInterfaces := make([]string, len(secNetConfig.OVSBridges[0].PhysicalInterfaces)) + copy(phyInterfaces, secNetConfig.OVSBridges[0].PhysicalInterfaces) + if len(phyInterfaces) == 1 { + externalIDs := map[string]interface{}{ + interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaHost, + } + ifaceName := phyInterfaces[0] + iface, ifaceIPs, ifaceRoutes, err := util.GetInterfaceConfig(ifaceName) + bridgedName, _, err := util.PrepareHostInterfaceConnection(ovsBridgeClient, iface.Name, iface.Index, + 0, iface.HardwareAddr, ifaceIPs, ifaceRoutes, externalIDs) + if err != nil { + return err + } + phyInterfaces[0] = bridgedName + } + + if err = connectPhyInterfacesToOVSBridge(ovsBridgeClient, phyInterfaces); err != nil { + return err + } + // Create the NetworkAttachmentDefinition client, which handles access to secondary network object // definition from the API Server. netAttachDefClient, err := createNetworkAttachDefClient(clientConnectionConfig, kubeAPIServerOverride) @@ -74,38 +96,54 @@ func Initialize( return nil } -// TODO: check and update bridge configuration. +// RestoreOVSBridge restores interface configuration from secondary-bridge back to host-interface. +func RestoreOVSBridge(secNetConfig *agentconfig.SecondaryNetworkConfig) { + if len(secNetConfig.OVSBridges[0].PhysicalInterfaces) == 1 { + iface, ifaceIPs, ifaceRoutes, err := util.GetInterfaceConfig(secNetConfig.OVSBridges[0].PhysicalInterfaces[0]) + if err != nil { + klog.ErrorS(err, "Failed to get interface config", "interface", secNetConfig.OVSBridges[0].PhysicalInterfaces[0]) + return + } + util.RestoreHostInterfaceConfiguration(secNetConfig.OVSBridges[0].BridgeName, iface.Name, ifaceIPs, ifaceRoutes) + } +} + func createOVSBridge(bridges []agentconfig.OVSBridgeConfig, ovsdb *ovsdb.OVSDB) (ovsconfig.OVSBridgeClient, error) { if len(bridges) == 0 { return nil, nil } // Only one OVS bridge is supported. bridgeConfig := bridges[0] - - for _, phyInterface := range bridgeConfig.PhysicalInterfaces { - if _, err := interfaceByNameFn(phyInterface); err != nil { - return nil, fmt.Errorf("failed to get interface %s: %v", phyInterface, err) - } - } - ovsBridgeClient := newOVSBridgeFn(bridgeConfig.BridgeName, ovsconfig.OVSDatapathSystem, ovsdb) if err := ovsBridgeClient.Create(); err != nil { return nil, fmt.Errorf("failed to create OVS bridge %s: %v", bridgeConfig.BridgeName, err) } klog.InfoS("OVS bridge created", "bridge", bridgeConfig.BridgeName) + return ovsBridgeClient, nil +} + +func connectPhyInterfacesToOVSBridge(ovsBridgeClient ovsconfig.OVSBridgeClient, phyInterfaces []string) error { + for _, phyInterface := range phyInterfaces { + if _, err := interfaceByNameFn(phyInterface); err != nil { + return fmt.Errorf("failed to get interface %s: %v", phyInterface, err) + } + } - for i, phyInterface := range bridgeConfig.PhysicalInterfaces { + externalIDs := map[string]interface{}{ + interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUplink, + } + for i, phyInterface := range phyInterfaces { if _, err := ovsBridgeClient.GetOFPort(phyInterface, false); err == nil { - klog.V(2).InfoS("Physical interface already connected to OVS bridge, skip the configuration", "device", phyInterface, "bridge", bridgeConfig.BridgeName) + klog.V(2).InfoS("Physical interface already connected to secondary OVS bridge, skip the configuration", "device", phyInterface) continue } - if _, err := ovsBridgeClient.CreateUplinkPort(phyInterface, int32(i), map[string]interface{}{interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUplink}); err != nil { - return nil, fmt.Errorf("failed to create OVS uplink port %s: %v", phyInterface, err) + if _, err := ovsBridgeClient.CreateUplinkPort(phyInterface, int32(i), externalIDs); err != nil { + return fmt.Errorf("failed to create OVS uplink port %s: %v", phyInterface, err) } - klog.InfoS("Physical interface added to OVS bridge", "device", phyInterface, "bridge", bridgeConfig.BridgeName) + klog.InfoS("Physical interface added to secondary OVS bridge", "device", phyInterface) } - return ovsBridgeClient, nil + return nil } // CreateNetworkAttachDefClient creates net-attach-def client handle from the given config. diff --git a/pkg/agent/secondarynetwork/init_test.go b/pkg/agent/secondarynetwork/init_test.go index b9be6fe0fd2..49de49a7afd 100644 --- a/pkg/agent/secondarynetwork/init_test.go +++ b/pkg/agent/secondarynetwork/init_test.go @@ -33,11 +33,10 @@ const nonExistingInterface = "non-existing" func TestCreateOVSBridge(t *testing.T) { tests := []struct { - name string - ovsBridges []string - physicalInterfaces []string - expectedErr string - expectedCalls func(m *ovsconfigtest.MockOVSBridgeClient) + name string + ovsBridges []string + expectedErr string + expectedCalls func(m *ovsconfigtest.MockOVSBridgeClient) }{ { name: "no bridge", @@ -64,22 +63,56 @@ func TestCreateOVSBridge(t *testing.T) { m.EXPECT().Create().Return(ovsconfig.InvalidArgumentsError("create error")) }, }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + var bridges []agentconfig.OVSBridgeConfig + for _, brName := range tc.ovsBridges { + br := agentconfig.OVSBridgeConfig{BridgeName: brName} + bridges = append(bridges, br) + } + + controller := mock.NewController(t) + mockOVSBridgeClient := ovsconfigtest.NewMockOVSBridgeClient(controller) + + mockNewOVSBridge(t, mockOVSBridgeClient) + if tc.expectedCalls != nil { + tc.expectedCalls(mockOVSBridgeClient) + } + + brClient, err := createOVSBridge(bridges, nil) + if tc.expectedErr != "" { + assert.ErrorContains(t, err, tc.expectedErr) + assert.Nil(t, brClient) + } else { + require.NoError(t, err) + if tc.expectedCalls != nil { + assert.NotNil(t, brClient) + } + } + }) + } +} + +func TestConnectPhyInterfacesToOVSBridge(t *testing.T) { + tests := []struct { + name string + physicalInterfaces []string + expectedErr string + expectedCalls func(m *ovsconfigtest.MockOVSBridgeClient) + }{ { name: "one interface", - ovsBridges: []string{"br1"}, - physicalInterfaces: []string{"eth1"}, + physicalInterfaces: []string{"eth0~"}, expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) { - m.EXPECT().Create().Return(nil) - m.EXPECT().GetOFPort("eth1", false).Return(int32(0), ovsconfig.InvalidArgumentsError("port not found")) - m.EXPECT().CreateUplinkPort("eth1", int32(0), map[string]interface{}{"antrea-type": "uplink"}).Return("", nil) + m.EXPECT().GetOFPort("eth0~", false).Return(int32(0), ovsconfig.InvalidArgumentsError("port not found")) + m.EXPECT().CreateUplinkPort("eth0~", int32(0), map[string]interface{}{"antrea-type": "uplink"}).Return("", nil) }, }, { name: "two interfaces", - ovsBridges: []string{"br1", "br2"}, physicalInterfaces: []string{"eth1", "eth2"}, expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) { - m.EXPECT().Create().Return(nil) m.EXPECT().GetOFPort("eth1", false).Return(int32(0), ovsconfig.InvalidArgumentsError("port not found")) m.EXPECT().CreateUplinkPort("eth1", int32(0), map[string]interface{}{"antrea-type": "uplink"}).Return("", nil) m.EXPECT().GetOFPort("eth2", false).Return(int32(1), ovsconfig.InvalidArgumentsError("port not found")) @@ -88,26 +121,21 @@ func TestCreateOVSBridge(t *testing.T) { }, { name: "interface already attached", - ovsBridges: []string{"br1"}, physicalInterfaces: []string{"eth1"}, expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) { - m.EXPECT().Create().Return(nil) m.EXPECT().GetOFPort("eth1", false).Return(int32(0), nil) }, }, { name: "non-existing interface", - ovsBridges: []string{"br1"}, physicalInterfaces: []string{nonExistingInterface, "eth2"}, expectedErr: "failed to get interface", }, { name: "create port error", - ovsBridges: []string{"br1"}, physicalInterfaces: []string{"eth1"}, expectedErr: "create error", expectedCalls: func(m *ovsconfigtest.MockOVSBridgeClient) { - m.EXPECT().Create().Return(nil) m.EXPECT().GetOFPort("eth1", false).Return(int32(0), ovsconfig.InvalidArgumentsError("port not found")) m.EXPECT().CreateUplinkPort("eth1", int32(0), map[string]interface{}{"antrea-type": "uplink"}).Return("", ovsconfig.InvalidArgumentsError("create error")) }, @@ -115,31 +143,20 @@ func TestCreateOVSBridge(t *testing.T) { } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - var bridges []agentconfig.OVSBridgeConfig - for _, brName := range tc.ovsBridges { - br := agentconfig.OVSBridgeConfig{BridgeName: brName} - br.PhysicalInterfaces = tc.physicalInterfaces - bridges = append(bridges, br) - } controller := mock.NewController(t) mockOVSBridgeClient := ovsconfigtest.NewMockOVSBridgeClient(controller) - mockNewOVSBridge(t, mockOVSBridgeClient) mockInterfaceByName(t) if tc.expectedCalls != nil { tc.expectedCalls(mockOVSBridgeClient) } - brClient, err := createOVSBridge(bridges, nil) + err := connectPhyInterfacesToOVSBridge(mockOVSBridgeClient, tc.physicalInterfaces) if tc.expectedErr != "" { assert.ErrorContains(t, err, tc.expectedErr) - assert.Nil(t, brClient) } else { - require.NoError(t, err) - if tc.expectedCalls != nil { - assert.NotNil(t, brClient) - } + assert.NoError(t, err) } }) } diff --git a/pkg/agent/util/net_linux.go b/pkg/agent/util/net_linux.go index 301691fb717..074392c6032 100644 --- a/pkg/agent/util/net_linux.go +++ b/pkg/agent/util/net_linux.go @@ -35,6 +35,7 @@ import ( utilnetlink "antrea.io/antrea/pkg/agent/util/netlink" "antrea.io/antrea/pkg/agent/util/sysctl" + "antrea.io/antrea/pkg/ovs/ovsconfig" ) var ( @@ -240,10 +241,19 @@ func SetAdapterMACAddress(adapterName string, macConfig *net.HardwareAddr) error return netlinkUtil.LinkSetHardwareAddr(link, *macConfig) } -// DeleteOVSPort deletes specific OVS port. This function calls ovs-vsctl command to bypass OVS bridge client to work when agent exiting. -func DeleteOVSPort(brName, portName string) error { - cmd := exec.Command("ovs-vsctl", "--if-exists", "del-port", brName, portName) - return cmd.Run() +// deleteOVSPort deletes the port from the given bridge. It returns an error if +// the deletion fails for an existing port and additionally returns if port exists. +// This function calls ovs-vsctl command to bypass OVS bridge client to work when agent exiting. +func deleteOVSPort(brName, portName string) (bool, error) { + cmd := exec.Command("ovs-vsctl", "del-port", brName, portName) + output, err := cmd.CombinedOutput() + if err != nil { + if strings.Contains(string(output), "no port named") { + return false, nil + } + return false, err + } + return true, nil } func HostInterfaceExists(ifName string) bool { @@ -376,3 +386,124 @@ func renameHostInterface(oriName string, newName string) error { } return nil } + +// PrepareHostInterfaceConnection prepares uplink connection to the OVS bridge client by: +// 1. Renaming the uplink (a bridged suffix will be added to it). +// 2. Creating an internal port (original name of the uplink will be used here). +// 3. Moving IPs of uplink to this new link/internal-port. +// 4. Moving routes of uplink to the new link/internal-port. +// and returns the bridged name, true if it already exists, and error. +func PrepareHostInterfaceConnection( + bridge ovsconfig.OVSBridgeClient, + interfaceName string, + interfaceIndex int, + interfaceOFPort int32, + interfaceMAC net.HardwareAddr, + interfaceIPs []*net.IPNet, + interfaceRoutes []interface{}, + externalIDs map[string]interface{}, +) (string, bool, error) { + bridgedName := GenerateUplinkInterfaceName(interfaceName) + // If the uplink port already exists, just return. + if uplinkOFPort, err := bridge.GetOFPort(bridgedName, false); err == nil { + klog.InfoS("Uplink already exists, skip the configuration", "uplink", bridgedName, "port", uplinkOFPort) + return "", true, nil + } + + if err := RenameInterface(interfaceName, bridgedName); err != nil { + return "", false, err + } + if _, err := bridge.CreateInternalPort(interfaceName, interfaceOFPort, interfaceMAC.String(), externalIDs); err != nil { + return "", false, fmt.Errorf("failed to create internal port: %v", 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. + if err := wait.PollImmediate(100*time.Millisecond, 10*time.Second, func() (bool, error) { + // Wait a few seconds for OVS bridge local port. + link, err := netlink.LinkByName(interfaceName) + if err != nil { + klog.V(4).InfoS("OVS bridge local port is not ready", "port", interfaceName, "err", err) + return false, nil + } + klog.InfoS("OVS bridge local port is ready", "type", link.Type(), "attrs", link.Attrs()) + return true, nil + }); err != nil { + return "", false, fmt.Errorf("failed waiting for internal port to show up: %v", err) + } + + localLink, err := netlink.LinkByName(interfaceName) + if err != nil { + return "", false, err + } + if _, _, err = SetLinkUp(interfaceName); err != nil { + return "", false, fmt.Errorf("failed to set link up: %v", err) + } + + // Check if interface is configured with an IPv6 address: if it is, we need to ensure that IPv6 + // is enabled on the OVS internal port as we need to move all IP addresses over. + for _, ip := range interfaceIPs { + if ip.IP.To4() == nil { + klog.InfoS("Interface has IPv6 address, ensuring that IPv6 is enabled on bridge local port", "port", interfaceName) + if err := EnsureIPv6EnabledOnInterface(interfaceName); err != nil { + klog.ErrorS(err, "Failed to ensure that IPv6 is enabled on bridge local port, moving uplink IPs to bridge is likely to fail", "port", interfaceName) + } + break + } + } + + if err = ConfigureLinkAddresses(localLink.Attrs().Index, interfaceIPs); err != nil { + return "", false, err + } + if err = ConfigureLinkAddresses(interfaceIndex, nil); err != nil { + return "", false, err + } + // Restore the host routes which are lost when moving the network configuration of the + // uplink interface to OVS bridge interface. + if err = ConfigureLinkRoutes(localLink, interfaceRoutes); err != nil { + return "", false, err + } + return bridgedName, false, nil +} + +// RestoreHostInterfaceConfiguration restore the configuration from bridge back to host interface, revering the +// actions taken in PrepareHostInterfaceConnection. +func RestoreHostInterfaceConfiguration( + brName string, + interfaceName string, + interfaceIPs []*net.IPNet, + interfaceRoutes []interface{}, +) { + klog.InfoS("Restoring bridge config to uplink...") + if interfaceName != "" { + bridgedName := GenerateUplinkInterfaceName(interfaceName) + + if exists, err := deleteOVSPort(brName, bridgedName); err != nil { + if !exists { + klog.InfoS("bridged port doesn't exists, skipping restoring host interface configuration", "bridgedPort", bridgedName) + return + } + klog.ErrorS(err, "Delete OVS port failed", "port", bridgedName) + } + + if _, err := deleteOVSPort(brName, interfaceName); err != nil { + klog.ErrorS(err, "Delete OVS port failed", "port", interfaceName) + } + + if err := RenameInterface(bridgedName, interfaceName); err != nil { + klog.ErrorS(err, "Restore uplink name failed", "uplink", bridgedName) + } + + link, err := netlink.LinkByName(interfaceName) + if err != nil { + klog.ErrorS(err, "failed to get link", "interface", interfaceName) + } + if err = ConfigureLinkAddresses(link.Attrs().Index, interfaceIPs); err != nil { + klog.ErrorS(err, "Configure IP to uplink failed", "uplink", interfaceName) + } + if err = ConfigureLinkRoutes(link, interfaceRoutes); err != nil { + klog.ErrorS(err, "Configure route to uplink interface failed", "uplink", interfaceName) + } + } + klog.InfoS("Finished to restore bridge config to uplink...") +}