From f112fed90ef858c11046c1dab223879d73d576af Mon Sep 17 00:00:00 2001 From: wenyingd Date: Tue, 20 Jul 2021 18:22:30 -0700 Subject: [PATCH] Provide generic API for OVS register match/set value 1. Use RegMark/RegField in OpenFlow Match or Load actions instead of passing the register ID and range. 2. The usage for OVS registers(including xxreg) should be predefined in regmarks.go. 3. Use reg0[0..3] to indicate the source of packet, and release reg0[4..15] for other usages. Signed-off-by: wenyingd --- docs/design/ovs-pipeline.md | 12 +- .../controller/networkpolicy/packetin.go | 31 +- pkg/agent/controller/traceflow/packetin.go | 12 +- .../connections/conntrack_connections.go | 2 +- .../connections/conntrack_connections_test.go | 2 +- pkg/agent/flowexporter/exporter/exporter.go | 2 +- pkg/agent/openflow/client.go | 6 +- pkg/agent/openflow/fields.go | 128 +++++++ pkg/agent/openflow/network_policy_test.go | 55 ++- pkg/agent/openflow/pipeline.go | 328 +++++++----------- pkg/agent/openflow/pipeline_windows.go | 16 +- pkg/ovs/openflow/interfaces.go | 69 +++- pkg/ovs/openflow/ofctrl_action.go | 77 ++-- pkg/ovs/openflow/ofctrl_builder.go | 44 ++- pkg/ovs/openflow/ofctrl_builder_test.go | 18 +- pkg/ovs/openflow/ofctrl_flow_test.go | 9 +- pkg/ovs/openflow/ofctrl_group.go | 15 +- pkg/ovs/openflow/ofctrl_nxfields.go | 110 ++++++ pkg/ovs/openflow/ofctrl_packetout.go | 7 +- pkg/ovs/openflow/testing/mock_openflow.go | 114 +++--- test/integration/agent/openflow_test.go | 22 +- test/integration/ovs/ofctrl_test.go | 132 +++---- 22 files changed, 731 insertions(+), 480 deletions(-) create mode 100644 pkg/agent/openflow/fields.go create mode 100644 pkg/ovs/openflow/ofctrl_nxfields.go diff --git a/docs/design/ovs-pipeline.md b/docs/design/ovs-pipeline.md index 95607f832df..44b5c0e6c9a 100644 --- a/docs/design/ovs-pipeline.md +++ b/docs/design/ovs-pipeline.md @@ -66,7 +66,7 @@ that Node and `` is the name of the bridge created by Antrea We use 2 32-bit OVS registers to carry information throughout the pipeline: * reg0 (NXM_NX_REG0): - - bits [0..15] are used to store the traffic source (from tunnel: 0, from + - bits [0..3] are used to store the traffic source (from tunnel: 0, from local gateway: 1, from local Pod: 2). It is set in the [ClassifierTable]. - bit 16 is used to indicate whether the destination MAC address of a packet is "known", i.e. corresponds to an entry in [L2ForwardingCalcTable], which @@ -621,8 +621,8 @@ be SNAT'd with a SNAT IP configured on the Node. In the latter case, the flow also rewrites the destination MAC to the local gateway interface MAC. ```text -table=70, priority=190,ip,reg0=0x2/0xffff actions=goto_table:71 -table=70, priority=190,ip,reg0=0/0xffff actions=mod_dl_dst:e2:e5:a4:9b:1c:b1,goto_table:71 +table=70, priority=190,ip,reg0=0x2/0xf actions=goto_table:71 +table=70, priority=190,ip,reg0=0/0xf actions=mod_dl_dst:e2:e5:a4:9b:1c:b1,goto_table:71 ``` ### SNATTable (71) @@ -639,7 +639,7 @@ Egress applied, to [L2ForwardingCalcTable]. Such traffic will be SNAT'd with the default SNAT IP (by an iptables masquerade rule). ```text -table=71, priority=190,ct_state=+new+trk,ip,reg0=0/0xffff actions=drop +table=71, priority=190,ct_state=+new+trk,ip,reg0=0/0xf actions=drop table=71, priority=0 actions=goto_table:80 ``` @@ -685,7 +685,7 @@ IP stack should have already decremented TTL if that is needed. If you dump the flows for this table, you should see flows like the following: ```text -1. table=72, priority=210,ip,reg0=0x1/0xffff, actions=goto_table:80 +1. table=72, priority=210,ip,reg0=0x1/0xf, actions=goto_table:80 2. table=72, priority=200,ip, actions=dec_ttl,goto_table:80 3. table=72, priority=0, actions=goto_table:80 ``` @@ -884,7 +884,7 @@ which are not dropped because of Network Policies. If you dump the flows for thi table, you should see something like this: ```text -1. table=105, priority=200,ct_state=+new+trk,ip,reg0=0x1/0xffff actions=ct(commit,table=110,zone=65520,exec(load:0x20->NXM_NX_CT_MARK[])) +1. table=105, priority=200,ct_state=+new+trk,ip,reg0=0x1/0xf actions=ct(commit,table=110,zone=65520,exec(load:0x20->NXM_NX_CT_MARK[])) 2. table=105, priority=190,ct_state=+new+trk,ip actions=ct(commit,table=110,zone=65520) 3. table=105, priority=0 actions=goto_table:110 ``` diff --git a/pkg/agent/controller/networkpolicy/packetin.go b/pkg/agent/controller/networkpolicy/packetin.go index 5d6da0ece6c..2ffa27aba81 100644 --- a/pkg/agent/controller/networkpolicy/packetin.go +++ b/pkg/agent/controller/networkpolicy/packetin.go @@ -59,24 +59,27 @@ func (c *Controller) HandlePacketIn(pktIn *ofctrl.PacketIn) error { matches := pktIn.GetMatches() // Get custom reasons in this packet-in. - match := getMatchRegField(matches, uint32(openflow.CustomReasonMarkReg)) - customReasons, err := getInfoInReg(match, openflow.CustomReasonMarkRange.ToNXRange()) + match := getMatchRegField(matches, openflow.CustomReasonField) + customReasons, err := getInfoInReg(match, openflow.CustomReasonField.GetRange().ToNXRange()) if err != nil { return fmt.Errorf("received error while unloading customReason from reg: %v", err) } // Use reasons to choose operations. - if customReasons&openflow.CustomReasonLogging == openflow.CustomReasonLogging { + var checkCustomReason = func(customReasonMark *binding.RegMark) bool { + return customReasons&customReasonMark.GetValue() == customReasonMark.GetValue() + } + if checkCustomReason(openflow.CustomReasonLoggingRegMark) { if err := c.logPacket(pktIn); err != nil { return err } } - if customReasons&openflow.CustomReasonReject == openflow.CustomReasonReject { + if checkCustomReason(openflow.CustomReasonRejectRegMark) { if err := c.rejectRequest(pktIn); err != nil { return err } } - if customReasons&openflow.CustomReasonDeny == openflow.CustomReasonDeny { + if checkCustomReason(openflow.CustomReasonDenyRegMark) { if err := c.storeDenyConnection(pktIn); err != nil { return err } @@ -85,8 +88,8 @@ func (c *Controller) HandlePacketIn(pktIn *ofctrl.PacketIn) error { } // getMatchRegField returns match to the regNum register. -func getMatchRegField(matchers *ofctrl.Matchers, regNum uint32) *ofctrl.MatchField { - return matchers.GetMatchByName(fmt.Sprintf("NXM_NX_REG%d", regNum)) +func getMatchRegField(matchers *ofctrl.Matchers, field *binding.RegField) *ofctrl.MatchField { + return matchers.GetMatchByName(field.GetNXFieldName()) } // getMatch receives ofctrl matchers and table id, match field. @@ -94,17 +97,17 @@ func getMatchRegField(matchers *ofctrl.Matchers, regNum uint32) *ofctrl.MatchFie func getMatch(matchers *ofctrl.Matchers, tableID binding.TableIDType, disposition uint32) *ofctrl.MatchField { // Get match from CNPDenyConjIDReg if disposition is not allow. if disposition != openflow.DispositionAllow { - return getMatchRegField(matchers, uint32(openflow.CNPDenyConjIDReg)) + return getMatchRegField(matchers, openflow.CNPDenyConjIDField) } // Get match from ingress/egress reg if disposition is allow for _, table := range append(openflow.GetAntreaPolicyEgressTables(), openflow.EgressRuleTable) { if tableID == table { - return getMatchRegField(matchers, uint32(openflow.EgressReg)) + return getMatchRegField(matchers, openflow.TFEgressConjIDField) } } for _, table := range append(openflow.GetAntreaPolicyIngressTables(), openflow.IngressRuleTable) { if tableID == table { - return getMatchRegField(matchers, uint32(openflow.IngressReg)) + return getMatchRegField(matchers, openflow.TFIngressConjIDField) } } return nil @@ -131,8 +134,8 @@ func getNetworkPolicyInfo(pktIn *ofctrl.PacketIn, c *Controller, ob *logInfo) er ob.tableName = openflow.GetFlowTableName(tableID) // Get disposition Allow or Drop - match = getMatchRegField(matchers, uint32(openflow.DispositionMarkReg)) - info, err := getInfoInReg(match, openflow.APDispositionMarkRange.ToNXRange()) + match = getMatchRegField(matchers, openflow.APDispositionField) + info, err := getInfoInReg(match, openflow.APDispositionField.GetRange().ToNXRange()) if err != nil { return fmt.Errorf("received error while unloading disposition from reg: %v", err) } @@ -325,8 +328,8 @@ func (c *Controller) storeDenyConnection(pktIn *ofctrl.PacketIn) error { // Get table ID tableID := binding.TableIDType(pktIn.TableId) // Get disposition Allow, Drop or Reject - match = getMatchRegField(matchers, uint32(openflow.DispositionMarkReg)) - id, err := getInfoInReg(match, openflow.APDispositionMarkRange.ToNXRange()) + match = getMatchRegField(matchers, openflow.APDispositionField) + id, err := getInfoInReg(match, openflow.APDispositionField.GetRange().ToNXRange()) if err != nil { return fmt.Errorf("error when getting disposition from reg: %v", err) } diff --git a/pkg/agent/controller/traceflow/packetin.go b/pkg/agent/controller/traceflow/packetin.go index 63c7ae6e4ec..dba0bc0f2ba 100644 --- a/pkg/agent/controller/traceflow/packetin.go +++ b/pkg/agent/controller/traceflow/packetin.go @@ -176,7 +176,7 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl obs = append(obs, *ob) } // Collect egress conjunctionID and get NetworkPolicy from cache. - if match := getMatchRegField(matchers, uint32(openflow.EgressReg)); match != nil { + if match := getMatchRegField(matchers, openflow.TFEgressConjIDField); match != nil { egressInfo, err := getRegValue(match, nil) if err != nil { return nil, nil, nil, err @@ -191,7 +191,7 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl } // Collect ingress conjunctionID and get NetworkPolicy from cache. - if match := getMatchRegField(matchers, uint32(openflow.IngressReg)); match != nil { + if match := getMatchRegField(matchers, openflow.TFIngressConjIDField); match != nil { ingressInfo, err := getRegValue(match, nil) if err != nil { return nil, nil, nil, err @@ -207,7 +207,7 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl // Get drop table. if tableID == uint8(openflow.EgressMetricTable) || tableID == uint8(openflow.IngressMetricTable) { ob := getNetworkPolicyObservation(tableID, tableID == uint8(openflow.IngressMetricTable)) - if match := getMatchRegField(matchers, uint32(openflow.CNPDenyConjIDReg)); match != nil { + if match := getMatchRegField(matchers, openflow.CNPDenyConjIDField); match != nil { notAllowConjInfo, err := getRegValue(match, nil) if err != nil { return nil, nil, nil, err @@ -239,7 +239,7 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl } } var outputPort uint32 - if match := getMatchRegField(matchers, uint32(openflow.PortCacheReg)); match != nil { + if match := getMatchRegField(matchers, openflow.TargetOFPortField); match != nil { outputPort, err = getRegValue(match, nil) if err != nil { return nil, nil, nil, err @@ -271,8 +271,8 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl return tf, &nodeResult, capturedPacket, nil } -func getMatchRegField(matchers *ofctrl.Matchers, regNum uint32) *ofctrl.MatchField { - return matchers.GetMatchByName(fmt.Sprintf("NXM_NX_REG%d", regNum)) +func getMatchRegField(matchers *ofctrl.Matchers, field *binding.RegField) *ofctrl.MatchField { + return matchers.GetMatchByName(field.GetNXFieldName()) } func getMatchTunnelDstField(matchers *ofctrl.Matchers, isIPv6 bool) *ofctrl.MatchField { diff --git a/pkg/agent/flowexporter/connections/conntrack_connections.go b/pkg/agent/flowexporter/connections/conntrack_connections.go index 265486672bf..75188f44025 100644 --- a/pkg/agent/flowexporter/connections/conntrack_connections.go +++ b/pkg/agent/flowexporter/connections/conntrack_connections.go @@ -231,7 +231,7 @@ func (cs *ConntrackConnectionStore) AddOrUpdateConn(conn *flowexporter.Connectio klog.V(4).Infof("Antrea flow updated: %v", existingConn) } else { cs.fillPodInfo(conn) - if conn.Mark == openflow.ServiceCTMark { + if conn.Mark == openflow.ServiceCTMark.GetValue() { clusterIP := conn.DestinationServiceAddress.String() svcPort := conn.DestinationServicePort protocol, err := lookupServiceProtocol(conn.FlowKey.Protocol) diff --git a/pkg/agent/flowexporter/connections/conntrack_connections_test.go b/pkg/agent/flowexporter/connections/conntrack_connections_test.go index 5310e08fc2c..fafabee72c7 100644 --- a/pkg/agent/flowexporter/connections/conntrack_connections_test.go +++ b/pkg/agent/flowexporter/connections/conntrack_connections_test.go @@ -140,7 +140,7 @@ func TestConntrackConnectionStore_AddOrUpdateConn(t *testing.T) { StartTime: refTime.Add(-(time.Second * 50)), StopTime: refTime, FlowKey: tuple4, - Mark: openflow.ServiceCTMark, + Mark: openflow.ServiceCTMark.GetValue(), IsPresent: true, } // Create copy of old conntrack flow for testing purposes. diff --git a/pkg/agent/flowexporter/exporter/exporter.go b/pkg/agent/flowexporter/exporter/exporter.go index 42cffc16703..47d50d18612 100644 --- a/pkg/agent/flowexporter/exporter/exporter.go +++ b/pkg/agent/flowexporter/exporter/exporter.go @@ -705,7 +705,7 @@ func (exp *flowExporter) findFlowType(conn flowexporter.Connection) uint8 { return 0 } if exp.nodeRouteController.IPInPodSubnets(conn.FlowKey.SourceAddress) { - if conn.Mark == openflow.ServiceCTMark || exp.nodeRouteController.IPInPodSubnets(conn.FlowKey.DestinationAddress) { + if conn.Mark == openflow.ServiceCTMark.GetValue() || exp.nodeRouteController.IPInPodSubnets(conn.FlowKey.DestinationAddress) { if conn.SourcePodName == "" || conn.DestinationPodName == "" { return ipfixregistry.FlowTypeInterNode } diff --git a/pkg/agent/openflow/client.go b/pkg/agent/openflow/client.go index c00bec3be23..47194402b28 100644 --- a/pkg/agent/openflow/client.go +++ b/pkg/agent/openflow/client.go @@ -1040,8 +1040,7 @@ func (c *client) SendTCPPacketOut( // Reject response packet should bypass ConnTrack if isReject { - name := fmt.Sprintf("%s%d", binding.NxmFieldReg, marksReg) - packetOutBuilder = packetOutBuilder.AddLoadAction(name, uint64(CustomReasonReject), CustomReasonMarkRange) + packetOutBuilder = packetOutBuilder.AddLoadRegMark(CustomReasonRejectRegMark) } packetOutObj := packetOutBuilder.Done() @@ -1079,8 +1078,7 @@ func (c *client) SendICMPPacketOut( // Reject response packet should bypass ConnTrack if isReject { - name := fmt.Sprintf("%s%d", binding.NxmFieldReg, marksReg) - packetOutBuilder = packetOutBuilder.AddLoadAction(name, uint64(CustomReasonReject), CustomReasonMarkRange) + packetOutBuilder = packetOutBuilder.AddLoadRegMark(CustomReasonRejectRegMark) } packetOutObj := packetOutBuilder.Done() diff --git a/pkg/agent/openflow/fields.go b/pkg/agent/openflow/fields.go new file mode 100644 index 00000000000..29660adffd7 --- /dev/null +++ b/pkg/agent/openflow/fields.go @@ -0,0 +1,128 @@ +// Copyright 2021 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openflow + +import binding "antrea.io/antrea/pkg/ovs/openflow" + +// Fields using reg. +var ( + // reg0 (NXM_NX_REG0) + // reg0[0..3]: Field to mark the packet source. Marks in this field include, + // - 0: from the tunnel port + // - 1: from antrea-gw0 + // - 2: from the local Pods + // - 4: from the Bridge interface + // - 5: from the uplink interface + PktSourceField = binding.NewRegField(0, 0, 3, "PacketSource") + FromTunnelRegMark = binding.NewRegMark(PktSourceField, 0) + FromGatewayRegMark = binding.NewRegMark(PktSourceField, 1) + FromLocalRegMark = binding.NewRegMark(PktSourceField, 2) + FromUplinkRegMark = binding.NewRegMark(PktSourceField, 4) + FromBridgeRegMark = binding.NewRegMark(PktSourceField, 5) + // reg0[16]: Mark to indicate the ofPort number of an interface is found. + OFPortFoundRegMark = binding.NewOneBitRegMark(0, 16, "OFPortFound") + // reg0[17]: Mark to indicate the packet needs to be SNATed with Node's IP. + SNATNodeIPRegMark = binding.NewOneBitRegMark(0, 17, "SNATWithNodeIP") + // reg0[18]: Mark to indicate the packet needs DNAT to virtual IP. + // If a packet uses HairpinRegMark, it will be output to the port where it enters OVS pipeline in L2ForwardingOutTable. + HairpinRegMark = binding.NewOneBitRegMark(0, 18, "Hairpin") + // reg0[19]: Mark to indicate the packet's MAC address needs to be rewritten. + RewriteMACRegMark = binding.NewOneBitRegMark(0, 19, "RewriteMAC") + // reg0[20]: Mark to indicate the packet is denied(Drop/Reject). + CnpDenyRegMark = binding.NewOneBitRegMark(0, 20, "CNPDeny") + // reg0[21..22]: Field to indicate disposition of Antrea Policy. It could have more bits to support more disposition + // that Antrea policy support in the future. + // Marks in this field include, + // - 0b00: allow + // - 0b01: drop + // - 0b10: reject + APDispositionField = binding.NewRegField(0, 21, 22, "APDisposition") + DispositionAllowRegMark = binding.NewRegMark(APDispositionField, DispositionAllow) + DispositionDropRegMark = binding.NewRegMark(APDispositionField, DispositionDrop) + DispositionRejRegMark = binding.NewRegMark(APDispositionField, DispositionRej) + // reg0[24..26]: Field to indicate the reasons of sending packet to the controller. + // Marks in this field include, + // - 0b001: logging + // - 0b010: reject + // - 0b100: deny (used by Flow Exporter) + CustomReasonField = binding.NewRegField(0, 24, 26, "PacketInReason") + CustomReasonLoggingRegMark = binding.NewRegMark(CustomReasonField, CustomReasonLogging) + CustomReasonRejectRegMark = binding.NewRegMark(CustomReasonField, CustomReasonReject) + CustomReasonDenyRegMark = binding.NewRegMark(CustomReasonField, CustomReasonDeny) + + // reg1(NXM_NX_REG1) + // Field to cache the ofPort of the OVS interface where to output packet. + TargetOFPortField = binding.NewRegField(1, 0, 31, "TargetOFPort") + + // reg2(NXM_NX_REG2) + // Field to help swap values in two different flow fields in the OpenFlow actions. This field is only used in func + // `arpResponderStaticFlow`. + SwapField = binding.NewRegField(2, 0, 31, "SwapValue") + + // reg3(NXM_NX_REG3) + // Field to store the selected Service Endpoint IP + EndpointIPField = binding.NewRegField(3, 0, 31, "EndpointIP") + // Field to store the conjunction ID which is for "deny" rule in CNP. It shares the same register with EndpointIPField, + // since the service selection will finish when a packet hitting NetworkPolicy related rules. + CNPDenyConjIDField = binding.NewRegField(3, 0, 31, "CNPDenyConjunctionID") + + // reg4(NXM_NX_REG4) + // reg4[0..15]: Field to store the selected Service Endpoint port. + EndpointPortField = binding.NewRegField(4, 0, 15, "EndpointPort") + // reg4[16..18]: Field to store the state of a packet accessing a Service. Marks in this field include, + // - 0b001: packet need to do service selection. + // - 0b010: packet has done service selection. + // - 0b011: packet has done service selection and the selection result needs to be cached. + ServiceEPStateField = binding.NewRegField(4, 16, 18, "EndpointState") + EpToSelectRegMark = binding.NewRegMark(ServiceEPStateField, 0b001) + EpSelectedRegMark = binding.NewRegMark(ServiceEPStateField, 0b010) + EpToLearnRegMark = binding.NewRegMark(ServiceEPStateField, 0b011) + // reg4[0..18]: Field to store the union value of Endpoint port and Endpoint status. It is used as a single match + // when needed. + EpUnionField = binding.NewRegField(4, 0, 18, "EndpointUnion") + + // reg5(NXM_NX_REG5) + // Field to cache the Egress conjunction ID hit by TraceFlow packet. + TFEgressConjIDField = binding.NewRegField(5, 0, 31, "TFEgressConjunctionID") + + // reg(N6XM_NX_REG6) + // Field to store the Ingress conjunction ID hit by TraceFlow packet. + TFIngressConjIDField = binding.NewRegField(6, 0, 31, "TFIngressConjunctionID") +) + +// Fields using xxreg. +var ( + // xxreg3(NXM_NX_XXREG3) + // xxreg3: Field to cache Endpoint IPv6 address. It occupies reg12-reg15 in the meanwhile. + EndpointIP6Field = binding.NewXXRegField(3, 0, 127) +) + +// Marks using CT. +var ( + // Mark to indicate the connection is initiated through the host gateway interface + // (i.e. for which the first packet of the connection was received through the gateway). + FromGatewayCTMark = binding.NewCTMark(0x20, 0, 31) + // Mark to indicate DNAT is performed on the connection for Service. + ServiceCTMark = binding.NewCTMark(0x21, 0, 31) +) + +// Fields using CT label. +var ( + // Field to store the ingress rule ID. + IngressRuleCTLabel = binding.NewCTLabel(0, 31, "ingressRuleCTLabel") + + // Field to store the egress rule ID. + EgressRuleCTLabel = binding.NewCTLabel(32, 63, "egressRuleCTLabel") +) diff --git a/pkg/agent/openflow/network_policy_test.go b/pkg/agent/openflow/network_policy_test.go index f67e8be0403..86bbb6916c8 100644 --- a/pkg/agent/openflow/network_policy_test.go +++ b/pkg/agent/openflow/network_policy_test.go @@ -336,12 +336,12 @@ func TestBatchInstallPolicyRuleFlows(t *testing.T) { return []binding.Flow{ c.pipeline[EgressRuleTable].BuildFlow(priorityLow).Cookie(cookiePolicy). MatchProtocol(binding.ProtocolIP).MatchConjID(10). - Action().LoadRegRange(int(EgressReg), 10, binding.Range{0, 31}). - Action().CT(true, EgressMetricTable, CtZone).LoadToLabelRange(10, &metricEgressRuleIDRange).CTDone().Done(), + Action().LoadToRegField(TFEgressConjIDField, 10). + Action().CT(true, EgressMetricTable, CtZone).LoadToLabelField(10, EgressRuleCTLabel).CTDone().Done(), c.pipeline[EgressRuleTable].BuildFlow(priorityLow).Cookie(cookiePolicy). MatchProtocol(binding.ProtocolIP).MatchConjID(11). - Action().LoadRegRange(int(EgressReg), 11, binding.Range{0, 31}). - Action().CT(true, EgressMetricTable, CtZone).LoadToLabelRange(11, &metricEgressRuleIDRange).CTDone().Done(), + Action().LoadToRegField(TFEgressConjIDField, 11). + Action().CT(true, EgressMetricTable, CtZone).LoadToLabelField(11, EgressRuleCTLabel).CTDone().Done(), c.pipeline[EgressRuleTable].BuildFlow(priorityNormal).Cookie(cookiePolicy). MatchProtocol(binding.ProtocolIP).MatchSrcIP(net.ParseIP("192.168.1.40")). Action().Conjunction(10, 1, 2). @@ -369,16 +369,16 @@ func TestBatchInstallPolicyRuleFlows(t *testing.T) { MatchProtocol(binding.ProtocolIP).MatchSrcIP(net.ParseIP("192.168.1.51")). Action().Drop().Done(), c.pipeline[EgressMetricTable].BuildFlow(priorityNormal).Cookie(cookiePolicy). - MatchProtocol(binding.ProtocolIP).MatchCTStateNew(true).MatchCTLabelRange(0, uint64(10)<<32, metricEgressRuleIDRange). + MatchProtocol(binding.ProtocolIP).MatchCTStateNew(true).MatchCTLabelField(0, uint64(10)<<32, EgressRuleCTLabel). Action().GotoTable(l3ForwardingTable).Done(), c.pipeline[EgressMetricTable].BuildFlow(priorityNormal).Cookie(cookiePolicy). - MatchProtocol(binding.ProtocolIP).MatchCTStateNew(false).MatchCTLabelRange(0, uint64(10)<<32, metricEgressRuleIDRange). + MatchProtocol(binding.ProtocolIP).MatchCTStateNew(false).MatchCTLabelField(0, uint64(10)<<32, EgressRuleCTLabel). Action().GotoTable(l3ForwardingTable).Done(), c.pipeline[EgressMetricTable].BuildFlow(priorityNormal).Cookie(cookiePolicy). - MatchProtocol(binding.ProtocolIP).MatchCTStateNew(true).MatchCTLabelRange(0, uint64(11)<<32, metricEgressRuleIDRange). + MatchProtocol(binding.ProtocolIP).MatchCTStateNew(true).MatchCTLabelField(0, uint64(11)<<32, EgressRuleCTLabel). Action().GotoTable(l3ForwardingTable).Done(), c.pipeline[EgressMetricTable].BuildFlow(priorityNormal).Cookie(cookiePolicy). - MatchProtocol(binding.ProtocolIP).MatchCTStateNew(false).MatchCTLabelRange(0, uint64(11)<<32, metricEgressRuleIDRange). + MatchProtocol(binding.ProtocolIP).MatchCTStateNew(false).MatchCTLabelField(0, uint64(11)<<32, EgressRuleCTLabel). Action().GotoTable(l3ForwardingTable).Done(), } }, @@ -441,17 +441,17 @@ func TestBatchInstallPolicyRuleFlows(t *testing.T) { return []binding.Flow{ c.pipeline[AntreaPolicyIngressRuleTable].BuildFlow(priority100).Cookie(cookiePolicy). MatchProtocol(binding.ProtocolIP).MatchConjID(10). - Action().LoadRegRange(int(IngressReg), 10, binding.Range{0, 31}). - Action().CT(true, IngressMetricTable, CtZone).LoadToLabelRange(10, &metricIngressRuleIDRange).CTDone().Done(), + Action().LoadToRegField(TFIngressConjIDField, 10). + Action().CT(true, IngressMetricTable, CtZone).LoadToLabelField(10, IngressRuleCTLabel).CTDone().Done(), c.pipeline[AntreaPolicyIngressRuleTable].BuildFlow(priority100).Cookie(cookiePolicy). MatchConjID(11). - Action().LoadRegRange(int(CNPDenyConjIDReg), 11, binding.Range{0, 31}). - Action().LoadRegRange(int(marksReg), cnpDenyMark, cnpDenyMarkRange). + Action().LoadToRegField(CNPDenyConjIDField, 11). + Action().LoadRegMark(CnpDenyRegMark). Action().GotoTable(IngressMetricTable).Done(), c.pipeline[AntreaPolicyIngressRuleTable].BuildFlow(priority200).Cookie(cookiePolicy). MatchConjID(12). - Action().LoadRegRange(int(CNPDenyConjIDReg), 12, binding.Range{0, 31}). - Action().LoadRegRange(int(marksReg), cnpDenyMark, cnpDenyMarkRange). + Action().LoadToRegField(CNPDenyConjIDField, 12). + Action().LoadRegMark(CnpDenyRegMark). Action().GotoTable(IngressMetricTable).Done(), c.pipeline[AntreaPolicyIngressRuleTable].BuildFlow(priority100).Cookie(cookiePolicy). MatchProtocol(binding.ProtocolIP).MatchSrcIP(net.ParseIP("192.168.1.40")). @@ -467,17 +467,17 @@ func TestBatchInstallPolicyRuleFlows(t *testing.T) { MatchProtocol(binding.ProtocolIP).MatchSrcIP(net.ParseIP("192.168.1.51")). Action().Conjunction(11, 1, 3).Done(), c.pipeline[AntreaPolicyIngressRuleTable].BuildFlow(priority100).Cookie(cookiePolicy). - MatchReg(int(PortCacheReg), uint32(1)). + MatchRegFieldWithValue(TargetOFPortField, uint32(1)). Action().Conjunction(10, 2, 2). Action().Conjunction(11, 2, 3).Done(), c.pipeline[AntreaPolicyIngressRuleTable].BuildFlow(priority200).Cookie(cookiePolicy). - MatchReg(int(PortCacheReg), uint32(1)). + MatchRegFieldWithValue(TargetOFPortField, uint32(1)). Action().Conjunction(12, 2, 3).Done(), c.pipeline[AntreaPolicyIngressRuleTable].BuildFlow(priority100).Cookie(cookiePolicy). - MatchReg(int(PortCacheReg), uint32(2)). + MatchRegFieldWithValue(TargetOFPortField, uint32(2)). Action().Conjunction(10, 2, 2).Done(), c.pipeline[AntreaPolicyIngressRuleTable].BuildFlow(priority100).Cookie(cookiePolicy). - MatchReg(int(PortCacheReg), uint32(3)). + MatchRegFieldWithValue(TargetOFPortField, uint32(3)). Action().Conjunction(11, 2, 3).Done(), c.pipeline[AntreaPolicyIngressRuleTable].BuildFlow(priority100).Cookie(cookiePolicy). MatchProtocol(binding.ProtocolTCP).MatchDstPort(8080, nil). @@ -486,16 +486,16 @@ func TestBatchInstallPolicyRuleFlows(t *testing.T) { MatchProtocol(binding.ProtocolTCP).MatchDstPort(8080, nil). Action().Conjunction(12, 3, 3).Done(), c.pipeline[IngressMetricTable].BuildFlow(priorityNormal).Cookie(cookiePolicy). - MatchProtocol(binding.ProtocolIP).MatchCTStateNew(true).MatchCTLabelRange(0, 10, metricIngressRuleIDRange). + MatchProtocol(binding.ProtocolIP).MatchCTStateNew(true).MatchCTLabelField(0, 10, IngressRuleCTLabel). Action().GotoTable(conntrackCommitTable).Done(), c.pipeline[IngressMetricTable].BuildFlow(priorityNormal).Cookie(cookiePolicy). - MatchProtocol(binding.ProtocolIP).MatchCTStateNew(false).MatchCTLabelRange(0, 10, metricIngressRuleIDRange). + MatchProtocol(binding.ProtocolIP).MatchCTStateNew(false).MatchCTLabelField(0, 10, IngressRuleCTLabel). Action().GotoTable(conntrackCommitTable).Done(), c.pipeline[IngressMetricTable].BuildFlow(priorityNormal).Cookie(cookiePolicy). - MatchRegRange(int(marksReg), cnpDenyMark, cnpDenyMarkRange).MatchReg(int(CNPDenyConjIDReg), 11). + MatchRegMark(CnpDenyRegMark).MatchRegFieldWithValue(CNPDenyConjIDField, 11). Action().Drop().Done(), c.pipeline[IngressMetricTable].BuildFlow(priorityNormal).Cookie(cookiePolicy). - MatchRegRange(int(marksReg), cnpDenyMark, cnpDenyMarkRange).MatchReg(int(CNPDenyConjIDReg), 12). + MatchRegMark(CnpDenyRegMark).MatchRegFieldWithValue(CNPDenyConjIDField, 12). Action().Drop().Done(), } }, @@ -858,7 +858,6 @@ func newMockDropFlowBuilder(ctrl *gomock.Controller) *mocks.MockFlowBuilder { dropFlowBuilder.EXPECT().MatchInPort(gomock.Any()).Return(dropFlowBuilder).AnyTimes() dropFlowBuilder.EXPECT().MatchConjID(gomock.Any()).Return(ruleFlowBuilder).AnyTimes() dropFlowBuilder.EXPECT().MatchPriority(gomock.Any()).Return(ruleFlowBuilder).AnyTimes() - dropFlowBuilder.EXPECT().MatchRegRange(gomock.Any(), gomock.Any(), gomock.Any()).Return(dropFlowBuilder).AnyTimes() action := mocks.NewMockAction(ctrl) action.EXPECT().Drop().Return(dropFlowBuilder).AnyTimes() dropFlowBuilder.EXPECT().Action().Return(action).AnyTimes() @@ -877,17 +876,16 @@ func newMockRuleFlowBuilder(ctrl *gomock.Controller) *mocks.MockFlowBuilder { ruleFlowBuilder.EXPECT().MatchDstIP(gomock.Any()).Return(ruleFlowBuilder).AnyTimes() ruleFlowBuilder.EXPECT().MatchSrcIP(gomock.Any()).Return(ruleFlowBuilder).AnyTimes() ruleFlowBuilder.EXPECT().MatchInPort(gomock.Any()).Return(ruleFlowBuilder).AnyTimes() - ruleFlowBuilder.EXPECT().MatchRegRange(gomock.Any(), gomock.Any(), gomock.Any()).Return(ruleFlowBuilder).AnyTimes() ruleFlowBuilder.EXPECT().MatchDstPort(gomock.Any(), gomock.Any()).Return(ruleFlowBuilder).AnyTimes() ruleFlowBuilder.EXPECT().MatchConjID(gomock.Any()).Return(ruleFlowBuilder).AnyTimes() ruleFlowBuilder.EXPECT().MatchPriority(gomock.Any()).Return(ruleFlowBuilder).AnyTimes() ruleAction = mocks.NewMockAction(ctrl) ruleCtAction := mocks.NewMockCTAction(ctrl) - ruleCtAction.EXPECT().LoadToLabelRange(gomock.Any(), gomock.Any()).Return(ruleCtAction).AnyTimes() + ruleCtAction.EXPECT().LoadToLabelField(gomock.Any(), gomock.Any()).Return(ruleCtAction).AnyTimes() ruleCtAction.EXPECT().CTDone().Return(ruleFlowBuilder).AnyTimes() ruleAction.EXPECT().CT(true, gomock.Any(), gomock.Any()).Return(ruleCtAction).AnyTimes() ruleAction.EXPECT().GotoTable(gomock.Any()).Return(ruleFlowBuilder).AnyTimes() - ruleAction.EXPECT().LoadRegRange(gomock.Any(), gomock.Any(), gomock.Any()).Return(ruleFlowBuilder).AnyTimes() + ruleAction.EXPECT().LoadToRegField(gomock.Any(), gomock.Any()).Return(ruleFlowBuilder).AnyTimes() ruleFlowBuilder.EXPECT().Action().Return(ruleAction).AnyTimes() ruleFlow = mocks.NewMockFlow(ctrl) ruleFlowBuilder.EXPECT().Done().Return(ruleFlow).AnyTimes() @@ -901,13 +899,12 @@ func newMockMetricFlowBuilder(ctrl *gomock.Controller) *mocks.MockFlowBuilder { metricFlowBuilder = mocks.NewMockFlowBuilder(ctrl) metricFlowBuilder.EXPECT().Cookie(gomock.Any()).Return(metricFlowBuilder).AnyTimes() metricFlowBuilder.EXPECT().MatchProtocol(gomock.Any()).Return(metricFlowBuilder).AnyTimes() - metricFlowBuilder.EXPECT().MatchRegRange(gomock.Any(), gomock.Any(), gomock.Any()).Return(metricFlowBuilder).AnyTimes() metricFlowBuilder.EXPECT().MatchPriority(gomock.Any()).Return(metricFlowBuilder).AnyTimes() metricFlowBuilder.EXPECT().MatchCTStateNew(gomock.Any()).Return(metricFlowBuilder).AnyTimes() - metricFlowBuilder.EXPECT().MatchCTLabelRange(gomock.Any(), gomock.Any(), gomock.Any()).Return(metricFlowBuilder).AnyTimes() + metricFlowBuilder.EXPECT().MatchCTLabelField(gomock.Any(), gomock.Any(), gomock.Any()).Return(metricFlowBuilder).AnyTimes() metricAction = mocks.NewMockAction(ctrl) metricAction.EXPECT().GotoTable(gomock.Any()).Return(metricFlowBuilder).AnyTimes() - metricAction.EXPECT().LoadRegRange(gomock.Any(), gomock.Any(), gomock.Any()).Return(metricFlowBuilder).AnyTimes() + metricAction.EXPECT().LoadToRegField(gomock.Any(), gomock.Any()).Return(metricFlowBuilder).AnyTimes() metricAction.EXPECT().Drop().Return(metricFlowBuilder).AnyTimes() metricFlowBuilder.EXPECT().Action().Return(metricAction).AnyTimes() metricFlow = mocks.NewMockFlow(ctrl) diff --git a/pkg/agent/openflow/pipeline.go b/pkg/agent/openflow/pipeline.go index be90f08616f..2fd739fe2b4 100644 --- a/pkg/agent/openflow/pipeline.go +++ b/pkg/agent/openflow/pipeline.go @@ -82,12 +82,6 @@ const ( // Index for priority cache priorityIndex = "priority" - // Traffic marks - markTrafficFromTunnel = 0 - markTrafficFromGateway = 1 - markTrafficFromLocal = 2 - markTrafficFromUplink = 4 - // IPv6 multicast prefix ipv6MulticastAddr = "FF00::/8" // IPv6 link-local prefix @@ -224,60 +218,14 @@ func (rt regType) reg() string { } const ( - // marksReg stores traffic-source mark and pod-found mark. - // traffic-source resides in [0..15], pod-found resides in [16], Antrea Policy disposition in [21-22], Custom Reasons in [24-26] - marksReg regType = 0 - PortCacheReg regType = 1 - swapReg regType = 2 - endpointIPReg regType = 3 // Use reg3 to store endpoint IP - endpointPortReg regType = 4 // Use reg4[0..15] to store endpoint port - serviceLearnReg = endpointPortReg // Use reg4[16..18] to store endpoint selection states. - EgressReg regType = 5 - IngressReg regType = 6 - TraceflowReg regType = 9 // Use reg9[28..31] to store traceflow dataplaneTag. - // CNPDenyConjIDReg reuses reg3 which will also be used for storing endpoint IP to store the rule ID. Since - // the service selection will finish when a packet hitting NetworkPolicy related rules, there is no conflict. - CNPDenyConjIDReg regType = 3 - endpointIPv6XXReg regType = 3 // xxReg3 will occupy reg12-reg15 - // marksRegServiceNeedLB indicates a packet need to do service selection. - marksRegServiceNeedLB uint32 = 0b001 - // marksRegServiceSelected indicates a packet has done service selection. - marksRegServiceSelected uint32 = 0b010 - // marksRegServiceNeedLearn indicates a packet has done service selection and - // the selection result needs to be cached. - marksRegServiceNeedLearn uint32 = 0b011 - CtZone = 0xfff0 CtZoneV6 = 0xffe6 - portFoundMark = 0b1 - hairpinMark = 0b1 - // macRewriteMark indicates the destination and source MACs of the - // packet should be rewritten in the l3ForwardingTable. - macRewriteMark = 0b1 - // cnpDenyMark indicates the packet is denied(Drop/Reject). - cnpDenyMark = 0b1 - - // gatewayCTMark is used to to mark connections initiated through the host gateway interface - // (i.e. for which the first packet of the connection was received through the gateway). - gatewayCTMark = 0x20 - ServiceCTMark = 0x21 - - // disposition is loaded in marksReg [21-22] - DispositionMarkReg regType = 0 - // disposition marks the flow action + // disposition values used in AP DispositionAllow = 0b00 DispositionDrop = 0b01 DispositionRej = 0b10 - // custom reason is loaded in marksReg [24-26] - // The custom reason mark is used to indicate the reason(s) for sending the packet - // to the controller. Reasons can be or-ed to indicate that the packets was sent - // for multiple reasons. - // For example, a value of 0b11 (CustomReasonLogging | CustomReasonReject) means - // that the packet is sent to the controller both for NetworkPolicy logging and - // because of a Reject action. - CustomReasonMarkReg regType = 0 // CustomReasonLogging is used when send packet-in to controller indicating this // packet need logging. CustomReasonLogging = 0b01 @@ -300,55 +248,13 @@ var DispositionToString = map[uint32]string{ } var ( - // ofPortMarkRange takes the 16th bit of register marksReg to indicate if the ofPort - // number of an interface. - // is found or not. Its value is 0x1 if yes. - ofPortMarkRange = binding.Range{16, 16} - // ofPortRegRange takes a 32-bit range of register PortCacheReg to cache the ofPort - // number of the interface. - ofPortRegRange = binding.Range{0, 31} - // hairpinMarkRange takes the 18th bit of register marksReg to indicate - // if the packet needs DNAT to virtual IP or not. Its value is 0x1 if yes. - hairpinMarkRange = binding.Range{18, 18} - // macRewriteMarkRange takes the 19th bit of register marksReg to indicate - // if the packet's MAC addresses need to be rewritten. Its value is 0x1 if yes. - macRewriteMarkRange = binding.Range{19, 19} - // cnpDenyMarkRange takes the 20th bit of register marksReg to indicate - // if the packet is denied(Drop/Reject). Its value is 0x1 if yes. - cnpDenyMarkRange = binding.Range{20, 20} - // APDispositionMarkRange takes the 21 to 22 bits of register marksReg to indicate - // disposition of Antrea Policy. It could have more bits to support more disposition - // that Antrea policy support in the future. - APDispositionMarkRange = binding.Range{21, 22} - // CustomReasonMarkRange takes the 24 to 26 bits of register marksReg to indicate - // the reason of sending packet to the controller. It could have more bits to - // support more customReason in the future. - CustomReasonMarkRange = binding.Range{24, 26} - // endpointIPRegRange takes a 32-bit range of register endpointIPReg to store - // the selected Service Endpoint IP. - endpointIPRegRange = binding.Range{0, 31} - // the selected Service Endpoint IPv6. - endpointIPv6XXRegRange = binding.Range{0, 127} - // endpointPortRegRange takes a 16-bit range of register endpointPortReg to store - // the selected Service Endpoint port. - endpointPortRegRange = binding.Range{0, 15} - // serviceLearnRegRange takes a 3-bit range of register serviceLearnReg to - // indicate if the packet accessing a Service has already selected the Service - // Endpoint, still needs to select an Endpoint, or if an Endpoint has already - // been selected and the selection decision needs to be learned. - serviceLearnRegRange = binding.Range{16, 18} - // metricIngressRuleIDRange takes 0..31 range of ct_label to store the ingress rule ID. - metricIngressRuleIDRange = binding.Range{0, 31} - // metricEgressRuleIDRange takes 32..63 range of ct_label to store the egress rule ID. - metricEgressRuleIDRange = binding.Range{32, 63} - // traceflowTagToSRange stores Traceflow dataplane tag to DSCP bits of // IP header ToS field. traceflowTagToSRange = binding.IPDSCPToSRange // snatPktMarkRange takes an 8-bit range of pkt_mark to store the ID of // a SNAT IP. The bit range must match SNATIPMarkMask. - snatPktMarkRange = binding.Range{0, 7} + snatPktMarkRange = &binding.Range{0, 7} globalVirtualMAC, _ = net.ParseMAC("aa:bb:cc:dd:ee:ff") hairpinIP = net.ParseIP("169.254.169.252").To4() @@ -553,8 +459,8 @@ func (c *client) defaultFlows() (flows []binding.Flow) { func (c *client) tunnelClassifierFlow(tunnelOFPort uint32, category cookie.Category) binding.Flow { return c.pipeline[ClassifierTable].BuildFlow(priorityNormal). MatchInPort(tunnelOFPort). - Action().LoadRegRange(int(marksReg), markTrafficFromTunnel, binding.Range{0, 15}). - Action().LoadRegRange(int(marksReg), macRewriteMark, macRewriteMarkRange). + Action().LoadRegMark(FromTunnelRegMark). + Action().LoadRegMark(RewriteMACRegMark). Action().GotoTable(conntrackTable). Cookie(c.cookieAllocator.Request(category).Raw()). Done() @@ -565,7 +471,7 @@ func (c *client) gatewayClassifierFlow(category cookie.Category) binding.Flow { classifierTable := c.pipeline[ClassifierTable] return classifierTable.BuildFlow(priorityNormal). MatchInPort(config.HostGatewayOFPort). - Action().LoadRegRange(int(marksReg), markTrafficFromGateway, binding.Range{0, 15}). + Action().LoadRegMark(FromGatewayRegMark). Action().GotoTable(classifierTable.GetNext()). Cookie(c.cookieAllocator.Request(category).Raw()). Done() @@ -576,7 +482,7 @@ func (c *client) podClassifierFlow(podOFPort uint32, category cookie.Category) b classifierTable := c.pipeline[ClassifierTable] return classifierTable.BuildFlow(priorityLow). MatchInPort(podOFPort). - Action().LoadRegRange(int(marksReg), markTrafficFromLocal, binding.Range{0, 15}). + Action().LoadRegMark(FromLocalRegMark). Action().GotoTable(classifierTable.GetNext()). Cookie(c.cookieAllocator.Request(category).Raw()). Done() @@ -616,15 +522,15 @@ func (c *client) connectionTrackFlows(category cookie.Category) []binding.Flow { Done(), connectionTrackCommitTable.BuildFlow(priorityLow).MatchProtocol(binding.ProtocolIP). MatchCTStateTrk(true). - MatchCTMark(ServiceCTMark, nil). - MatchRegRange(int(serviceLearnReg), marksRegServiceSelected, serviceLearnRegRange). + MatchCTMark(ServiceCTMark). + MatchRegMark(EpSelectedRegMark). Cookie(c.cookieAllocator.Request(category).Raw()). Action().GotoTable(connectionTrackCommitTable.GetNext()). Done(), connectionTrackCommitTable.BuildFlow(priorityLow).MatchProtocol(binding.ProtocolIPv6). MatchCTStateTrk(true). - MatchCTMark(ServiceCTMark, nil). - MatchRegRange(int(serviceLearnReg), marksRegServiceSelected, serviceLearnRegRange). + MatchCTMark(ServiceCTMark). + MatchRegMark(EpSelectedRegMark). Cookie(c.cookieAllocator.Request(category).Raw()). Action().GotoTable(connectionTrackCommitTable.GetNext()). Done(), @@ -641,11 +547,11 @@ func (c *client) connectionTrackFlows(category cookie.Category) []binding.Flow { ctZone = CtZoneV6 } flows = append(flows, - // Connections initiated through the gateway are marked with gatewayCTMark. + // Connections initiated through the gateway are marked with FromGatewayCTMark. connectionTrackCommitTable.BuildFlow(priorityNormal).MatchProtocol(proto). - MatchRegRange(int(marksReg), markTrafficFromGateway, binding.Range{0, 15}). + MatchRegMark(FromGatewayRegMark). MatchCTStateNew(true).MatchCTStateTrk(true). - Action().CT(true, connectionTrackCommitTable.GetNext(), ctZone).LoadToMark(gatewayCTMark).CTDone(). + Action().CT(true, connectionTrackCommitTable.GetNext(), ctZone).LoadToCtMark(FromGatewayCTMark).CTDone(). Cookie(c.cookieAllocator.Request(category).Raw()). Done(), // Add reject response packet bypass flow. @@ -661,7 +567,7 @@ func (c *client) conntrackBypassRejectFlow(proto binding.Protocol) binding.Flow connectionTrackStateTable := c.pipeline[conntrackStateTable] return connectionTrackStateTable.BuildFlow(priorityHigh). MatchProtocol(proto). - MatchRegRange(int(marksReg), CustomReasonReject, CustomReasonMarkRange). + MatchRegMark(CustomReasonRejectRegMark). Cookie(c.cookieAllocator.Request(cookie.Default).Raw()). Action().ResubmitToTable(connectionTrackStateTable.GetNext()). Done() @@ -775,8 +681,8 @@ func (c *client) traceflowConnectionTrackFlows(dataplaneTag uint8, receiverOnly nextTable := c.ingressEntryTable flowBuilder = l2FwdCalcTable.BuildFlow(priorityHigh). MatchDstMAC(packet.DestinationMAC). - Action().LoadRegRange(int(PortCacheReg), ofPort, ofPortRegRange). - Action().LoadRegRange(int(marksReg), portFoundMark, ofPortMarkRange). + Action().LoadToRegField(TargetOFPortField, ofPort). + Action().LoadRegMark(OFPortFoundRegMark). Action().LoadIPDSCP(dataplaneTag). Action().GotoTable(nextTable) if packet.SourceIP != nil { @@ -896,9 +802,9 @@ func (c *client) serviceLBBypassFlows(ipProtocol binding.Protocol) []binding.Flo // Tracked connections with the ServiceCTMark (load-balanced by AntreaProxy) receive // the macRewriteMark and are sent to egressRuleTable. connectionTrackStateTable.BuildFlow(priorityNormal).MatchProtocol(ipProtocol). - MatchCTMark(ServiceCTMark, nil). + MatchCTMark(ServiceCTMark). MatchCTStateNew(false).MatchCTStateTrk(true). - Action().LoadRegRange(int(marksReg), macRewriteMark, macRewriteMarkRange). + Action().LoadRegMark(RewriteMACRegMark). Action().GotoTable(EgressRuleTable). Cookie(c.cookieAllocator.Request(cookie.Service).Raw()). Done(), @@ -924,8 +830,8 @@ func (c *client) l2ForwardCalcFlow(dstMAC net.HardwareAddr, ofPort uint32, skipI } return l2FwdCalcTable.BuildFlow(priorityNormal). MatchDstMAC(dstMAC). - Action().LoadRegRange(int(PortCacheReg), ofPort, ofPortRegRange). - Action().LoadRegRange(int(marksReg), portFoundMark, ofPortMarkRange). + Action().LoadToRegField(TargetOFPortField, ofPort). + Action().LoadRegMark(OFPortFoundRegMark). Action().GotoTable(nextTable). Cookie(c.cookieAllocator.Request(category).Raw()). Done() @@ -942,23 +848,23 @@ func (c *client) traceflowL2ForwardOutputFlows(dataplaneTag uint8, liveTraffic, if c.encapMode.SupportsEncap() { // SendToController and Output if output port is tunnel port. fb1 := l2FwdOutTable.BuildFlow(priorityNormal+3). - MatchReg(int(PortCacheReg), config.DefaultTunOFPort). + MatchRegFieldWithValue(TargetOFPortField, config.DefaultTunOFPort). MatchIPDSCP(dataplaneTag). SetHardTimeout(timeout). MatchProtocol(ipProtocol). - MatchRegRange(int(marksReg), portFoundMark, ofPortMarkRange). - Action().OutputRegRange(int(PortCacheReg), ofPortRegRange). + MatchRegMark(OFPortFoundRegMark). + Action().OutputToRegField(TargetOFPortField). Cookie(c.cookieAllocator.Request(category).Raw()) // For injected packets, only SendToController if output port is local // gateway. In encapMode, a Traceflow packet going out of the gateway // port (i.e. exiting the overlay) essentially means that the Traceflow // request is complete. fb2 := l2FwdOutTable.BuildFlow(priorityNormal+2). - MatchReg(int(PortCacheReg), config.HostGatewayOFPort). + MatchRegFieldWithValue(TargetOFPortField, config.HostGatewayOFPort). MatchIPDSCP(dataplaneTag). SetHardTimeout(timeout). MatchProtocol(ipProtocol). - MatchRegRange(int(marksReg), portFoundMark, ofPortMarkRange). + MatchRegMark(OFPortFoundRegMark). Cookie(c.cookieAllocator.Request(category).Raw()) // Do not send to controller if captures only dropped packet. @@ -973,7 +879,7 @@ func (c *client) traceflowL2ForwardOutputFlows(dataplaneTag uint8, liveTraffic, if liveTraffic { // Clear the loaded DSCP bits before output. fb2 = fb2.Action().LoadIPDSCP(0). - Action().OutputRegRange(int(PortCacheReg), ofPortRegRange) + Action().OutputToRegField(TargetOFPortField) } flows = append(flows, fb1.Done(), fb2.Done()) } else { @@ -981,12 +887,12 @@ func (c *client) traceflowL2ForwardOutputFlows(dataplaneTag uint8, liveTraffic, // encapMode, inter-Node Pod-to-Pod traffic is expected to go out of the // gateway port on the way to its destination. fb1 := l2FwdOutTable.BuildFlow(priorityNormal+2). - MatchReg(int(PortCacheReg), config.HostGatewayOFPort). + MatchRegFieldWithValue(TargetOFPortField, config.HostGatewayOFPort). MatchIPDSCP(dataplaneTag). SetHardTimeout(timeout). MatchProtocol(ipProtocol). - MatchRegRange(int(marksReg), portFoundMark, ofPortMarkRange). - Action().OutputRegRange(int(PortCacheReg), ofPortRegRange). + MatchRegMark(OFPortFoundRegMark). + Action().OutputToRegField(TargetOFPortField). Cookie(c.cookieAllocator.Request(category).Raw()) if !droppedOnly { if c.ovsMetersAreSupported { @@ -1003,12 +909,12 @@ func (c *client) traceflowL2ForwardOutputFlows(dataplaneTag uint8, liveTraffic, } if gatewayIP != nil { fb := l2FwdOutTable.BuildFlow(priorityNormal+3). - MatchReg(int(PortCacheReg), config.HostGatewayOFPort). + MatchRegFieldWithValue(TargetOFPortField, config.HostGatewayOFPort). MatchDstIP(gatewayIP). MatchIPDSCP(dataplaneTag). SetHardTimeout(timeout). MatchProtocol(ipProtocol). - MatchRegRange(int(marksReg), portFoundMark, ofPortMarkRange). + MatchRegMark(OFPortFoundRegMark). Cookie(c.cookieAllocator.Request(category).Raw()) if !droppedOnly { if c.ovsMetersAreSupported { @@ -1018,16 +924,16 @@ func (c *client) traceflowL2ForwardOutputFlows(dataplaneTag uint8, liveTraffic, } if liveTraffic { fb = fb.Action().LoadIPDSCP(0). - Action().OutputRegRange(int(PortCacheReg), ofPortRegRange) + Action().OutputToRegField(TargetOFPortField) } flows = append(flows, fb.Done()) } // Only SendToController if output port is Pod port. - fb := l2FwdOutTable.BuildFlow(priorityNormal+2). + fb := l2FwdOutTable.BuildFlow(priorityNormal + 2). MatchIPDSCP(dataplaneTag). SetHardTimeout(timeout). MatchProtocol(ipProtocol). - MatchRegRange(int(marksReg), portFoundMark, ofPortMarkRange). + MatchRegMark(OFPortFoundRegMark). Cookie(c.cookieAllocator.Request(category).Raw()) if !droppedOnly { if c.ovsMetersAreSupported { @@ -1037,17 +943,17 @@ func (c *client) traceflowL2ForwardOutputFlows(dataplaneTag uint8, liveTraffic, } if liveTraffic { fb = fb.Action().LoadIPDSCP(0). - Action().OutputRegRange(int(PortCacheReg), ofPortRegRange) + Action().OutputToRegField(TargetOFPortField) } flows = append(flows, fb.Done()) if c.enableProxy { // Only SendToController for hairpin traffic. // This flow must have higher priority than the one installed by l2ForwardOutputServiceHairpinFlow - fbHairpin := l2FwdOutTable.BuildFlow(priorityHigh+2). + fbHairpin := l2FwdOutTable.BuildFlow(priorityHigh + 2). MatchIPDSCP(dataplaneTag). SetHardTimeout(timeout). MatchProtocol(ipProtocol). - MatchRegRange(int(marksReg), hairpinMark, hairpinMarkRange). + MatchRegMark(HairpinRegMark). Cookie(c.cookieAllocator.Request(cookie.Service).Raw()) if !droppedOnly { if c.ovsMetersAreSupported { @@ -1069,7 +975,7 @@ func (c *client) traceflowL2ForwardOutputFlows(dataplaneTag uint8, liveTraffic, // hairpin packets to avoid packets from being dropped by OVS. func (c *client) l2ForwardOutputServiceHairpinFlow() binding.Flow { return c.pipeline[L2ForwardingOutTable].BuildFlow(priorityHigh). - MatchRegRange(int(marksReg), hairpinMark, hairpinMarkRange). + MatchRegMark(HairpinRegMark). Action().OutputInPort(). Cookie(c.cookieAllocator.Request(cookie.Service).Raw()). Done() @@ -1080,13 +986,13 @@ func (c *client) l2ForwardOutputFlows(category cookie.Category) []binding.Flow { var flows []binding.Flow flows = append(flows, c.pipeline[L2ForwardingOutTable].BuildFlow(priorityNormal).MatchProtocol(binding.ProtocolIP). - MatchRegRange(int(marksReg), portFoundMark, ofPortMarkRange). - Action().OutputRegRange(int(PortCacheReg), ofPortRegRange). + MatchRegMark(OFPortFoundRegMark). + Action().OutputToRegField(TargetOFPortField). Cookie(c.cookieAllocator.Request(category).Raw()). Done(), c.pipeline[L2ForwardingOutTable].BuildFlow(priorityNormal).MatchProtocol(binding.ProtocolIPv6). - MatchRegRange(int(marksReg), portFoundMark, ofPortMarkRange). - Action().OutputRegRange(int(PortCacheReg), ofPortRegRange). + MatchRegMark(OFPortFoundRegMark). + Action().OutputToRegField(TargetOFPortField). Cookie(c.cookieAllocator.Request(category).Raw()). Done(), ) @@ -1103,7 +1009,7 @@ func (c *client) l3FwdFlowToPod(localGatewayMAC net.HardwareAddr, podInterfaceIP for _, ip := range podInterfaceIPs { ipProtocol := getIPProtocol(ip) flows = append(flows, l3FwdTable.BuildFlow(priorityNormal).MatchProtocol(ipProtocol). - MatchRegRange(int(marksReg), macRewriteMark, macRewriteMarkRange). + MatchRegMark(RewriteMACRegMark). MatchDstIP(ip). Action().SetSrcMAC(localGatewayMAC). // Rewrite src MAC to local gateway MAC, and rewrite dst MAC to pod MAC @@ -1160,7 +1066,7 @@ func (c *client) l3FwdFlowToGateway(localGatewayIPs []net.IP, localGatewayMAC ne for _, ip := range localGatewayIPs { ipProtocol := getIPProtocol(ip) flows = append(flows, l3FwdTable.BuildFlow(priorityNormal).MatchProtocol(ipProtocol). - MatchRegRange(int(marksReg), macRewriteMark, macRewriteMarkRange). + MatchRegMark(RewriteMACRegMark). MatchDstIP(ip). Action().SetDstMAC(localGatewayMAC). Action().GotoTable(l3FwdTable.GetNext()). @@ -1168,7 +1074,7 @@ func (c *client) l3FwdFlowToGateway(localGatewayIPs []net.IP, localGatewayMAC ne Done()) } // Rewrite the destination MAC address with the local host gateway MAC if the packet is in the reply direction and - // is marked with gatewayCTMark. This is for connections which were initiated through the gateway, to ensure that + // is marked with FromGatewayCTMark. This is for connections which were initiated through the gateway, to ensure that // this reply traffic gets forwarded correctly (back to the host network namespace, through the gateway). In // particular, it is necessary in the following 2 cases: // 1) reply traffic for connections from a local Pod to a ClusterIP Service (when AntreaProxy is disabled and @@ -1181,7 +1087,7 @@ func (c *client) l3FwdFlowToGateway(localGatewayIPs []net.IP, localGatewayMAC ne // externalTrafficPolicy is set to Local, using the local Node's IP address. for _, proto := range c.ipProtocols { flows = append(flows, l3FwdTable.BuildFlow(priorityHigh).MatchProtocol(proto). - MatchCTMark(gatewayCTMark, nil). + MatchCTMark(FromGatewayCTMark). MatchCTStateRpl(true).MatchCTStateTrk(true). Action().SetDstMAC(localGatewayMAC). Action().GotoTable(l3FwdTable.GetNext()). @@ -1256,9 +1162,9 @@ func (c *client) arpResponderStaticFlow(category cookie.Category) binding.Flow { Action().LoadARPOperation(2). Action().Move(binding.NxmFieldARPSha, binding.NxmFieldARPTha). Action().SetARPSha(globalVirtualMAC). - Action().Move(binding.NxmFieldARPTpa, swapReg.nxm()). + Action().Move(binding.NxmFieldARPTpa, SwapField.GetNXFieldName()). Action().Move(binding.NxmFieldARPSpa, binding.NxmFieldARPTpa). - Action().Move(swapReg.nxm(), binding.NxmFieldARPSpa). + Action().Move(SwapField.GetNXFieldName(), binding.NxmFieldARPSpa). Action().OutputInPort(). Cookie(c.cookieAllocator.Request(category).Raw()). Done() @@ -1318,7 +1224,7 @@ func (c *client) serviceHairpinResponseDNATFlow(ipProtocol binding.Protocol) bin return c.pipeline[serviceHairpinTable].BuildFlow(priorityNormal).MatchProtocol(ipProtocol). MatchDstIP(hpIP). Action().Move(from, to). - Action().LoadRegRange(int(marksReg), hairpinMark, hairpinMarkRange). + Action().LoadRegMark(HairpinRegMark). Action().GotoTable(conntrackTable). Cookie(c.cookieAllocator.Request(cookie.Service).Raw()). Done() @@ -1352,8 +1258,8 @@ func (c *client) arpSpoofGuardFlow(ifIP net.IP, ifMAC net.HardwareAddr, ifOFPort // selection of the Service. func (c *client) sessionAffinityReselectFlow() binding.Flow { return c.pipeline[endpointDNATTable].BuildFlow(priorityLow). - MatchRegRange(int(serviceLearnReg), marksRegServiceSelected, serviceLearnRegRange). - Action().LoadRegRange(int(serviceLearnReg), marksRegServiceNeedLB, serviceLearnRegRange). + MatchRegMark(EpSelectedRegMark). + Action().LoadRegMark(EpToSelectRegMark). Action().ResubmitToTable(serviceLBTable). Cookie(c.cookieAllocator.Request(cookie.Service).Raw()). Done() @@ -1388,8 +1294,8 @@ func (c *client) serviceCIDRDNATFlows(serviceCIDRs []*net.IPNet) []binding.Flow ipProto := getIPProtocol(serviceCIDR.IP) flows = append(flows, c.pipeline[dnatTable].BuildFlow(priorityNormal).MatchProtocol(ipProto). MatchDstIPNet(*serviceCIDR). - Action().LoadRegRange(int(PortCacheReg), config.HostGatewayOFPort, ofPortRegRange). - Action().LoadRegRange(int(marksReg), portFoundMark, ofPortMarkRange). + Action().LoadToRegField(TargetOFPortField, config.HostGatewayOFPort). + Action().LoadRegMark(OFPortFoundRegMark). Action().GotoTable(conntrackCommitTable). Cookie(c.cookieAllocator.Request(cookie.Service).Raw()). Done()) @@ -1402,7 +1308,7 @@ func (c *client) serviceCIDRDNATFlows(serviceCIDRs []*net.IPNet) []binding.Flow func (c *client) serviceNeedLBFlow() binding.Flow { return c.pipeline[sessionAffinityTable].BuildFlow(priorityMiss). Cookie(c.cookieAllocator.Request(cookie.Service).Raw()). - Action().LoadRegRange(int(serviceLearnReg), marksRegServiceNeedLB, serviceLearnRegRange). + Action().LoadRegMark(EpToSelectRegMark). Done() } @@ -1419,17 +1325,17 @@ func (c *client) allowRulesMetricFlows(conjunctionID uint32, ingress bool) []bin offset := 0 // We use the 0..31 bits of the ct_label to store the ingress rule ID and use the 32..63 bits to store the // egress rule ID. - labelRange := metricIngressRuleIDRange + field := IngressRuleCTLabel if !ingress { metricTableID = EgressMetricTable offset = 32 - labelRange = metricEgressRuleIDRange + field = EgressRuleCTLabel } metricFlow := func(isCTNew bool, protocol binding.Protocol) binding.Flow { return c.pipeline[metricTableID].BuildFlow(priorityNormal). MatchProtocol(protocol). MatchCTStateNew(isCTNew). - MatchCTLabelRange(0, uint64(conjunctionID)< DNAT(CtZone) --> SNAT(ctZoneSNAT) --> Endpoint(API server NodeIP) // Pod <-- unDNAT(CtZone) <-- unSNAT(ctZoneSNAT) <-- Endpoint(API server NodeIP) ctZoneSNAT = 0xffdc +) +var ( // snatCTMark indicates SNAT is performed for packets of the connection. - snatCTMark = 0x40 + snatCTMark = binding.NewCTMark(0x40, 0, 31) ) func (c *client) snatMarkFlows(snatIP net.IP, mark uint32) []binding.Flow { @@ -56,7 +58,7 @@ func (c *client) snatMarkFlows(snatIP net.IP, mark uint32) []binding.Flow { MatchPktMark(mark, &types.SNATIPMarkMask). Action().CT(true, nextTable, CtZone). SNAT(snatIPRange, nil). - LoadToMark(snatCTMark).CTDone(). + LoadToCtMark(snatCTMark).CTDone(). Cookie(c.cookieAllocator.Request(cookie.SNAT).Raw()). Done(), } @@ -68,7 +70,7 @@ func (c *client) snatMarkFlows(snatIP net.IP, mark uint32) []binding.Flow { MatchPktMark(mark, &types.SNATIPMarkMask). Action().CT(true, nextTable, ctZoneSNAT). SNAT(snatIPRange, nil). - LoadToMark(snatCTMark).CTDone(). + LoadToCtMark(snatCTMark).CTDone(). Cookie(c.cookieAllocator.Request(cookie.SNAT).Raw()). Done()) } @@ -97,8 +99,8 @@ func (c *client) hostBridgeUplinkFlows(localSubnet net.IPNet, category cookie.Ca flows = append(flows, c.pipeline[ClassifierTable].BuildFlow(priorityHigh).MatchProtocol(binding.ProtocolIP). MatchInPort(config.UplinkOFPort). MatchDstIPNet(localSubnet). - Action().LoadRegRange(int(marksReg), markTrafficFromUplink, binding.Range{0, 15}). - Action().LoadRegRange(int(marksReg), macRewriteMark, macRewriteMarkRange). + Action().LoadRegMark(FromUplinkRegMark). + Action().LoadRegMark(RewriteMACRegMark). Action().GotoTable(serviceHairpinTable). Cookie(c.cookieAllocator.Request(category).Raw()). Done()) @@ -114,8 +116,8 @@ func (c *client) l3FwdFlowToRemoteViaRouting(localGatewayMAC net.HardwareAddr, r // It enhances Windows Noencap mode performance by bypassing host network. flows := []binding.Flow{c.pipeline[l2ForwardingCalcTable].BuildFlow(priorityNormal). MatchDstMAC(remoteGatewayMAC). - Action().LoadRegRange(int(PortCacheReg), config.UplinkOFPort, ofPortRegRange). - Action().LoadRegRange(int(marksReg), macRewriteMark, ofPortMarkRange). + Action().LoadToRegField(TargetOFPortField, config.UplinkOFPort). + Action().LoadRegMark(OFPortFoundRegMark). Action().GotoTable(conntrackCommitTable). Cookie(c.cookieAllocator.Request(category).Raw()). Done(), diff --git a/pkg/ovs/openflow/interfaces.go b/pkg/ovs/openflow/interfaces.go index b6abef24603..0ca0a304312 100644 --- a/pkg/ovs/openflow/interfaces.go +++ b/pkg/ovs/openflow/interfaces.go @@ -80,7 +80,7 @@ const ( ) // IPDSCPToSRange stores the DSCP bits in ToS field of IP header. -var IPDSCPToSRange = Range{2, 7} +var IPDSCPToSRange = &Range{2, 7} // Bridge defines operations on an openflow bridge. type Bridge interface { @@ -178,10 +178,11 @@ type Flow interface { type Action interface { LoadARPOperation(value uint16) FlowBuilder - LoadRegRange(regID int, value uint32, to Range) FlowBuilder - LoadPktMarkRange(value uint32, to Range) FlowBuilder + LoadToRegField(field *RegField, value uint32) FlowBuilder + LoadRegMark(mark *RegMark) FlowBuilder + LoadPktMarkRange(value uint32, to *Range) FlowBuilder LoadIPDSCP(value uint8) FlowBuilder - LoadRange(name string, addr uint64, to Range) FlowBuilder + LoadRange(name string, addr uint64, to *Range) FlowBuilder Move(from, to string) FlowBuilder MoveRange(fromName, toName string, from, to Range) FlowBuilder Resubmit(port uint16, table TableIDType) FlowBuilder @@ -189,8 +190,8 @@ type Action interface { CT(commit bool, tableID TableIDType, zone int) CTAction Drop() FlowBuilder Output(port int) FlowBuilder - OutputFieldRange(from string, rng Range) FlowBuilder - OutputRegRange(regID int, rng Range) FlowBuilder + OutputFieldRange(from string, rng *Range) FlowBuilder + OutputToRegField(field *RegField) FlowBuilder OutputInPort() FlowBuilder SetDstMAC(addr net.HardwareAddr) FlowBuilder SetSrcMAC(addr net.HardwareAddr) FlowBuilder @@ -216,9 +217,9 @@ type FlowBuilder interface { MatchPriority(uint16) FlowBuilder MatchProtocol(name Protocol) FlowBuilder MatchIPProtocolValue(isIPv6 bool, protoValue uint8) FlowBuilder - MatchReg(regID int, data uint32) FlowBuilder MatchXXReg(regID int, data []byte) FlowBuilder - MatchRegRange(regID int, data uint32, rng Range) FlowBuilder + MatchRegMark(mark *RegMark) FlowBuilder + MatchRegFieldWithValue(field *RegField, data uint32) FlowBuilder MatchInPort(inPort uint32) FlowBuilder MatchDstIP(ip net.IP) FlowBuilder MatchDstIPNet(ipNet net.IPNet) FlowBuilder @@ -240,8 +241,8 @@ type FlowBuilder interface { MatchCTStateInv(isSet bool) FlowBuilder MatchCTStateDNAT(isSet bool) FlowBuilder MatchCTStateSNAT(isSet bool) FlowBuilder - MatchCTMark(value uint32, mask *uint32) FlowBuilder - MatchCTLabelRange(high, low uint64, bitRange Range) FlowBuilder + MatchCTMark(mark *CtMark) FlowBuilder + MatchCTLabelField(high, low uint64, field *CtLabel) FlowBuilder MatchPktMark(value uint32, mask *uint32) FlowBuilder MatchConjID(value uint32) FlowBuilder MatchDstPort(port uint16, portMask *uint16) FlowBuilder @@ -285,10 +286,10 @@ type LearnAction interface { MatchLearnedDstIP() LearnAction MatchLearnedSrcIPv6() LearnAction MatchLearnedDstIPv6() LearnAction - MatchReg(regID int, data uint32, rng Range) LearnAction - LoadReg(regID int, data uint32, rng Range) LearnAction - LoadRegToReg(fromRegID, toRegID int, fromRng, toRng Range) LearnAction - LoadXXRegToXXReg(fromRegID, toRegID int, fromRng, toRng Range) LearnAction + MatchRegMark(mark *RegMark) LearnAction + LoadRegMark(mark *RegMark) LearnAction + LoadFieldToField(fromField, toField *RegField) LearnAction + LoadXXRegToXXReg(fromXXField, toXXField *XXRegField) LearnAction SetDstMAC(mac net.HardwareAddr) LearnAction Done() FlowBuilder } @@ -301,9 +302,12 @@ type Group interface { type BucketBuilder interface { Weight(val uint16) BucketBuilder + // Deprecated. LoadReg(regID int, data uint32) BucketBuilder LoadXXReg(regID int, data []byte) BucketBuilder - LoadRegRange(regID int, data uint32, rng Range) BucketBuilder + // Deprecated. + LoadRegRange(regID int, data uint32, rng *Range) BucketBuilder + LoadToRegField(field *RegField, data uint32) BucketBuilder ResubmitToTable(tableID TableIDType) BucketBuilder Done() Group } @@ -325,7 +329,8 @@ type MeterBandBuilder interface { type CTAction interface { LoadToMark(value uint32) CTAction - LoadToLabelRange(value uint64, rng *Range) CTAction + LoadToCtMark(mark *CtMark) CTAction + LoadToLabelField(value uint64, labelField *CtLabel) CTAction MoveToLabel(fromName string, fromRng, labelRng *Range) CTAction // NAT action translates the packet in the way that the connection was committed into the conntrack zone, e.g., if // a connection was committed with SNAT, the later packets would be translated with the earlier SNAT configurations. @@ -364,7 +369,8 @@ type PacketOutBuilder interface { SetICMPData(data []byte) PacketOutBuilder SetInport(inPort uint32) PacketOutBuilder SetOutport(outport uint32) PacketOutBuilder - AddLoadAction(name string, data uint64, rng Range) PacketOutBuilder + AddLoadAction(name string, data uint64, rng *Range) PacketOutBuilder + AddLoadRegMark(mark *RegMark) PacketOutBuilder Done() *ofctrl.PacketOut } @@ -403,3 +409,32 @@ type Packet struct { ICMPEchoID uint16 ICMPEchoSeq uint16 } + +// RegField specifies a bit range of a register. regID is the register number, and rng is the range of bits +// taken by the field. The OF client could use a RegField to cache or match varied value. +type RegField struct { + regID int + rng *Range + name string +} + +// RegMark is a value saved in a RegField. A RegMark is used to indicate the traffic +// has some expected characteristics. +type RegMark struct { + field *RegField + value uint32 +} + +// XXRegField specifies a xxreg with a required bit range. +type XXRegField RegField + +// CtMark is used to indicate the connection characteristics. +type CtMark struct { + rng *Range + value uint32 +} + +type CtLabel struct { + rng *Range + name string +} diff --git a/pkg/ovs/openflow/ofctrl_action.go b/pkg/ovs/openflow/ofctrl_action.go index 4308188db6b..1b1bbd81995 100644 --- a/pkg/ovs/openflow/ofctrl_action.go +++ b/pkg/ovs/openflow/ofctrl_action.go @@ -31,16 +31,15 @@ func (a *ofFlowAction) Output(port int) FlowBuilder { } // OutputFieldRange is an action to output packets to the port located in the specified NXM field with rng. -func (a *ofFlowAction) OutputFieldRange(name string, rng Range) FlowBuilder { +func (a *ofFlowAction) OutputFieldRange(name string, rng *Range) FlowBuilder { outputAction, _ := ofctrl.NewNXOutput(name, int(rng[0]), int(rng[1])) a.builder.ApplyAction(outputAction) return a.builder } -// OutputFieldRange is an action to output packets to a port which is located in the specified NXM register[rng[0]..rng[1]]. -func (a *ofFlowAction) OutputRegRange(regID int, rng Range) FlowBuilder { - name := fmt.Sprintf("%s%d", NxmFieldReg, regID) - return a.OutputFieldRange(name, rng) +func (a *ofFlowAction) OutputToRegField(field *RegField) FlowBuilder { + name := field.GetNXFieldName() + return a.OutputFieldRange(name, field.rng) } // OutputInPort is an action to output packets to the ofport from where the packet enters the OFSwitch. @@ -79,10 +78,15 @@ func (a *ofCTAction) LoadToMark(value uint32) CTAction { return a } -// LoadToLabelRange is an action to load data into ct_label at specified range. -func (a *ofCTAction) LoadToLabelRange(value uint64, rng *Range) CTAction { +func (a *ofCTAction) LoadToCtMark(mark *CtMark) CTAction { + field, _, _ := getFieldRange(NxmFieldCtMark) + a.load(field, uint64(mark.value), mark.rng) + return a +} + +func (a *ofCTAction) LoadToLabelField(value uint64, labelField *CtLabel) CTAction { field, _, _ := getFieldRange(NxmFieldCtLabel) - a.load(field, value, rng) + a.load(field, value, labelField.rng) return a } @@ -222,7 +226,7 @@ func (a *ofFlowAction) LoadARPOperation(value uint16) FlowBuilder { } // LoadRange is an action to Load data to the target field at specified range. -func (a *ofFlowAction) LoadRange(name string, value uint64, rng Range) FlowBuilder { +func (a *ofFlowAction) LoadRange(name string, value uint64, rng *Range) FlowBuilder { loadAct, _ := ofctrl.NewNXLoadAction(name, value, rng.ToNXRange()) if a.builder.ofFlow.Table != nil && a.builder.ofFlow.Table.Switch != nil { loadAct.ResetFieldLength(a.builder.ofFlow.Table.Switch) @@ -231,16 +235,19 @@ func (a *ofFlowAction) LoadRange(name string, value uint64, rng Range) FlowBuild return a.builder } -// LoadRegRange is an action to Load data to the target register at specified range. -func (a *ofFlowAction) LoadRegRange(regID int, value uint32, rng Range) FlowBuilder { - name := fmt.Sprintf("%s%d", NxmFieldReg, regID) - loadAct, _ := ofctrl.NewNXLoadAction(name, uint64(value), rng.ToNXRange()) +func (a *ofFlowAction) LoadToRegField(field *RegField, value uint32) FlowBuilder { + name := field.GetNXFieldName() + loadAct, _ := ofctrl.NewNXLoadAction(name, uint64(value), field.rng.ToNXRange()) a.builder.ApplyAction(loadAct) return a.builder } +func (a *ofFlowAction) LoadRegMark(mark *RegMark) FlowBuilder { + return a.LoadToRegField(mark.field, mark.value) +} + // LoadToPktMarkRange is an action to load data into pkt_mark at specified range. -func (a *ofFlowAction) LoadPktMarkRange(value uint32, rng Range) FlowBuilder { +func (a *ofFlowAction) LoadPktMarkRange(value uint32, rng *Range) FlowBuilder { return a.LoadRange(NxmFieldPktMark, uint64(value), rng) } @@ -469,16 +476,15 @@ func (a *ofLearnAction) MatchLearnedDstIPv6() LearnAction { return a } -// MatchReg makes the learned flow to match the data in the reg of specific range. -func (a *ofLearnAction) MatchReg(regID int, data uint32, rng Range) LearnAction { - toField := &ofctrl.LearnField{Name: fmt.Sprintf("NXM_NX_REG%d", regID), Start: uint16(rng[0])} +func (a *ofLearnAction) MatchRegMark(mark *RegMark) LearnAction { + toField := &ofctrl.LearnField{Name: mark.field.GetNXFieldName(), Start: uint16(mark.field.rng[0])} valBuf := make([]byte, 4) - binary.BigEndian.PutUint32(valBuf, data) - offset := (rng.Length()-1)/8 + 1 + binary.BigEndian.PutUint32(valBuf, mark.value) + offset := (mark.field.rng.Length()-1)/8 + 1 if offset < 2 { offset = 2 } - a.nxLearn.AddMatch(toField, uint16(rng.Length()), nil, valBuf[4-offset:]) + a.nxLearn.AddMatch(toField, uint16(mark.field.rng.Length()), nil, valBuf[4-offset:]) return a } @@ -494,34 +500,31 @@ func (a *ofLearnAction) MatchXXReg(regID int, data []byte, rng Range) LearnActio return a } -// LoadRegToReg makes the learned flow to load reg[fromRegID] to reg[toRegID] -// with specific ranges. -func (a *ofLearnAction) LoadRegToReg(fromRegID, toRegID int, fromRng, toRng Range) LearnAction { - fromField := &ofctrl.LearnField{Name: fmt.Sprintf("NXM_NX_REG%d", fromRegID), Start: uint16(fromRng[0])} - toField := &ofctrl.LearnField{Name: fmt.Sprintf("NXM_NX_REG%d", toRegID), Start: uint16(toRng[0])} - a.nxLearn.AddLoadAction(toField, uint16(toRng.Length()), fromField, nil) +func (a *ofLearnAction) LoadFieldToField(fromField, toField *RegField) LearnAction { + from := &ofctrl.LearnField{Name: fromField.GetNXFieldName(), Start: uint16(fromField.rng[0])} + to := &ofctrl.LearnField{Name: toField.GetNXFieldName(), Start: uint16(toField.rng[0])} + a.nxLearn.AddLoadAction(to, uint16(toField.rng.Length()), from, nil) return a } -// LoadXXRegToXXReg makes the learned flow to load reg[fromXxRegID] to reg[toXxRegID] +// LoadXXRegToXXReg makes the learned flow to load reg[fromXXField.regID] to reg[toXXField.regID] // with specific ranges. -func (a *ofLearnAction) LoadXXRegToXXReg(fromXxRegID, toXxRegID int, fromRng, toRng Range) LearnAction { - fromField := &ofctrl.LearnField{Name: fmt.Sprintf("%s%d", NxmFieldXXReg, fromXxRegID), Start: uint16(fromRng[0])} - toField := &ofctrl.LearnField{Name: fmt.Sprintf("%s%d", NxmFieldXXReg, toXxRegID), Start: uint16(toRng[0])} - a.nxLearn.AddLoadAction(toField, uint16(toRng.Length()), fromField, nil) +func (a *ofLearnAction) LoadXXRegToXXReg(fromXXField, toXXField *XXRegField) LearnAction { + from := &ofctrl.LearnField{Name: fromXXField.GetNXFieldName(), Start: uint16(fromXXField.rng[0])} + to := &ofctrl.LearnField{Name: toXXField.GetNXFieldName(), Start: uint16(toXXField.rng[0])} + a.nxLearn.AddLoadAction(to, uint16(toXXField.rng.Length()), from, nil) return a } -// LoadReg makes the learned flow to load data to reg[regID] with specific range. -func (a *ofLearnAction) LoadReg(regID int, data uint32, rng Range) LearnAction { - toField := &ofctrl.LearnField{Name: fmt.Sprintf("NXM_NX_REG%d", regID), Start: uint16(rng[0])} +func (a *ofLearnAction) LoadRegMark(mark *RegMark) LearnAction { + toField := &ofctrl.LearnField{Name: mark.field.GetNXFieldName(), Start: uint16(mark.field.rng[0])} valBuf := make([]byte, 4) - binary.BigEndian.PutUint32(valBuf, data) - offset := (rng.Length()-1)/8 + 1 + binary.BigEndian.PutUint32(valBuf, mark.value) + offset := (mark.field.rng.Length()-1)/8 + 1 if offset < 2 { offset = 2 } - a.nxLearn.AddLoadAction(toField, uint16(rng.Length()), nil, valBuf[4-offset:]) + a.nxLearn.AddLoadAction(toField, uint16(mark.field.rng.Length()), nil, valBuf[4-offset:]) return a } diff --git a/pkg/ovs/openflow/ofctrl_builder.go b/pkg/ovs/openflow/ofctrl_builder.go index d665e2749c5..eb7cc48b153 100644 --- a/pkg/ovs/openflow/ofctrl_builder.go +++ b/pkg/ovs/openflow/ofctrl_builder.go @@ -60,8 +60,8 @@ func (b *ofFlowBuilder) Done() Flow { return &b.ofFlow } -// MatchReg adds match condition for matching data in the target register. -func (b *ofFlowBuilder) MatchReg(regID int, data uint32) FlowBuilder { +// matchReg adds match condition for matching data in the target register. +func (b *ofFlowBuilder) matchReg(regID int, data uint32) FlowBuilder { b.matchers = append(b.matchers, fmt.Sprintf("reg%d=0x%x", regID, data)) reg := &ofctrl.NXRegister{ ID: regID, @@ -83,8 +83,8 @@ func (b *ofFlowBuilder) MatchXXReg(regID int, data []byte) FlowBuilder { return b } -// MatchRegRange adds match condition for matching data in the target register at specified range. -func (b *ofFlowBuilder) MatchRegRange(regID int, data uint32, rng Range) FlowBuilder { +// matchRegRange adds match condition for matching data in the target register at specified range. +func (b *ofFlowBuilder) matchRegRange(regID int, data uint32, rng *Range) FlowBuilder { s := fmt.Sprintf("reg%d[%d..%d]=0x%x", regID, rng[0], rng[1], data) b.matchers = append(b.matchers, s) if rng[0] > 0 { @@ -99,6 +99,17 @@ func (b *ofFlowBuilder) MatchRegRange(regID int, data uint32, rng Range) FlowBui return b } +func (b *ofFlowBuilder) MatchRegMark(mark *RegMark) FlowBuilder { + return b.MatchRegFieldWithValue(mark.field, mark.value) +} + +func (b *ofFlowBuilder) MatchRegFieldWithValue(field *RegField, data uint32) FlowBuilder { + if field.isFullRange() { + return b.matchReg(field.regID, data) + } + return b.matchRegRange(field.regID, data, field.rng) +} + func (b *ofFlowBuilder) addCTStateString(value string) { if b.ctStateString == "" { b.ctStateString = fmt.Sprintf("ct_state=%s", value) @@ -219,12 +230,17 @@ func (b *ofFlowBuilder) MatchCTStateSNAT(set bool) FlowBuilder { return b } -// MatchCTMark adds match condition for matching ct_mark. If mask is nil, the mask should be not set in the OpenFlow -// message which is sent to OVS, and OVS should match the value exactly. -func (b *ofFlowBuilder) MatchCTMark(value uint32, mask *uint32) FlowBuilder { - b.matchers = append(b.matchers, fmt.Sprintf("ct_mark=%d", value)) - b.ofFlow.Match.CtMark = value - b.ofFlow.Match.CtMarkMask = mask +func (b *ofFlowBuilder) MatchCTMark(mark *CtMark) FlowBuilder { + ctmarkKey := fmt.Sprintf("ct_mark=0x%x", mark.value) + b.ofFlow.Match.CtMark = mark.value + if mark.isFullRange() { + b.ofFlow.Match.CtMarkMask = nil + } else { + mask := mark.rng.ToNXRange().ToUint32Mask() + ctmarkKey = fmt.Sprintf("%s/0x%x", ctmarkKey, mask) + b.ofFlow.Match.CtMarkMask = &mask + } + b.matchers = append(b.matchers, ctmarkKey) return b } @@ -262,7 +278,7 @@ func (b *ofFlowBuilder) MatchTunnelDst(dstIP net.IP) FlowBuilder { return b } -func ctLabelRange(high, low uint64, rng Range, match *ofctrl.FlowMatch) { +func ctLabelRange(high, low uint64, rng *Range, match *ofctrl.FlowMatch) { // [127..64] [63..0] // high low match.CtLabelHi = high @@ -291,9 +307,9 @@ func ctLabelRange(high, low uint64, rng Range, match *ofctrl.FlowMatch) { } } -func (b *ofFlowBuilder) MatchCTLabelRange(high, low uint64, bitRange Range) FlowBuilder { - b.matchers = append(b.matchers, fmt.Sprintf("ct_label[%d..%d]=0x%x%x", bitRange[0], bitRange[1], high, low)) - ctLabelRange(high, low, bitRange, &b.ofFlow.Match) +func (b *ofFlowBuilder) MatchCTLabelField(high, low uint64, field *CtLabel) FlowBuilder { + b.matchers = append(b.matchers, fmt.Sprintf("ct_label[%d..%d]=0x%x%x", field.rng[0], field.rng[1], high, low)) + ctLabelRange(high, low, field.GetRange(), &b.ofFlow.Match) return b } diff --git a/pkg/ovs/openflow/ofctrl_builder_test.go b/pkg/ovs/openflow/ofctrl_builder_test.go index e3f0d6d1e42..375507b04c2 100644 --- a/pkg/ovs/openflow/ofctrl_builder_test.go +++ b/pkg/ovs/openflow/ofctrl_builder_test.go @@ -24,17 +24,17 @@ import ( func TestMatchCTLabelRange(t *testing.T) { for _, tc := range []struct { - rng Range + rng *Range expectedLowMask, expectedHighMask uint64 }{ - {rng: Range{0, 0}, expectedLowMask: 0x1, expectedHighMask: 0x0}, - {rng: Range{1, 1}, expectedLowMask: 0b10, expectedHighMask: 0x0}, - {rng: Range{127, 127}, expectedLowMask: 0x0, expectedHighMask: 0x8000_0000_0000_0000}, - {rng: Range{126, 127}, expectedLowMask: 0x0, expectedHighMask: 0xc000_0000_0000_0000}, - {rng: Range{0, 127}, expectedLowMask: 0xffff_ffff_ffff_ffff, expectedHighMask: 0xffff_ffff_ffff_ffff}, - {rng: Range{0, 64}, expectedLowMask: 0xffff_ffff_ffff_ffff, expectedHighMask: 0x1}, - {rng: Range{0, 63}, expectedLowMask: 0xffff_ffff_ffff_ffff, expectedHighMask: 0x0}, - {rng: Range{64, 127}, expectedLowMask: 0x0, expectedHighMask: 0xffff_ffff_ffff_ffff}, + {rng: &Range{0, 0}, expectedLowMask: 0x1, expectedHighMask: 0x0}, + {rng: &Range{1, 1}, expectedLowMask: 0b10, expectedHighMask: 0x0}, + {rng: &Range{127, 127}, expectedLowMask: 0x0, expectedHighMask: 0x8000_0000_0000_0000}, + {rng: &Range{126, 127}, expectedLowMask: 0x0, expectedHighMask: 0xc000_0000_0000_0000}, + {rng: &Range{0, 127}, expectedLowMask: 0xffff_ffff_ffff_ffff, expectedHighMask: 0xffff_ffff_ffff_ffff}, + {rng: &Range{0, 64}, expectedLowMask: 0xffff_ffff_ffff_ffff, expectedHighMask: 0x1}, + {rng: &Range{0, 63}, expectedLowMask: 0xffff_ffff_ffff_ffff, expectedHighMask: 0x0}, + {rng: &Range{64, 127}, expectedLowMask: 0x0, expectedHighMask: 0xffff_ffff_ffff_ffff}, } { match := new(ofctrl.FlowMatch) ctLabelRange(0, 0, tc.rng, match) diff --git a/pkg/ovs/openflow/ofctrl_flow_test.go b/pkg/ovs/openflow/ofctrl_flow_test.go index 4bc23da6633..789013fa9b6 100644 --- a/pkg/ovs/openflow/ofctrl_flow_test.go +++ b/pkg/ovs/openflow/ofctrl_flow_test.go @@ -6,20 +6,23 @@ import ( "github.com/stretchr/testify/assert" ) +var testField = NewRegField(1, 0, 15, "testField") + func TestCopyToBuilder(t *testing.T) { table := &ofTable{ id: 0, next: 1, } + mark := NewCTMark(12345, 0, 31) oriFlow := table.BuildFlow(uint16(100)).MatchProtocol(ProtocolIP). Cookie(uint64(1004)). - MatchRegRange(1, 0x101, Range{0, 15}). + MatchRegFieldWithValue(testField, 0x101). MatchCTStateNew(true).MatchCTStateTrk(true). Action().CT( true, 1, 0x1234). - LoadToMark(uint32(12345)). + LoadToCtMark(mark). MoveToLabel(NxmFieldSrcMAC, &Range{0, 47}, &Range{0, 47}).CTDone(). Done() newFlow := oriFlow.CopyToBuilder(0, false) @@ -37,7 +40,7 @@ func TestCopyToBuilder_Drop(t *testing.T) { } oriFlow := table.BuildFlow(uint16(100)).MatchProtocol(ProtocolIP). Cookie(uint64(1004)). - MatchRegRange(1, 0x101, Range{0, 15}). + MatchRegFieldWithValue(testField, 0x101). MatchCTStateNew(true).MatchCTStateTrk(true). Action().Drop(). Done() diff --git a/pkg/ovs/openflow/ofctrl_group.go b/pkg/ovs/openflow/ofctrl_group.go index db5f92a80b5..e3618b924ce 100644 --- a/pkg/ovs/openflow/ofctrl_group.go +++ b/pkg/ovs/openflow/ofctrl_group.go @@ -93,7 +93,7 @@ type bucketBuilder struct { // LoadReg makes the learned flow to load data to reg[regID] with specific range. func (b *bucketBuilder) LoadReg(regID int, data uint32) BucketBuilder { - return b.LoadRegRange(regID, data, Range{0, 31}) + return b.LoadRegRange(regID, data, &Range{0, 31}) } // LoadXXReg makes the learned flow to load data to xxreg[regID] with specific range. @@ -104,13 +104,24 @@ func (b *bucketBuilder) LoadXXReg(regID int, data []byte) BucketBuilder { } // LoadRegRange is an action to Load data to the target register at specified range. -func (b *bucketBuilder) LoadRegRange(regID int, data uint32, rng Range) BucketBuilder { +func (b *bucketBuilder) LoadRegRange(regID int, data uint32, rng *Range) BucketBuilder { reg := fmt.Sprintf("%s%d", NxmFieldReg, regID) regField, _ := openflow13.FindFieldHeaderByName(reg, true) b.bucket.AddAction(openflow13.NewNXActionRegLoad(rng.ToNXRange().ToOfsBits(), regField, uint64(data))) return b } +func (b *bucketBuilder) LoadToRegField(field *RegField, data uint32) BucketBuilder { + reg := field.GetNXFieldName() + regField, _ := openflow13.FindFieldHeaderByName(reg, true) + b.bucket.AddAction(openflow13.NewNXActionRegLoad(field.rng.ToNXRange().ToOfsBits(), regField, uint64(data))) + return b +} + +func (b *bucketBuilder) LoadRegMark(mark *RegMark) BucketBuilder { + return b.LoadToRegField(mark.field, mark.value) +} + // ResubmitToTable is an action to resubmit packet to the specified table when the bucket is selected. func (b *bucketBuilder) ResubmitToTable(tableID TableIDType) BucketBuilder { b.bucket.AddAction(openflow13.NewNXActionResubmitTableAction(openflow13.OFPP_IN_PORT, uint8(tableID))) diff --git a/pkg/ovs/openflow/ofctrl_nxfields.go b/pkg/ovs/openflow/ofctrl_nxfields.go new file mode 100644 index 00000000000..9917fbf88d0 --- /dev/null +++ b/pkg/ovs/openflow/ofctrl_nxfields.go @@ -0,0 +1,110 @@ +// Copyright 2021 Antrea Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package openflow + +import "fmt" + +func (f *RegField) GetRegID() int { + return f.regID +} + +func (f *RegField) GetRange() *Range { + return f.rng +} + +func (f *RegField) GetNXFieldName() string { + return fmt.Sprintf("%s%d", NxmFieldReg, f.regID) +} + +func (f *RegField) GetName() string { + return f.name +} + +func (f *RegField) isFullRange() bool { + return f.rng.Length() == 32 +} + +func NewRegField(id int, start, end uint32, name string) *RegField { + return &RegField{regID: id, rng: &Range{start, end}, name: name} +} + +func NewOneBitRegMark(id int, bit uint32, name string) *RegMark { + field := NewRegField(id, bit, bit, name) + return &RegMark{value: 1, field: field} +} + +func NewRegMark(field *RegField, value uint32) *RegMark { + return &RegMark{value: value, field: field} +} + +func (m *RegMark) GetValue() uint32 { + return m.value +} + +func (m *RegMark) GetField() *RegField { + return m.field +} + +func (f *XXRegField) GetRegID() int { + return f.regID +} + +func (f *XXRegField) GetRange() *Range { + return f.rng +} + +func (f *XXRegField) GetNXFieldName() string { + return fmt.Sprintf("%s%d", NxmFieldXXReg, f.regID) +} + +func (f *XXRegField) isFullRange() bool { + return f.rng.Length() == 128 +} + +func NewXXRegField(id int, start, end uint32) *XXRegField { + return &XXRegField{regID: id, rng: &Range{start, end}} +} + +func (m *CtMark) GetRange() *Range { + return m.rng +} + +func (m *CtMark) GetValue() uint32 { + return m.value +} + +func (m *CtMark) isFullRange() bool { + return m.rng.Length() == 32 +} + +func NewCTMark(value uint32, start, end uint32) *CtMark { + return &CtMark{value: value, rng: &Range{start, end}} +} + +func NewCTLabel(start, end uint32, name string) *CtLabel { + return &CtLabel{name: name, rng: &Range{start, end}} +} + +func (f *CtLabel) GetNXFieldName() string { + return NxmFieldCtLabel +} + +func (f *CtLabel) GetName() string { + return f.name +} + +func (f *CtLabel) GetRange() *Range { + return f.rng +} diff --git a/pkg/ovs/openflow/ofctrl_packetout.go b/pkg/ovs/openflow/ofctrl_packetout.go index a3df4bd1550..2fe5f077fdf 100644 --- a/pkg/ovs/openflow/ofctrl_packetout.go +++ b/pkg/ovs/openflow/ofctrl_packetout.go @@ -268,12 +268,17 @@ func (b *ofPacketOutBuilder) SetOutport(outport uint32) PacketOutBuilder { } // AddLoadAction loads the data to the target field at specified range when the packet is received by OVS Switch. -func (b *ofPacketOutBuilder) AddLoadAction(name string, data uint64, rng Range) PacketOutBuilder { +func (b *ofPacketOutBuilder) AddLoadAction(name string, data uint64, rng *Range) PacketOutBuilder { act, _ := ofctrl.NewNXLoadAction(name, data, rng.ToNXRange()) b.pktOut.Actions = append(b.pktOut.Actions, act) return b } +func (b *ofPacketOutBuilder) AddLoadRegMark(mark *RegMark) PacketOutBuilder { + name := mark.field.GetNXFieldName() + return b.AddLoadAction(name, uint64(mark.value), mark.field.rng) +} + func (b *ofPacketOutBuilder) Done() *ofctrl.PacketOut { if b.pktOut.IPHeader != nil && b.pktOut.IPv6Header != nil { klog.Errorf("Invalid PacketOutBuilder: IP header and IPv6 header are not allowed to exist at the same time") diff --git a/pkg/ovs/openflow/testing/mock_openflow.go b/pkg/ovs/openflow/testing/mock_openflow.go index 3397aebac91..baed34c0d77 100644 --- a/pkg/ovs/openflow/testing/mock_openflow.go +++ b/pkg/ovs/openflow/testing/mock_openflow.go @@ -750,7 +750,7 @@ func (mr *MockActionMockRecorder) LoadIPDSCP(arg0 interface{}) *gomock.Call { } // LoadPktMarkRange mocks base method -func (m *MockAction) LoadPktMarkRange(arg0 uint32, arg1 openflow.Range) openflow.FlowBuilder { +func (m *MockAction) LoadPktMarkRange(arg0 uint32, arg1 *openflow.Range) openflow.FlowBuilder { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "LoadPktMarkRange", arg0, arg1) ret0, _ := ret[0].(openflow.FlowBuilder) @@ -764,7 +764,7 @@ func (mr *MockActionMockRecorder) LoadPktMarkRange(arg0, arg1 interface{}) *gomo } // LoadRange mocks base method -func (m *MockAction) LoadRange(arg0 string, arg1 uint64, arg2 openflow.Range) openflow.FlowBuilder { +func (m *MockAction) LoadRange(arg0 string, arg1 uint64, arg2 *openflow.Range) openflow.FlowBuilder { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "LoadRange", arg0, arg1, arg2) ret0, _ := ret[0].(openflow.FlowBuilder) @@ -777,18 +777,32 @@ func (mr *MockActionMockRecorder) LoadRange(arg0, arg1, arg2 interface{}) *gomoc return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadRange", reflect.TypeOf((*MockAction)(nil).LoadRange), arg0, arg1, arg2) } -// LoadRegRange mocks base method -func (m *MockAction) LoadRegRange(arg0 int, arg1 uint32, arg2 openflow.Range) openflow.FlowBuilder { +// LoadRegMark mocks base method +func (m *MockAction) LoadRegMark(arg0 *openflow.RegMark) openflow.FlowBuilder { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LoadRegRange", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "LoadRegMark", arg0) ret0, _ := ret[0].(openflow.FlowBuilder) return ret0 } -// LoadRegRange indicates an expected call of LoadRegRange -func (mr *MockActionMockRecorder) LoadRegRange(arg0, arg1, arg2 interface{}) *gomock.Call { +// LoadRegMark indicates an expected call of LoadRegMark +func (mr *MockActionMockRecorder) LoadRegMark(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadRegRange", reflect.TypeOf((*MockAction)(nil).LoadRegRange), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadRegMark", reflect.TypeOf((*MockAction)(nil).LoadRegMark), arg0) +} + +// LoadToRegField mocks base method +func (m *MockAction) LoadToRegField(arg0 *openflow.RegField, arg1 uint32) openflow.FlowBuilder { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LoadToRegField", arg0, arg1) + ret0, _ := ret[0].(openflow.FlowBuilder) + return ret0 +} + +// LoadToRegField indicates an expected call of LoadToRegField +func (mr *MockActionMockRecorder) LoadToRegField(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadToRegField", reflect.TypeOf((*MockAction)(nil).LoadToRegField), arg0, arg1) } // Meter mocks base method @@ -876,7 +890,7 @@ func (mr *MockActionMockRecorder) Output(arg0 interface{}) *gomock.Call { } // OutputFieldRange mocks base method -func (m *MockAction) OutputFieldRange(arg0 string, arg1 openflow.Range) openflow.FlowBuilder { +func (m *MockAction) OutputFieldRange(arg0 string, arg1 *openflow.Range) openflow.FlowBuilder { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "OutputFieldRange", arg0, arg1) ret0, _ := ret[0].(openflow.FlowBuilder) @@ -903,18 +917,18 @@ func (mr *MockActionMockRecorder) OutputInPort() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OutputInPort", reflect.TypeOf((*MockAction)(nil).OutputInPort)) } -// OutputRegRange mocks base method -func (m *MockAction) OutputRegRange(arg0 int, arg1 openflow.Range) openflow.FlowBuilder { +// OutputToRegField mocks base method +func (m *MockAction) OutputToRegField(arg0 *openflow.RegField) openflow.FlowBuilder { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "OutputRegRange", arg0, arg1) + ret := m.ctrl.Call(m, "OutputToRegField", arg0) ret0, _ := ret[0].(openflow.FlowBuilder) return ret0 } -// OutputRegRange indicates an expected call of OutputRegRange -func (mr *MockActionMockRecorder) OutputRegRange(arg0, arg1 interface{}) *gomock.Call { +// OutputToRegField indicates an expected call of OutputToRegField +func (mr *MockActionMockRecorder) OutputToRegField(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OutputRegRange", reflect.TypeOf((*MockAction)(nil).OutputRegRange), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "OutputToRegField", reflect.TypeOf((*MockAction)(nil).OutputToRegField), arg0) } // Resubmit mocks base method @@ -1136,18 +1150,32 @@ func (mr *MockCTActionMockRecorder) DNAT(arg0, arg1 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DNAT", reflect.TypeOf((*MockCTAction)(nil).DNAT), arg0, arg1) } -// LoadToLabelRange mocks base method -func (m *MockCTAction) LoadToLabelRange(arg0 uint64, arg1 *openflow.Range) openflow.CTAction { +// LoadToCtMark mocks base method +func (m *MockCTAction) LoadToCtMark(arg0 *openflow.CtMark) openflow.CTAction { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "LoadToCtMark", arg0) + ret0, _ := ret[0].(openflow.CTAction) + return ret0 +} + +// LoadToCtMark indicates an expected call of LoadToCtMark +func (mr *MockCTActionMockRecorder) LoadToCtMark(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadToCtMark", reflect.TypeOf((*MockCTAction)(nil).LoadToCtMark), arg0) +} + +// LoadToLabelField mocks base method +func (m *MockCTAction) LoadToLabelField(arg0 uint64, arg1 *openflow.CtLabel) openflow.CTAction { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LoadToLabelRange", arg0, arg1) + ret := m.ctrl.Call(m, "LoadToLabelField", arg0, arg1) ret0, _ := ret[0].(openflow.CTAction) return ret0 } -// LoadToLabelRange indicates an expected call of LoadToLabelRange -func (mr *MockCTActionMockRecorder) LoadToLabelRange(arg0, arg1 interface{}) *gomock.Call { +// LoadToLabelField indicates an expected call of LoadToLabelField +func (mr *MockCTActionMockRecorder) LoadToLabelField(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadToLabelRange", reflect.TypeOf((*MockCTAction)(nil).LoadToLabelRange), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadToLabelField", reflect.TypeOf((*MockCTAction)(nil).LoadToLabelField), arg0, arg1) } // LoadToMark mocks base method @@ -1383,32 +1411,32 @@ func (mr *MockFlowBuilderMockRecorder) MatchCTDstPort(arg0 interface{}) *gomock. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchCTDstPort", reflect.TypeOf((*MockFlowBuilder)(nil).MatchCTDstPort), arg0) } -// MatchCTLabelRange mocks base method -func (m *MockFlowBuilder) MatchCTLabelRange(arg0, arg1 uint64, arg2 openflow.Range) openflow.FlowBuilder { +// MatchCTLabelField mocks base method +func (m *MockFlowBuilder) MatchCTLabelField(arg0, arg1 uint64, arg2 *openflow.CtLabel) openflow.FlowBuilder { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MatchCTLabelRange", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "MatchCTLabelField", arg0, arg1, arg2) ret0, _ := ret[0].(openflow.FlowBuilder) return ret0 } -// MatchCTLabelRange indicates an expected call of MatchCTLabelRange -func (mr *MockFlowBuilderMockRecorder) MatchCTLabelRange(arg0, arg1, arg2 interface{}) *gomock.Call { +// MatchCTLabelField indicates an expected call of MatchCTLabelField +func (mr *MockFlowBuilderMockRecorder) MatchCTLabelField(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchCTLabelRange", reflect.TypeOf((*MockFlowBuilder)(nil).MatchCTLabelRange), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchCTLabelField", reflect.TypeOf((*MockFlowBuilder)(nil).MatchCTLabelField), arg0, arg1, arg2) } // MatchCTMark mocks base method -func (m *MockFlowBuilder) MatchCTMark(arg0 uint32, arg1 *uint32) openflow.FlowBuilder { +func (m *MockFlowBuilder) MatchCTMark(arg0 *openflow.CtMark) openflow.FlowBuilder { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MatchCTMark", arg0, arg1) + ret := m.ctrl.Call(m, "MatchCTMark", arg0) ret0, _ := ret[0].(openflow.FlowBuilder) return ret0 } // MatchCTMark indicates an expected call of MatchCTMark -func (mr *MockFlowBuilderMockRecorder) MatchCTMark(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockFlowBuilderMockRecorder) MatchCTMark(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchCTMark", reflect.TypeOf((*MockFlowBuilder)(nil).MatchCTMark), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchCTMark", reflect.TypeOf((*MockFlowBuilder)(nil).MatchCTMark), arg0) } // MatchCTProtocol mocks base method @@ -1761,32 +1789,32 @@ func (mr *MockFlowBuilderMockRecorder) MatchProtocol(arg0 interface{}) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchProtocol", reflect.TypeOf((*MockFlowBuilder)(nil).MatchProtocol), arg0) } -// MatchReg mocks base method -func (m *MockFlowBuilder) MatchReg(arg0 int, arg1 uint32) openflow.FlowBuilder { +// MatchRegFieldWithValue mocks base method +func (m *MockFlowBuilder) MatchRegFieldWithValue(arg0 *openflow.RegField, arg1 uint32) openflow.FlowBuilder { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MatchReg", arg0, arg1) + ret := m.ctrl.Call(m, "MatchRegFieldWithValue", arg0, arg1) ret0, _ := ret[0].(openflow.FlowBuilder) return ret0 } -// MatchReg indicates an expected call of MatchReg -func (mr *MockFlowBuilderMockRecorder) MatchReg(arg0, arg1 interface{}) *gomock.Call { +// MatchRegFieldWithValue indicates an expected call of MatchRegFieldWithValue +func (mr *MockFlowBuilderMockRecorder) MatchRegFieldWithValue(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchReg", reflect.TypeOf((*MockFlowBuilder)(nil).MatchReg), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchRegFieldWithValue", reflect.TypeOf((*MockFlowBuilder)(nil).MatchRegFieldWithValue), arg0, arg1) } -// MatchRegRange mocks base method -func (m *MockFlowBuilder) MatchRegRange(arg0 int, arg1 uint32, arg2 openflow.Range) openflow.FlowBuilder { +// MatchRegMark mocks base method +func (m *MockFlowBuilder) MatchRegMark(arg0 *openflow.RegMark) openflow.FlowBuilder { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MatchRegRange", arg0, arg1, arg2) + ret := m.ctrl.Call(m, "MatchRegMark", arg0) ret0, _ := ret[0].(openflow.FlowBuilder) return ret0 } -// MatchRegRange indicates an expected call of MatchRegRange -func (mr *MockFlowBuilderMockRecorder) MatchRegRange(arg0, arg1, arg2 interface{}) *gomock.Call { +// MatchRegMark indicates an expected call of MatchRegMark +func (mr *MockFlowBuilderMockRecorder) MatchRegMark(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchRegRange", reflect.TypeOf((*MockFlowBuilder)(nil).MatchRegRange), arg0, arg1, arg2) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MatchRegMark", reflect.TypeOf((*MockFlowBuilder)(nil).MatchRegMark), arg0) } // MatchSrcIP mocks base method diff --git a/test/integration/agent/openflow_test.go b/test/integration/agent/openflow_test.go index e343658d789..b44329c6b25 100644 --- a/test/integration/agent/openflow_test.go +++ b/test/integration/agent/openflow_test.go @@ -940,7 +940,7 @@ func preparePodFlows(podIPs []net.IP, podMAC net.HardwareAddr, podOFPort uint32, []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=190,in_port=%d", podOFPort), - ActStr: "load:0x2->NXM_NX_REG0[0..15],goto_table:10", + ActStr: "load:0x2->NXM_NX_REG0[0..3],goto_table:10", }, }, }, @@ -1011,7 +1011,7 @@ func prepareGatewayFlows(gwIPs []net.IP, gwMAC net.HardwareAddr, vMAC net.Hardwa []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,in_port=%d", config1.HostGatewayOFPort), - ActStr: "load:0x1->NXM_NX_REG0[0..15],goto_table:10", + ActStr: "load:0x1->NXM_NX_REG0[0..3],goto_table:10", }, }, }, @@ -1092,7 +1092,7 @@ func prepareTunnelFlows(tunnelPort uint32, vMAC net.HardwareAddr) []expectTableF []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,in_port=%d", tunnelPort), - ActStr: "load:0->NXM_NX_REG0[0..15],load:0x1->NXM_NX_REG0[19],goto_table:30", + ActStr: "load:0->NXM_NX_REG0[0..3],load:0x1->NXM_NX_REG0[19],goto_table:30", }, }, }, @@ -1172,11 +1172,11 @@ func prepareDefaultFlows(config *testConfig) []expectTableFlows { &ofTestUtils.ExpectFlow{MatchStr: "priority=190,ct_state=+inv+trk,ip", ActStr: "drop"}, ) table105Flows.flows = append(table105Flows.flows, - &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ip,reg0=0x1/0xffff", ActStr: "ct(commit,table=106,zone=65520,exec(load:0x20->NXM_NX_CT_MARK[])"}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ip,reg0=0x1/0xf", ActStr: "ct(commit,table=106,zone=65520,exec(load:0x20->NXM_NX_CT_MARK[])"}, &ofTestUtils.ExpectFlow{MatchStr: "priority=190,ct_state=+new+trk,ip", ActStr: "ct(commit,table=106,zone=65520)"}, ) table72Flows.flows = append(table72Flows.flows, - &ofTestUtils.ExpectFlow{MatchStr: "priority=210,ip,reg0=0x1/0xffff", ActStr: "goto_table:80"}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=210,ip,reg0=0x1/0xf", ActStr: "goto_table:80"}, &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ip", ActStr: "dec_ttl,goto_table:80"}, ) } @@ -1185,11 +1185,11 @@ func prepareDefaultFlows(config *testConfig) []expectTableFlows { &ofTestUtils.ExpectFlow{MatchStr: "priority=190,ct_state=+inv+trk,ipv6", ActStr: "drop"}, ) table105Flows.flows = append(table105Flows.flows, - &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ipv6,reg0=0x1/0xffff", ActStr: "ct(commit,table=106,zone=65510,exec(load:0x20->NXM_NX_CT_MARK[])"}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ipv6,reg0=0x1/0xf", ActStr: "ct(commit,table=106,zone=65510,exec(load:0x20->NXM_NX_CT_MARK[])"}, &ofTestUtils.ExpectFlow{MatchStr: "priority=190,ct_state=+new+trk,ipv6", ActStr: "ct(commit,table=106,zone=65510)"}, ) table72Flows.flows = append(table72Flows.flows, - &ofTestUtils.ExpectFlow{MatchStr: "priority=210,ipv6,reg0=0x1/0xffff", ActStr: "goto_table:80"}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=210,ipv6,reg0=0x1/0xf", ActStr: "goto_table:80"}, &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ipv6", ActStr: "dec_ttl,goto_table:80"}, ) } @@ -1298,15 +1298,15 @@ func prepareExternalFlows(nodeIP net.IP, localSubnet *net.IPNet, gwMAC net.Hardw ActStr: "goto_table:80", }, { - MatchStr: fmt.Sprintf("priority=200,%s,reg0=0x2/0xffff,%s=%s", ipProtoStr, nwDstFieldName, nodeIP.String()), + MatchStr: fmt.Sprintf("priority=200,%s,reg0=0x2/0xf,%s=%s", ipProtoStr, nwDstFieldName, nodeIP.String()), ActStr: "goto_table:80", }, { - MatchStr: fmt.Sprintf("priority=190,%s,reg0=0x2/0xffff", ipProtoStr), + MatchStr: fmt.Sprintf("priority=190,%s,reg0=0x2/0xf", ipProtoStr), ActStr: "goto_table:71", }, { - MatchStr: fmt.Sprintf("priority=190,%s,reg0=0/0xffff", ipProtoStr), + MatchStr: fmt.Sprintf("priority=190,%s,reg0=0/0xf", ipProtoStr), ActStr: fmt.Sprintf("set_field:%s->eth_dst,goto_table:71", gwMAC.String()), }, }, @@ -1315,7 +1315,7 @@ func prepareExternalFlows(nodeIP net.IP, localSubnet *net.IPNet, gwMAC net.Hardw uint8(71), []*ofTestUtils.ExpectFlow{ { - MatchStr: fmt.Sprintf("priority=190,ct_state=+new+trk,%s,reg0=0/0xffff", ipProtoStr), + MatchStr: fmt.Sprintf("priority=190,ct_state=+new+trk,%s,reg0=0/0xf", ipProtoStr), ActStr: "drop", }, { diff --git a/test/integration/ovs/ofctrl_test.go b/test/integration/ovs/ofctrl_test.go index ffc469bf239..0b1bc319a56 100644 --- a/test/integration/ovs/ofctrl_test.go +++ b/test/integration/ovs/ofctrl_test.go @@ -41,17 +41,15 @@ var ( priorityNormal = uint16(200) - portFoundMark = uint32(0x1) - portCacheReg = 1 + portFoundMark = binding.NewOneBitRegMark(0, 16, "OFPortFound") + portCacheField = binding.NewRegField(1, 0, 31, "OFPortCache") + sourceField = binding.NewRegField(0, 0, 15, "PacketSourceField") + fromLocalMark = binding.NewRegMark(sourceField, 2) + fromGatewayMark = binding.NewRegMark(sourceField, 1) - marksReg = 0 - markTrafficFromLocal = uint32(2) - markTrafficFromGateway = uint32(1) - gatewayCTMark = uint32(0x20) - ctZone = 0xfff0 - - ofportRegRange = binding.Range{0, 31} - ofportMarkRange = binding.Range{16, 16} + marksReg = 0 + gatewayCTMark = binding.NewCTMark(0x20, 0, 7) + ctZone = 0xfff0 count uint64 @@ -284,7 +282,8 @@ func TestOFctrlGroup(t *testing.T) { bucketBuilder = bucketBuilder.ResubmitToTable(bucket.resubmitTable) } for _, loading := range bucket.reg2reg { - bucketBuilder = bucketBuilder.LoadRegRange(int(loading[0]), loading[1], [2]uint32{loading[2], loading[3]}) + regField := binding.NewRegField(int(loading[0]), loading[2], loading[3], "field") + bucketBuilder = bucketBuilder.LoadToRegField(regField, loading[1]) } group = bucketBuilder.Done() } @@ -516,24 +515,28 @@ func TestBundleWithGroupAndFlow(t *testing.T) { ovsCtlClient := ovsctl.NewClient(br) groupID := binding.GroupIDType(4) + field1 := binding.NewRegField(1, 0, 31, "field1") + field2 := binding.NewRegField(2, 0, 31, "field2") + field3 := binding.NewRegField(3, 0, 31, "field3") group := bridge.CreateGroup(groupID). Bucket().Weight(100). - LoadReg(1, uint32(0xa0a0002)). - LoadReg(2, uint32(0x35)). - LoadReg(3, uint32(0xfff1)). + LoadToRegField(field1, uint32(0xa0a0002)). + LoadToRegField(field2, uint32(0x35)). + LoadToRegField(field3, uint32(0xfff1)). ResubmitToTable(table.GetNext()).Done(). Bucket().Weight(100). - LoadReg(1, uint32(0xa0a0202)). - LoadReg(2, uint32(0x35)). - LoadReg(3, uint32(0xfff1)). + LoadToRegField(field1, uint32(0xa0a0202)). + LoadToRegField(field2, uint32(0x35)). + LoadToRegField(field3, uint32(0xfff1)). ResubmitToTable(table.GetNext()).Done() + reg3Field := binding.NewRegField(3, 0, 31, "reg3Field") flow := table.BuildFlow(priorityNormal). Cookie(getCookieID()). MatchProtocol(binding.ProtocolTCP). MatchDstIP(net.ParseIP("10.96.0.10")). MatchDstPort(uint16(53), nil). - MatchReg(3, uint32(0xfff2)). + MatchRegFieldWithValue(reg3Field, uint32(0xfff2)). Action().Group(groupID).Done() expectedFlows := []*ExpectFlow{ { @@ -583,9 +586,9 @@ func TestPacketOutIn(t *testing.T) { srcPort := uint16(10001) dstPort := uint16(8080) reg2Data := uint32(0x1234) - reg2Range := binding.Range{0, 15} + reg2Field := binding.NewRegField(2, 0, 15, "reg2Field") reg3Data := uint32(0x1234) - reg3Range := binding.Range{0, 31} + reg3Field := binding.NewRegField(3, 0, 31, "reg3Field") stopCh := make(chan struct{}) go func() { @@ -598,7 +601,7 @@ func TestPacketOutIn(t *testing.T) { assert.NotNil(t, reg2Value) value2, ok2 := reg2Value.(*ofctrl.NXRegister) assert.True(t, ok2) - assert.Equal(t, reg2Data, ofctrl.GetUint32ValueWithRange(value2.Data, reg2Range.ToNXRange())) + assert.Equal(t, reg2Data, ofctrl.GetUint32ValueWithRange(value2.Data, reg2Field.GetRange().ToNXRange())) reg3Match := matchers.GetMatchByName("NXM_NX_REG3") assert.NotNil(t, reg3Match) @@ -620,25 +623,26 @@ func TestPacketOutIn(t *testing.T) { }() pktBuilder := bridge.BuildPacketOut() + regField := binding.NewRegField(0, 18, 18, "field") pkt := pktBuilder.SetSrcMAC(srcMAC).SetDstMAC(dstcMAC). SetDstIP(dstIP).SetSrcIP(srcIP).SetIPProtocol(binding.ProtocolTCP). SetTCPSrcPort(srcPort).SetTCPDstPort(dstPort). - AddLoadAction("NXM_NX_REG0", uint64(0x1), binding.Range{18, 18}). + AddLoadAction(regField.GetNXFieldName(), uint64(0x1), regField.GetRange()). Done() require.Nil(t, err) flow0 := table0.BuildFlow(100). MatchSrcMAC(srcMAC).MatchDstMAC(dstcMAC). MatchSrcIP(srcIP).MatchDstIP(dstIP).MatchProtocol(binding.ProtocolTCP). - MatchRegRange(0, 0x1, binding.Range{18, 18}). - Action().LoadRegRange(2, reg2Data, reg2Range). - Action().LoadRegRange(3, reg3Data, reg3Range). + MatchRegFieldWithValue(regField, 0x1). + Action().LoadToRegField(reg2Field, reg2Data). + Action().LoadToRegField(reg3Field, reg3Data). Action().SetTunnelDst(tunDst). Action().ResubmitToTable(table0.GetNext()). Done() flow1 := table1.BuildFlow(100). MatchSrcMAC(srcMAC).MatchDstMAC(dstcMAC). MatchSrcIP(srcIP).MatchDstIP(dstIP).MatchProtocol(binding.ProtocolTCP). - MatchRegRange(0, 0x1, binding.Range{18, 18}). + MatchRegFieldWithValue(regField, 0x1). Action().SendToController(0x1). Done() err = bridge.AddFlowsInBundle([]binding.Flow{flow0, flow1}, nil, nil) @@ -835,11 +839,16 @@ func prepareFlows(table binding.Table) ([]binding.Flow, []*ExpectFlow) { gwMACData, _ := strconv.ParseUint(strings.Replace(gwMAC.String(), ":", "", -1), 16, 64) _, peerSubnetIPv6, _ := net.ParseCIDR("fd74:ca9b:172:21::/64") tunnelPeerIPv6 := net.ParseIP("20:ca9b:172:35::3") + regField0 := binding.NewRegField(0, 0, 15, "field0") + mark0 := binding.NewRegMark(regField0, 0x0fff) + regField1 := binding.NewRegField(0, 16, 31, "field1") + mark1 := binding.NewRegMark(regField1, 0x0ffe) + //gatewayCTMark := binding.NewCTMark() flows = append(flows, table.BuildFlow(priorityNormal-10). Cookie(getCookieID()). MatchInPort(podOFport). - Action().LoadRegRange(int(marksReg), markTrafficFromLocal, binding.Range{0, 15}). + Action().LoadRegMark(fromLocalMark). Action().GotoTable(table.GetNext()). Done(), table.BuildFlow(priorityNormal).MatchProtocol(binding.ProtocolARP). @@ -877,9 +886,9 @@ func prepareFlows(table binding.Table) ([]binding.Flow, []*ExpectFlow) { Action().Learn(table.GetID(), priorityNormal-10, 10, 0, 1). DeleteLearned(). MatchLearnedTCPDstPort(). - MatchReg(0, 0x0fff, binding.Range{0, 15}). - LoadRegToReg(0, 0, binding.Range{0, 15}, binding.Range{0, 15}). - LoadReg(0, 0x0ffe, binding.Range{16, 31}). + MatchRegMark(mark0). + LoadFieldToField(regField0, regField0). + LoadRegMark(mark1). Done(). // Finish learn action. Action().ResubmitToTable(table.GetID()). Done(), @@ -889,26 +898,26 @@ func prepareFlows(table binding.Table) ([]binding.Flow, []*ExpectFlow) { Done(), table.BuildFlow(priorityNormal+10).MatchProtocol(binding.ProtocolIP). Cookie(getCookieID()). - MatchRegRange(int(marksReg), markTrafficFromGateway, binding.Range{0, 15}). - MatchCTMark(gatewayCTMark, nil). + MatchRegMark(fromGatewayMark). + MatchCTMark(gatewayCTMark). MatchCTStateNew(false).MatchCTStateTrk(true). Action().GotoTable(table.GetNext()). Done(), table.BuildFlow(priorityNormal).MatchProtocol(binding.ProtocolIP). Cookie(getCookieID()). - MatchRegRange(int(marksReg), markTrafficFromGateway, binding.Range{0, 15}). + MatchRegMark(fromGatewayMark). MatchCTStateNew(true).MatchCTStateTrk(true). Action().CT( true, table.GetNext(), ctZone). - LoadToMark(uint32(gatewayCTMark)).CTDone(). + LoadToCtMark(gatewayCTMark).CTDone(). Done(), table.BuildFlow(priorityNormal).MatchProtocol(binding.ProtocolIP). Cookie(getCookieID()). - MatchCTMark(gatewayCTMark, nil). + MatchCTMark(gatewayCTMark). MatchCTStateNew(false).MatchCTStateTrk(true). - Action().LoadRange(binding.NxmFieldDstMAC, gwMACData, binding.Range{0, 47}). + Action().LoadRange(binding.NxmFieldDstMAC, gwMACData, &binding.Range{0, 47}). Action().GotoTable(table.GetNext()). Done(), table.BuildFlow(priorityNormal).MatchProtocol(binding.ProtocolIP). @@ -957,15 +966,15 @@ func prepareFlows(table binding.Table) ([]binding.Flow, []*ExpectFlow) { table.BuildFlow(priorityNormal). Cookie(getCookieID()). MatchDstMAC(podMAC). - Action().LoadRegRange(portCacheReg, podOFport, ofportRegRange). - Action().LoadRegRange(int(marksReg), portFoundMark, ofportMarkRange). + Action().LoadToRegField(portCacheField, podOFport). + Action().LoadRegMark(portFoundMark). Action().GotoTable(table.GetNext()). Done(), table.BuildFlow(priorityNormal). Cookie(getCookieID()). MatchProtocol(binding.ProtocolIP). - MatchRegRange(int(marksReg), portFoundMark, ofportMarkRange). - Action().OutputRegRange(int(portCacheReg), ofportRegRange). + MatchRegMark(portFoundMark). + Action().OutputToRegField(portCacheField). Done(), table.BuildFlow(priorityNormal).MatchProtocol(binding.ProtocolIP). Cookie(getCookieID()). MatchDstIPNet(*serviceCIDR). @@ -986,7 +995,7 @@ func prepareFlows(table binding.Table) ([]binding.Flow, []*ExpectFlow) { Action().Conjunction(uint32(1001), uint8(2), uint8(3)).Done(), table.BuildFlow(priorityNormal+20).MatchProtocol(binding.ProtocolIP).Cookie(getCookieID()).MatchSrcIPNet(*AllIPs). Action().Conjunction(uint32(1001), uint8(1), uint8(3)).Done(), - table.BuildFlow(priorityNormal+20).MatchProtocol(binding.ProtocolIP).Cookie(getCookieID()).MatchRegRange(int(portCacheReg), podOFport, ofportRegRange). + table.BuildFlow(priorityNormal+20).MatchProtocol(binding.ProtocolIP).Cookie(getCookieID()).MatchRegFieldWithValue(portCacheField, podOFport). Action().Conjunction(uint32(1001), uint8(2), uint8(3)).Done(), table.BuildFlow(priorityNormal+20).MatchProtocol(binding.ProtocolIP).Cookie(getCookieID()).MatchConjID(1001). Action().GotoTable(table.GetNext()).Done(), @@ -1004,9 +1013,9 @@ func prepareFlows(table binding.Table) ([]binding.Flow, []*ExpectFlow) { &ExpectFlow{"priority=190,arp", "NORMAL"}, &ExpectFlow{"priority=200,tcp", fmt.Sprintf("learn(table=%d,idle_timeout=10,priority=190,delete_learned,cookie=0x1,eth_type=0x800,nw_proto=6,NXM_OF_TCP_DST[],NXM_NX_REG0[0..15]=0xfff,load:NXM_NX_REG0[0..15]->NXM_NX_REG0[0..15],load:0xffe->NXM_NX_REG0[16..31]),resubmit(,%d)", table.GetID(), table.GetID())}, &ExpectFlow{"priority=200,ip", fmt.Sprintf("ct(table=%d,zone=65520)", table.GetNext())}, - &ExpectFlow{"priority=210,ct_state=-new+trk,ct_mark=0x20,ip,reg0=0x1/0xffff", gotoTableAction}, - &ExpectFlow{"priority=200,ct_state=+new+trk,ip,reg0=0x1/0xffff", fmt.Sprintf("ct(commit,table=%d,zone=65520,exec(load:0x20->NXM_NX_CT_MARK[])", table.GetNext())}, - &ExpectFlow{"priority=200,ct_state=-new+trk,ct_mark=0x20,ip", fmt.Sprintf("load:0xaaaaaaaaaa11->NXM_OF_ETH_DST[],%s", gotoTableAction)}, + &ExpectFlow{"priority=210,ct_state=-new+trk,ct_mark=0x20/0xff,ip,reg0=0x1/0xffff", gotoTableAction}, + &ExpectFlow{"priority=200,ct_state=+new+trk,ip,reg0=0x1/0xffff", fmt.Sprintf("ct(commit,table=%d,zone=65520,exec(load:0x20->NXM_NX_CT_MARK[0..7])", table.GetNext())}, + &ExpectFlow{"priority=200,ct_state=-new+trk,ct_mark=0x20/0xff,ip", fmt.Sprintf("load:0xaaaaaaaaaa11->NXM_OF_ETH_DST[],%s", gotoTableAction)}, &ExpectFlow{"priority=200,ct_state=+new+inv,ip", "drop"}, &ExpectFlow{"priority=190,ct_state=+new+trk,ip", fmt.Sprintf("ct(commit,table=%d,zone=65520)", table.GetNext())}, &ExpectFlow{"priority=200,ip,dl_dst=aa:bb:cc:dd:ee:ff,nw_dst=192.168.1.3", fmt.Sprintf("set_field:aa:aa:aa:aa:aa:11->eth_src,set_field:aa:aa:aa:aa:aa:13->eth_dst,dec_ttl,%s", gotoTableAction)}, @@ -1034,12 +1043,11 @@ func prepareNATflows(table binding.Table) ([]binding.Flow, []*ExpectFlow) { natedIP2 := net.ParseIP("10.10.0.10") natIPRange1 := &binding.IPRange{StartIP: natedIP1, EndIP: natedIP1} natIPRange2 := &binding.IPRange{StartIP: natedIP1, EndIP: natedIP2} - snatCTMark := uint32(0x40) - natRequireMark := uint32(0x1) - snatMarkRange1 := binding.Range{17, 17} - snatMarkRange2 := binding.Range{18, 18} - dnatMarkRange1 := binding.Range{19, 19} - dnatMarkRange2 := binding.Range{20, 20} + snatCTMark := binding.NewCTMark(0x40, 0, 7) + snatMark1 := binding.NewOneBitRegMark(marksReg, 17, "SNATMark1") + snatMark2 := binding.NewOneBitRegMark(marksReg, 18, "SNATMark2") + dnatMark1 := binding.NewOneBitRegMark(marksReg, 19, "DNATMark1") + dnatMark2 := binding.NewOneBitRegMark(marksReg, 20, "DNATMark2") flows := []binding.Flow{ table.BuildFlow(priorityNormal).MatchProtocol(binding.ProtocolIP). Action().CT(false, table.GetNext(), ctZone).NAT().CTDone(). @@ -1047,34 +1055,34 @@ func prepareNATflows(table binding.Table) ([]binding.Flow, []*ExpectFlow) { Done(), table.BuildFlow(priorityNormal). MatchProtocol(binding.ProtocolIP). - MatchRegRange(marksReg, natRequireMark, snatMarkRange1). + MatchRegMark(snatMark1). Action().CT(true, table.GetNext(), ctZone). SNAT(natIPRange1, nil). - LoadToMark(snatCTMark).CTDone(). + LoadToCtMark(snatCTMark).CTDone(). Cookie(getCookieID()). Done(), table.BuildFlow(priorityNormal). MatchProtocol(binding.ProtocolIP). - MatchRegRange(marksReg, natRequireMark, snatMarkRange2). + MatchRegMark(snatMark2). Action().CT(true, table.GetNext(), ctZone). SNAT(natIPRange2, nil). - LoadToMark(snatCTMark).CTDone(). + LoadToCtMark(snatCTMark).CTDone(). Cookie(getCookieID()). Done(), table.BuildFlow(priorityNormal). MatchProtocol(binding.ProtocolIP). - MatchRegRange(marksReg, natRequireMark, dnatMarkRange1). + MatchRegMark(dnatMark1). Action().CT(true, table.GetNext(), ctZone). DNAT(natIPRange1, nil). - LoadToMark(snatCTMark).CTDone(). + LoadToCtMark(snatCTMark).CTDone(). Cookie(getCookieID()). Done(), table.BuildFlow(priorityNormal). MatchProtocol(binding.ProtocolIP). - MatchRegRange(marksReg, natRequireMark, dnatMarkRange2). + MatchRegMark(dnatMark2). Action().CT(true, table.GetNext(), ctZone). DNAT(natIPRange2, nil). - LoadToMark(snatCTMark).CTDone(). + LoadToCtMark(snatCTMark).CTDone(). Cookie(getCookieID()). Done(), } @@ -1082,19 +1090,19 @@ func prepareNATflows(table binding.Table) ([]binding.Flow, []*ExpectFlow) { flowStrs := []*ExpectFlow{ {"priority=200,ip", fmt.Sprintf("ct(table=%d,zone=65520,nat)", table.GetNext())}, {"priority=200,ip,reg0=0x20000/0x20000", - fmt.Sprintf("ct(commit,table=%d,zone=65520,nat(src=%s),exec(load:0x40->NXM_NX_CT_MARK[]))", + fmt.Sprintf("ct(commit,table=%d,zone=65520,nat(src=%s),exec(load:0x40->NXM_NX_CT_MARK[0..7]))", table.GetNext(), natedIP1.String()), }, {"priority=200,ip,reg0=0x40000/0x40000", - fmt.Sprintf("ct(commit,table=%d,zone=65520,nat(src=%s-%s),exec(load:0x40->NXM_NX_CT_MARK[]))", + fmt.Sprintf("ct(commit,table=%d,zone=65520,nat(src=%s-%s),exec(load:0x40->NXM_NX_CT_MARK[0..7]))", table.GetNext(), natedIP1.String(), natedIP2.String()), }, {"priority=200,ip,reg0=0x80000/0x80000", - fmt.Sprintf("ct(commit,table=%d,zone=65520,nat(dst=%s),exec(load:0x40->NXM_NX_CT_MARK[]))", + fmt.Sprintf("ct(commit,table=%d,zone=65520,nat(dst=%s),exec(load:0x40->NXM_NX_CT_MARK[0..7]))", table.GetNext(), natedIP1.String()), }, {"priority=200,ip,reg0=0x100000/0x100000", - fmt.Sprintf("ct(commit,table=%d,zone=65520,nat(dst=%s-%s),exec(load:0x40->NXM_NX_CT_MARK[]))", + fmt.Sprintf("ct(commit,table=%d,zone=65520,nat(dst=%s-%s),exec(load:0x40->NXM_NX_CT_MARK[0..7]))", table.GetNext(), natedIP1.String(), natedIP2.String()), }, }