Skip to content

Commit

Permalink
Restore NO_FLOOD to OVS ports after reconnecting the OVS bridge
Browse files Browse the repository at this point in the history
The NO_FLOOD configuration is lost when the OVS daemon is restarted.
Currently, the only way to recover this configuration is by restarting
the agent. This pull request adds logic to recover the configuration
when receiving OVS reconnection events.

Signed-off-by: Xu Liu <[email protected]>
  • Loading branch information
xliuxu committed Feb 27, 2023
1 parent d5dd02e commit d2472a2
Show file tree
Hide file tree
Showing 5 changed files with 68 additions and 8 deletions.
41 changes: 35 additions & 6 deletions pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@ func (i *Initializer) initInterfaceStore() error {
return intf
}
ifaceList := make([]*interfacestore.InterfaceConfig, 0, len(ovsPorts))
ovsCtlClient := ovsctl.NewClient(i.ovsBridge)
for index := range ovsPorts {
port := &ovsPorts[index]
ovsPort := &interfacestore.OVSPortConfig{
Expand Down Expand Up @@ -322,9 +321,8 @@ func (i *Initializer) initInterfaceStore() error {
intf = cniserver.ParseOVSPortInterfaceConfig(port, ovsPort)
case interfacestore.AntreaTrafficControl:
intf = trafficcontrol.ParseTrafficControlInterfaceConfig(port, ovsPort)
if err := ovsCtlClient.SetPortNoFlood(int(ovsPort.OFPort)); err != nil {
klog.ErrorS(err, "Failed to set port with no-flood config", "PortName", port.Name)
}
case interfacestore.AntreaIPsec:
intf = noderoute.ParseTunnelInterfaceConfig(port, ovsPort)
default:
klog.InfoS("Unknown Antrea interface type", "type", interfaceType)
}
Expand All @@ -348,7 +346,11 @@ func (i *Initializer) initInterfaceStore() error {
fallthrough
case port.IFType == ovsconfig.STTTunnel:
intf = parseTunnelInterfaceFunc(port, ovsPort)
antreaIFType = interfacestore.AntreaTunnel
if intf.Type == interfacestore.IPSecTunnelInterface {
antreaIFType = interfacestore.AntreaIPsec
} else {
antreaIFType = interfacestore.AntreaTunnel
}
case port.Name == i.ovsBridge:
intf = nil
antreaIFType = interfacestore.AntreaHost
Expand Down Expand Up @@ -376,6 +378,23 @@ func (i *Initializer) initInterfaceStore() error {
return nil
}

func (i *Initializer) restorePortConfigs() error {
ovsCtlClient := ovsctl.NewClient(i.ovsBridge)
interfaces := i.ifaceStore.ListInterfaces()
for _, intf := range interfaces {
switch intf.Type {
case interfacestore.IPSecTunnelInterface:
fallthrough
case interfacestore.TrafficControlInterface:
if err := ovsCtlClient.SetPortNoFlood(int(intf.OFPort)); err != nil {
return fmt.Errorf("failed to set port %s with no-flood: %w", intf.InterfaceName, err)
}
klog.InfoS("Set port no-flood successfully", "PortName", intf.InterfaceName)
}
}
return nil
}

// Initialize sets up agent initial configurations.
func (i *Initializer) Initialize() error {
klog.Info("Setting up node network")
Expand All @@ -394,6 +413,10 @@ func (i *Initializer) Initialize() error {
return err
}

if err := i.restorePortConfigs(); err != nil {
return err
}

if i.enableL7NetworkPolicy {
// prepareL7NetworkPolicyInterfaces must be executed after setupOVSBridge since it requires interfaceStore.
if err := i.prepareL7NetworkPolicyInterfaces(); err != nil {
Expand Down Expand Up @@ -568,11 +591,17 @@ func (i *Initializer) initOpenFlowPipeline() error {
i.ofClient.ReplayFlows()
klog.Info("Flow replay completed")

klog.InfoS("Restoring OF port configs to OVS bridge")
if err := i.restorePortConfigs(); err != nil {
klog.ErrorS(err, "Failed to restore OF port configs")
} else {
klog.InfoS("Port configs restoration completed")
}
// ofClient and ovsBridgeClient have their own mechanisms to restore connections with OVS, and it could
// happen that ovsBridgeClient's connection is not ready when ofClient completes flow replay. We retry it
// with a timeout that is longer time than ovsBridgeClient's maximum connecting retry interval (8 seconds)
// to ensure the flag can be removed successfully.
err := wait.PollImmediate(200*time.Millisecond, 10*time.Second, func() (done bool, err error) {
err = wait.PollImmediate(200*time.Millisecond, 10*time.Second, func() (done bool, err error) {
if err := i.FlowRestoreComplete(); err != nil {
return false, nil
}
Expand Down
6 changes: 5 additions & 1 deletion pkg/agent/controller/noderoute/node_route_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -677,8 +677,11 @@ func (c *Controller) createIPSecTunnelPort(nodeName string, nodeIP net.IP) (int3
exists = false
}
}
ovsExternalIDs := map[string]interface{}{
ovsExternalIDNodeName: nodeName,
interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaIPsec,
}
if !exists {
ovsExternalIDs := map[string]interface{}{ovsExternalIDNodeName: nodeName}
portUUID, err := c.ovsBridgeClient.CreateTunnelPortExt(
portName,
c.networkConfig.TunnelType,
Expand Down Expand Up @@ -714,6 +717,7 @@ func (c *Controller) createIPSecTunnelPort(nodeName string, nodeIP net.IP) (int3
// Let NodeRouteController retry at errors.
return 0, fmt.Errorf("failed to get of_port of IPsec tunnel port for Node %s", nodeName)
}

// Set the port with no-flood to reject ARP flood packets.
if err := c.ovsCtlClient.SetPortNoFlood(int(ofPort)); err != nil {
return 0, fmt.Errorf("failed to set port %s with no-flood config: %w", portName, err)
Expand Down
9 changes: 9 additions & 0 deletions pkg/agent/interfacestore/interface_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,15 @@ func (c *interfaceCache) GetInterface(interfaceKey string) (*InterfaceConfig, bo
return iface.(*InterfaceConfig), found
}

// ListInterfacesByType lists all interfaces from local cache.
func (c *interfaceCache) ListInterfaces() []*InterfaceConfig {
interfaceConfigs := make([]*InterfaceConfig, 0)
for _, iface := range c.cache.List() {
interfaceConfigs = append(interfaceConfigs, iface.(*InterfaceConfig))
}
return interfaceConfigs
}

// GetInterfaceByName retrieves interface from local cache given the interface
// name.
func (c *interfaceCache) GetInterfaceByName(interfaceName string) (*InterfaceConfig, bool) {
Expand Down
14 changes: 14 additions & 0 deletions pkg/agent/interfacestore/testing/mock_interfacestore.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion pkg/agent/interfacestore/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ const (
TrafficControlInterface
// ExternalEntityInterface is used to mark current interface is for ExternalEntity Endpoint
ExternalEntityInterface
// IPSecTunnelInterface is used to mark current interface is for IPSec tunnel port
IPSecTunnelInterface

AntreaInterfaceTypeKey = "antrea-type"
AntreaGateway = "gateway"
Expand All @@ -43,6 +45,7 @@ const (
AntreaUplink = "uplink"
AntreaHost = "host"
AntreaTrafficControl = "traffic-control"
AntreaIPsec = "ipsec-tunnel"
AntreaUnset = ""
)

Expand Down Expand Up @@ -108,6 +111,7 @@ type InterfaceConfig struct {
type InterfaceStore interface {
Initialize(interfaces []*InterfaceConfig)
AddInterface(interfaceConfig *InterfaceConfig)
ListInterfaces() []*InterfaceConfig
DeleteInterface(interfaceConfig *InterfaceConfig)
GetInterface(interfaceKey string) (*InterfaceConfig, bool)
GetInterfaceByName(interfaceName string) (*InterfaceConfig, bool)
Expand Down Expand Up @@ -162,7 +166,7 @@ func NewTunnelInterface(tunnelName string, tunnelType ovsconfig.TunnelType, dest
// Node.
func NewIPSecTunnelInterface(interfaceName string, tunnelType ovsconfig.TunnelType, nodeName string, nodeIP net.IP, psk, remoteName string, ovsPortConfig *OVSPortConfig) *InterfaceConfig {
tunnelConfig := &TunnelInterfaceConfig{Type: tunnelType, NodeName: nodeName, RemoteIP: nodeIP, PSK: psk, RemoteName: remoteName}
return &InterfaceConfig{InterfaceName: interfaceName, Type: TunnelInterface, TunnelInterfaceConfig: tunnelConfig, OVSPortConfig: ovsPortConfig}
return &InterfaceConfig{InterfaceName: interfaceName, Type: IPSecTunnelInterface, TunnelInterfaceConfig: tunnelConfig, OVSPortConfig: ovsPortConfig}
}

// NewUplinkInterface creates InterfaceConfig for the uplink interface.
Expand Down

0 comments on commit d2472a2

Please sign in to comment.