From 22b4aa2cb8a0b424001eea84a680fbfbf45f83dd Mon Sep 17 00:00:00 2001 From: Wenqi Qiu Date: Wed, 27 Apr 2022 14:56:46 +0800 Subject: [PATCH] rebase and add unit test Signed-off-by: Wenqi Qiu --- .../controller/trafficcontrol/controller.go | 178 ++++++++++++------ .../trafficcontrol/controller_test.go | 97 ++++++---- pkg/agent/openflow/client.go | 26 +-- pkg/agent/openflow/testing/mock_openflow.go | 32 ++-- 4 files changed, 215 insertions(+), 118 deletions(-) diff --git a/pkg/agent/controller/trafficcontrol/controller.go b/pkg/agent/controller/trafficcontrol/controller.go index 02fe1c32e1b..0e00c10d0ee 100644 --- a/pkg/agent/controller/trafficcontrol/controller.go +++ b/pkg/agent/controller/trafficcontrol/controller.go @@ -16,10 +16,12 @@ package trafficcontrol import ( "fmt" + "strconv" "strings" "sync" "time" + uuid "github.com/satori/go.uuid" v1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -41,15 +43,26 @@ import ( ) const ( - controllerName = "TrafficControlController" - defaultWorkers = 4 - resyncPeriod = 0 + controllerName = "TrafficControlController" + defaultWorkers = 4 + resyncPeriod = 0 + defaultVXLANTunnelDestinationPort = 4789 + defaultGENEVETunnelDestinationPort = 6081 + portNamePrefixVXLAN = "vxlan" + portNamePrefixGENEVE = "geneve" + portNamePrefixGRE = "gre" + portNamePrefixERSPAN = "erspan" +) + +var ( + // 1133a2c3-a42c-4c36-9396-5f17ec9541c5 was generated using uuid.NewV4() function. + uuidNamespace = uuid.FromStringOrNil("1133a2c3-a42c-4c36-9396-5f17ec9541c5") ) type tcState struct { ofPorts sets.Int32 pods sets.String - dstOfInPort uint32 + targetPort uint32 dstOfOutPort uint32 } @@ -241,50 +254,90 @@ func (c *Controller) filterPods(appliedTo *v1alpha2.AppliedTo) ([]*v1.Pod, error return c.podLister.List(podSelector) } -func (c *Controller) getDevicePort(device *v1alpha2.OVSPort) (ofPort uint32, err error) { - // TODO:Not tested yet - if device == nil || device.Name == "" { - return 0, fmt.Errorf("device is invalid") +func genName(name string) string { + return uuid.NewV5(uuidNamespace, name).String() +} + +func genPortNameUDPTunnel(tunnel *v1alpha2.UDPTunnel) string { + names := []string{tunnel.RemoteIP} + if tunnel.DestinationPort != nil { + names = append(names, strconv.Itoa(int(*tunnel.DestinationPort))) + } + if tunnel.VNI != nil { + names = append(names, strconv.Itoa(int(*tunnel.VNI))) + } + normalizedName := strings.Join(names, " And ") + return genName(normalizedName) +} + +func genPortNameGRETunnel(tunnel *v1alpha2.GRETunnel) string { + names := []string{tunnel.RemoteIP} + if tunnel.Key != nil { + names = append(names, strconv.Itoa(int(*tunnel.Key))) + } + normalizedName := strings.Join(names, " And ") + return genName(normalizedName) +} + +func genPortNameERSPANTunnel(tunnel *v1alpha2.ERSPANTunnel) string { + names := []string{tunnel.RemoteIP, strconv.Itoa(int(tunnel.Version))} + if tunnel.SessionID != nil { + names = append(names, strconv.Itoa(int(*tunnel.SessionID))) + } + if tunnel.Index != nil { + names = append(names, strconv.Itoa(int(*tunnel.Index))) } - itf, ok := c.interfaceStore.GetInterfaceByName(device.Name) - if ok { - return uint32(itf.OFPort), nil + if tunnel.Dir != nil { + names = append(names, strconv.Itoa(int(*tunnel.Dir))) } - if ofPort, err := c.ovsBridgeClient.GetOFPort(device.Name, false); err == nil { - return uint32(ofPort), nil + if tunnel.HardwareID != nil { + names = append(names, strconv.Itoa(int(*tunnel.HardwareID))) + } + normalizedName := strings.Join(names, " And ") + return genName(normalizedName) +} + +func (c *Controller) getDevicePort(device *v1alpha2.TrafficControlPort) (ofPort uint32, err error) { + // TODO:Not tested yet + if device == nil { + return 0, fmt.Errorf("device is invalid") } var ofPortTmp int32 - createTunnelPortExt := func(tunnelType ovsconfig.TunnelType) error { - tunnelConfig := device.TunnelConfig - remoteIP := tunnelConfig.RemoteIP + createUDPTunnel := func(tunnelType ovsconfig.TunnelType, portName, remoteIP string, dstPort int32) error { externalIDs := map[string]interface{}{ interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaTunnel, } + if dstPort != 0 { + externalIDs["dst_port"] = dstPort + } c.ovsPortUpdateMutex.Lock() defer c.ovsPortUpdateMutex.Unlock() portUUID, err := c.ovsBridgeClient.CreateTunnelPortExt( - device.Name, tunnelType, 0, false, "", remoteIP, "", externalIDs) + portName, tunnelType, 0, false, "", remoteIP, "", externalIDs) if err != nil { return err } - ofPortTmp, err = c.ovsBridgeClient.GetOFPort(device.Name, false) + ofPortTmp, err = c.ovsBridgeClient.GetOFPort(portName, false) if err != nil { return err } - itf := interfacestore.NewTunnelInterface(device.Name, tunnelType, nil, false) + itf := interfacestore.NewTunnelInterface(portName, tunnelType, nil, false) itf.OVSPortConfig = &interfacestore.OVSPortConfig{PortUUID: portUUID, OFPort: ofPortTmp} c.interfaceStore.AddInterface(itf) ofPort = uint32(ofPortTmp) return nil } - switch device.Type { - case v1alpha2.OVSPortTypeInternal: + switch { + case device.OVSInternal != nil: + if ofPort, err := c.ovsBridgeClient.GetOFPort(device.OVSInternal.Name, false); err == nil { + return uint32(ofPort), nil + } externalIDs := map[string]interface{}{ interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUnset, } c.ovsPortUpdateMutex.Lock() defer c.ovsPortUpdateMutex.Unlock() - portUUID, err := c.ovsBridgeClient.CreateInternalPort(device.Name, 0, externalIDs) + portUUID, err := c.ovsBridgeClient.CreateInternalPort(device.OVSInternal.Name, 0, externalIDs) if err != nil { return 0, err } @@ -293,22 +346,26 @@ func (c *Controller) getDevicePort(device *v1alpha2.OVSPort) (ofPort uint32, err _ = c.ovsBridgeClient.DeletePort(portUUID) } }() - ofPortTmp, err = c.ovsBridgeClient.GetOFPort(device.Name, false) + ofPortTmp, err = c.ovsBridgeClient.GetOFPort(device.OVSInternal.Name, false) if err != nil { return 0, err } - intf := interfacestore.NewGatewayInterface(device.Name) + intf := interfacestore.NewGatewayInterface(device.OVSInternal.Name) intf.OVSPortConfig = &interfacestore.OVSPortConfig{PortUUID: portUUID, OFPort: ofPortTmp} c.interfaceStore.AddInterface(intf) ofPort = uint32(ofPortTmp) klog.V(2).InfoS("Create internal port", "portUUID", portUUID) - case v1alpha2.OVSPortTypeDevice: + case device.Device != nil: + itf, ok := c.interfaceStore.GetInterfaceByName(device.Device.Name) + if ok { + return uint32(itf.OFPort), nil + } externalIDs := map[string]interface{}{ interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUnset, } c.ovsPortUpdateMutex.Lock() defer c.ovsPortUpdateMutex.Unlock() - portUUID, err := c.ovsBridgeClient.CreatePort(device.Name, device.Name, externalIDs) + portUUID, err := c.ovsBridgeClient.CreatePort(device.Device.Name, device.Device.Name, externalIDs) if err != nil { return 0, err } @@ -317,31 +374,42 @@ func (c *Controller) getDevicePort(device *v1alpha2.OVSPort) (ofPort uint32, err _ = c.ovsBridgeClient.DeletePort(portUUID) } }() - ofPortTmp, err = c.ovsBridgeClient.GetOFPort(device.Name, false) + ofPortTmp, err = c.ovsBridgeClient.GetOFPort(device.Device.Name, false) if err != nil { return 0, err } - itf := interfacestore.NewUplinkInterface(device.Name) - itf.OVSPortConfig = &interfacestore.OVSPortConfig{PortUUID: portUUID, OFPort: ofPortTmp} - c.interfaceStore.AddInterface(itf) + newItf := interfacestore.NewUplinkInterface(device.Device.Name) + newItf.OVSPortConfig = &interfacestore.OVSPortConfig{PortUUID: portUUID, OFPort: ofPortTmp} + c.interfaceStore.AddInterface(newItf) ofPort = uint32(ofPortTmp) klog.V(2).InfoS("Create device", "portUUID", portUUID) - case v1alpha2.OVSPortTypeVXLAN: - if err := createTunnelPortExt(ovsconfig.VXLANTunnel); err != nil { + case device.VXLAN != nil: + dstPort := int32(defaultVXLANTunnelDestinationPort) + if device.VXLAN.DestinationPort != nil { + dstPort = *device.VXLAN.DestinationPort + } + portName := strings.Join([]string{portNamePrefixVXLAN, genPortNameUDPTunnel(device.VXLAN)}, "-") + if err := createUDPTunnel(ovsconfig.VXLANTunnel, portName, device.VXLAN.RemoteIP, dstPort); err != nil { return 0, err } - klog.V(2).InfoS("Create VXLANTunnel port", "portName", device.Name) - case v1alpha2.OVSPortTypeGENEVE: - if err := createTunnelPortExt(ovsconfig.GeneveTunnel); err != nil { + klog.V(2).InfoS("Create VXLANTunnel port", "config", device.VXLAN) + case device.GENEVE != nil: + dstPort := int32(defaultGENEVETunnelDestinationPort) + if device.VXLAN.DestinationPort != nil { + dstPort = *device.VXLAN.DestinationPort + } + portName := strings.Join([]string{portNamePrefixGENEVE, genPortNameUDPTunnel(device.GENEVE)}, "-") + if err := createUDPTunnel(ovsconfig.GeneveTunnel, portName, device.GENEVE.RemoteIP, dstPort); err != nil { return 0, err } - klog.V(2).InfoS("Create Geneve Tunnel port", "portName", device.Name) - case v1alpha2.OVSPortTypeGRE: - if err := createTunnelPortExt(ovsconfig.GRETunnel); err != nil { + klog.V(2).InfoS("Create Geneve Tunnel port", "config", device.GENEVE) + case device.GRE != nil: + portName := strings.Join([]string{portNamePrefixGRE, genPortNameGRETunnel(device.GRE)}, "-") + if err := createUDPTunnel(ovsconfig.GRETunnel, portName, device.GRE.RemoteIP, 0); err != nil { return 0, err } - klog.V(2).InfoS("Create GRETunnel port", "portName", device.Name) - case v1alpha2.OVSPortTypeERSPAN: + klog.V(2).InfoS("Create GRETunnel port", "config", device.GRE) + case device.ERSPAN != nil: // ERSPAN version I and version II over IPv4 GRE and IPv6 GRE tunnel are supported. See ovs-fields(7) for matching and setting ERSPAN fields. // $ ovs-vsctl add-br br0 // $ #For ERSPAN type 2 (version I) @@ -356,14 +424,16 @@ func (c *Controller) getDevicePort(device *v1alpha2.OVSPort) (ofPort uint32, err // options:remote_ip=172.31.1.1 \ // options:erspan_ver=2 options:erspan_dir=1 \ // options:erspan_hwid=4 - config := device.ERSPANConfig - tunnelID := config.TunnelID + + config := device.ERSPAN remoteIP := config.RemoteIP version := config.Version index := config.Index dir := config.Dir hardwareID := config.HardwareID + portName := strings.Join([]string{portNamePrefixERSPAN, genPortNameERSPANTunnel(device.ERSPAN)}, "-") + externalIDs := map[string]interface{}{ interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUnset, "erspan_ver": version, @@ -379,21 +449,21 @@ func (c *Controller) getDevicePort(device *v1alpha2.OVSPort) (ofPort uint32, err } c.ovsPortUpdateMutex.Lock() defer c.ovsPortUpdateMutex.Unlock() - portUUID, err := c.ovsBridgeClient.CreateTunnelPortExt(device.Name, + portUUID, err := c.ovsBridgeClient.CreateTunnelPortExt(portName, ovsconfig.ERSpanTunnel, 0, false, "", remoteIP, "", externalIDs) if err != nil { return 0, err } - ofPortTmp, err = c.ovsBridgeClient.GetOFPort(device.Name, false) + ofPortTmp, err = c.ovsBridgeClient.GetOFPort(portName, false) if err != nil { return 0, err } - itf := interfacestore.NewTunnelInterface(device.Name, ovsconfig.ERSpanTunnel, nil, false) + itf := interfacestore.NewTunnelInterface(portName, ovsconfig.ERSpanTunnel, nil, false) itf.OVSPortConfig = &interfacestore.OVSPortConfig{PortUUID: portUUID, OFPort: ofPortTmp} c.interfaceStore.AddInterface(itf) ofPort = uint32(ofPortTmp) - klog.V(2).InfoS("Create ERSPAN port", "tunnelID", tunnelID, "remoteIP", remoteIP, "version", version, "index", index, + klog.V(2).InfoS("Create ERSPAN port", "remoteIP", remoteIP, "version", version, "index", index, "dir", dir, "hardwareID", hardwareID) } return @@ -424,21 +494,21 @@ func (c *Controller) syncTrafficControl(tcName string) (err error) { if !exist { tcState = c.createTcState(tcName) - var dstInPort, dstOutPort uint32 + var returnPort, targetPort uint32 // ReturnPort should only be set for Redirect action.The validation webhook checked it. if tc.Spec.ReturnPort != nil { - if dstOutPort, err = c.getDevicePort(tc.Spec.ReturnPort); err != nil { + if returnPort, err = c.getDevicePort(tc.Spec.ReturnPort); err != nil { return err } } - if dstInPort, err = c.getDevicePort(&tc.Spec.TargetPort); err != nil { + if targetPort, err = c.getDevicePort(&tc.Spec.TargetPort); err != nil { return err } - if err := c.ofClient.InstallTrafficControlInitFlows(dstInPort, dstOutPort, tc.Spec.Action); err != nil { + if err := c.ofClient.InstallTrafficControlCommonFlows(targetPort, returnPort); err != nil { return err } - tcState.dstOfInPort = dstInPort - tcState.dstOfOutPort = dstOutPort + tcState.targetPort = targetPort + tcState.dstOfOutPort = returnPort } var pods []*v1.Pod if pods, err = c.filterPods(&tc.Spec.AppliedTo); err != nil { @@ -463,7 +533,7 @@ func (c *Controller) syncTrafficControl(tcName string) (err error) { podOfPorts = append(podOfPorts, uint32(ofPort)) } - if err := c.ofClient.InstallTrafficControlMarkFlows(tc.Name, podOfPorts, tcState.dstOfInPort, tc.Spec.Direction); err != nil { + if err := c.ofClient.InstallTrafficControlMarkFlows(tc.Name, podOfPorts, tcState.targetPort, tc.Spec.Direction, tc.Spec.Action); err != nil { return err } @@ -475,7 +545,7 @@ func (c *Controller) uninstallTrafficControl(tcName string, ts *tcState) error { return err } - if err := c.ofClient.UninstallTrafficControlInitFlows(ts.dstOfInPort); err != nil { + if err := c.ofClient.UninstallTrafficControlCommonFlows(ts.targetPort); err != nil { return err } diff --git a/pkg/agent/controller/trafficcontrol/controller_test.go b/pkg/agent/controller/trafficcontrol/controller_test.go index c1614f5a117..58f22d32e78 100644 --- a/pkg/agent/controller/trafficcontrol/controller_test.go +++ b/pkg/agent/controller/trafficcontrol/controller_test.go @@ -148,14 +148,18 @@ func TestSyncTrafficControl(t *testing.T) { PodSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}}}, Direction: v1alpha2.DirectionIngress, Action: v1alpha2.ActionMirror, - TargetPort: v1alpha2.OVSPort{Name: "test-device"}, + TargetPort: v1alpha2.TrafficControlPort{OVSInternal: &v1alpha2.OVSInternalPort{Name: "test-device"}}, }}, localPods: []*v1.Pod{ newPod("ns1", "pod1", "fakeNode", map[string]string{"app": "foo"}), }, expectedCalls: func(mockOFClient *openflowtest.MockClient, mockOVSBridgeClient *ovsconfigtest.MockOVSBridgeClient) { - mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(3), v1alpha2.DirectionIngress) - mockOFClient.EXPECT().InstallTrafficControlInitFlows(uint32(3), uint32(0), v1alpha2.ActionMirror) + mockOVSBridgeClient.EXPECT().GetOFPort("test-device", false).Return(int32(0), ovsconfig.NewTransactionError(fmt.Errorf("failed to get OVS port"), true)).Times(1) + mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(0), v1alpha2.DirectionIngress, v1alpha2.ActionMirror) + mockOFClient.EXPECT().InstallTrafficControlCommonFlows(uint32(0), uint32(0)) + mockOVSBridgeClient.EXPECT().CreateInternalPort("test-device", int32(0), + map[string]interface{}{interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUnset}) + mockOVSBridgeClient.EXPECT().GetOFPort("test-device", false).Times(1) }, }, { @@ -167,15 +171,15 @@ func TestSyncTrafficControl(t *testing.T) { PodSelector: &metav1.LabelSelector{MatchLabels: map[string]string{"app": "foo"}}}, Direction: v1alpha2.DirectionIngress, Action: v1alpha2.ActionMirror, - TargetPort: v1alpha2.OVSPort{Name: "test-device"}, + TargetPort: v1alpha2.TrafficControlPort{Device: &v1alpha2.NetworkDevice{Name: "test-device"}}, }}, localPods: []*v1.Pod{ newPod("ns1", "pod1", "fakeNode", map[string]string{"app": "foo"}), newPod("ns2", "pod2", "fakeNode", map[string]string{"app": "foo1"}), }, expectedCalls: func(mockOFClient *openflowtest.MockClient, mockOVSBridgeClient *ovsconfigtest.MockOVSBridgeClient) { - mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(3), v1alpha2.DirectionIngress) - mockOFClient.EXPECT().InstallTrafficControlInitFlows(uint32(3), uint32(0), v1alpha2.ActionMirror) + mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(3), v1alpha2.DirectionIngress, v1alpha2.ActionMirror) + mockOFClient.EXPECT().InstallTrafficControlCommonFlows(uint32(3), uint32(0)) }, }, { @@ -185,15 +189,15 @@ func TestSyncTrafficControl(t *testing.T) { Spec: v1alpha2.TrafficControlSpec{ Direction: v1alpha2.DirectionIngress, Action: v1alpha2.ActionRedirect, - ReturnPort: &v1alpha2.OVSPort{Name: "test-device"}, - TargetPort: v1alpha2.OVSPort{Name: "test-device"}, + ReturnPort: &v1alpha2.TrafficControlPort{Device: &v1alpha2.NetworkDevice{Name: "test-device"}}, + TargetPort: v1alpha2.TrafficControlPort{Device: &v1alpha2.NetworkDevice{Name: "test-device"}}, }}, localPods: []*v1.Pod{ newPod("ns1", "pod1", "fakeNode", map[string]string{"app": "foo"}), }, expectedCalls: func(mockOFClient *openflowtest.MockClient, mockOVSBridgeClient *ovsconfigtest.MockOVSBridgeClient) { - mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(3), v1alpha2.DirectionIngress) - mockOFClient.EXPECT().InstallTrafficControlInitFlows(uint32(3), uint32(3), v1alpha2.ActionRedirect) + mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(3), v1alpha2.DirectionIngress, v1alpha2.ActionRedirect) + mockOFClient.EXPECT().InstallTrafficControlCommonFlows(uint32(3), uint32(3)) }, }, { @@ -204,15 +208,15 @@ func TestSyncTrafficControl(t *testing.T) { AppliedTo: v1alpha2.AppliedTo{}, Direction: v1alpha2.DirectionIngress, Action: v1alpha2.ActionRedirect, - ReturnPort: &v1alpha2.OVSPort{Name: "test-device"}, - TargetPort: v1alpha2.OVSPort{Name: "test-device"}, + ReturnPort: &v1alpha2.TrafficControlPort{Device: &v1alpha2.NetworkDevice{Name: "test-device"}}, + TargetPort: v1alpha2.TrafficControlPort{Device: &v1alpha2.NetworkDevice{Name: "test-device"}}, }}, localPods: []*v1.Pod{ newPod("ns1", "pod1", "fakeNode", map[string]string{"app": "foo"}), }, expectedCalls: func(mockOFClient *openflowtest.MockClient, mockOVSBridgeClient *ovsconfigtest.MockOVSBridgeClient) { - mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(3), v1alpha2.DirectionIngress) - mockOFClient.EXPECT().InstallTrafficControlInitFlows(uint32(3), uint32(3), v1alpha2.ActionRedirect) + mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(3), v1alpha2.DirectionIngress, v1alpha2.ActionRedirect) + mockOFClient.EXPECT().InstallTrafficControlCommonFlows(uint32(3), uint32(3)) }, }, { @@ -223,14 +227,14 @@ func TestSyncTrafficControl(t *testing.T) { AppliedTo: v1alpha2.AppliedTo{}, Direction: v1alpha2.DirectionIngress, Action: v1alpha2.ActionMirror, - TargetPort: v1alpha2.OVSPort{Name: "fake-internal-device", Type: v1alpha2.OVSPortTypeInternal}, + TargetPort: v1alpha2.TrafficControlPort{OVSInternal: &v1alpha2.OVSInternalPort{Name: "fake-internal-device"}}, }}, localPods: []*v1.Pod{ newPod("ns1", "pod1", "fakeNode", map[string]string{"app": "foo"}), }, expectedCalls: func(mockOFClient *openflowtest.MockClient, mockOVSBridgeClient *ovsconfigtest.MockOVSBridgeClient) { - mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(0), v1alpha2.DirectionIngress) - mockOFClient.EXPECT().InstallTrafficControlInitFlows(uint32(0), uint32(0), v1alpha2.ActionMirror) + mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(0), v1alpha2.DirectionIngress, v1alpha2.ActionMirror) + mockOFClient.EXPECT().InstallTrafficControlCommonFlows(uint32(0), uint32(0)) mockOVSBridgeClient.EXPECT().GetOFPort("fake-internal-device", false).Return(int32(0), ovsconfig.NewTransactionError(fmt.Errorf("failed to get OVS port"), true)).Times(1) mockOVSBridgeClient.EXPECT().CreateInternalPort("fake-internal-device", int32(0), map[string]interface{}{interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUnset}) @@ -245,13 +249,12 @@ func TestSyncTrafficControl(t *testing.T) { AppliedTo: v1alpha2.AppliedTo{}, Direction: v1alpha2.DirectionIngress, Action: v1alpha2.ActionMirror, - TargetPort: v1alpha2.OVSPort{Name: "fake-device", Type: v1alpha2.OVSPortTypeDevice}, + TargetPort: v1alpha2.TrafficControlPort{Device: &v1alpha2.NetworkDevice{Name: "fake-device"}}, }}, localPods: []*v1.Pod{newPod("ns1", "pod1", "fakeNode", map[string]string{"app": "foo"})}, expectedCalls: func(mockOFClient *openflowtest.MockClient, mockOVSBridgeClient *ovsconfigtest.MockOVSBridgeClient) { - mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(0), v1alpha2.DirectionIngress) - mockOFClient.EXPECT().InstallTrafficControlInitFlows(uint32(0), uint32(0), v1alpha2.ActionMirror) - mockOVSBridgeClient.EXPECT().GetOFPort("fake-device", false).Return(int32(0), ovsconfig.NewTransactionError(fmt.Errorf("failed to get OVS port"), true)).Times(1) + mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(0), v1alpha2.DirectionIngress, v1alpha2.ActionMirror) + mockOFClient.EXPECT().InstallTrafficControlCommonFlows(uint32(0), uint32(0)) mockOVSBridgeClient.EXPECT().CreatePort("fake-device", "fake-device", map[string]interface{}{interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUnset}) mockOVSBridgeClient.EXPECT().GetOFPort("fake-device", false) @@ -265,17 +268,41 @@ func TestSyncTrafficControl(t *testing.T) { AppliedTo: v1alpha2.AppliedTo{}, Direction: v1alpha2.DirectionIngress, Action: v1alpha2.ActionMirror, - TargetPort: v1alpha2.OVSPort{Name: "fake-gre-tunnel", Type: v1alpha2.OVSPortTypeGRE, - TunnelConfig: &v1alpha2.TunnelConfig{TunnelID: 0, RemoteIP: "1.1.1.1"}}, + TargetPort: v1alpha2.TrafficControlPort{GRE: &v1alpha2.GRETunnel{ + RemoteIP: "1.1.1.1", + Key: nil, + }}, }}, localPods: []*v1.Pod{newPod("ns1", "pod1", "fakeNode", map[string]string{"app": "foo"})}, expectedCalls: func(mockOFClient *openflowtest.MockClient, mockOVSBridgeClient *ovsconfigtest.MockOVSBridgeClient) { - mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(0), v1alpha2.DirectionIngress) - mockOFClient.EXPECT().InstallTrafficControlInitFlows(uint32(0), uint32(0), v1alpha2.ActionMirror) - mockOVSBridgeClient.EXPECT().GetOFPort("fake-gre-tunnel", false).Return(int32(0), ovsconfig.NewTransactionError(fmt.Errorf("failed to get OVS port"), true)).Times(1) - mockOVSBridgeClient.EXPECT().CreateTunnelPortExt("fake-gre-tunnel", ovsconfig.TunnelType(ovsconfig.GRETunnel), int32(0), false, "", "1.1.1.1", "", + mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(0), v1alpha2.DirectionIngress, v1alpha2.ActionMirror) + mockOFClient.EXPECT().InstallTrafficControlCommonFlows(uint32(0), uint32(0)) + mockOVSBridgeClient.EXPECT().CreateTunnelPortExt("gre-6477b31e-7e8d-506e-a868-724dd1d17150", ovsconfig.TunnelType(ovsconfig.GRETunnel), int32(0), false, "", "1.1.1.1", "", map[string]interface{}{interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaTunnel}) - mockOVSBridgeClient.EXPECT().GetOFPort("fake-gre-tunnel", false).Times(1) + mockOVSBridgeClient.EXPECT().GetOFPort("gre-6477b31e-7e8d-506e-a868-724dd1d17150", false).Times(1) + }, + }, + { + name: "sync trafficControl with VXLAN OVSPort type", + tc: &v1alpha2.TrafficControl{ + ObjectMeta: metav1.ObjectMeta{Name: "trafficControl1", UID: "tc-uid"}, + Spec: v1alpha2.TrafficControlSpec{ + AppliedTo: v1alpha2.AppliedTo{}, + Direction: v1alpha2.DirectionIngress, + Action: v1alpha2.ActionMirror, + TargetPort: v1alpha2.TrafficControlPort{VXLAN: &v1alpha2.UDPTunnel{ + RemoteIP: "1.1.1.1", + VNI: nil, + DestinationPort: nil, + }}, + }}, + localPods: []*v1.Pod{newPod("ns1", "pod1", "fakeNode", map[string]string{"app": "foo"})}, + expectedCalls: func(mockOFClient *openflowtest.MockClient, mockOVSBridgeClient *ovsconfigtest.MockOVSBridgeClient) { + mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(0), v1alpha2.DirectionIngress, v1alpha2.ActionMirror) + mockOFClient.EXPECT().InstallTrafficControlCommonFlows(uint32(0), uint32(0)) + mockOVSBridgeClient.EXPECT().CreateTunnelPortExt("vxlan-6477b31e-7e8d-506e-a868-724dd1d17150", ovsconfig.TunnelType(ovsconfig.VXLANTunnel), int32(0), false, "", "1.1.1.1", "", + map[string]interface{}{interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaTunnel, "dst_port": int32(defaultVXLANTunnelDestinationPort)}) + mockOVSBridgeClient.EXPECT().GetOFPort("vxlan-6477b31e-7e8d-506e-a868-724dd1d17150", false).Times(1) }, }, { @@ -286,8 +313,8 @@ func TestSyncTrafficControl(t *testing.T) { AppliedTo: v1alpha2.AppliedTo{}, Direction: v1alpha2.DirectionIngress, Action: v1alpha2.ActionMirror, - TargetPort: v1alpha2.OVSPort{Name: "fake-erspan", Type: v1alpha2.OVSPortTypeERSPAN, - ERSPANConfig: &v1alpha2.ERSPANConfig{ + TargetPort: v1alpha2.TrafficControlPort{ + ERSPAN: &v1alpha2.ERSPANTunnel{ Version: 1, Dir: nil, HardwareID: nil, @@ -295,16 +322,16 @@ func TestSyncTrafficControl(t *testing.T) { }}, localPods: []*v1.Pod{newPod("ns1", "pod1", "fakeNode", map[string]string{"app": "foo"})}, expectedCalls: func(mockOFClient *openflowtest.MockClient, mockOVSBridgeClient *ovsconfigtest.MockOVSBridgeClient) { - mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(0), v1alpha2.DirectionIngress) - mockOFClient.EXPECT().InstallTrafficControlInitFlows(uint32(0), uint32(0), v1alpha2.ActionMirror) - mockOVSBridgeClient.EXPECT().GetOFPort("fake-erspan", false).Return(int32(0), ovsconfig.NewTransactionError(fmt.Errorf("failed to get OVS port"), true)).Times(1) - mockOVSBridgeClient.EXPECT().CreateTunnelPortExt("fake-erspan", ovsconfig.TunnelType(ovsconfig.ERSpanTunnel), int32(0), false, "", "", "", + mockOFClient.EXPECT().InstallTrafficControlMarkFlows("trafficControl1", []uint32{1}, uint32(0), v1alpha2.DirectionIngress, v1alpha2.ActionMirror) + mockOFClient.EXPECT().InstallTrafficControlCommonFlows(uint32(0), uint32(0)) + // mockOVSBridgeClient.EXPECT().GetOFPort("", false).Return(int32(0), ovsconfig.NewTransactionError(fmt.Errorf("failed to get OVS port"), true)).Times(1) + mockOVSBridgeClient.EXPECT().CreateTunnelPortExt("erspan-bea412fa-2506-511e-95b6-24e5e883ce47", ovsconfig.TunnelType(ovsconfig.ERSpanTunnel), int32(0), false, "", "", "", map[string]interface{}{ interfacestore.AntreaInterfaceTypeKey: interfacestore.AntreaUnset, "erspan_ver": int32(1), "key": 1, }) - mockOVSBridgeClient.EXPECT().GetOFPort("fake-erspan", false).Times(1) + mockOVSBridgeClient.EXPECT().GetOFPort("erspan-bea412fa-2506-511e-95b6-24e5e883ce47", false).Times(1) }, }, } diff --git a/pkg/agent/openflow/client.go b/pkg/agent/openflow/client.go index 7bfa5956a69..82db45a1429 100644 --- a/pkg/agent/openflow/client.go +++ b/pkg/agent/openflow/client.go @@ -281,17 +281,17 @@ type Client interface { outPort uint32, igmp ofutil.Message) error - // InstallTrafficControlMarkFlows installs the flows to mark the packets for the traffic control rule. - InstallTrafficControlMarkFlows(name string, srcOfPorts []uint32, dstOfPort uint32, direction v1alpha2.Direction) error + // InstallTrafficControlMarkFlows installs the flows to mark the packets for a traffic control rule. + InstallTrafficControlMarkFlows(name string, sourcePorts []uint32, targetPort uint32, direction v1alpha2.Direction, action v1alpha2.TrafficControlAction) error - // UninstallTrafficControlMarkFlows removes the flows for the traffic control rule. + // UninstallTrafficControlMarkFlows removes the flows for a traffic control rule. UninstallTrafficControlMarkFlows(name string) error - // InstallTrafficControlInitFlows installs the initial flows for the destination ports. - InstallTrafficControlInitFlows(dstOfInPort, dstOfOutPort uint32, action v1alpha2.TrafficControlAction) error + // InstallTrafficControlCommonFlows installs the common flows for the target and return ports of traffic control rules. + InstallTrafficControlCommonFlows(targetPort, returnPort uint32) error - // UninstallTrafficControlInitFlows removes the initial flows for the destination ports. - UninstallTrafficControlInitFlows(dstOfInPort uint32) error + // UninstallTrafficControlCommonFlows removes the common flows for the target and return ports of traffic control rules. + UninstallTrafficControlCommonFlows(targetPort uint32) error // Implement in #3580, https://github.com/antrea-io/antrea/pull/3580 } @@ -1146,8 +1146,8 @@ func (c *client) SendIGMPQueryPacketOut( } // InstallTrafficControlMarkFlows Implement in #3580, https://github.com/antrea-io/antrea/pull/3580 -func (c *client) InstallTrafficControlMarkFlows(name string, srcOfPorts []uint32, dstOfPort uint32, direction v1alpha2.Direction) error { - klog.InfoS("InstallTrafficControlMarkFlows", "name", name, "srcOfPorts", srcOfPorts, "dstOfPort", dstOfPort, "direction", direction) +func (c *client) InstallTrafficControlMarkFlows(name string, srcOfPorts []uint32, dstOfPort uint32, direction v1alpha2.Direction, action v1alpha2.TrafficControlAction) error { + klog.InfoS("InstallTrafficControlMarkFlows", "name", name, "srcOfPorts", srcOfPorts, "dstOfPort", dstOfPort, "direction", direction, "action", action) return nil } @@ -1156,12 +1156,12 @@ func (c *client) UninstallTrafficControlMarkFlows(name string) error { return nil } -func (c *client) InstallTrafficControlInitFlows(dstOfInPort, dstOfOutPort uint32, action v1alpha2.TrafficControlAction) error { - klog.InfoS("InstallTrafficControlInitFlows", "action", action, "dstOfInPort", dstOfInPort, "dstOfOutPort", dstOfOutPort) +func (c *client) InstallTrafficControlCommonFlows(targetPort, returnPort uint32) error { + klog.InfoS("InstallTrafficControlCommonFlows", "targetPort", targetPort, "returnPort", returnPort) return nil } -func (c *client) UninstallTrafficControlInitFlows(dstOfInPort uint32) error { - klog.InfoS("UninstallTrafficControlInitFlows", "dstOfInPort", dstOfInPort) +func (c *client) UninstallTrafficControlCommonFlows(targetPort uint32) error { + klog.InfoS("UninstallTrafficControlCommonFlows", "targetPort", targetPort) return nil } diff --git a/pkg/agent/openflow/testing/mock_openflow.go b/pkg/agent/openflow/testing/mock_openflow.go index c54ceaeba2e..ac26cb9f6f4 100644 --- a/pkg/agent/openflow/testing/mock_openflow.go +++ b/pkg/agent/openflow/testing/mock_openflow.go @@ -422,32 +422,32 @@ func (mr *MockClientMockRecorder) InstallTraceflowFlows(arg0, arg1, arg2, arg3, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallTraceflowFlows", reflect.TypeOf((*MockClient)(nil).InstallTraceflowFlows), arg0, arg1, arg2, arg3, arg4, arg5, arg6) } -// InstallTrafficControlInitFlows mocks base method -func (m *MockClient) InstallTrafficControlInitFlows(arg0, arg1 uint32, arg2 v1alpha2.TrafficControlAction) error { +// InstallTrafficControlCommonFlows mocks base method +func (m *MockClient) InstallTrafficControlCommonFlows(arg0, arg1 uint32) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InstallTrafficControlInitFlows", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "InstallTrafficControlCommonFlows", arg0, arg1) ret0, _ := ret[0].(error) return ret0 } -// InstallTrafficControlInitFlows indicates an expected call of InstallTrafficControlInitFlows -func (mr *MockClientMockRecorder) InstallTrafficControlInitFlows(arg0, arg1, arg2 interface{}) *gomock.Call { +// InstallTrafficControlCommonFlows indicates an expected call of InstallTrafficControlCommonFlows +func (mr *MockClientMockRecorder) InstallTrafficControlCommonFlows(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallTrafficControlInitFlows", reflect.TypeOf((*MockClient)(nil).InstallTrafficControlInitFlows), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallTrafficControlCommonFlows", reflect.TypeOf((*MockClient)(nil).InstallTrafficControlCommonFlows), arg0, arg1) } // InstallTrafficControlMarkFlows mocks base method -func (m *MockClient) InstallTrafficControlMarkFlows(arg0 string, arg1 []uint32, arg2 uint32, arg3 v1alpha2.Direction) error { +func (m *MockClient) InstallTrafficControlMarkFlows(arg0 string, arg1 []uint32, arg2 uint32, arg3 v1alpha2.Direction, arg4 v1alpha2.TrafficControlAction) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "InstallTrafficControlMarkFlows", arg0, arg1, arg2, arg3) + ret := m.ctrl.Call(m, "InstallTrafficControlMarkFlows", arg0, arg1, arg2, arg3, arg4) ret0, _ := ret[0].(error) return ret0 } // InstallTrafficControlMarkFlows indicates an expected call of InstallTrafficControlMarkFlows -func (mr *MockClientMockRecorder) InstallTrafficControlMarkFlows(arg0, arg1, arg2, arg3 interface{}) *gomock.Call { +func (mr *MockClientMockRecorder) InstallTrafficControlMarkFlows(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallTrafficControlMarkFlows", reflect.TypeOf((*MockClient)(nil).InstallTrafficControlMarkFlows), arg0, arg1, arg2, arg3) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstallTrafficControlMarkFlows", reflect.TypeOf((*MockClient)(nil).InstallTrafficControlMarkFlows), arg0, arg1, arg2, arg3, arg4) } // IsConnected mocks base method @@ -767,18 +767,18 @@ func (mr *MockClientMockRecorder) UninstallTraceflowFlows(arg0 interface{}) *gom return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallTraceflowFlows", reflect.TypeOf((*MockClient)(nil).UninstallTraceflowFlows), arg0) } -// UninstallTrafficControlInitFlows mocks base method -func (m *MockClient) UninstallTrafficControlInitFlows(arg0 uint32) error { +// UninstallTrafficControlCommonFlows mocks base method +func (m *MockClient) UninstallTrafficControlCommonFlows(arg0 uint32) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UninstallTrafficControlInitFlows", arg0) + ret := m.ctrl.Call(m, "UninstallTrafficControlCommonFlows", arg0) ret0, _ := ret[0].(error) return ret0 } -// UninstallTrafficControlInitFlows indicates an expected call of UninstallTrafficControlInitFlows -func (mr *MockClientMockRecorder) UninstallTrafficControlInitFlows(arg0 interface{}) *gomock.Call { +// UninstallTrafficControlCommonFlows indicates an expected call of UninstallTrafficControlCommonFlows +func (mr *MockClientMockRecorder) UninstallTrafficControlCommonFlows(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallTrafficControlInitFlows", reflect.TypeOf((*MockClient)(nil).UninstallTrafficControlInitFlows), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UninstallTrafficControlCommonFlows", reflect.TypeOf((*MockClient)(nil).UninstallTrafficControlCommonFlows), arg0) } // UninstallTrafficControlMarkFlows mocks base method