Skip to content

Commit cba501f

Browse files
committed
Ensure OVS port is valid before setting NO_FLOOD (#4674)
There could be some cases that OVS ports are left invalid. Setting NO_FLOOD for these ports will fail for sure and restarting agents would just meet the same error. Later we should enhance the port cleanup logic, either when they are firstly identified, or when their owners do the initialization. For now, as there could be invalid ports in interface cache, we should ensure a port is valid before setting NO_FLOOD. Signed-off-by: Quan Tian <qtian@vmware.com>
1 parent 7acf82c commit cba501f

6 files changed

Lines changed: 87 additions & 12 deletions

File tree

cmd/antrea-agent/agent.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ func run(o *Options) error {
222222
agentInitializer := agent.NewInitializer(
223223
k8sClient,
224224
ovsBridgeClient,
225+
ovsctl.NewClient(o.config.OVSBridge),
225226
ofClient,
226227
routeClient,
227228
ifaceStore,

pkg/agent/agent.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ var otherConfigKeysForIPsecCertificates = []string{"certificate", "private_key",
9090
type Initializer struct {
9191
client clientset.Interface
9292
ovsBridgeClient ovsconfig.OVSBridgeClient
93+
ovsCtlClient ovsctl.OVSCtlClient
9394
ofClient openflow.Client
9495
routeClient route.Interface
9596
wireGuardClient wireguard.Interface
@@ -114,6 +115,7 @@ type Initializer struct {
114115
func NewInitializer(
115116
k8sClient clientset.Interface,
116117
ovsBridgeClient ovsconfig.OVSBridgeClient,
118+
ovsCtlClient ovsctl.OVSCtlClient,
117119
ofClient openflow.Client,
118120
routeClient route.Interface,
119121
ifaceStore interfacestore.InterfaceStore,
@@ -132,6 +134,7 @@ func NewInitializer(
132134
) *Initializer {
133135
return &Initializer{
134136
ovsBridgeClient: ovsBridgeClient,
137+
ovsCtlClient: ovsCtlClient,
135138
client: k8sClient,
136139
ifaceStore: ifaceStore,
137140
ofClient: ofClient,
@@ -348,17 +351,20 @@ func (i *Initializer) initInterfaceStore() error {
348351
}
349352

350353
func (i *Initializer) restorePortConfigs() error {
351-
ovsCtlClient := ovsctl.NewClient(i.ovsBridge)
352354
interfaces := i.ifaceStore.ListInterfaces()
353355
for _, intf := range interfaces {
354356
switch intf.Type {
355357
case interfacestore.IPSecTunnelInterface:
356358
fallthrough
357359
case interfacestore.TrafficControlInterface:
358-
if err := ovsCtlClient.SetPortNoFlood(int(intf.OFPort)); err != nil {
359-
return fmt.Errorf("failed to set port %s with no-flood: %w", intf.InterfaceName, err)
360+
if intf.OFPort < 0 {
361+
klog.InfoS("Skipped setting no-flood for port due to invalid ofPort", "port", intf.InterfaceName, "ofport", intf.OFPort)
362+
continue
363+
}
364+
if err := i.ovsCtlClient.SetPortNoFlood(int(intf.OFPort)); err != nil {
365+
return fmt.Errorf("failed to set no-flood for port %s: %w", intf.InterfaceName, err)
360366
}
361-
klog.InfoS("Set port no-flood successfully", "PortName", intf.InterfaceName)
367+
klog.InfoS("Set no-flood for port", "port", intf.InterfaceName)
362368
}
363369
}
364370
return nil

pkg/agent/agent_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"antrea.io/antrea/pkg/agent/types"
3838
"antrea.io/antrea/pkg/ovs/ovsconfig"
3939
ovsconfigtest "antrea.io/antrea/pkg/ovs/ovsconfig/testing"
40+
ovsctltest "antrea.io/antrea/pkg/ovs/ovsctl/testing"
4041
"antrea.io/antrea/pkg/util/env"
4142
"antrea.io/antrea/pkg/util/ip"
4243
)
@@ -516,3 +517,72 @@ func mockConfigureLinkAddress(returnedErr error) func() {
516517
configureLinkAddresses = originalConfigureLinkAddresses
517518
}
518519
}
520+
521+
func TestRestorePortConfigs(t *testing.T) {
522+
ipsecTunnelInterface := interfacestore.NewIPSecTunnelInterface("antrea-ipsec1",
523+
ovsconfig.GeneveTunnel,
524+
"node1",
525+
net.ParseIP("1.1.1.1"),
526+
"abcdefg",
527+
"node1")
528+
ipsecTunnelInterface.OVSPortConfig = &interfacestore.OVSPortConfig{OFPort: 11, PortUUID: "uuid1"}
529+
tunnelInterface := interfacestore.NewTunnelInterface(defaultTunInterfaceName,
530+
ovsconfig.GeneveTunnel,
531+
net.ParseIP("1.1.1.10"),
532+
true)
533+
tunnelInterface.OVSPortConfig = &interfacestore.OVSPortConfig{OFPort: 12}
534+
535+
tests := []struct {
536+
name string
537+
existingInterfaces []*interfacestore.InterfaceConfig
538+
expectedOVSCtlCalls func(client *ovsctltest.MockOVSCtlClientMockRecorder)
539+
expectedErr string
540+
}{
541+
{
542+
name: "success",
543+
existingInterfaces: []*interfacestore.InterfaceConfig{
544+
ipsecTunnelInterface,
545+
tunnelInterface,
546+
interfacestore.NewTrafficControlInterface("antrea-tap1",
547+
&interfacestore.OVSPortConfig{OFPort: 13, PortUUID: "uuid3"}),
548+
interfacestore.NewTrafficControlInterface("antrea-tap2",
549+
&interfacestore.OVSPortConfig{OFPort: -1, PortUUID: "uuid3"}),
550+
},
551+
expectedOVSCtlCalls: func(client *ovsctltest.MockOVSCtlClientMockRecorder) {
552+
client.SetPortNoFlood(11).Return(nil)
553+
client.SetPortNoFlood(13).Return(nil)
554+
},
555+
},
556+
{
557+
name: "fail",
558+
existingInterfaces: []*interfacestore.InterfaceConfig{
559+
interfacestore.NewTrafficControlInterface("antrea-tap1",
560+
&interfacestore.OVSPortConfig{OFPort: 10, PortUUID: "uuid3"}),
561+
},
562+
expectedOVSCtlCalls: func(client *ovsctltest.MockOVSCtlClientMockRecorder) {
563+
client.SetPortNoFlood(10).Return(fmt.Errorf("server unavailable"))
564+
},
565+
expectedErr: "failed to set no-flood for port antrea-tap1: server unavailable",
566+
},
567+
}
568+
for _, tt := range tests {
569+
t.Run(tt.name, func(t *testing.T) {
570+
controller := mock.NewController(t)
571+
defer controller.Finish()
572+
mockOVSCtlClient := ovsctltest.NewMockOVSCtlClient(controller)
573+
ifaceStore := interfacestore.NewInterfaceStore()
574+
initializer := &Initializer{
575+
ifaceStore: ifaceStore,
576+
ovsCtlClient: mockOVSCtlClient,
577+
}
578+
ifaceStore.Initialize(tt.existingInterfaces)
579+
tt.expectedOVSCtlCalls(mockOVSCtlClient.EXPECT())
580+
err := initializer.restorePortConfigs()
581+
if tt.expectedErr == "" {
582+
assert.NoError(t, err)
583+
} else {
584+
assert.ErrorContains(t, err, tt.expectedErr)
585+
}
586+
})
587+
}
588+
}

pkg/agent/controller/trafficcontrol/controller.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -762,8 +762,7 @@ func (c *Controller) getOrCreateTrafficControlPort(port *v1alpha2.TrafficControl
762762
return 0, err
763763
}
764764
}
765-
itf := interfacestore.NewTrafficControlInterface(portName)
766-
itf.OVSPortConfig = &interfacestore.OVSPortConfig{PortUUID: portUUID, OFPort: ofPort}
765+
itf := interfacestore.NewTrafficControlInterface(portName, &interfacestore.OVSPortConfig{PortUUID: portUUID, OFPort: ofPort})
767766
c.interfaceStore.AddInterface(itf)
768767
// Create binding for the newly created port.
769768
c.portToTCBindings[portName] = &portToTCBinding{

pkg/agent/interfacestore/interface_cache_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -166,12 +166,11 @@ func testUplinkInterface(t *testing.T) {
166166
}
167167

168168
func testTrafficControlInterface(t *testing.T) {
169-
tcInterface := NewTrafficControlInterface("tc0")
170-
tcInterface.IPs = []net.IP{hostIP}
171-
tcInterface.OVSPortConfig = &OVSPortConfig{
169+
tcInterface := NewTrafficControlInterface("tc0", &OVSPortConfig{
172170
OFPort: 17,
173171
PortUUID: "1234567890",
174-
}
172+
})
173+
tcInterface.IPs = []net.IP{hostIP}
175174
testGeneralInterface(t, tcInterface, TrafficControlInterface)
176175
}
177176

pkg/agent/interfacestore/types.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ func NewHostInterface(hostInterfaceName string) *InterfaceConfig {
171171
return &InterfaceConfig{InterfaceName: hostInterfaceName, Type: HostInterface}
172172
}
173173

174-
func NewTrafficControlInterface(interfaceName string) *InterfaceConfig {
175-
trafficControlConfig := &InterfaceConfig{InterfaceName: interfaceName, Type: TrafficControlInterface}
174+
func NewTrafficControlInterface(interfaceName string, ovsPortConfig *OVSPortConfig) *InterfaceConfig {
175+
trafficControlConfig := &InterfaceConfig{InterfaceName: interfaceName, Type: TrafficControlInterface, OVSPortConfig: ovsPortConfig}
176176
return trafficControlConfig
177177
}
178178

0 commit comments

Comments
 (0)