From a057c4ef4280b3f1b573b154f512aceab84eb1c7 Mon Sep 17 00:00:00 2001 From: wenyingd Date: Tue, 26 Apr 2022 18:02:39 +0800 Subject: [PATCH] OpenFlow1.5 support 1. Consume messages defined in OpenFlow1.5 2. Use set_field instead of load, and use copy_field instead of move 3. The type of PacketIn.Data and PacketOut.Data is changed to Buffer in libOpenflow, so a conversion from Buffer to Ethernet is needed in both logic and tests 4. Parse matches set NXM_NX_REGX via message OXM_CLASS_PACKET_REGS in packetIn message. xreg (64bit) is used in OpenFlow1.5 in PacketIn to provide OVS register settings, a convention from xreg to reg (32bit) is used in functions. 5. Meter works as an Action instead of Instruction in OpenFlow1.5. So Antrea needs to apply MeterAction if the meter id is expected to be consumed in flow actions. Signed-off-by: wenyingd --- docs/antctl.md | 8 +- docs/design/ovs-pipeline.md | 28 +-- docs/design/windows-design.md | 2 +- go.mod | 7 +- go.sum | 8 +- pkg/agent/controller/networkpolicy/fqdn.go | 18 +- .../controller/networkpolicy/packetin.go | 17 +- pkg/agent/controller/networkpolicy/reject.go | 14 +- pkg/agent/controller/traceflow/packetin.go | 24 ++- .../controller/traceflow/packetin_test.go | 6 +- pkg/agent/multicast/mcast_discovery.go | 19 +- pkg/agent/multicast/mcast_discovery_test.go | 21 +-- pkg/agent/openflow/client.go | 5 +- pkg/agent/openflow/packetin.go | 22 +++ pkg/agent/openflow/pipeline.go | 8 +- pkg/ovs/openflow/interfaces.go | 8 +- pkg/ovs/openflow/ofctrl_action.go | 163 +++++++++++++----- pkg/ovs/openflow/ofctrl_bridge.go | 99 ++++++----- pkg/ovs/openflow/ofctrl_builder.go | 20 +-- pkg/ovs/openflow/ofctrl_flow.go | 22 +-- pkg/ovs/openflow/ofctrl_group.go | 51 ++++-- pkg/ovs/openflow/ofctrl_meter.go | 18 +- pkg/ovs/openflow/ofctrl_packetin.go | 51 +++--- pkg/ovs/openflow/ofctrl_packetin_test.go | 27 +-- pkg/ovs/openflow/ofctrl_packetout.go | 34 +++- pkg/ovs/openflow/ofctrl_packetout_test.go | 8 +- pkg/ovs/openflow/testing/mock_openflow.go | 14 ++ pkg/ovs/ovsconfig/ovs_client.go | 8 +- pkg/ovs/ovsctl/ofctl.go | 10 +- plugins/octant/go.sum | 1 + test/e2e/proxy_test.go | 10 +- test/integration/agent/openflow_test.go | 85 +++++---- test/integration/ovs/ofctrl_test.go | 46 ++--- test/integration/ovs/openflow_test_utils.go | 11 +- 34 files changed, 558 insertions(+), 335 deletions(-) diff --git a/docs/antctl.md b/docs/antctl.md index 2cb7700d3a2..bfff9ec60c7 100644 --- a/docs/antctl.md +++ b/docs/antctl.md @@ -282,10 +282,10 @@ Example outputs of dumping Pod and NetworkPolicy OVS flows: # Dump OVS flows of Pod "coredns-6955765f44-zcbwj" $ antctl get of -p coredns-6955765f44-zcbwj -n kube-system FLOW -table=classification, n_packets=513122, n_bytes=42615080, priority=190,in_port="coredns--d0c58e" actions=load:0x2->NXM_NX_REG0[0..15],resubmit(,10) +table=classification, n_packets=513122, n_bytes=42615080, priority=190,in_port="coredns--d0c58e" actions=set_field:0x2/0xffff->reg0,resubmit(,10) table=10, n_packets=513122, n_bytes=42615080, priority=200,ip,in_port="coredns--d0c58e",dl_src=52:bd:c6:e0:eb:c1,nw_src=172.100.1.7 actions=resubmit(,30) table=10, n_packets=0, n_bytes=0, priority=200,arp,in_port="coredns--d0c58e",arp_spa=172.100.1.7,arp_sha=52:bd:c6:e0:eb:c1 actions=resubmit(,20) -table=80, n_packets=556468, n_bytes=166477824, priority=200,dl_dst=52:bd:c6:e0:eb:c1 actions=load:0x5->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[16],resubmit(,90) +table=80, n_packets=556468, n_bytes=166477824, priority=200,dl_dst=52:bd:c6:e0:eb:c1 actions=load:0x5->NXM_NX_REG1[],set_field:0x10000/0x10000->reg0,resubmit(,90) table=70, n_packets=0, n_bytes=0, priority=200,ip,dl_dst=aa:bb:cc:dd:ee:ff,nw_dst=172.100.1.7 actions=set_field:62:39:b4:e8:05:76->eth_src,set_field:52:bd:c6:e0:eb:c1->eth_dst,dec_ttl,resubmit(,80) # Get NetworkPolicies applied to Pod "coredns-6955765f44-zcbwj" @@ -378,8 +378,8 @@ result: | dec_ttl resubmit(,80) 80. dl_dst=52:bd:c6:e0:eb:c1, priority 200, cookie 0x5e030000000000 - load:0x5->NXM_NX_REG1[] - load:0x1->NXM_NX_REG0[16] + set_field:0x5->reg1 + set_field:0x10000/0x10000->reg0 resubmit(,90) 90. conj_id=2,ip, priority 190, cookie 0x5e050000000000 resubmit(,105) diff --git a/docs/design/ovs-pipeline.md b/docs/design/ovs-pipeline.md index 30e78058f6a..9d6a434fa9c 100644 --- a/docs/design/ovs-pipeline.md +++ b/docs/design/ovs-pipeline.md @@ -234,10 +234,10 @@ should be performed for the packet in [L3ForwardingTable]. If you dump the flows for this table, you may see the following: ```text -1. table=0, priority=200,in_port=2 actions=load:0x1->NXM_NX_REG0[0..3],resubmit(,10) -2. table=0, priority=200,in_port=1 actions=load:0->NXM_NX_REG0[0..3],load:0x1->NXM_NX_REG0[19],resubmit(,30) -3. table=0, priority=190,in_port=4 actions=load:0x2->NXM_NX_REG0[0..3],resubmit(,10) -4. table=0, priority=190,in_port=3 actions=load:0x2->NXM_NX_REG0[0..3],resubmit(,10) +1. table=0, priority=200,in_port=2 actions=set_field:0x1/0xf->reg0,resubmit(,10) +2. table=0, priority=200,in_port=1 actions=set_field:0/0xf->reg0,load:0x1->NXM_NX_REG0[19],resubmit(,30) +3. table=0, priority=190,in_port=4 actions=set_field:0x2/0xf->reg0,resubmit(,10) +4. table=0, priority=190,in_port=3 actions=set_field:0x2/0xf->reg0,resubmit(,10) 5. table=0, priority=0 actions=drop ``` @@ -305,7 +305,7 @@ address for all the traffic being tunnelled. If you dump the flows for this table, you may see the following: ```text -1. table=20, priority=200,arp,arp_tpa=10.10.1.1,arp_op=1 actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:aa:bb:cc:dd:ee:ff,load:0x2->NXM_OF_ARP_OP[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],load:0xaabbccddeeff->NXM_NX_ARP_SHA[],move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],load:0xa0a0101->NXM_OF_ARP_SPA[],IN_PORT +1. table=20, priority=200,arp,arp_tpa=10.10.1.1,arp_op=1 actions=move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],mod_dl_src:aa:bb:cc:dd:ee:ff,set_field:2->arp_op,move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],load:0xaabbccddeeff->NXM_NX_ARP_SHA[],move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],load:0xa0a0101->NXM_OF_ARP_SPA[],IN_PORT 2. table=20, priority=190,arp actions=NORMAL 3. table=20, priority=0 actions=drop ``` @@ -781,7 +781,7 @@ table=70, priority=210,ct_state=+rpl+trk,ct_mark=0x20,ip actions=mod_dl_dst:e2:e For a given peer Node, the flow may look like this: ```text -table=70, priority=200,ip,nw_dst=10.10.1.0/24 actions=mod_dl_src:e2:e5:a4:9b:1c:b1,mod_dl_dst:aa:bb:cc:dd:ee:ff,load:0x1->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[16],load:0xc0a80102->NXM_NX_TUN_IPV4_DST[],goto_table:72 +table=70, priority=200,ip,nw_dst=10.10.1.0/24 actions=mod_dl_src:e2:e5:a4:9b:1c:b1,mod_dl_dst:aa:bb:cc:dd:ee:ff,load:0x1->NXM_NX_REG1[],set_field:0x10000/0x10000->reg0,load:0xc0a80102->NXM_NX_TUN_IPV4_DST[],goto_table:72 ``` If none of the flows described above are hit, traffic goes directly to @@ -842,7 +842,7 @@ the right SNAT IP (Antrea Agent adds an iptables SNAT rule for each local SNAT IP that matches the ID). ```text -table=71, priority=200,ct_state=+new+trk,ip,in_port="pod1-7e503a" actions=load:0x1->NXM_NX_PKT_MARK[0..7],goto_table:80 +table=71, priority=200,ct_state=+new+trk,ip,in_port="pod1-7e503a" actions=set_field:0x1/0xff->pkt_mark,goto_table:80 ``` When the SNAT IP of the Egress is on a remote Node, the flow will tunnel the @@ -853,7 +853,7 @@ destination MAC addresses, load the SNAT IP to NXM_NX_TUN_IPV4_DST, and send the packets to [L3DecTTLTable]. ```text -table=71, priority=200,ct_state=+new+trk,ip,in_port="pod2-357c21" actions=mod_dl_src:e2:e5:a4:9b:1c:b1,mod_dl_dst:aa:bb:cc:dd:ee:ff,load:0x1->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[16],load:0xc0a80a66->NXM_NX_TUN_IPV4_DST[],goto_table:72 +table=71, priority=200,ct_state=+new+trk,ip,in_port="pod2-357c21" actions=mod_dl_src:e2:e5:a4:9b:1c:b1,mod_dl_dst:aa:bb:cc:dd:ee:ff,load:0x1->NXM_NX_REG1[],set_field:0x10000/0x10000->reg0,load:0xc0a80a66->NXM_NX_TUN_IPV4_DST[],goto_table:72 ``` Last, when a SNAT IP configured for Egresses is on the local Node, an additional @@ -862,7 +862,7 @@ use the SNAT IP. The flow matches the tunnel destination IP (which should be equal to the SNAT IP), and sets the 8 bits ID of the SNAT IP to pkt_mark. ```text -table=71, priority=200,ct_state=+new+trk,ip,tun_dst="192.168.10.101" actions=load:0x1->NXM_NX_PKT_MARK[0..7],goto_table:80 +table=71, priority=200,ct_state=+new+trk,ip,tun_dst="192.168.10.101" actions=set_field:0x1/0xff->pkt_mark,goto_table:80 ``` ### L3DecTTLTable (72) @@ -891,10 +891,10 @@ port (tunnel port, gateway port, and local Pod ports), as you can see if you dump the flows: ```text -1. table=80, priority=200,dl_dst=aa:bb:cc:dd:ee:ff actions=load:0x1->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[16],goto_table:105 -2. table=80, priority=200,dl_dst=e2:e5:a4:9b:1c:b1 actions=load:0x2->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[16],goto_table:105 -3. table=80, priority=200,dl_dst=12:9e:a6:47:d0:70 actions=load:0x3->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[16],goto_table:90 -4. table=80, priority=200,dl_dst=ba:a8:13:ca:ed:cf actions=load:0x4->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[16],goto_table:90 +1. table=80, priority=200,dl_dst=aa:bb:cc:dd:ee:ff actions=set_field:0x1->reg1,set_field:0x10000/0x10000->reg0,goto_table:105 +2. table=80, priority=200,dl_dst=e2:e5:a4:9b:1c:b1 actions=set_field:0x2->reg1,set_field:0x10000/0x10000->reg0,goto_table:105 +3. table=80, priority=200,dl_dst=12:9e:a6:47:d0:70 actions=set_field:0x3->reg1,set_field:0x10000/0x10000->reg0,goto_table:90 +4. table=80, priority=200,dl_dst=ba:a8:13:ca:ed:cf actions=set_field:0x4->reg1,set_field:0x10000/0x10000->reg0,goto_table:90 5. table=80, priority=0 actions=goto_table:105 ``` @@ -1149,7 +1149,7 @@ across the different backends for each Service. If you dump the flows for this table, you should see something like this: ```text -1. table=40, priority=200,ip,nw_dst=10.96.0.0/12 actions=load:0x2->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[16],goto_table:105 +1. table=40, priority=200,ip,nw_dst=10.96.0.0/12 actions=set_field:0x2->reg1,load:0x1->NXM_NX_REG0[16],goto_table:105 2. table=40, priority=0 actions=goto_table:45 ``` diff --git a/docs/design/windows-design.md b/docs/design/windows-design.md index 0c935f991c2..1fb1cc0847a 100644 --- a/docs/design/windows-design.md +++ b/docs/design/windows-design.md @@ -160,7 +160,7 @@ table=70, priority=200,ip,nw_dst=$peerPodSubnet actions=mod_dl_dst:$peerNodeMAC, table=70, priority=200,ct_state=+rpl+trk,ip,nw_dst=$peerNodeIP actions=mod_dl_dst:$peerNodeMAC,resubmit(,80) L2ForwardingCalcTable: 80 -table=80, priority=200,dl_dst=$peerNodeMAC actions=load:$uplink->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[16],resubmit(,105) +table=80, priority=200,dl_dst=$peerNodeMAC actions=load:$uplink->NXM_NX_REG1[],set_field:0x10000/0x10000->reg0,resubmit(,105) ``` ### SNAT configuration diff --git a/go.mod b/go.mod index 41b39dbbc35..fb273b9f305 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module antrea.io/antrea go 1.17 require ( - antrea.io/libOpenflow v0.6.2 + antrea.io/libOpenflow v0.8.0 antrea.io/ofnet v0.5.7 github.com/ClickHouse/clickhouse-go v1.5.1 github.com/DATA-DOG/go-sqlmock v1.5.0 @@ -192,4 +192,7 @@ require ( // Newer version of github.com/googleapis/gnostic make use of newer gopkg.in/yaml(v3), which conflicts with // explicit imports of gopkg.in/yaml.v2. -replace github.com/googleapis/gnostic v0.5.5 => github.com/googleapis/gnostic v0.4.1 +replace ( + antrea.io/ofnet v0.5.7 => github.com/ashish-varma/ofnet v0.2.5-0.20220729063042-5b9cfc220c7b + github.com/googleapis/gnostic v0.5.5 => github.com/googleapis/gnostic v0.4.1 +) diff --git a/go.sum b/go.sum index fae66592d3e..916b3f2f85f 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ -antrea.io/libOpenflow v0.6.2 h1:1JMSJ7Lp7yOhKybHey9VDtRI6JuIgkhUWJBX5GIFY9I= -antrea.io/libOpenflow v0.6.2/go.mod h1:CzEJZxDNAupiGxeL5VOw92PsxfyvehEAvE3PiC6gr8o= -antrea.io/ofnet v0.5.7 h1:x0q0lZqp05wu01gk1+S5S15FmIpmTGPhi/z/aIDmuMw= -antrea.io/ofnet v0.5.7/go.mod h1:8TJVF6MLe9/gZ/KbhGUvULs9/TxssepEaYEe+o1SEgs= +antrea.io/libOpenflow v0.8.0 h1:Xm6mlSqdXtDD418nf1lndoDvMi8scqUan8pkEUZ2oas= +antrea.io/libOpenflow v0.8.0/go.mod h1:CzEJZxDNAupiGxeL5VOw92PsxfyvehEAvE3PiC6gr8o= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= @@ -126,6 +124,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPd github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= +github.com/ashish-varma/ofnet v0.2.5-0.20220729063042-5b9cfc220c7b h1:LSVvtpsHuutmIDGC7PJgnkVWVVi3whFZ9f8qfLWuX8U= +github.com/ashish-varma/ofnet v0.2.5-0.20220729063042-5b9cfc220c7b/go.mod h1:qWqi11pI3kBYcS9SYWm92ZOiOPBx04Jx21cDmJlJhOg= github.com/awalterschulze/gographviz v2.0.1+incompatible h1:XIECBRq9VPEQqkQL5pw2OtjCAdrtIgFKoJU8eT98AS8= github.com/awalterschulze/gographviz v2.0.1+incompatible/go.mod h1:GEV5wmg4YquNw7v1kkyoX9etIk8yVmXj+AkDHuuETHs= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= diff --git a/pkg/agent/controller/networkpolicy/fqdn.go b/pkg/agent/controller/networkpolicy/fqdn.go index 1d9bbfa49ad..48a7eb3b70e 100644 --- a/pkg/agent/controller/networkpolicy/fqdn.go +++ b/pkg/agent/controller/networkpolicy/fqdn.go @@ -756,7 +756,11 @@ func (f *fqdnController) handlePacketIn(pktIn *ofctrl.PacketIn) error { f.onDNSResponseMsg(&dnsMsg, time.Now(), waitCh) } go func() { - switch ipPkt := pktIn.Data.Data.(type) { + ethernetPkt, err := getEthernetPacket(pktIn) + if err != nil { + return + } + switch ipPkt := ethernetPkt.Data.(type) { case *protocol.IPv4: switch dnsPkt := ipPkt.Data.(type) { case *protocol.UDP: @@ -789,7 +793,11 @@ func (f *fqdnController) sendDNSPacketout(pktIn *ofctrl.PacketIn) error { prot uint8 isIPv6 bool ) - switch ipPkt := pktIn.Data.Data.(type) { + ethernetPkt, err := getEthernetPacket(pktIn) + if err != nil { + return err + } + switch ipPkt := ethernetPkt.Data.(type) { case *protocol.IPv4: srcIP = ipPkt.NWSrc.String() dstIP = ipPkt.NWDst.String() @@ -820,7 +828,7 @@ func (f *fqdnController) sendDNSPacketout(pktIn *ofctrl.PacketIn) error { inPort = inPortField.GetValue().(uint32) } } - udpSrcPort, udpDstPort, err := binding.GetUDPHeaderData(pktIn.Data.Data) + udpSrcPort, udpDstPort, err := binding.GetUDPHeaderData(ethernetPkt.Data) if err != nil { klog.ErrorS(err, "Failed to get UDP header data") return err @@ -829,8 +837,8 @@ func (f *fqdnController) sendDNSPacketout(pktIn *ofctrl.PacketIn) error { return packetOutBuilder.AddLoadRegMark(openflow.CustomReasonDNSRegMark) } return f.ofClient.SendUDPPacketOut( - pktIn.Data.HWSrc.String(), - pktIn.Data.HWDst.String(), + ethernetPkt.HWSrc.String(), + ethernetPkt.HWDst.String(), srcIP, dstIP, inPort, diff --git a/pkg/agent/controller/networkpolicy/packetin.go b/pkg/agent/controller/networkpolicy/packetin.go index 634520f3c75..dbd30c6f3f0 100644 --- a/pkg/agent/controller/networkpolicy/packetin.go +++ b/pkg/agent/controller/networkpolicy/packetin.go @@ -20,7 +20,9 @@ import ( "net" "time" - "antrea.io/libOpenflow/openflow13" + "antrea.io/libOpenflow/openflow15" + "antrea.io/libOpenflow/protocol" + "antrea.io/libOpenflow/util" "antrea.io/ofnet/ofctrl" "github.com/vmware/go-ipfix/pkg/registry" "k8s.io/klog/v2" @@ -70,7 +72,7 @@ func (c *Controller) HandlePacketIn(pktIn *ofctrl.PacketIn) error { // getMatchRegField returns match to the regNum register. func getMatchRegField(matchers *ofctrl.Matchers, field *binding.RegField) *ofctrl.MatchField { - return matchers.GetMatchByName(field.GetNXFieldName()) + return openflow.GetRegMatchInPacketIn(matchers, field.GetRegID()) } // getMatch receives ofctrl matchers and table id, match field. @@ -95,7 +97,7 @@ func getMatch(matchers *ofctrl.Matchers, tableID uint8, disposition uint32) *ofc } // getInfoInReg unloads and returns data stored in the match field. -func getInfoInReg(regMatch *ofctrl.MatchField, rng *openflow13.NXRange) (uint32, error) { +func getInfoInReg(regMatch *ofctrl.MatchField, rng *openflow15.NXRange) (uint32, error) { regValue, ok := regMatch.GetValue().(*ofctrl.NXRegister) if !ok { return 0, errors.New("register value cannot be retrieved") @@ -208,3 +210,12 @@ func isAntreaPolicyEgressTable(tableID uint8) bool { } return false } + +func getEthernetPacket(pktIn *ofctrl.PacketIn) (*protocol.Ethernet, error) { + ethernetPkt := new(protocol.Ethernet) + if err := ethernetPkt.UnmarshalBinary(pktIn.Data.(*util.Buffer).Bytes()); err != nil { + klog.ErrorS(err, "Failed to parse ethernet packet from packet-in message") + return nil, err + } + return ethernetPkt, nil +} diff --git a/pkg/agent/controller/networkpolicy/reject.go b/pkg/agent/controller/networkpolicy/reject.go index 5c5e4690b18..627afeeb92c 100644 --- a/pkg/agent/controller/networkpolicy/reject.go +++ b/pkg/agent/controller/networkpolicy/reject.go @@ -83,8 +83,12 @@ const ( // packet-in message. func (c *Controller) rejectRequest(pktIn *ofctrl.PacketIn) error { // Get ethernet data. - srcMAC := pktIn.Data.HWDst.String() - dstMAC := pktIn.Data.HWSrc.String() + ethernetPkt, err := getEthernetPacket(pktIn) + if err != nil { + return err + } + srcMAC := ethernetPkt.HWDst.String() + dstMAC := ethernetPkt.HWSrc.String() var ( srcIP string @@ -92,7 +96,7 @@ func (c *Controller) rejectRequest(pktIn *ofctrl.PacketIn) error { proto uint8 isIPv6 bool ) - switch ipPkt := pktIn.Data.Data.(type) { + switch ipPkt := ethernetPkt.Data.(type) { case *protocol.IPv4: // Get IP data. srcIP = ipPkt.NWDst.String() @@ -162,7 +166,7 @@ func (c *Controller) rejectRequest(pktIn *ofctrl.PacketIn) error { if proto == protocol.Type_TCP { // Get TCP data. - oriTCPSrcPort, oriTCPDstPort, oriTCPSeqNum, _, _, err := binding.GetTCPHeaderData(pktIn.Data.Data) + oriTCPSrcPort, oriTCPDstPort, oriTCPSeqNum, _, _, err := binding.GetTCPHeaderData(ethernetPkt.Data) if err != nil { return err } @@ -191,7 +195,7 @@ func (c *Controller) rejectRequest(pktIn *ofctrl.PacketIn) error { icmpCode = ICMPv6DstAdminProhibitedCode ipHdrLen = IPv6HdrLen } - ipHdr, _ := pktIn.Data.Data.MarshalBinary() + ipHdr, _ := ethernetPkt.Data.MarshalBinary() icmpData := make([]byte, int(ICMPUnusedHdrLen+ipHdrLen+8)) // Put ICMP unused header in Data prop and set it to zero. binary.BigEndian.PutUint32(icmpData[:ICMPUnusedHdrLen], 0) diff --git a/pkg/agent/controller/traceflow/packetin.go b/pkg/agent/controller/traceflow/packetin.go index 5ce9ef931c3..9eb9012b9ad 100644 --- a/pkg/agent/controller/traceflow/packetin.go +++ b/pkg/agent/controller/traceflow/packetin.go @@ -21,8 +21,9 @@ import ( "net" "time" - "antrea.io/libOpenflow/openflow13" + "antrea.io/libOpenflow/openflow15" "antrea.io/libOpenflow/protocol" + "antrea.io/libOpenflow/util" "antrea.io/ofnet/ofctrl" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/util/retry" @@ -77,8 +78,13 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl var err error var tag uint8 var ctNwDst, ctNwSrc, ipDst, ipSrc string - if pktIn.Data.Ethertype == protocol.IPv4_MSG { - ipPacket, ok := pktIn.Data.Data.(*protocol.IPv4) + etherData := new(protocol.Ethernet) + if err := etherData.UnmarshalBinary(pktIn.Data.(*util.Buffer).Bytes()); err != nil { + klog.ErrorS(err, "Failed to parse ethernet packet from packet-in message") + return nil, nil, nil, fmt.Errorf("failed to parse packet data") + } + if etherData.Ethertype == protocol.IPv4_MSG { + ipPacket, ok := etherData.Data.(*protocol.IPv4) if !ok { return nil, nil, nil, errors.New("invalid traceflow IPv4 packet") } @@ -93,8 +99,8 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl } ipDst = ipPacket.NWDst.String() ipSrc = ipPacket.NWSrc.String() - } else if pktIn.Data.Ethertype == protocol.IPv6_MSG { - ipv6Packet, ok := pktIn.Data.Data.(*protocol.IPv6) + } else if etherData.Ethertype == protocol.IPv6_MSG { + ipv6Packet, ok := etherData.Data.(*protocol.IPv6) if !ok { return nil, nil, nil, errors.New("invalid traceflow IPv6 packet") } @@ -110,7 +116,7 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl ipDst = ipv6Packet.NWDst.String() ipSrc = ipv6Packet.NWSrc.String() } else { - return nil, nil, nil, fmt.Errorf("unsupported traceflow packet Ethertype: %d", pktIn.Data.Ethertype) + return nil, nil, nil, fmt.Errorf("unsupported traceflow packet Ethertype: %d", etherData.Ethertype) } firstPacket := false @@ -246,7 +252,7 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl } } gatewayIP := c.nodeConfig.GatewayConfig.IPv4 - if pktIn.Data.Ethertype == protocol.IPv6_MSG { + if etherData.Ethertype == protocol.IPv6_MSG { gatewayIP = c.nodeConfig.GatewayConfig.IPv6 } gwPort := c.nodeConfig.GatewayConfig.OFPort @@ -274,7 +280,7 @@ func (c *Controller) parsePacketIn(pktIn *ofctrl.PacketIn) (*crdv1alpha1.Tracefl } func getMatchRegField(matchers *ofctrl.Matchers, field *binding.RegField) *ofctrl.MatchField { - return matchers.GetMatchByName(field.GetNXFieldName()) + return openflow.GetRegMatchInPacketIn(matchers, field.GetRegID()) } func getMatchTunnelDstField(matchers *ofctrl.Matchers, isIPv6 bool) *ofctrl.MatchField { @@ -284,7 +290,7 @@ func getMatchTunnelDstField(matchers *ofctrl.Matchers, isIPv6 bool) *ofctrl.Matc return matchers.GetMatchByName("NXM_NX_TUN_IPV4_DST") } -func getRegValue(regMatch *ofctrl.MatchField, rng *openflow13.NXRange) (uint32, error) { +func getRegValue(regMatch *ofctrl.MatchField, rng *openflow15.NXRange) (uint32, error) { regValue, ok := regMatch.GetValue().(*ofctrl.NXRegister) if !ok { return 0, errors.New("register value cannot be got") diff --git a/pkg/agent/controller/traceflow/packetin_test.go b/pkg/agent/controller/traceflow/packetin_test.go index 8f01e33524d..c2a5eb92870 100644 --- a/pkg/agent/controller/traceflow/packetin_test.go +++ b/pkg/agent/controller/traceflow/packetin_test.go @@ -171,7 +171,11 @@ func TestParseCapturedPacket(t *testing.T) { if tt.isIPv6 { ethType = uint16(protocol.IPv6_MSG) } - pktIn := ofctrl.PacketIn{Data: protocol.Ethernet{Ethertype: ethType, Data: tt.pktInData}} + etherPkt := protocol.NewEthernet() + etherPkt.Ethertype = ethType + etherPkt.Data = tt.pktInData + pktBytes, _ := etherPkt.MarshalBinary() + pktIn := ofctrl.PacketIn{Data: util.NewBuffer(pktBytes)} packet := parseCapturedPacket(&pktIn) assert.True(t, reflect.DeepEqual(packet, tt.pktCap), "parsed packet does not match the expected") }) diff --git a/pkg/agent/multicast/mcast_discovery.go b/pkg/agent/multicast/mcast_discovery.go index 648163dd367..697af1b2306 100644 --- a/pkg/agent/multicast/mcast_discovery.go +++ b/pkg/agent/multicast/mcast_discovery.go @@ -21,7 +21,7 @@ import ( "sync" "time" - "antrea.io/libOpenflow/openflow13" + "antrea.io/libOpenflow/openflow15" "antrea.io/libOpenflow/protocol" "antrea.io/libOpenflow/util" "antrea.io/ofnet/ofctrl" @@ -73,9 +73,9 @@ type IGMPSnooper struct { } func (s *IGMPSnooper) HandlePacketIn(pktIn *ofctrl.PacketIn) error { - matches := pktIn.GetMatches() + matchers := pktIn.GetMatches() // Get custom reasons in this packet-in. - match := matches.GetMatchByName(openflow.CustomReasonField.GetNXFieldName()) + match := openflow.GetRegMatchInPacketIn(matchers, openflow.CustomReasonField.GetRegID()) customReasons, err := getInfoInReg(match, openflow.CustomReasonField.GetRange().ToNXRange()) if err != nil { klog.ErrorS(err, "Received error while unloading customReason from OVS reg", "regField", openflow.CustomReasonField.GetName()) @@ -87,7 +87,7 @@ func (s *IGMPSnooper) HandlePacketIn(pktIn *ofctrl.PacketIn) error { return nil } -func getInfoInReg(regMatch *ofctrl.MatchField, rng *openflow13.NXRange) (uint32, error) { +func getInfoInReg(regMatch *ofctrl.MatchField, rng *openflow15.NXRange) (uint32, error) { regValue, ok := regMatch.GetValue().(*ofctrl.NXRegister) if !ok { return 0, errors.New("register value cannot be retrieved") @@ -268,7 +268,12 @@ func (s *IGMPSnooper) processPacketIn(pktIn *ofctrl.PacketIn) error { return err } } - igmp, err := parseIGMPPacket(pktIn.Data) + pktData := new(protocol.Ethernet) + if err := pktData.UnmarshalBinary(pktIn.Data.(*util.Buffer).Bytes()); err != nil { + klog.ErrorS(err, "Failed to parse ethernet packet from packet-in message") + return err + } + igmp, err := parseIGMPPacket(*pktData) if err != nil { return err } @@ -285,7 +290,7 @@ func (s *IGMPSnooper) processPacketIn(pktIn *ofctrl.PacketIn) error { time: now, iface: iface, } - s.validatePacketAndNotify(event, igmpType, pktIn.Data) + s.validatePacketAndNotify(event, igmpType, *pktData) case protocol.IGMPv3Report: msg := igmp.(*protocol.IGMPv3MembershipReport) for _, gr := range msg.GroupRecords { @@ -302,7 +307,7 @@ func (s *IGMPSnooper) processPacketIn(pktIn *ofctrl.PacketIn) error { iface: iface, srcNode: srcNode, } - s.validatePacketAndNotify(event, igmpType, pktIn.Data) + s.validatePacketAndNotify(event, igmpType, *pktData) } case protocol.IGMPv2LeaveGroup: mgroup := igmp.(*protocol.IGMPv1or2).GroupAddress diff --git a/pkg/agent/multicast/mcast_discovery_test.go b/pkg/agent/multicast/mcast_discovery_test.go index 3af352277f3..620b69d7c34 100644 --- a/pkg/agent/multicast/mcast_discovery_test.go +++ b/pkg/agent/multicast/mcast_discovery_test.go @@ -19,7 +19,7 @@ import ( "sync" "testing" - "antrea.io/libOpenflow/openflow13" + "antrea.io/libOpenflow/openflow15" "antrea.io/libOpenflow/protocol" "antrea.io/libOpenflow/util" "antrea.io/ofnet/ofctrl" @@ -149,11 +149,11 @@ func TestIGMPRemoteReport(t *testing.T) { } func generatePacket(m util.Message, ofport uint32, srcNodeIP net.IP) ofctrl.PacketIn { - pkt := openflow13.NewPacketIn() - matchInport := openflow13.NewInPortField(ofport) + pkt := openflow15.NewPacketIn() + matchInport := openflow15.NewInPortField(ofport) pkt.Match.AddField(*matchInport) if srcNodeIP != nil { - matchTunSrc := openflow13.NewTunnelIpv4SrcField(srcNodeIP, nil) + matchTunSrc := openflow15.NewTunnelIpv4SrcField(srcNodeIP, nil) pkt.Match.AddField(*matchTunSrc) } ipPacket := &protocol.IPv4{ @@ -163,12 +163,13 @@ func generatePacket(m util.Message, ofport uint32, srcNodeIP net.IP) ofctrl.Pack Length: 20 + m.Len(), Data: m, } - pkt.Data = protocol.Ethernet{ - HWDst: pktInDstMAC, - HWSrc: pktInSrcMAC, - Ethertype: protocol.IPv4_MSG, - Data: ipPacket, - } + ethernetPkt := protocol.NewEthernet() + ethernetPkt.HWDst = pktInDstMAC + ethernetPkt.HWSrc = pktInSrcMAC + ethernetPkt.Ethertype = protocol.IPv4_MSG + ethernetPkt.Data = ipPacket + pktBytes, _ := ethernetPkt.MarshalBinary() + pkt.Data = util.NewBuffer(pktBytes) return ofctrl.PacketIn(*pkt) } diff --git a/pkg/agent/openflow/client.go b/pkg/agent/openflow/client.go index 1f5fe3be0ab..70486f2e98a 100644 --- a/pkg/agent/openflow/client.go +++ b/pkg/agent/openflow/client.go @@ -996,8 +996,7 @@ func (c *client) SendTraceflowPacket(dataplaneTag uint8, packet *binding.Packet, if outPort != -1 { packetOutBuilder = packetOutBuilder.SetOutport(uint32(outPort)) } - packetOutBuilder = packetOutBuilder.AddLoadAction(binding.NxmFieldIPToS, uint64(dataplaneTag), traceflowTagToSRange) - + packetOutBuilder = packetOutBuilder.AddSetIPToSAction(dataplaneTag) packetOutObj := packetOutBuilder.Done() return c.bridge.SendPacketOut(packetOutObj) } @@ -1023,7 +1022,7 @@ func (c *client) UninstallTraceflowFlows(dataplaneTag uint8) error { return c.deleteFlows(c.featureTraceflow.cachedFlows, cacheKey) } -// Add TLV map optClass 0x0104, optType 0x80 optLength 4 tunMetadataIndex 0 to store data plane tag +// InitialTLVMap adds TLV map optClass 0x0104, optType 0x80 optLength 4 tunMetadataIndex 0 to store data plane tag // in tunnel. Data plane tag will be stored to NXM_NX_TUN_METADATA0[28..31] when packet get encapsulated // into geneve, and will be stored back to NXM_NX_REG9[28..31] when packet get decapsulated. func (c *client) InitialTLVMap() error { diff --git a/pkg/agent/openflow/packetin.go b/pkg/agent/openflow/packetin.go index f157f8c3909..7dd49a114f9 100644 --- a/pkg/agent/openflow/packetin.go +++ b/pkg/agent/openflow/packetin.go @@ -15,8 +15,10 @@ package openflow import ( + "encoding/binary" "fmt" + "antrea.io/libOpenflow/openflow15" "antrea.io/ofnet/ofctrl" "golang.org/x/time/rate" "k8s.io/klog/v2" @@ -127,3 +129,23 @@ func (c *client) parsePacketIn(featurePacketIn *featureStartPacketIn) { } } } + +func GetRegMatchInPacketIn(matchers *ofctrl.Matchers, regID int) *ofctrl.MatchField { + xregID := uint8(regID / 2) + startBit := 4 * (regID % 2) + f := matchers.GetMatch(openflow15.OXM_CLASS_PACKET_REGS, xregID) + if f == nil { + return nil + } + dataBytes := f.Value.(*openflow15.ByteArrayField).Data + data := binary.BigEndian.Uint32(dataBytes[startBit : startBit+4]) + var mask uint32 + if f.HasMask { + maskBytes, _ := f.Mask.MarshalBinary() + mask = binary.BigEndian.Uint32(maskBytes[startBit : startBit+4]) + } + if data == 0 && mask == 0 { + return nil + } + return &ofctrl.MatchField{MatchField: openflow15.NewRegMatchFieldWithMask(regID, data, mask)} +} diff --git a/pkg/agent/openflow/pipeline.go b/pkg/agent/openflow/pipeline.go index b928ea13bef..bbfb4fab092 100644 --- a/pkg/agent/openflow/pipeline.go +++ b/pkg/agent/openflow/pipeline.go @@ -22,7 +22,7 @@ import ( "sync" "time" - "antrea.io/libOpenflow/openflow13" + "antrea.io/libOpenflow/openflow15" "antrea.io/libOpenflow/protocol" "antrea.io/ofnet/ofctrl" v1 "k8s.io/api/core/v1" @@ -370,10 +370,6 @@ var DispositionToString = map[uint32]string{ } var ( - // 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} @@ -2869,7 +2865,7 @@ func (f *featurePodConnectivity) hostBridgeLocalFlows() []binding.Flow { // hostBridgeUplinkVLANFlows generates the flows to match VLAN packets from uplink port. func (f *featurePodConnectivity) hostBridgeUplinkVLANFlows() []binding.Flow { - vlanMask := uint16(openflow13.OFPVID_PRESENT) + vlanMask := uint16(openflow15.OFPVID_PRESENT) return []binding.Flow{ VLANTable.ofTable.BuildFlow(priorityLow). Cookie(f.cookieAllocator.Request(f.category).Raw()). diff --git a/pkg/ovs/openflow/interfaces.go b/pkg/ovs/openflow/interfaces.go index e55ceb2df47..38cb5e22bfa 100644 --- a/pkg/ovs/openflow/interfaces.go +++ b/pkg/ovs/openflow/interfaces.go @@ -210,6 +210,7 @@ type Action interface { LoadRange(name string, addr uint64, to *Range) FlowBuilder Move(from, to string) FlowBuilder MoveRange(fromName, toName string, from, to Range) FlowBuilder + MoveFromTunMetadata(fromTunMetadataId int, toField string, fromRange, toRange Range, tlvLength uint8) FlowBuilder Resubmit(port uint16, table uint8) FlowBuilder ResubmitToTables(tables ...uint8) FlowBuilder CT(commit bool, tableID uint8, zone int, zoneSrcField *RegField) CTAction @@ -364,6 +365,9 @@ type MeterBandBuilder interface { type CTAction interface { LoadToMark(value uint32) CTAction LoadToCtMark(marks ...*CtMark) CTAction + // LoadToLabelField loads a data into ct_label field. If the expected label is larger than the max value of uint64 + // (0xffffffffffffffff), call this function twice: one is to set the low 64 bits, and the other is to set the high + // 64 bits. LoadToLabelField(value uint64, labelField *CtLabel) CTAction MoveToLabel(fromName string, fromRng, labelRng *Range) CTAction MoveToCtMarkField(fromRegField *RegField, ctMark *CtMarkField) CTAction @@ -406,7 +410,9 @@ type PacketOutBuilder interface { SetICMPData(data []byte) PacketOutBuilder SetInport(inPort uint32) PacketOutBuilder SetOutport(outport uint32) PacketOutBuilder - AddLoadAction(name string, data uint64, rng *Range) PacketOutBuilder + // AddSetIPToSAction sets the IP_TOS field in the packet-out message. The action clears the two ECN bits as 0, + // and only 2-7 bits of the DSCP field in IP header is set. + AddSetIPToSAction(data uint8) PacketOutBuilder AddLoadRegMark(mark *RegMark) PacketOutBuilder AddResubmitAction(inPort *uint16, table *uint8) PacketOutBuilder SetL4Packet(packet util.Message) PacketOutBuilder diff --git a/pkg/ovs/openflow/ofctrl_action.go b/pkg/ovs/openflow/ofctrl_action.go index e4ec8cc7769..ac062dd0f96 100644 --- a/pkg/ovs/openflow/ofctrl_action.go +++ b/pkg/ovs/openflow/ofctrl_action.go @@ -20,10 +20,10 @@ import ( "net" "strings" - utilnet "k8s.io/utils/net" - - "antrea.io/libOpenflow/openflow13" + "antrea.io/libOpenflow/openflow15" + "antrea.io/libOpenflow/util" "antrea.io/ofnet/ofctrl" + utilnet "k8s.io/utils/net" ) type ofFlowAction struct { @@ -83,59 +83,80 @@ func (a *ofFlowAction) CT(commit bool, tableID uint8, zone int, zoneSrcField *Re // ofCTAction is a struct to implement CTAction. type ofCTAction struct { ctBase - actions []openflow13.Action + actions []openflow15.Action builder *ofFlowBuilder } // LoadToMark is an action to load data into ct_mark. func (a *ofCTAction) LoadToMark(value uint32) CTAction { - field, rng, _ := getFieldRange(NxmFieldCtMark) - a.load(field, uint64(value), &rng) + ctMarkField := openflow15.NewCTMarkMatchField(value, nil) + action := openflow15.NewActionSetField(*ctMarkField) + a.actions = append(a.actions, action) return a } func (a *ofCTAction) LoadToCtMark(marks ...*CtMark) CTAction { - field, _, _ := getFieldRange(NxmFieldCtMark) for _, mark := range marks { - a.load(field, uint64(mark.value), mark.field.rng) + var mask *uint32 + maskData := uint32(0) + valueData := mark.value + if mark.field.rng != nil { + maskData = ^maskData >> (32 - mark.field.rng.Length()) << mark.field.rng.Offset() + mask = &maskData + valueData = valueData << mark.field.rng.Offset() + } + ctMarkField := openflow15.NewCTMarkMatchField(valueData, mask) + action := openflow15.NewActionSetField(*ctMarkField) + a.actions = append(a.actions, action) } return a } func (a *ofCTAction) LoadToLabelField(value uint64, labelField *CtLabel) CTAction { - field, _, _ := getFieldRange(NxmFieldCtLabel) - a.load(field, value, labelField.rng) - return a -} - -func (a *ofCTAction) load(field *openflow13.MatchField, value uint64, rng *Range) { - action := openflow13.NewNXActionRegLoad(rng.ToNXRange().ToOfsBits(), field, value) + var labelBytes, maskBytes [16]byte + valueData := value + if labelField.rng != nil { + mask := ^uint64(0) >> (64 - labelField.rng.Length()) << labelField.rng.Offset() + valueData = valueData << (labelField.rng.Offset() % 64) + if labelField.rng.Offset() > 64 { + binary.BigEndian.PutUint64(maskBytes[0:8], mask) + binary.BigEndian.PutUint64(labelBytes[0:8], valueData) + } else { + binary.BigEndian.PutUint64(maskBytes[8:], mask) + binary.BigEndian.PutUint64(labelBytes[8:], valueData) + } + } else { + binary.BigEndian.PutUint64(labelBytes[0:8], valueData) + } + ctLabelField := openflow15.NewCTLabelMatchField(labelBytes, &maskBytes) + action := openflow15.NewActionSetField(*ctLabelField) a.actions = append(a.actions, action) + return a } // MoveToLabel is an action to move data into ct_label. func (a *ofCTAction) MoveToLabel(fromName string, fromRng, labelRng *Range) CTAction { - fromField, _ := openflow13.FindFieldHeaderByName(fromName, false) - toField, _ := openflow13.FindFieldHeaderByName(NxmFieldCtLabel, false) + fromField, _ := openflow15.FindOxmIdByName(fromName, false) + toField, _ := openflow15.FindOxmIdByName(NxmFieldCtLabel, false) a.move(fromField, toField, uint16(fromRng.Length()), uint16(fromRng[0]), uint16(labelRng[0])) return a } // MoveToCtMarkField is an action to move data into ct_mark. func (a *ofCTAction) MoveToCtMarkField(fromRegField *RegField, ctMarkField *CtMarkField) CTAction { - fromField, _ := openflow13.FindFieldHeaderByName(fromRegField.GetNXFieldName(), false) - toField, _ := openflow13.FindFieldHeaderByName(NxmFieldCtMark, false) + fromField, _ := openflow15.FindOxmIdByName(fromRegField.GetNXFieldName(), false) + toField, _ := openflow15.FindOxmIdByName(NxmFieldCtMark, false) a.move(fromField, toField, uint16(fromRegField.GetRange().Length()), uint16(fromRegField.GetRange()[0]), uint16(ctMarkField.rng[0])) return a } -func (a *ofCTAction) move(fromField *openflow13.MatchField, toField *openflow13.MatchField, nBits, fromStart, toStart uint16) { - action := openflow13.NewNXActionRegMove(nBits, fromStart, toStart, fromField, toField) +func (a *ofCTAction) move(fromField *openflow15.OxmId, toField *openflow15.OxmId, nBits, fromStart, toStart uint16) { + action := openflow15.NewActionCopyField(nBits, fromStart, toStart, *fromField, *toField) a.actions = append(a.actions, action) } func (a *ofCTAction) natAction(isSNAT bool, ipRange *IPRange, portRange *PortRange) CTAction { - action := openflow13.NewNXActionCTNAT() + action := openflow15.NewNXActionCTNAT() if isSNAT { action.SetSNAT() } else { @@ -169,7 +190,7 @@ func (a *ofCTAction) DNAT(ipRange *IPRange, portRange *PortRange) CTAction { } func (a *ofCTAction) NAT() CTAction { - action := openflow13.NewNXActionCTNAT() + action := openflow15.NewNXActionCTNAT() a.actions = append(a.actions, action) return a } @@ -272,25 +293,38 @@ func (a *ofFlowAction) SetVLAN(vlanID uint16) FlowBuilder { // LoadARPOperation is an action to load data to NXM_OF_ARP_OP field. func (a *ofFlowAction) LoadARPOperation(value uint16) FlowBuilder { - loadAct, _ := ofctrl.NewNXLoadAction(NxmFieldARPOp, uint64(value), openflow13.NewNXRange(0, 15)) + loadAct := &ofctrl.SetARPOpAction{Value: value} a.builder.ApplyAction(loadAct) return a.builder } // 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 { - 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) + hasMask := rng != nil + field, _ := openflow15.FindFieldHeaderByName(name, hasMask) + var valueBytes, maskBytes []byte + valueData := value + if hasMask { + mask := ^uint64(0) >> (64 - rng.Length()) << rng.Offset() + binary.BigEndian.PutUint64(maskBytes, mask) + field.Mask = util.NewBuffer(maskBytes) + valueData = valueData << rng.Offset() } - a.builder.ApplyAction(loadAct) - return a.builder + binary.BigEndian.PutUint64(valueBytes, valueData) + field.Value = util.NewBuffer(valueBytes) + return a.setField(field) } 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) + valueData := value + mask := uint32(0) + if field.rng != nil { + mask = ^mask >> (32 - field.rng.Length()) << field.rng.Offset() + valueData = valueData << field.rng.Offset() + } + f := openflow15.NewRegMatchFieldWithMask(field.regID, valueData, mask) + act := ofctrl.NewSetFieldAction(f) + a.builder.ApplyAction(act) return a.builder } @@ -303,14 +337,35 @@ func (a *ofFlowAction) LoadRegMark(marks ...*RegMark) FlowBuilder { return fb } -// LoadToPktMarkRange is an action to load data into pkt_mark at specified range. +// LoadPktMarkRange is an action to load data into pkt_mark at specified range. func (a *ofFlowAction) LoadPktMarkRange(value uint32, rng *Range) FlowBuilder { - return a.LoadRange(NxmFieldPktMark, uint64(value), rng) + pktMarkField, _ := openflow15.FindFieldHeaderByName(NxmFieldPktMark, true) + var valueBytes, maskBytes [4]byte + valueData := value + mask := uint32(0) + if rng != nil { + mask = ^mask >> (32 - rng.Length()) << rng.Offset() + binary.BigEndian.PutUint32(maskBytes[:], mask) + pktMarkField.Mask = util.NewBuffer(maskBytes[:]) + valueData = valueData << rng.Offset() + } + binary.BigEndian.PutUint32(valueBytes[:], valueData) + pktMarkField.Value = util.NewBuffer(valueBytes[:]) + return a.setField(pktMarkField) } // LoadIPDSCP is an action to load data to IP DSCP bits. func (a *ofFlowAction) LoadIPDSCP(value uint8) FlowBuilder { - return a.LoadRange(NxmFieldIPToS, uint64(value), IPDSCPToSRange) + field, _ := openflow15.FindFieldHeaderByName(NxmFieldIPToS, true) + field.Value = &openflow15.IpDscpField{Dscp: value << IPDSCPToSRange.Offset()} + field.Mask = &openflow15.IpDscpField{Dscp: uint8(0xff) >> (8 - IPDSCPToSRange.Length()) << IPDSCPToSRange.Offset()} + return a.setField(field) +} + +func (a *ofFlowAction) setField(field *openflow15.MatchField) FlowBuilder { + loadAct := ofctrl.NewSetFieldAction(field) + a.builder.ApplyAction(loadAct) + return a.builder } // Move is an action to copy all data from "fromField" to "toField". Fields with name "fromField" and "fromField" should @@ -323,14 +378,26 @@ func (a *ofFlowAction) Move(fromField, toField string) FlowBuilder { // MoveRange is an action to move data from "fromField" at "fromRange" to "toField" at "toRange". func (a *ofFlowAction) MoveRange(fromField, toField string, fromRange, toRange Range) FlowBuilder { - moveAct, _ := ofctrl.NewNXMoveAction(fromField, toField, fromRange.ToNXRange(), toRange.ToNXRange()) - if a.builder.ofFlow.Table != nil && a.builder.ofFlow.Table.Switch != nil { - moveAct.ResetFieldsLength(a.builder.ofFlow.Table.Switch) - } + srcOxmId, _ := openflow15.FindOxmIdByName(fromField, false) + dstOxmId, _ := openflow15.FindOxmIdByName(toField, false) + return a.copyField(srcOxmId, dstOxmId, fromRange, toRange) +} + +func (a *ofFlowAction) copyField(srcOxmId, dstOxmId *openflow15.OxmId, fromRange, toRange Range) FlowBuilder { + nBits := fromRange.ToNXRange().GetNbits() + srcOffset := fromRange.ToNXRange().GetOfs() + dstOffset := toRange.ToNXRange().GetOfs() + moveAct := ofctrl.NewCopyFieldAction(nBits, srcOffset, dstOffset, srcOxmId, dstOxmId) a.builder.ApplyAction(moveAct) return a.builder } +func (a *ofFlowAction) MoveFromTunMetadata(fromTunMetadataId int, toField string, fromRange, toRange Range, tlvLength uint8) FlowBuilder { + dstOxmId, _ := openflow15.FindOxmIdByName(toField, false) + srcOxmId := getTunMetadataOxmId(fromTunMetadataId, tlvLength) + return a.copyField(srcOxmId, dstOxmId, fromRange, toRange) +} + // Resubmit is an action to resubmit packet to the specified table with the port as new in_port. If port is empty string, // the in_port field is not changed. func (a *ofFlowAction) Resubmit(ofPort uint16, tableID uint8) FlowBuilder { @@ -343,7 +410,7 @@ func (a *ofFlowAction) Resubmit(ofPort uint16, tableID uint8) FlowBuilder { func (a *ofFlowAction) ResubmitToTables(tables ...uint8) FlowBuilder { var fb FlowBuilder for _, t := range tables { - fb = a.Resubmit(openflow13.OFPP_IN_PORT, t) + fb = a.Resubmit(openflow15.OFPP_IN_PORT, t) } return fb } @@ -399,11 +466,12 @@ func (a *ofFlowAction) SendToController(reason uint8) FlowBuilder { } func (a *ofFlowAction) Meter(meterID uint32) FlowBuilder { - a.builder.ofFlow.Meter(meterID) + meterAction := ofctrl.NewMeterAction(meterID) + a.builder.ApplyAction(meterAction) return a.builder } -// Learn is an action which adds or modifies a flow in an OpenFlow table. +// Learn is an action which adds or modifies a flow in an OpenFlow table. func (a *ofFlowAction) Learn(id uint8, priority uint16, idleTimeout, hardTimeout uint16, cookieID uint64) LearnAction { la := &ofLearnAction{ flowBuilder: a.builder, @@ -600,8 +668,8 @@ func (a *ofLearnAction) Done() FlowBuilder { return a.flowBuilder } -func getFieldRange(name string) (*openflow13.MatchField, Range, error) { - field, err := openflow13.FindFieldHeaderByName(name, false) +func getFieldRange(name string) (*openflow15.MatchField, Range, error) { + field, err := openflow15.FindFieldHeaderByName(name, false) if err != nil { return field, Range{0, 0}, err } @@ -626,3 +694,10 @@ func (a *ofFlowAction) GotoStage(stage StageID) FlowBuilder { a.builder.ofFlow.Goto(table.GetID()) return a.builder } + +func getTunMetadataOxmId(id int, tlvLength uint8) *openflow15.OxmId { + field := fmt.Sprintf("%s%d", NxmFieldTunMetadata, id) + oxmId, _ := openflow15.FindOxmIdByName(field, false) + oxmId.Length = tlvLength + return oxmId +} diff --git a/pkg/ovs/openflow/ofctrl_bridge.go b/pkg/ovs/openflow/ofctrl_bridge.go index e5b2b886cfc..357d9aba7f1 100644 --- a/pkg/ovs/openflow/ofctrl_bridge.go +++ b/pkg/ovs/openflow/ofctrl_bridge.go @@ -21,7 +21,7 @@ import ( "sync" "time" - "antrea.io/libOpenflow/openflow13" + "antrea.io/libOpenflow/openflow15" "antrea.io/ofnet/ofctrl" "golang.org/x/time/rate" "k8s.io/klog/v2" @@ -138,17 +138,31 @@ func (t *ofTable) DumpFlows(cookieID, cookieMask uint64) (map[uint64]*FlowStates if ofStats == nil { return nil, nil } + return parseFlowStats(ofStats), nil +} + +func parseFlowStats(ofStats []*openflow15.FlowDesc) map[uint64]*FlowStates { flowStats := make(map[uint64]*FlowStates) for _, stat := range ofStats { cookie := stat.Cookie s := &FlowStates{ - TableID: stat.TableId, - PacketCount: stat.PacketCount, - DurationNSecond: stat.DurationNSec, + TableID: stat.TableId, + } + for _, field := range stat.Stats.Fields { + count, ok := field.(*openflow15.PBCountStatField) + if ok { + if count.Header.Field == openflow15.XST_OFB_PACKET_COUNT { + s.PacketCount = count.Count + } + } else if count, ok := field.(*openflow15.TimeStatField); ok { + if count.Header.Field == openflow15.XST_OFB_DURATION { + s.DurationNSecond = count.NSec + } + } } flowStats[cookie] = s } - return flowStats, nil + return flowStats } func NewOFTable(id uint8, name string, stageID StageID, pipelineID PipelineID, missAction MissActionType) Table { @@ -186,7 +200,10 @@ type OFBridge struct { connected chan bool // pktConsumers is a map from PacketIn reason to the channel that is used to publish the PacketIn message. pktConsumers sync.Map - multipartReplyChs map[uint32]chan *openflow13.MultipartReply + multipartReplyChs map[uint32]chan *openflow15.MultipartReply + // tunMetadataLengthMap is used to store the tlv-map settings on the OVS bridge. Key is the index of tunnel metedata, + // and value the length configured in this tunnel metadata. + tunMetadataLengthMap map[uint16]uint8 } func (b *OFBridge) CreateGroupTypeAll(id GroupIDType) Group { @@ -242,9 +259,9 @@ func (b *OFBridge) DeleteMeterAll() error { // Clear all existing meter entries // TODO: this should be defined in libOpenflow const OFPM_ALL = 0xffffffff // Represents all meters - meterMod := openflow13.NewMeterMod() + meterMod := openflow15.NewMeterMod() meterMod.MeterId = OFPM_ALL - meterMod.Command = openflow13.OFPMC_DELETE + meterMod.Command = openflow15.MC_DELETE if err := b.ofSwitch.Send(meterMod); err != nil { return err } @@ -320,7 +337,7 @@ func (b *OFBridge) SwitchConnected(sw *ofctrl.OFSwitch) { // MultipartReply is a callback when multipartReply message is received on ofctrl.OFSwitch is connected. // Client uses this method to handle the reply message if it has customized MultipartRequest message. -func (b *OFBridge) MultipartReply(sw *ofctrl.OFSwitch, rep *openflow13.MultipartReply) { +func (b *OFBridge) MultipartReply(sw *ofctrl.OFSwitch, rep *openflow15.MultipartReply) { if ch, ok := b.multipartReplyChs[rep.Xid]; ok { ch <- rep } @@ -396,28 +413,18 @@ func (b *OFBridge) DumpFlows(cookieID, cookieMask uint64) (map[uint64]*FlowState if ofStats == nil { return nil, nil } - flowStats := make(map[uint64]*FlowStates) - for _, stat := range ofStats { - cookie := stat.Cookie - s := &FlowStates{ - TableID: stat.TableId, - PacketCount: stat.PacketCount, - DurationNSecond: stat.DurationNSec, - } - flowStats[cookie] = s - } - return flowStats, nil + return parseFlowStats(ofStats), nil } // DeleteFlowsByCookie removes Openflow entries from OFSwitch. The removed Openflow entries use the specific CookieID. func (b *OFBridge) DeleteFlowsByCookie(cookieID, cookieMask uint64) error { - flowMod := openflow13.NewFlowMod() - flowMod.Command = openflow13.FC_DELETE + flowMod := openflow15.NewFlowMod() + flowMod.Command = openflow15.FC_DELETE flowMod.Cookie = cookieID flowMod.CookieMask = cookieMask - flowMod.OutPort = openflow13.P_ANY - flowMod.OutGroup = openflow13.OFPG_ANY - flowMod.TableId = openflow13.OFPTT_ALL + flowMod.OutPort = openflow15.P_ANY + flowMod.OutGroup = openflow15.OFPG_ANY + flowMod.TableId = openflow15.OFPTT_ALL return b.ofSwitch.Send(flowMod) } @@ -462,15 +469,15 @@ func (b *OFBridge) AddFlowsInBundle(addflows []Flow, modFlows []Flow, delFlows [ } // Install new Openflow entries with the opened bundle. - if err := syncFlows(addflows, openflow13.FC_ADD); err != nil { + if err := syncFlows(addflows, openflow15.FC_ADD); err != nil { return err } // Modify existing Openflow entries with the opened bundle. - if err := syncFlows(modFlows, openflow13.FC_MODIFY_STRICT); err != nil { + if err := syncFlows(modFlows, openflow15.FC_MODIFY_STRICT); err != nil { return err } // Delete Openflow entries with the opened bundle. - if err := syncFlows(delFlows, openflow13.FC_DELETE_STRICT); err != nil { + if err := syncFlows(delFlows, openflow15.FC_DELETE_STRICT); err != nil { return err } @@ -662,6 +669,7 @@ func (b *OFBridge) AddTLVMap(optClass uint16, optType uint8, optLength uint8, tu if err := b.ofSwitch.AddTunnelTLVMap(optClass, optType, optLength, tunMetadataIndex); err != nil { return err } + b.tunMetadataLengthMap[tunMetadataIndex] = optLength return nil } @@ -687,17 +695,17 @@ func (b *OFBridge) RetryInterval() time.Duration { } func (b *OFBridge) queryTableFeatures() { - mpartRequest := &openflow13.MultipartRequest{ - Header: openflow13.NewOfp13Header(), - Type: openflow13.MultipartType_TableFeatures, + mpartRequest := &openflow15.MultipartRequest{ + Header: openflow15.NewOfp15Header(), + Type: openflow15.MultipartType_TableFeatures, Flags: 0, } - mpartRequest.Header.Type = openflow13.Type_MultiPartRequest + mpartRequest.Header.Type = openflow15.Type_MultiPartRequest mpartRequest.Header.Length = mpartRequest.Len() // Use a buffer for the channel to avoid blocking the OpenFlow connection inbound channel, since it takes time when // sending the Multipart Request messages to modify the tables' names. The buffer size "20" is the observed number // of the Multipart Reply messages sent from OVS. - tableFeatureCh := make(chan *openflow13.MultipartReply, 20) + tableFeatureCh := make(chan *openflow15.MultipartReply, 20) b.multipartReplyChs[mpartRequest.Xid] = tableFeatureCh go func() { // Delete the channel which is used to receive the MultipartReply message after all tables' features are received. @@ -709,24 +717,24 @@ func (b *OFBridge) queryTableFeatures() { b.ofSwitch.Send(mpartRequest) } -func (b *OFBridge) processTableFeatures(ch chan *openflow13.MultipartReply) { - header := openflow13.NewOfp13Header() - header.Type = openflow13.Type_MultiPartRequest +func (b *OFBridge) processTableFeatures(ch chan *openflow15.MultipartReply) { + header := openflow15.NewOfp15Header() + header.Type = openflow15.Type_MultiPartRequest // Since the initial MultipartRequest doesn't specify any table ID, OVS will reply all tables' (except the hidden one) // features in the reply. Here we complete the loop after we receive all the reply messages, while the reply message // is configured with Flags=0. for { select { case rpl := <-ch: - request := &openflow13.MultipartRequest{ + request := &openflow15.MultipartRequest{ Header: header, - Type: openflow13.MultipartType_TableFeatures, + Type: openflow15.MultipartType_TableFeatures, Flags: rpl.Flags, } // A MultipartReply message may have one or many OFPTableFeatures messages, and MultipartReply.Body is a // slice of these messages. for _, body := range rpl.Body { - tableFeature := body.(*openflow13.OFPTableFeatures) + tableFeature := body.(*openflow15.TableFeatures) // Modify table name if the table is in the pipeline, otherwise use the default table features. // OVS doesn't allow to skip any table except the hidden table (always the last table) in a table_features // request. So use the existing table features for the tables that Antrea doesn't define in the pipeline. @@ -749,12 +757,13 @@ func (b *OFBridge) processTableFeatures(ch chan *openflow13.MultipartReply) { func NewOFBridge(br string, mgmtAddr string) Bridge { s := &OFBridge{ - bridgeName: br, - mgmtAddr: mgmtAddr, - tableCache: make(map[uint8]*ofTable), - retryInterval: 1 * time.Second, - pktConsumers: sync.Map{}, - multipartReplyChs: make(map[uint32]chan *openflow13.MultipartReply), + bridgeName: br, + mgmtAddr: mgmtAddr, + tableCache: make(map[uint8]*ofTable), + retryInterval: 1 * time.Second, + pktConsumers: sync.Map{}, + multipartReplyChs: make(map[uint32]chan *openflow15.MultipartReply), + tunMetadataLengthMap: make(map[uint16]uint8), } s.controller = ofctrl.NewController(s) return s diff --git a/pkg/ovs/openflow/ofctrl_builder.go b/pkg/ovs/openflow/ofctrl_builder.go index b6b36f52dff..3135b967431 100644 --- a/pkg/ovs/openflow/ofctrl_builder.go +++ b/pkg/ovs/openflow/ofctrl_builder.go @@ -19,7 +19,7 @@ import ( "net" "strings" - "antrea.io/libOpenflow/openflow13" + "antrea.io/libOpenflow/openflow15" "antrea.io/ofnet/ofctrl" ) @@ -28,7 +28,7 @@ type ofFlowBuilder struct { } func (b *ofFlowBuilder) MatchTunMetadata(index int, data uint32) FlowBuilder { - rng := openflow13.NewNXRange(0, 31) + rng := openflow15.NewNXRange(0, 31) tm := &ofctrl.NXTunMetadata{ ID: index, Data: data, @@ -133,7 +133,7 @@ func (b *ofFlowBuilder) addCTStateString(value string) { func (b *ofFlowBuilder) MatchCTStateNew(set bool) FlowBuilder { if b.ctStates == nil { - b.ctStates = openflow13.NewCTStates() + b.ctStates = openflow15.NewCTStates() } if set { b.ctStates.SetNew() @@ -147,7 +147,7 @@ func (b *ofFlowBuilder) MatchCTStateNew(set bool) FlowBuilder { func (b *ofFlowBuilder) MatchCTStateRel(set bool) FlowBuilder { if b.ctStates == nil { - b.ctStates = openflow13.NewCTStates() + b.ctStates = openflow15.NewCTStates() } if set { b.ctStates.SetRel() @@ -161,7 +161,7 @@ func (b *ofFlowBuilder) MatchCTStateRel(set bool) FlowBuilder { func (b *ofFlowBuilder) MatchCTStateRpl(set bool) FlowBuilder { if b.ctStates == nil { - b.ctStates = openflow13.NewCTStates() + b.ctStates = openflow15.NewCTStates() } if set { b.ctStates.SetRpl() @@ -175,7 +175,7 @@ func (b *ofFlowBuilder) MatchCTStateRpl(set bool) FlowBuilder { func (b *ofFlowBuilder) MatchCTStateEst(set bool) FlowBuilder { if b.ctStates == nil { - b.ctStates = openflow13.NewCTStates() + b.ctStates = openflow15.NewCTStates() } if set { b.ctStates.SetEst() @@ -189,7 +189,7 @@ func (b *ofFlowBuilder) MatchCTStateEst(set bool) FlowBuilder { func (b *ofFlowBuilder) MatchCTStateTrk(set bool) FlowBuilder { if b.ctStates == nil { - b.ctStates = openflow13.NewCTStates() + b.ctStates = openflow15.NewCTStates() } if set { b.ctStates.SetTrk() @@ -203,7 +203,7 @@ func (b *ofFlowBuilder) MatchCTStateTrk(set bool) FlowBuilder { func (b *ofFlowBuilder) MatchCTStateInv(set bool) FlowBuilder { if b.ctStates == nil { - b.ctStates = openflow13.NewCTStates() + b.ctStates = openflow15.NewCTStates() } if set { b.ctStates.SetInv() @@ -217,7 +217,7 @@ func (b *ofFlowBuilder) MatchCTStateInv(set bool) FlowBuilder { func (b *ofFlowBuilder) MatchCTStateDNAT(set bool) FlowBuilder { if b.ctStates == nil { - b.ctStates = openflow13.NewCTStates() + b.ctStates = openflow15.NewCTStates() } if set { b.ctStates.SetDNAT() @@ -231,7 +231,7 @@ func (b *ofFlowBuilder) MatchCTStateDNAT(set bool) FlowBuilder { func (b *ofFlowBuilder) MatchCTStateSNAT(set bool) FlowBuilder { if b.ctStates == nil { - b.ctStates = openflow13.NewCTStates() + b.ctStates = openflow15.NewCTStates() } if set { b.ctStates.SetSNAT() diff --git a/pkg/ovs/openflow/ofctrl_flow.go b/pkg/ovs/openflow/ofctrl_flow.go index b3a1dc60033..5428bb423ef 100644 --- a/pkg/ovs/openflow/ofctrl_flow.go +++ b/pkg/ovs/openflow/ofctrl_flow.go @@ -18,7 +18,7 @@ import ( "fmt" "strings" - "antrea.io/libOpenflow/openflow13" + "antrea.io/libOpenflow/openflow15" "antrea.io/ofnet/ofctrl" ) @@ -42,9 +42,9 @@ type ofFlow struct { // ctStateString is a temporary variable for the readable ct_state configuration. Its value is changed when the client // updates the matching condition of "ct_states". When FlowBuilder.Done is called, its value is added into the matchers. ctStateString string - // ctStates is a temporary variable to maintain openflow13.CTStates. When FlowBuilder.Done is called, it is used to + // ctStates is a temporary variable to maintain openflow15.CTStates. When FlowBuilder.Done is called, it is used to // set the CtStates field in ofctrl.Flow.Match. - ctStates *openflow13.CTStates + ctStates *openflow15.CTStates // isDropFlow is true if this flow actions contain "drop" isDropFlow bool } @@ -69,7 +69,7 @@ func (f *ofFlow) Reset() { } func (f *ofFlow) Add() error { - err := f.Flow.Send(openflow13.FC_ADD) + err := f.Flow.Send(openflow15.FC_ADD) if err != nil { return err } @@ -78,7 +78,7 @@ func (f *ofFlow) Add() error { } func (f *ofFlow) Modify() error { - err := f.Flow.Send(openflow13.FC_MODIFY_STRICT) + err := f.Flow.Send(openflow15.FC_MODIFY_STRICT) if err != nil { return err } @@ -88,7 +88,7 @@ func (f *ofFlow) Modify() error { func (f *ofFlow) Delete() error { f.Flow.UpdateInstallStatus(true) - err := f.Flow.Send(openflow13.FC_DELETE_STRICT) + err := f.Flow.Send(openflow15.FC_DELETE_STRICT) if err != nil { return err } @@ -128,11 +128,11 @@ func (f *ofFlow) GetBundleMessage(entryOper OFOperation) (ofctrl.OpenFlowModMess var operation int switch entryOper { case AddMessage: - operation = openflow13.FC_ADD + operation = openflow15.FC_ADD case ModifyMessage: - operation = openflow13.FC_MODIFY_STRICT + operation = openflow15.FC_MODIFY_STRICT case DeleteMessage: - operation = openflow13.FC_DELETE_STRICT + operation = openflow15.FC_DELETE_STRICT } message, err := f.Flow.GetBundleMessage(operation) if err != nil { @@ -175,8 +175,8 @@ func (f *ofFlow) IsDropFlow() bool { return f.isDropFlow } -func (r *Range) ToNXRange() *openflow13.NXRange { - return openflow13.NewNXRange(int(r[0]), int(r[1])) +func (r *Range) ToNXRange() *openflow15.NXRange { + return openflow15.NewNXRange(int(r[0]), int(r[1])) } func (r *Range) Length() uint32 { diff --git a/pkg/ovs/openflow/ofctrl_group.go b/pkg/ovs/openflow/ofctrl_group.go index b16495b0c4a..7402aa8e638 100644 --- a/pkg/ovs/openflow/ofctrl_group.go +++ b/pkg/ovs/openflow/ofctrl_group.go @@ -18,13 +18,15 @@ import ( "fmt" "net" - "antrea.io/libOpenflow/openflow13" + "antrea.io/libOpenflow/openflow15" + "antrea.io/libOpenflow/util" "antrea.io/ofnet/ofctrl" ) type ofGroup struct { - ofctrl *ofctrl.Group - bridge *OFBridge + ofctrl *ofctrl.Group + bridge *OFBridge + bucketsCount int } // Reset creates a new ofctrl.Group object for the updated ofSwitch. The @@ -62,9 +64,10 @@ func (g *ofGroup) KeyString() string { } func (g *ofGroup) Bucket() BucketBuilder { + id := uint32(len(g.ofctrl.Buckets)) return &bucketBuilder{ group: g, - bucket: openflow13.NewBucket(), + bucket: openflow15.NewBucket(id), } } @@ -72,11 +75,11 @@ func (g *ofGroup) GetBundleMessage(entryOper OFOperation) (ofctrl.OpenFlowModMes var operation int switch entryOper { case AddMessage: - operation = openflow13.OFPGC_ADD + operation = openflow15.OFPGC_ADD case ModifyMessage: - operation = openflow13.OFPGC_MODIFY + operation = openflow15.OFPGC_MODIFY case DeleteMessage: - operation = openflow13.OFPGC_DELETE + operation = openflow15.OFPGC_DELETE } message := g.ofctrl.GetBundleMessage(operation) return message, nil @@ -89,7 +92,7 @@ func (g *ofGroup) ResetBuckets() Group { type bucketBuilder struct { group *ofGroup - bucket *openflow13.Bucket + bucket *openflow15.Bucket } // LoadReg makes the learned flow to load data to reg[regID] with specific range. @@ -99,23 +102,34 @@ func (b *bucketBuilder) LoadReg(regID int, data uint32) BucketBuilder { // LoadXXReg makes the learned flow to load data to xxreg[regID] with specific range. func (b *bucketBuilder) LoadXXReg(regID int, data []byte) BucketBuilder { - regAction := &ofctrl.NXLoadXXRegAction{FieldNumber: uint8(regID), Value: data, Mask: nil} - b.bucket.AddAction(regAction.GetActionMessage()) + field, _ := openflow15.FindFieldHeaderByName(fmt.Sprintf("NXM_NX_XXREG%d", regID), false) + field.Value = util.NewBuffer(data) + b.bucket.AddAction(openflow15.NewActionSetField(*field)) return b } // 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 { - reg := fmt.Sprintf("%s%d", NxmFieldReg, regID) - regField, _ := openflow13.FindFieldHeaderByName(reg, true) - b.bucket.AddAction(openflow13.NewNXActionRegLoad(rng.ToNXRange().ToOfsBits(), regField, uint64(data))) + valueData := data + mask := uint32(0) + if rng != nil { + mask = ^mask >> (32 - rng.Length()) << rng.Offset() + valueData = valueData << rng.Offset() + } + tgtField := openflow15.NewRegMatchFieldWithMask(regID, valueData, mask) + b.bucket.AddAction(openflow15.NewActionSetField(*tgtField)) 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))) + valueData := data + mask := uint32(0) + if field.rng != nil { + mask = ^mask >> (32 - field.rng.Length()) << field.rng.Offset() + valueData = valueData << field.rng.Offset() + } + tgtField := openflow15.NewRegMatchFieldWithMask(field.regID, valueData, mask) + b.bucket.AddAction(openflow15.NewActionSetField(*tgtField)) return b } @@ -125,7 +139,7 @@ func (b *bucketBuilder) LoadRegMark(mark *RegMark) BucketBuilder { // ResubmitToTable is an action to resubmit packet to the specified table when the bucket is selected. func (b *bucketBuilder) ResubmitToTable(tableID uint8) BucketBuilder { - b.bucket.AddAction(openflow13.NewNXActionResubmitTableAction(openflow13.OFPP_IN_PORT, tableID)) + b.bucket.AddAction(openflow15.NewNXActionResubmitTableAction(openflow15.OFPP_IN_PORT, tableID)) return b } @@ -138,7 +152,8 @@ func (b *bucketBuilder) SetTunnelDst(addr net.IP) BucketBuilder { // Weight sets the weight of a bucket. func (b *bucketBuilder) Weight(val uint16) BucketBuilder { - b.bucket.Weight = val + weight := openflow15.NewGroupBucketPropWeight(val) + b.bucket.AddProperty(weight) return b } diff --git a/pkg/ovs/openflow/ofctrl_meter.go b/pkg/ovs/openflow/ofctrl_meter.go index cca0a53cb95..a6af7e46f3e 100644 --- a/pkg/ovs/openflow/ofctrl_meter.go +++ b/pkg/ovs/openflow/ofctrl_meter.go @@ -17,7 +17,7 @@ package openflow import ( "fmt" - "antrea.io/libOpenflow/openflow13" + "antrea.io/libOpenflow/openflow15" "antrea.io/libOpenflow/util" "antrea.io/ofnet/ofctrl" ) @@ -55,11 +55,11 @@ func (m *ofMeter) GetBundleMessage(entryOper OFOperation) (ofctrl.OpenFlowModMes var operation int switch entryOper { case AddMessage: - operation = openflow13.OFPMC_ADD + operation = openflow15.MC_ADD case ModifyMessage: - operation = openflow13.OFPMC_MODIFY + operation = openflow15.MC_MODIFY case DeleteMessage: - operation = openflow13.OFPMC_DELETE + operation = openflow15.MC_DELETE } message := m.ofctrl.GetBundleMessage(operation) return message, nil @@ -73,7 +73,7 @@ func (m *ofMeter) ResetMeterBands() Meter { func (m *ofMeter) MeterBand() MeterBandBuilder { return &meterBandBuilder{ meter: m, - meterBandHeader: openflow13.NewMeterBandHeader(), + meterBandHeader: openflow15.NewMeterBandHeader(), prevLevel: 0, experimenter: 0, } @@ -81,7 +81,7 @@ func (m *ofMeter) MeterBand() MeterBandBuilder { type meterBandBuilder struct { meter *ofMeter - meterBandHeader *openflow13.MeterBandHeader + meterBandHeader *openflow15.MeterBandHeader prevLevel uint8 experimenter uint32 } @@ -115,16 +115,16 @@ func (m *meterBandBuilder) Done() Meter { var mb util.Message switch m.meterBandHeader.Type { case uint16(ofctrl.MeterDrop): - mbDrop := new(openflow13.MeterBandDrop) + mbDrop := new(openflow15.MeterBandDrop) mbDrop.MeterBandHeader = *m.meterBandHeader mb = mbDrop case uint16(ofctrl.MeterDSCPRemark): - mbDscp := new(openflow13.MeterBandDSCP) + mbDscp := new(openflow15.MeterBandDSCP) mbDscp.MeterBandHeader = *m.meterBandHeader mbDscp.PrecLevel = m.prevLevel mb = mbDscp case uint16(ofctrl.MeterExperimenter): - mbExp := new(openflow13.MeterBandExperimenter) + mbExp := new(openflow15.MeterBandExperimenter) mbExp.MeterBandHeader = *m.meterBandHeader mbExp.Experimenter = m.experimenter } diff --git a/pkg/ovs/openflow/ofctrl_packetin.go b/pkg/ovs/openflow/ofctrl_packetin.go index 50e49717e47..61ae8199b0a 100644 --- a/pkg/ovs/openflow/ofctrl_packetin.go +++ b/pkg/ovs/openflow/ofctrl_packetin.go @@ -63,39 +63,50 @@ func GetUDPHeaderData(ipPkt util.Message) (udpSrcPort, udpDstPort uint16, err er } func getICMPHeaderData(ipPkt util.Message) (icmpType, icmpCode uint8, icmpEchoID, icmpEchoSeq uint16, err error) { - var icmpIn *protocol.ICMP switch typedIPPkt := ipPkt.(type) { case *protocol.IPv4: - icmpIn = typedIPPkt.Data.(*protocol.ICMP) + icmpIn := typedIPPkt.Data.(*protocol.ICMP) + if icmpIn.Type == icmpEchoRequestType { + if len(icmpIn.Data) < 4 { + return 0, 0, 0, 0, errors.New("ICMP payload is too short to unmarshal an ICMP echo message") + } + icmpEchoID = binary.BigEndian.Uint16(icmpIn.Data[:2]) + icmpEchoSeq = binary.BigEndian.Uint16(icmpIn.Data[2:4]) + } + icmpType = icmpIn.Type + icmpCode = icmpIn.Code case *protocol.IPv6: - icmpIn = typedIPPkt.Data.(*protocol.ICMP) - } - - if icmpIn.Type == icmpEchoRequestType || icmpIn.Type == icmp6EchoRequestType { - if len(icmpIn.Data) < 4 { - return 0, 0, 0, 0, errors.New("ICMP payload is too short to unmarshal an ICMP echo message") + icmpIn := typedIPPkt.Data.(*protocol.ICMPv6EchoReqRpl) + if icmpIn.Type == icmp6EchoRequestType { + icmpEchoID = icmpIn.Identifier + icmpEchoSeq = icmpIn.SeqNum } - icmpEchoID = binary.BigEndian.Uint16(icmpIn.Data[:2]) - icmpEchoSeq = binary.BigEndian.Uint16(icmpIn.Data[2:4]) + icmpType = icmpIn.Type + icmpCode = icmpIn.Code } - return icmpIn.Type, icmpIn.Code, icmpEchoID, icmpEchoSeq, nil + + return icmpType, icmpCode, icmpEchoID, icmpEchoSeq, nil } func ParsePacketIn(pktIn *ofctrl.PacketIn) (*Packet, error) { packet := Packet{} - packet.DestinationMAC = pktIn.Data.HWDst - packet.SourceMAC = pktIn.Data.HWSrc + ethernetData := new(protocol.Ethernet) + if err := ethernetData.UnmarshalBinary(pktIn.Data.(*util.Buffer).Bytes()); err != nil { + return nil, err + } + packet.DestinationMAC = ethernetData.HWDst + packet.SourceMAC = ethernetData.HWSrc - if pktIn.Data.Ethertype == protocol.IPv4_MSG { - ipPkt := pktIn.Data.Data.(*protocol.IPv4) + if ethernetData.Ethertype == protocol.IPv4_MSG { + ipPkt := ethernetData.Data.(*protocol.IPv4) packet.DestinationIP = ipPkt.NWDst packet.SourceIP = ipPkt.NWSrc packet.TTL = ipPkt.TTL packet.IPProto = ipPkt.Protocol packet.IPFlags = ipPkt.Flags packet.IPLength = ipPkt.Length - } else if pktIn.Data.Ethertype == protocol.IPv6_MSG { - ipPkt := pktIn.Data.Data.(*protocol.IPv6) + } else if ethernetData.Ethertype == protocol.IPv6_MSG { + ipPkt := ethernetData.Data.(*protocol.IPv6) packet.DestinationIP = ipPkt.NWDst packet.SourceIP = ipPkt.NWSrc packet.TTL = ipPkt.HopLimit @@ -111,11 +122,11 @@ func ParsePacketIn(pktIn *ofctrl.PacketIn) (*Packet, error) { var err error if packet.IPProto == protocol.Type_TCP { - packet.SourcePort, packet.DestinationPort, _, _, packet.TCPFlags, err = GetTCPHeaderData(pktIn.Data.Data) + packet.SourcePort, packet.DestinationPort, _, _, packet.TCPFlags, err = GetTCPHeaderData(ethernetData.Data) } else if packet.IPProto == protocol.Type_UDP { - packet.SourcePort, packet.DestinationPort, err = GetUDPHeaderData(pktIn.Data.Data) + packet.SourcePort, packet.DestinationPort, err = GetUDPHeaderData(ethernetData.Data) } else if packet.IPProto == protocol.Type_ICMP || packet.IPProto == protocol.Type_IPv6ICMP { - _, _, packet.ICMPEchoID, packet.ICMPEchoSeq, err = getICMPHeaderData(pktIn.Data.Data) + _, _, packet.ICMPEchoID, packet.ICMPEchoSeq, err = getICMPHeaderData(ethernetData.Data) } if err != nil { return nil, err diff --git a/pkg/ovs/openflow/ofctrl_packetin_test.go b/pkg/ovs/openflow/ofctrl_packetin_test.go index b4d82de2195..536f0fb8174 100644 --- a/pkg/ovs/openflow/ofctrl_packetin_test.go +++ b/pkg/ovs/openflow/ofctrl_packetin_test.go @@ -168,6 +168,19 @@ func TestParsePacketIn(t *testing.T) { testBytes, _ := testTCP.MarshalBinary() testBuffer := new(util.Buffer) testBuffer.UnmarshalBinary(testBytes) + ethPkt := protocol.NewEthernet() + ethPkt.HWDst = testMac1 + ethPkt.HWSrc = testMac2 + ethPkt.Ethertype = protocol.IPv6_MSG + ethPkt.Data = util.Message(&protocol.IPv6{ + Length: 1, + NextHeader: protocol.Type_TCP, + HopLimit: 0, + NWSrc: testIP1, + NWDst: testIP2, + Data: testBuffer, + }) + pktBytes, _ := ethPkt.MarshalBinary() tests := []struct { name string pktIn *ofctrl.PacketIn @@ -178,19 +191,7 @@ func TestParsePacketIn(t *testing.T) { "ParsePacketIn-ipv6", &ofctrl.PacketIn{ Reason: 1, - Data: protocol.Ethernet{ - Ethertype: protocol.IPv6_MSG, - HWDst: testMac1, - HWSrc: testMac2, - Data: util.Message(&protocol.IPv6{ - Length: 1, - NextHeader: protocol.Type_TCP, - HopLimit: 0, - NWSrc: testIP1, - NWDst: testIP2, - Data: testBuffer, - }), - }, + Data: util.NewBuffer(pktBytes), }, &Packet{ IsIPv6: true, diff --git a/pkg/ovs/openflow/ofctrl_packetout.go b/pkg/ovs/openflow/ofctrl_packetout.go index 7ad37c20c78..2aa9c9963af 100644 --- a/pkg/ovs/openflow/ofctrl_packetout.go +++ b/pkg/ovs/openflow/ofctrl_packetout.go @@ -19,6 +19,7 @@ import ( "math/rand" "net" + "antrea.io/libOpenflow/openflow15" "antrea.io/libOpenflow/protocol" "antrea.io/libOpenflow/util" "antrea.io/ofnet/ofctrl" @@ -112,7 +113,7 @@ func (b *ofPacketOutBuilder) SetIPProtocol(proto Protocol) PacketOutBuilder { return b } -// ofPacketOutBuilder sets IP protocol in the packet's IP header with the +// SetIPProtocolValue sets IP protocol in the packet's IP header with the // intetger protocol value. func (b *ofPacketOutBuilder) SetIPProtocolValue(isIPv6 bool, protoValue uint8) PacketOutBuilder { if isIPv6 { @@ -153,7 +154,7 @@ func (b *ofPacketOutBuilder) SetIPFlags(flags uint16) PacketOutBuilder { return b } -// SetIPFlags sets flags in the packet's IP header. IPv4 only. +// SetIPHeaderID sets identifier field in the packet's IP header. IPv4 only. func (b *ofPacketOutBuilder) SetIPHeaderID(id uint16) PacketOutBuilder { if b.pktOut.IPv6Header == nil { if b.pktOut.IPHeader == nil { @@ -242,7 +243,7 @@ func (b *ofPacketOutBuilder) SetICMPCode(icmpCode uint8) PacketOutBuilder { return b } -// SetICMs sets the identifier in the packet's ICMP header. +// SetICMPID sets the identifier in the packet's ICMP header. func (b *ofPacketOutBuilder) SetICMPID(id uint16) PacketOutBuilder { if b.pktOut.ICMPHeader == nil { b.pktOut.ICMPHeader = new(protocol.ICMP) @@ -283,7 +284,7 @@ func (b *ofPacketOutBuilder) SetInport(inPort uint32) PacketOutBuilder { } // SetOutport sets the output port of the packetOut message. If the message is expected to go through OVS pipeline -// from table0, use openflow13.P_TABLE, which is also the default value. +// from table0, use openflow15.P_TABLE, which is also the default value. func (b *ofPacketOutBuilder) SetOutport(outport uint32) PacketOutBuilder { b.pktOut.OutPort = outport return b @@ -296,16 +297,28 @@ func (b *ofPacketOutBuilder) SetL4Packet(packet util.Message) PacketOutBuilder { return b } -// 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 { - act, _ := ofctrl.NewNXLoadAction(name, data, rng.ToNXRange()) +// AddSetIPToSAction sets the IP_TOS field in the packet-out message. The action clears the two ECN bits as 0, +// and only 2-7 bits of the DSCP field in IP header is set. +func (b *ofPacketOutBuilder) AddSetIPToSAction(data uint8) PacketOutBuilder { + field, _ := openflow15.FindFieldHeaderByName(NxmFieldIPToS, true) + field.Value = &openflow15.IpDscpField{Dscp: data << IPDSCPToSRange.Offset()} + field.Mask = &openflow15.IpDscpField{Dscp: uint8(0xff) >> (8 - IPDSCPToSRange.Length()) << IPDSCPToSRange.Offset()} + act := ofctrl.NewSetFieldAction(field) 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) + valueData := mark.value + mask := uint32(0) + if mark.field.rng != nil { + mask = ^mask >> (32 - mark.field.rng.Length()) << mark.field.rng.Offset() + valueData = valueData << mark.field.rng.Offset() + } + tgtField := openflow15.NewRegMatchFieldWithMask(mark.field.regID, valueData, mask) + act := ofctrl.NewSetFieldAction(tgtField) + b.pktOut.Actions = append(b.pktOut.Actions, act) + return b } func (b *ofPacketOutBuilder) AddResubmitAction(inPort *uint16, table *uint8) PacketOutBuilder { @@ -319,6 +332,9 @@ func (b *ofPacketOutBuilder) Done() *ofctrl.PacketOut { klog.Errorf("Invalid PacketOutBuilder: IP header and IPv6 header are not allowed to exist at the same time") return nil } + if b.pktOut.InPort == 0 { + b.pktOut.InPort = openflow15.P_CONTROLLER + } if b.pktOut.IPv6Header == nil { if b.pktOut.ICMPHeader != nil { if len(b.pktOut.ICMPHeader.Data) == 0 { diff --git a/pkg/ovs/openflow/ofctrl_packetout_test.go b/pkg/ovs/openflow/ofctrl_packetout_test.go index 64001df1008..1e2653a0f8b 100644 --- a/pkg/ovs/openflow/ofctrl_packetout_test.go +++ b/pkg/ovs/openflow/ofctrl_packetout_test.go @@ -19,6 +19,7 @@ import ( "reflect" "testing" + "antrea.io/libOpenflow/openflow15" "antrea.io/libOpenflow/protocol" "antrea.io/ofnet/ofctrl" ) @@ -782,6 +783,9 @@ func Test_ofPacketOutBuilder_Done(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + if tt.want != nil && tt.want.InPort == 0 { + tt.want.InPort = openflow15.P_CONTROLLER + } b := &ofPacketOutBuilder{ pktOut: tt.fields.pktOut, icmpID: tt.fields.icmpID, @@ -805,7 +809,7 @@ func Test_ofPacketOutBuilder_Done(t *testing.T) { t.Errorf("Done() = %v, want %v", got.ICMPHeader, tt.want.ICMPHeader) } if !reflect.DeepEqual(got.TCPHeader, tt.want.TCPHeader) { - t.Errorf("Done() = %v, want %v", got.TCPHeader, tt.want.TCPHeader) + t.Errorf("Done() = %+v, want %+v", got.TCPHeader, tt.want.TCPHeader) } if !reflect.DeepEqual(got.UDPHeader, tt.want.UDPHeader) { t.Errorf("Done() = %v, want %v", got.UDPHeader, tt.want.UDPHeader) @@ -817,7 +821,7 @@ func Test_ofPacketOutBuilder_Done(t *testing.T) { t.Errorf("Done() = %v, want %v", got.IPv6Header, tt.want.IPv6Header) } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("Done() = %v, want %v", got, tt.want) + t.Errorf("Done() = %+v, want %+v", got, tt.want) } }) } diff --git a/pkg/ovs/openflow/testing/mock_openflow.go b/pkg/ovs/openflow/testing/mock_openflow.go index 45a1e3f474c..6f1b6ef6ed7 100644 --- a/pkg/ovs/openflow/testing/mock_openflow.go +++ b/pkg/ovs/openflow/testing/mock_openflow.go @@ -917,6 +917,20 @@ func (mr *MockActionMockRecorder) Move(arg0, arg1 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Move", reflect.TypeOf((*MockAction)(nil).Move), arg0, arg1) } +// MoveFromTunMetadata mocks base method +func (m *MockAction) MoveFromTunMetadata(arg0 int, arg1 string, arg2, arg3 openflow.Range, arg4 byte) openflow.FlowBuilder { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "MoveFromTunMetadata", arg0, arg1, arg2, arg3, arg4) + ret0, _ := ret[0].(openflow.FlowBuilder) + return ret0 +} + +// MoveFromTunMetadata indicates an expected call of MoveFromTunMetadata +func (mr *MockActionMockRecorder) MoveFromTunMetadata(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MoveFromTunMetadata", reflect.TypeOf((*MockAction)(nil).MoveFromTunMetadata), arg0, arg1, arg2, arg3, arg4) +} + // MoveRange mocks base method func (m *MockAction) MoveRange(arg0, arg1 string, arg2, arg3 openflow.Range) openflow.FlowBuilder { m.ctrl.T.Helper() diff --git a/pkg/ovs/ovsconfig/ovs_client.go b/pkg/ovs/ovsconfig/ovs_client.go index 67f784f3d2c..ca57845623b 100644 --- a/pkg/ovs/ovsconfig/ovs_client.go +++ b/pkg/ovs/ovsconfig/ovs_client.go @@ -54,8 +54,8 @@ const ( openvSwitchSchema = "Open_vSwitch" // Openflow protocol version 1.0. openflowProtoVersion10 = "OpenFlow10" - // Openflow protocol version 1.3. - openflowProtoVersion13 = "OpenFlow13" + // Openflow protocol version 1.5. + openflowProtoVersion15 = "OpenFlow15" // Maximum allowed value of ofPortRequest. ofPortRequestMax = 65279 hardwareOffload = "hw-offload" @@ -156,7 +156,7 @@ func (br *OVSBridge) updateBridgeConfiguration() Error { Where: [][]interface{}{{"name", "==", br.name}}, Row: map[string]interface{}{ "protocols": makeOVSDBSetFromList([]string{openflowProtoVersion10, - openflowProtoVersion13}), + openflowProtoVersion15}), "datapath_type": br.datapathType, }, }) @@ -174,7 +174,7 @@ func (br *OVSBridge) create() Error { Name: br.name, // Use Openflow protocol version 1.0 and 1.3. Protocols: makeOVSDBSetFromList([]string{openflowProtoVersion10, - openflowProtoVersion13}), + openflowProtoVersion15}), DatapathType: string(br.datapathType), } namedUUID := tx.Insert(dbtransaction.Insert{ diff --git a/pkg/ovs/ovsctl/ofctl.go b/pkg/ovs/ovsctl/ofctl.go index abe50a53211..7f7fb6a79e0 100644 --- a/pkg/ovs/ovsctl/ofctl.go +++ b/pkg/ovs/ovsctl/ofctl.go @@ -84,7 +84,7 @@ func (c *ovsCtlClient) DumpGroup(groupID uint32) (string, error) { // versions of OpenFlow always dump all groups. But when OpenFlow // version is not specified, ovs-ofctl defaults to use OpenFlow10 but // with the Nicira extensions enabled, which can support dumping a - // single group too. So here, we do not specify Openflow13 to run the + // single group too. So here, we do not specify Openflow15 to run the // command. groupDump, err := c.runOfctlCmd(false, "dump-groups", strconv.FormatUint(uint64(groupID), 10)) if err != nil { @@ -163,11 +163,11 @@ func (c *ovsCtlClient) SetPortNoFlood(ofport int) error { return nil } -func (c *ovsCtlClient) runOfctlCmd(openflow13 bool, cmd string, args ...string) ([]byte, error) { +func (c *ovsCtlClient) runOfctlCmd(openflow15 bool, cmd string, args ...string) ([]byte, error) { cmdStr := fmt.Sprintf("ovs-ofctl %s %s", cmd, c.bridge) cmdStr = cmdStr + " " + strings.Join(args, " ") - if openflow13 { - cmdStr += " -O Openflow13" + if openflow15 { + cmdStr += " -O Openflow15" } out, err := getOVSCommand(cmdStr).Output() if err != nil { @@ -177,7 +177,7 @@ func (c *ovsCtlClient) runOfctlCmd(openflow13 bool, cmd string, args ...string) } func (c *ovsCtlClient) RunOfctlCmd(cmd string, args ...string) ([]byte, error) { - // Default to use Openflow13. + // Default to use Openflow15. return c.runOfctlCmd(true, cmd, args...) } diff --git a/plugins/octant/go.sum b/plugins/octant/go.sum index 7bda8ba247f..40984f5aa14 100644 --- a/plugins/octant/go.sum +++ b/plugins/octant/go.sum @@ -1,4 +1,5 @@ antrea.io/libOpenflow v0.6.2/go.mod h1:CzEJZxDNAupiGxeL5VOw92PsxfyvehEAvE3PiC6gr8o= +antrea.io/libOpenflow v0.8.0/go.mod h1:CzEJZxDNAupiGxeL5VOw92PsxfyvehEAvE3PiC6gr8o= antrea.io/ofnet v0.5.7/go.mod h1:8TJVF6MLe9/gZ/KbhGUvULs9/TxssepEaYEe+o1SEgs= bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= diff --git a/test/e2e/proxy_test.go b/test/e2e/proxy_test.go index db9ac888078..fba471b11db 100644 --- a/test/e2e/proxy_test.go +++ b/test/e2e/proxy_test.go @@ -941,9 +941,10 @@ func testProxyEndpointLifeCycle(ipFamily *corev1.IPFamily, data *TestData, t *te var groupKeywords []string if *ipFamily == corev1.IPv6Protocol { - groupKeywords = append(groupKeywords, fmt.Sprintf("set_field:0x%s->xxreg3", strings.TrimPrefix(hex.EncodeToString(*nginxIPs.ipv6), "0"))) + groupKeywords = append(groupKeywords, + fmt.Sprintf("load:0x%s->NXM_NX_XXREG3[0..63],load:0x%s->NXM_NX_XXREG3[64..127]", strings.TrimLeft(hex.EncodeToString((*nginxIPs.ipv6)[8:16]), "0"), strings.TrimLeft(hex.EncodeToString((*nginxIPs.ipv6)[:8]), "0"))) } else { - groupKeywords = append(groupKeywords, fmt.Sprintf("0x%s->NXM_NX_REG3[]", strings.TrimPrefix(hex.EncodeToString(nginxIPs.ipv4.To4()), "0"))) + groupKeywords = append(groupKeywords, fmt.Sprintf("0x%s->NXM_NX_REG3[]", strings.TrimLeft(hex.EncodeToString(nginxIPs.ipv4.To4()), "0"))) } for tableName, keyword := range keywords { @@ -1063,7 +1064,10 @@ func testProxyServiceLifeCycle(ipFamily *corev1.IPFamily, ingressIPs []string, d var groupKeyword string if *ipFamily == corev1.IPv6Protocol { - groupKeyword = fmt.Sprintf("set_field:0x%s->xxreg3,load:0x%x->NXM_NX_REG4[0..15]", strings.TrimLeft(hex.EncodeToString(nginxIPs.ipv6.To16()), "0"), 80) + groupKeyword = fmt.Sprintf("load:0x%s->NXM_NX_XXREG3[0..63],load:0x%s->NXM_NX_XXREG3[64..127],load:0x%x->NXM_NX_REG4[0..15]", + strings.TrimLeft(hex.EncodeToString(nginxIPs.ipv6.To16()[8:16]), "0"), + strings.TrimLeft(hex.EncodeToString(nginxIPs.ipv6.To16()[:8]), "0"), + 80) } else { groupKeyword = fmt.Sprintf("load:0x%s->NXM_NX_REG3[],load:0x%x->NXM_NX_REG4[0..15]", strings.TrimLeft(hex.EncodeToString(nginxIPs.ipv4.To4()), "0"), 80) } diff --git a/test/integration/agent/openflow_test.go b/test/integration/agent/openflow_test.go index b3fdc916206..12cbd83be34 100644 --- a/test/integration/agent/openflow_test.go +++ b/test/integration/agent/openflow_test.go @@ -733,11 +733,11 @@ func expectedProxyServiceGroupAndFlows(gid uint32, svc svcConfig, endpointList [ svcFlows := expectTableFlows{tableName: "ServiceLB", flows: []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,%s,reg4=0x10000/0x70000,nw_dst=%s,tp_dst=%d", string(svc.protocol), svc.ip.String(), svc.port), - ActStr: fmt.Sprintf("load:0x%x->NXM_NX_REG4[16..18],load:0x1->NXM_NX_REG0[9],load:0x%x->NXM_NX_REG7[],group:%d", serviceLearnReg, gid, gid), + ActStr: fmt.Sprintf("set_field:0x%x/0x70000->reg4,set_field:0x200/0x200->reg0,set_field:0x%x->reg7,group:%d", serviceLearnReg<<16, gid, gid), }, { MatchStr: fmt.Sprintf("priority=190,%s,reg4=0x30000/0x70000,nw_dst=%s,tp_dst=%d", string(svc.protocol), svc.ip.String(), svc.port), - ActStr: fmt.Sprintf("learn(table=SessionAffinity,hard_timeout=%d,priority=200,delete_learned,cookie=0x%x,eth_type=0x800,nw_proto=%d,%s,NXM_OF_IP_DST[],NXM_OF_IP_SRC[],load:NXM_NX_REG3[]->NXM_NX_REG3[],load:NXM_NX_REG4[0..15]->NXM_NX_REG4[0..15],load:0x2->NXM_NX_REG4[16..18],load:0x1->NXM_NX_REG0[9]),load:0x2->NXM_NX_REG4[16..18],goto_table:EndpointDNAT", stickyAge, cookieAllocator.RequestWithObjectID(cookie.Service, gid).Raw(), nw_proto, learnProtoField), + ActStr: fmt.Sprintf("learn(table=SessionAffinity,hard_timeout=%d,priority=200,delete_learned,cookie=0x%x,eth_type=0x800,nw_proto=%d,%s,NXM_OF_IP_DST[],NXM_OF_IP_SRC[],load:NXM_NX_REG3[]->NXM_NX_REG3[],load:NXM_NX_REG4[0..15]->NXM_NX_REG4[0..15],load:0x2->NXM_NX_REG4[16..18],load:0x1->NXM_NX_REG0[9]),set_field:0x20000/0x70000->reg4,goto_table:EndpointDNAT", stickyAge, cookieAllocator.RequestWithObjectID(cookie.Service, gid).Raw(), nw_proto, learnProtoField), }, }} epDNATFlows := expectTableFlows{tableName: "EndpointDNAT", flows: []*ofTestUtils.ExpectFlow{}} @@ -746,19 +746,19 @@ func expectedProxyServiceGroupAndFlows(gid uint32, svc svcConfig, endpointList [ for _, ep := range endpointList { epIP := ipToHexString(net.ParseIP(ep.IP())) epPort, _ := ep.Port() - bucket := fmt.Sprintf("weight:100,actions=load:%s->NXM_NX_REG3[],load:0x%x->NXM_NX_REG4[0..15],resubmit(,%d)", epIP, epPort, ofClient.EndpointDNATTable.GetID()) + bucket := fmt.Sprintf("weight:100,actions=set_field:%s->reg3,set_field:0x%x/0xffff->reg4,resubmit(,%d)", epIP, epPort, ofClient.EndpointDNATTable.GetID()) groupBuckets = append(groupBuckets, bucket) unionVal := (0b010 << 16) + uint32(epPort) epDNATFlows.flows = append(epDNATFlows.flows, &ofTestUtils.ExpectFlow{ MatchStr: fmt.Sprintf("priority=200,%s,reg3=%s,reg4=0x%x/0x7ffff", string(svc.protocol), epIP, unionVal), - ActStr: fmt.Sprintf("ct(commit,table=EgressRule,zone=65520,nat(dst=%s:%d),exec(load:0x1->NXM_NX_CT_MARK[4],move:NXM_NX_REG0[0..3]->NXM_NX_CT_MARK[0..3])", ep.IP(), epPort), + ActStr: fmt.Sprintf("ct(commit,table=EgressRule,zone=65520,nat(dst=%s:%d),exec(set_field:0x10/0x10->ct_mark,move:NXM_NX_REG0[0..3]->NXM_NX_CT_MARK[0..3])", ep.IP(), epPort), }) if ep.GetIsLocal() { hairpinFlows.flows = append(hairpinFlows.flows, &ofTestUtils.ExpectFlow{ MatchStr: fmt.Sprintf("priority=190,ct_state=+new+trk,ip,nw_src=%s,nw_dst=%s", ep.IP(), ep.IP()), - ActStr: "ct(commit,table=SNAT,zone=65520,exec(load:0x1->NXM_NX_CT_MARK[5],load:0x1->NXM_NX_CT_MARK[6]))", + ActStr: "ct(commit,table=SNAT,zone=65520,exec(set_field:0x20/0x20->ct_mark,set_field:0x40/0x40->ct_mark))", }) } } @@ -861,9 +861,8 @@ func checkConjunctionFlows(t *testing.T, ruleTable string, priority int, ruleID nextTable = ofClient.EgressMetricTable.GetName() } - flow := &ofTestUtils.ExpectFlow{MatchStr: conjunctionActionMatch, ActStr: fmt.Sprintf("load:0x%x->NXM_NX_REG%d[],ct(commit,table=%s,zone=65520,exec(load:0x%x->NXM_NX_CT_LABEL[0..31])", ruleID, conjReg, nextTable, ruleID)} + flow := &ofTestUtils.ExpectFlow{MatchStr: conjunctionActionMatch, ActStr: fmt.Sprintf("set_field:0x%x->reg%d,ct(commit,table=%s,zone=65520,exec(set_field:0x%x/0xffffffff->ct_label)", ruleID, conjReg, nextTable, ruleID)} testFunc(t, ofTestUtils.OfctlFlowMatch(flowList, ruleTable, flow), "Failed to update conjunction action flow") - useIPv4 := false useIPv6 := false @@ -1027,7 +1026,7 @@ func preparePodFlows(podIPs []net.IP, podMAC net.HardwareAddr, podOFPort uint32, actionNotAntreaFlexibleIPAMString := "" matchRewriteMACMarkString := ",reg0=0x200/0x200" if isAntreaFlexibleIPAM { - actionNotAntreaFlexibleIPAMString = ",load:0x1->NXM_NX_REG4[20],load:0x1->NXM_NX_REG0[9]" + actionNotAntreaFlexibleIPAMString = ",set_field:0x100000/0x100000->reg4,set_field:0x200/0x200->reg0" matchRewriteMACMarkString = "" } flows := []expectTableFlows{ @@ -1036,7 +1035,7 @@ func preparePodFlows(podIPs []net.IP, podMAC net.HardwareAddr, podOFPort uint32, []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=190,in_port=%d", podOFPort), - ActStr: fmt.Sprintf("load:0x3->NXM_NX_REG0[0..3]%s,goto_table:SpoofGuard", actionNotAntreaFlexibleIPAMString), + ActStr: fmt.Sprintf("set_field:0x3/0xf->reg0%s,goto_table:SpoofGuard", actionNotAntreaFlexibleIPAMString), }, }, }, @@ -1045,7 +1044,7 @@ func preparePodFlows(podIPs []net.IP, podMAC net.HardwareAddr, podOFPort uint32, []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,dl_dst=%s", podMAC.String()), - ActStr: fmt.Sprintf("load:0x%x->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[8],goto_table:IngressSecurityClassifier", podOFPort), + ActStr: fmt.Sprintf("set_field:0x%x->reg1,set_field:0x100/0x100->reg0,goto_table:IngressSecurityClassifier", podOFPort), }, }, }, @@ -1070,7 +1069,7 @@ func preparePodFlows(podIPs []net.IP, podMAC net.HardwareAddr, podOFPort uint32, []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=210,ip,in_port=%d%s,dl_dst=%s", 3, matchVlanVIDString, podMAC.String()), - ActStr: fmt.Sprintf("load:0x1->NXM_NX_REG8[12..15],load:0x4->NXM_NX_REG0[0..3],load:%s->NXM_NX_REG8[0..11],goto_table:UnSNAT", vlanVIDString), + ActStr: fmt.Sprintf("set_field:0x1000/0xf000->reg8,set_field:0x4/0xf->reg0,set_field:%s/0xfff->reg8,goto_table:UnSNAT", vlanVIDString), }, }, }}...) @@ -1080,7 +1079,7 @@ func preparePodFlows(podIPs []net.IP, podMAC net.HardwareAddr, podOFPort uint32, []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=210,ip,in_port=LOCAL,vlan_tci=0x0000/0x1fff,dl_dst=%s", podMAC.String()), - ActStr: fmt.Sprintf("load:0x1->NXM_NX_REG8[12..15],load:0x5->NXM_NX_REG0[0..3],goto_table:UnSNAT"), + ActStr: fmt.Sprintf("set_field:0x1000/0xf000->reg8,set_field:0x5/0xf->reg0,goto_table:UnSNAT"), }, }, }}...) @@ -1129,7 +1128,7 @@ func preparePodFlows(podIPs []net.IP, podMAC net.HardwareAddr, podOFPort uint32, vlanType = 3 } if isAntreaFlexibleIPAM { - actionSetCtZoneField = fmt.Sprintf("load:0x%x->NXM_NX_REG8[12..15],load:%s->NXM_NX_REG8[0..11],", vlanType, vlanVIDString) + actionSetCtZoneField = fmt.Sprintf("set_field:0x%x/0xf000->reg8,set_field:%s/0xfff->reg8,", vlanType<<12, vlanVIDString) } flows = append(flows, expectTableFlows{ @@ -1163,7 +1162,7 @@ func prepareGatewayFlows(gwIPs []net.IP, gwMAC net.HardwareAddr, vMAC net.Hardwa []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,in_port=%d", agentconfig.HostGatewayOFPort), - ActStr: "load:0x2->NXM_NX_REG0[0..3],goto_table:SpoofGuard", + ActStr: "set_field:0x2/0xf->reg0,goto_table:SpoofGuard", }, }, }, @@ -1172,7 +1171,7 @@ func prepareGatewayFlows(gwIPs []net.IP, gwMAC net.HardwareAddr, vMAC net.Hardwa []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,dl_dst=%s", gwMAC.String()), - ActStr: fmt.Sprintf("load:0x%x->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[8],goto_table:IngressSecurityClassifier", agentconfig.HostGatewayOFPort), + ActStr: fmt.Sprintf("set_field:0x%x->reg1,set_field:0x100/0x100->reg0,goto_table:IngressSecurityClassifier", agentconfig.HostGatewayOFPort), }, }, }, @@ -1183,7 +1182,7 @@ func prepareGatewayFlows(gwIPs []net.IP, gwMAC net.HardwareAddr, vMAC net.Hardwa actionSetCtZoneField := "" vlanType := uint16(1) if connectUplinkToBridge { - actionSetCtZoneField = fmt.Sprintf("load:0x%x->NXM_NX_REG8[12..15],", vlanType) + actionSetCtZoneField = fmt.Sprintf("set_field:0x%x/0xf000->reg8,", vlanType<<12) } if gwIP.To4() != nil { ipProtoStr = "ip" @@ -1235,11 +1234,11 @@ func prepareGatewayFlows(gwIPs []net.IP, gwMAC net.HardwareAddr, vMAC net.Hardwa []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=210,ct_state=+rpl+trk,ct_mark=0x2/0xf,%s", ipProtoStr), - ActStr: fmt.Sprintf("set_field:%s->eth_dst,load:0x2->NXM_NX_REG0[4..7],goto_table:L3DecTTL", gwMAC.String()), + ActStr: fmt.Sprintf("set_field:%s->eth_dst,set_field:0x20/0xf0->reg0,goto_table:L3DecTTL", gwMAC.String()), }, { MatchStr: fmt.Sprintf("priority=210,%s,%s=%s", ipProtoStr, nwDstStr, gwIP.String()), - ActStr: fmt.Sprintf("set_field:%s->eth_dst,load:0x2->NXM_NX_REG0[4..7],goto_table:L3DecTTL", gwMAC.String()), + ActStr: fmt.Sprintf("set_field:%s->eth_dst,set_field:0x20/0xf0->reg0,goto_table:L3DecTTL", gwMAC.String()), }, }, }, @@ -1256,7 +1255,7 @@ func prepareTunnelFlows(tunnelPort uint32, vMAC net.HardwareAddr) []expectTableF []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,in_port=%d", tunnelPort), - ActStr: "load:0x1->NXM_NX_REG0[0..3],load:0x1->NXM_NX_REG0[9],goto_table:UnSNAT", + ActStr: "set_field:0x1/0xf->reg0,set_field:0x200/0x200->reg0,goto_table:UnSNAT", }, }, }, @@ -1265,7 +1264,7 @@ func prepareTunnelFlows(tunnelPort uint32, vMAC net.HardwareAddr) []expectTableF []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,dl_dst=%s", vMAC.String()), - ActStr: fmt.Sprintf("load:0x%x->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[8],goto_table:IngressSecurityClassifier", agentconfig.DefaultTunOFPort), + ActStr: fmt.Sprintf("set_field:0x%x->reg1,set_field:0x100/0x100->reg0,goto_table:IngressSecurityClassifier", agentconfig.DefaultTunOFPort), }, }, }, @@ -1283,7 +1282,7 @@ func prepareNodeFlows(peerSubnet net.IPNet, peerGwIP, peerNodeIP net.IP, vMAC, l []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,arp,arp_tpa=%s,arp_op=1", peerGwIP.String()), - ActStr: fmt.Sprintf("move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],set_field:%s->eth_src,load:0x2->NXM_OF_ARP_OP[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],set_field:%s->arp_sha,move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],set_field:%s->arp_spa,IN_PORT", vMAC.String(), vMAC.String(), peerGwIP.String()), + ActStr: fmt.Sprintf("move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],set_field:%s->eth_src,set_field:2->arp_op,move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],set_field:%s->arp_sha,move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],set_field:%s->arp_spa,IN_PORT", vMAC.String(), vMAC.String(), peerGwIP.String()), }, }, }) @@ -1296,7 +1295,7 @@ func prepareNodeFlows(peerSubnet net.IPNet, peerGwIP, peerNodeIP net.IP, vMAC, l []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,%s,%s=%s", ipProtoStr, nwDstFieldName, peerSubnet.String()), - ActStr: fmt.Sprintf("set_field:%s->eth_src,set_field:%s->eth_dst,set_field:%s->tun_dst,load:0x1->NXM_NX_REG0[4..7],goto_table:L3DecTTL", localGwMAC.String(), vMAC.String(), peerNodeIP.String()), + ActStr: fmt.Sprintf("set_field:%s->eth_src,set_field:%s->eth_dst,set_field:%s->tun_dst,set_field:0x10/0xf0->reg0,goto_table:L3DecTTL", localGwMAC.String(), vMAC.String(), peerNodeIP.String()), }, }, }) @@ -1306,7 +1305,7 @@ func prepareNodeFlows(peerSubnet net.IPNet, peerGwIP, peerNodeIP net.IP, vMAC, l []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,%s,reg4=0x100000/0x100000,reg8=0/0xfff,%s=%s", ipProtoStr, nwDstFieldName, peerSubnet.String()), - ActStr: fmt.Sprintf("set_field:%s->eth_dst,load:0x4->NXM_NX_REG0[4..7],goto_table:L3DecTTL", peerNodeMAC.String()), + ActStr: fmt.Sprintf("set_field:%s->eth_dst,set_field:0x40/0xf0->reg0,goto_table:L3DecTTL", peerNodeMAC.String()), }, }, }) @@ -1322,7 +1321,7 @@ func prepareServiceHelperFlows() []expectTableFlows { []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprint("priority=0"), - ActStr: fmt.Sprint("load:0x1->NXM_NX_REG4[16..18]"), + ActStr: fmt.Sprint("set_field:0x10000/0x70000->reg4"), }, }, }, @@ -1359,7 +1358,7 @@ func prepareDefaultFlows(config *testConfig) []expectTableFlows { } tableL3ForwardingFlows := expectTableFlows{ "L3Forwarding", - []*ofTestUtils.ExpectFlow{{MatchStr: "priority=0", ActStr: "load:0x2->NXM_NX_REG0[4..7],goto_table:L2ForwardingCalc"}}, + []*ofTestUtils.ExpectFlow{{MatchStr: "priority=0", ActStr: "set_field:0x20/0xf0->reg0,goto_table:L2ForwardingCalc"}}, } tableL3DecTTLFlows := expectTableFlows{ tableName: "L3DecTTL", @@ -1398,15 +1397,15 @@ func prepareDefaultFlows(config *testConfig) []expectTableFlows { tableSNATFlows.flows = append(tableSNATFlows.flows, &ofTestUtils.ExpectFlow{ MatchStr: "priority=200,ct_state=+new+trk,ct_mark=0x40/0x40,ip,reg0=0x2/0xf", - ActStr: fmt.Sprintf("ct(commit,table=L2ForwardingCalc,zone=65521,nat(src=%s),exec(load:0x1->NXM_NX_CT_MARK[4],load:0x1->NXM_NX_CT_MARK[6]))", agentconfig.VirtualServiceIPv4), + ActStr: fmt.Sprintf("ct(commit,table=L2ForwardingCalc,zone=65521,nat(src=%s),exec(set_field:0x10/0x10->ct_mark,set_field:0x40/0x40->ct_mark))", agentconfig.VirtualServiceIPv4), }, &ofTestUtils.ExpectFlow{ MatchStr: "priority=200,ct_state=+new+trk,ct_mark=0x40/0x40,ip,reg0=0x3/0xf", - ActStr: fmt.Sprintf("ct(commit,table=L2ForwardingCalc,zone=65521,nat(src=%s),exec(load:0x1->NXM_NX_CT_MARK[4],load:0x1->NXM_NX_CT_MARK[6]))", config.nodeConfig.GatewayConfig.IPv4), + ActStr: fmt.Sprintf("ct(commit,table=L2ForwardingCalc,zone=65521,nat(src=%s),exec(set_field:0x10/0x10->ct_mark,set_field:0x40/0x40->ct_mark))", config.nodeConfig.GatewayConfig.IPv4), }, &ofTestUtils.ExpectFlow{ MatchStr: "priority=190,ct_state=+new+trk,ct_mark=0x20/0x20,ip,reg0=0x2/0xf", - ActStr: fmt.Sprintf("ct(commit,table=L2ForwardingCalc,zone=65521,nat(src=%s),exec(load:0x1->NXM_NX_CT_MARK[4]))", config.nodeConfig.GatewayConfig.IPv4), + ActStr: fmt.Sprintf("ct(commit,table=L2ForwardingCalc,zone=65521,nat(src=%s),exec(set_field:0x10/0x10->ct_mark))", config.nodeConfig.GatewayConfig.IPv4), }, &ofTestUtils.ExpectFlow{ MatchStr: "priority=200,ct_state=-new-rpl+trk,ct_mark=0x20/0x20,ip", @@ -1418,8 +1417,8 @@ func prepareDefaultFlows(config *testConfig) []expectTableFlows { &ofTestUtils.ExpectFlow{MatchStr: fmt.Sprintf("priority=200,ip,reg0=0/0x200%s,nw_dst=%s", matchVLANString, podCIDR), ActStr: "goto_table:L2ForwardingCalc"}, ) tableSNATMarkFlows.flows = append(tableSNATMarkFlows.flows, - &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ip,reg0=0x22/0xff", ActStr: fmt.Sprintf("ct(commit,table=SNAT,zone=%s,exec(load:0x1->NXM_NX_CT_MARK[5],load:0x1->NXM_NX_CT_MARK[6]))", ctZone)}, - &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ip,reg0=0x12/0xff,reg4=0x200000/0x200000", ActStr: fmt.Sprintf("ct(commit,table=SNAT,zone=%s,exec(load:0x1->NXM_NX_CT_MARK[5]))", ctZone)}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ip,reg0=0x22/0xff", ActStr: fmt.Sprintf("ct(commit,table=SNAT,zone=%s,exec(set_field:0x20/0x20->ct_mark,set_field:0x40/0x40->ct_mark))", ctZone)}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ip,reg0=0x12/0xff,reg4=0x200000/0x200000", ActStr: fmt.Sprintf("ct(commit,table=SNAT,zone=%s,exec(set_field:0x20/0x20->ct_mark))", ctZone)}, ) tableL3DecTTLFlows.flows = append(tableL3DecTTLFlows.flows, &ofTestUtils.ExpectFlow{MatchStr: "priority=210,ip,reg0=0x2/0xf", ActStr: "goto_table:SNATMark"}, @@ -1443,15 +1442,15 @@ func prepareDefaultFlows(config *testConfig) []expectTableFlows { tableSNATFlows.flows = append(tableSNATFlows.flows, &ofTestUtils.ExpectFlow{ MatchStr: "priority=200,ct_state=+new+trk,ct_mark=0x40/0x40,ipv6,reg0=0x2/0xf", - ActStr: fmt.Sprintf("ct(commit,table=L2ForwardingCalc,zone=65511,nat(src=%s),exec(load:0x1->NXM_NX_CT_MARK[4],load:0x1->NXM_NX_CT_MARK[6]))", agentconfig.VirtualServiceIPv6), + ActStr: fmt.Sprintf("ct(commit,table=L2ForwardingCalc,zone=65511,nat(src=%s),exec(set_field:0x10/0x10->ct_mark,set_field:0x40/0x40->ct_mark))", agentconfig.VirtualServiceIPv6), }, &ofTestUtils.ExpectFlow{ MatchStr: "priority=200,ct_state=+new+trk,ct_mark=0x40/0x40,ipv6,reg0=0x3/0xf", - ActStr: fmt.Sprintf("ct(commit,table=L2ForwardingCalc,zone=65511,nat(src=%s),exec(load:0x1->NXM_NX_CT_MARK[4],load:0x1->NXM_NX_CT_MARK[6]))", config.nodeConfig.GatewayConfig.IPv6), + ActStr: fmt.Sprintf("ct(commit,table=L2ForwardingCalc,zone=65511,nat(src=%s),exec(set_field:0x10/0x10->ct_mark,set_field:0x40/0x40->ct_mark))", config.nodeConfig.GatewayConfig.IPv6), }, &ofTestUtils.ExpectFlow{ MatchStr: "priority=190,ct_state=+new+trk,ct_mark=0x20/0x20,ipv6,reg0=0x2/0xf", - ActStr: fmt.Sprintf("ct(commit,table=L2ForwardingCalc,zone=65511,nat(src=%s),exec(load:0x1->NXM_NX_CT_MARK[4]))", config.nodeConfig.GatewayConfig.IPv6), + ActStr: fmt.Sprintf("ct(commit,table=L2ForwardingCalc,zone=65511,nat(src=%s),exec(set_field:0x10/0x10->ct_mark))", config.nodeConfig.GatewayConfig.IPv6), }, &ofTestUtils.ExpectFlow{ MatchStr: "priority=200,ct_state=-new-rpl+trk,ct_mark=0x20/0x20,ipv6", @@ -1463,8 +1462,8 @@ func prepareDefaultFlows(config *testConfig) []expectTableFlows { &ofTestUtils.ExpectFlow{MatchStr: fmt.Sprintf("priority=200,ipv6,reg0=0/0x200,ipv6_dst=%s", podCIDR), ActStr: "goto_table:L2ForwardingCalc"}, ) tableSNATMarkFlows.flows = append(tableSNATMarkFlows.flows, - &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ipv6,reg0=0x22/0xff", ActStr: "ct(commit,table=SNAT,zone=65510,exec(load:0x1->NXM_NX_CT_MARK[5],load:0x1->NXM_NX_CT_MARK[6]))"}, - &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ipv6,reg0=0x12/0xff,reg4=0x200000/0x200000", ActStr: "ct(commit,table=SNAT,zone=65510,exec(load:0x1->NXM_NX_CT_MARK[5]))"}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ipv6,reg0=0x22/0xff", ActStr: "ct(commit,table=SNAT,zone=65510,exec(set_field:0x20/0x20->ct_mark,set_field:0x40/0x40->ct_mark))"}, + &ofTestUtils.ExpectFlow{MatchStr: "priority=200,ct_state=+new+trk,ipv6,reg0=0x12/0xff,reg4=0x200000/0x200000", ActStr: "ct(commit,table=SNAT,zone=65510,exec(set_field:0x20/0x20->ct_mark))"}, ) tableL3DecTTLFlows.flows = append(tableL3DecTTLFlows.flows, &ofTestUtils.ExpectFlow{MatchStr: "priority=210,ipv6,reg0=0x2/0xf", ActStr: "goto_table:SNATMark"}, @@ -1475,7 +1474,7 @@ func prepareDefaultFlows(config *testConfig) []expectTableFlows { tableARPResponderFlows.flows = append(tableARPResponderFlows.flows, &ofTestUtils.ExpectFlow{ MatchStr: fmt.Sprintf("priority=200,arp,arp_tpa=%s,arp_op=1", config.nodeConfig.GatewayConfig.IPv4.String()), - ActStr: fmt.Sprintf("move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],set_field:%s->eth_src,load:0x2->NXM_OF_ARP_OP[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],set_field:%s->arp_sha,move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],set_field:%s->arp_spa,IN_PORT", config.nodeConfig.GatewayConfig.MAC.String(), config.nodeConfig.GatewayConfig.MAC.String(), config.nodeConfig.GatewayConfig.IPv4.String()), + ActStr: fmt.Sprintf("move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],set_field:%s->eth_src,set_field:2->arp_op,move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],set_field:%s->arp_sha,move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],set_field:%s->arp_spa,IN_PORT", config.nodeConfig.GatewayConfig.MAC.String(), config.nodeConfig.GatewayConfig.MAC.String(), config.nodeConfig.GatewayConfig.IPv4.String()), }, ) } @@ -1593,7 +1592,7 @@ func expectedExternalFlows(ipProtoStr, gwMACStr string) []expectTableFlows { }, { MatchStr: "priority=0", - ActStr: "load:0x2->NXM_NX_REG0[4..7],goto_table:L2ForwardingCalc", + ActStr: "set_field:0x20/0xf0->reg0,goto_table:L2ForwardingCalc", }, }, }, @@ -1615,15 +1614,15 @@ func prepareEgressMarkFlows(snatIP net.IP, mark, podOFPort, podOFPortRemote uint []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,ct_state=+new+trk,%s,%s=%s", ipProtoStr, tunDstFieldName, snatIP), - ActStr: fmt.Sprintf("load:0x%x->NXM_NX_PKT_MARK[0..7],load:0x2->NXM_NX_REG0[4..7],goto_table:L2ForwardingCalc", mark), + ActStr: fmt.Sprintf("set_field:0x%x/0xff->pkt_mark,set_field:0x20/0xf0->reg0,goto_table:L2ForwardingCalc", mark), }, { MatchStr: fmt.Sprintf("priority=200,ct_state=+new+trk,%s,in_port=%d", ipProtoStr, podOFPort), - ActStr: fmt.Sprintf("load:0x%x->NXM_NX_PKT_MARK[0..7],load:0x2->NXM_NX_REG0[4..7],goto_table:L2ForwardingCalc", mark), + ActStr: fmt.Sprintf("set_field:0x%x/0xff->pkt_mark,set_field:0x20/0xf0->reg0,goto_table:L2ForwardingCalc", mark), }, { MatchStr: fmt.Sprintf("priority=200,%s,in_port=%d", ipProtoStr, podOFPortRemote), - ActStr: fmt.Sprintf("set_field:%s->eth_src,set_field:%s->eth_dst,set_field:%s->%s,load:0x1->NXM_NX_REG0[4..7],goto_table:L2ForwardingCalc", localGwMAC.String(), vMAC.String(), snatIP, tunDstFieldName), + ActStr: fmt.Sprintf("set_field:%s->eth_src,set_field:%s->eth_dst,set_field:%s->%s,set_field:0x10/0xf0->reg0,goto_table:L2ForwardingCalc", localGwMAC.String(), vMAC.String(), snatIP, tunDstFieldName), }, }, }, @@ -1637,7 +1636,7 @@ func prepareTrafficControlFlows(sourceOFPorts []uint32, targetOFPort, returnOFPo []*ofTestUtils.ExpectFlow{ { MatchStr: fmt.Sprintf("priority=200,in_port=%d", returnOFPort), - ActStr: "load:0x6->NXM_NX_REG0[0..3],goto_table:L3Forwarding", + ActStr: "set_field:0x6/0xf->reg0,goto_table:L3Forwarding", }, }, }, @@ -1668,11 +1667,11 @@ func prepareTrafficControlFlows(sourceOFPorts []uint32, targetOFPort, returnOFPo trafficControlTableFlows.flows = append(trafficControlTableFlows.flows, &ofTestUtils.ExpectFlow{ MatchStr: fmt.Sprintf("priority=200,reg1=0x%x", port), - ActStr: fmt.Sprintf("load:0x%x->NXM_NX_REG9[],load:0x2->NXM_NX_REG4[22..23],goto_table:IngressSecurityClassifier", targetOFPort), + ActStr: fmt.Sprintf("set_field:0x%x->reg9,set_field:0x800000/0xc00000->reg4,goto_table:IngressSecurityClassifier", targetOFPort), }, &ofTestUtils.ExpectFlow{ MatchStr: fmt.Sprintf("priority=200,in_port=%d", port), - ActStr: fmt.Sprintf("load:0x%x->NXM_NX_REG9[],load:0x2->NXM_NX_REG4[22..23],goto_table:IngressSecurityClassifier", targetOFPort), + ActStr: fmt.Sprintf("set_field:0x%x->reg9,set_field:0x800000/0xc00000->reg4,goto_table:IngressSecurityClassifier", targetOFPort), }, ) } diff --git a/test/integration/ovs/ofctrl_test.go b/test/integration/ovs/ofctrl_test.go index e70bcd976da..e840a42f7ce 100644 --- a/test/integration/ovs/ofctrl_test.go +++ b/test/integration/ovs/ofctrl_test.go @@ -17,7 +17,6 @@ package ovs import ( "fmt" "net" - "strconv" "strings" "sync" "sync/atomic" @@ -30,6 +29,7 @@ import ( "golang.org/x/time/rate" "k8s.io/apimachinery/pkg/util/wait" + "antrea.io/antrea/pkg/agent/openflow" binding "antrea.io/antrea/pkg/ovs/openflow" "antrea.io/antrea/pkg/ovs/ovsconfig" "antrea.io/antrea/pkg/ovs/ovsctl" @@ -324,11 +324,15 @@ func TestOFctrlGroup(t *testing.T) { assert.True(t, strings.Contains(dumpedGroup[i+1], fmt.Sprintf("weight:%d", bucket.weight))) } for _, loading := range bucket.reg2reg { - rngStr := "[]" + rngStr := "" + data := loading[1] if !(loading[2] == 0 && loading[3] == 31) { - rngStr = fmt.Sprintf("[%d..%d]", loading[2], loading[3]) + length := loading[3] - loading[2] + 1 + mask := ^uint32(0) >> (32 - length) << loading[2] + rngStr = fmt.Sprintf("/0x%x", mask) + data = data << loading[2] } - loadStr := fmt.Sprintf("load:0x%x->NXM_NX_REG%d%s", loading[1], loading[0], rngStr) + loadStr := fmt.Sprintf("set_field:0x%x%s->reg%d", data, rngStr, loading[0]) assert.Contains(t, dumpedGroup[i+1], loadStr) } if bucket.resubmitTable != 0 { @@ -575,8 +579,8 @@ func TestBundleWithGroupAndFlow(t *testing.T) { }, } - bucket0 := "weight:100,actions=load:0xa0a0002->NXM_NX_REG1[],load:0x35->NXM_NX_REG2[],load:0xfff1->NXM_NX_REG3[],resubmit(,3)" - bucket1 := "weight:100,actions=load:0xa0a0202->NXM_NX_REG1[],load:0x35->NXM_NX_REG2[],load:0xfff1->NXM_NX_REG3[],resubmit(,3)" + bucket0 := "weight:100,actions=set_field:0xa0a0002->reg1,set_field:0x35->reg2,set_field:0xfff1->reg3,resubmit(,3)" + bucket1 := "weight:100,actions=set_field:0xa0a0202->reg1,set_field:0x35->reg2,set_field:0xfff1->reg3,resubmit(,3)" expectedGroupBuckets := []string{bucket0, bucket1} err = bridge.AddOFEntriesInBundle([]binding.OFEntry{flow, group}, nil, nil) require.Nil(t, err) @@ -625,7 +629,7 @@ func TestPacketOutIn(t *testing.T) { pktIn := pktInQueue.GetRateLimited(make(chan struct{})) matchers := pktIn.GetMatches() - reg2Match := matchers.GetMatchByName("NXM_NX_REG2") + reg2Match := openflow.GetRegMatchInPacketIn(matchers, 2) assert.NotNil(t, reg2Match) reg2Value := reg2Match.GetValue() assert.NotNil(t, reg2Value) @@ -633,7 +637,7 @@ func TestPacketOutIn(t *testing.T) { assert.True(t, ok2) assert.Equal(t, reg2Data, ofctrl.GetUint32ValueWithRange(value2.Data, reg2Field.GetRange().ToNXRange())) - reg3Match := matchers.GetMatchByName("NXM_NX_REG3") + reg3Match := openflow.GetRegMatchInPacketIn(matchers, 3) assert.NotNil(t, reg3Match) reg3Value := reg3Match.GetValue() assert.NotNil(t, reg3Value) @@ -654,10 +658,11 @@ func TestPacketOutIn(t *testing.T) { pktBuilder := bridge.BuildPacketOut() regField := binding.NewRegField(0, 18, 18, "field") + mark := binding.NewRegMark(regField, 0x1) pkt := pktBuilder.SetSrcMAC(srcMAC).SetDstMAC(dstcMAC). SetDstIP(dstIP).SetSrcIP(srcIP).SetIPProtocol(binding.ProtocolTCP). SetTCPSrcPort(srcPort).SetTCPDstPort(dstPort). - AddLoadAction(regField.GetNXFieldName(), uint64(0x1), regField.GetRange()). + AddLoadRegMark(mark). Done() require.Nil(t, err) flow0 := table0.BuildFlow(100). @@ -736,7 +741,7 @@ func TestMoveTunMetadata(t *testing.T) { time.Sleep(1 * time.Second) flow1 := table.BuildFlow(100). MatchProtocol(binding.ProtocolIP).MatchTunMetadata(0, 0x1234). - Action().MoveRange("NXM_NX_TUN_METADATA0", "NXM_NX_REG0", binding.Range{28, 31}, binding.Range{28, 31}). + Action().MoveFromTunMetadata(0, "NXM_NX_REG0", binding.Range{28, 31}, binding.Range{28, 31}, 4). Action().NextTable(). Done() err = bridge.AddFlowsInBundle([]binding.Flow{flow1}, nil, nil) @@ -866,7 +871,6 @@ func prepareFlows(table binding.Table) ([]binding.Flow, []*ExpectFlow) { var flows []binding.Flow _, AllIPs, _ := net.ParseCIDR("0.0.0.0/0") _, conjSrcIPNet, _ := net.ParseCIDR("192.168.3.0/24") - 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") @@ -944,7 +948,7 @@ func prepareFlows(table binding.Table) ([]binding.Flow, []*ExpectFlow) { Cookie(getCookieID()). MatchCTMark(gatewayCTMark). MatchCTStateNew(false).MatchCTStateTrk(true). - Action().LoadRange(binding.NxmFieldDstMAC, gwMACData, &binding.Range{0, 47}). + Action().SetDstMAC(gwMAC). Action().NextTable(). Done(), table.BuildFlow(priorityNormal).MatchProtocol(binding.ProtocolIP). @@ -1033,23 +1037,23 @@ func prepareFlows(table binding.Table) ([]binding.Flow, []*ExpectFlow) { gotoTableAction := fmt.Sprintf("goto_table:%d", table.GetNext()) var flowStrs []*ExpectFlow flowStrs = append(flowStrs, - &ExpectFlow{"priority=190,in_port=3", fmt.Sprintf("load:0x2->NXM_NX_REG0[0..15],%s", gotoTableAction)}, + &ExpectFlow{"priority=190,in_port=3", fmt.Sprintf("set_field:0x2/0xffff->reg0,%s", gotoTableAction)}, &ExpectFlow{"priority=200,arp,in_port=3,arp_spa=192.168.1.3,arp_sha=aa:aa:aa:aa:aa:13", gotoTableAction}, &ExpectFlow{"priority=200,ip,in_port=3,dl_src=aa:aa:aa:aa:aa:13,nw_src=192.168.1.3", gotoTableAction}, - &ExpectFlow{"priority=200,arp,arp_tpa=192.168.2.1,arp_op=1", "move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],set_field:aa:bb:cc:dd:ee:ff->eth_src,load:0x2->NXM_OF_ARP_OP[],move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],set_field:aa:bb:cc:dd:ee:ff->arp_sha,move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],set_field:192.168.2.1->arp_spa,IN_PORT"}, + &ExpectFlow{"priority=200,arp,arp_tpa=192.168.2.1,arp_op=1", "move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],set_field:aa:bb:cc:dd:ee:ff->eth_src,set_field:2->arp_op,move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],set_field:aa:bb:cc:dd:ee:ff->arp_sha,move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],set_field:192.168.2.1->arp_spa,IN_PORT"}, &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]),goto_table:%d", table.GetID(), table.GetNext())}, &ExpectFlow{"priority=200,ip", fmt.Sprintf("ct(table=%d,zone=65520)", table.GetNext())}, &ExpectFlow{"priority=210,ct_state=-new+trk,ct_mark=0x2/0x2,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:0x1->NXM_NX_CT_MARK[1])", table.GetNext())}, - &ExpectFlow{"priority=200,ct_state=-new+trk,ct_mark=0x2/0x2,ip", fmt.Sprintf("load:0xaaaaaaaaaa11->NXM_OF_ETH_DST[],%s", gotoTableAction)}, + &ExpectFlow{"priority=200,ct_state=+new+trk,ip,reg0=0x1/0xffff", fmt.Sprintf("ct(commit,table=%d,zone=65520,exec(set_field:0x2/0x2->ct_mark)", table.GetNext())}, + &ExpectFlow{"priority=200,ct_state=-new+trk,ct_mark=0x2/0x2,ip", fmt.Sprintf("set_field:aa:aa:aa:aa:aa:11->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)}, &ExpectFlow{"priority=200,ip,nw_dst=192.168.2.0/24", fmt.Sprintf("dec_ttl,set_field:aa:aa:aa:aa:aa:11->eth_src,set_field:aa:bb:cc:dd:ee:ff->eth_dst,set_field:10.1.1.2->tun_dst,%s", gotoTableAction)}, &ExpectFlow{"priority=200,ipv6,ipv6_dst=fd74:ca9b:172:21::/64", fmt.Sprintf("dec_ttl,set_field:aa:aa:aa:aa:aa:11->eth_src,set_field:aa:bb:cc:dd:ee:ff->eth_dst,set_field:20:ca9b:172:35::3->tun_ipv6_dst,%s", gotoTableAction)}, &ExpectFlow{"priority=200,ip,nw_dst=192.168.1.1", fmt.Sprintf("set_field:aa:aa:aa:aa:aa:11->eth_dst,%s", gotoTableAction)}, - &ExpectFlow{"priority=200,dl_dst=aa:aa:aa:aa:aa:13", fmt.Sprintf("load:0x3->NXM_NX_REG1[],load:0x1->NXM_NX_REG0[16],%s", gotoTableAction)}, + &ExpectFlow{"priority=200,dl_dst=aa:aa:aa:aa:aa:13", fmt.Sprintf("set_field:0x3->reg1,set_field:0x10000/0x10000->reg0,%s", gotoTableAction)}, &ExpectFlow{"priority=200,ip,reg0=0x10000/0x10000", "output:NXM_NX_REG1[]"}, &ExpectFlow{"priority=200,ip,nw_dst=172.16.0.0/16", "output:1"}, &ExpectFlow{fmt.Sprintf("priority=200,ip,nw_src=192.168.1.3,nw_tos=%d", ipDSCP<<2), gotoTableAction}, @@ -1117,19 +1121,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[0..7]))", + fmt.Sprintf("ct(commit,table=%d,zone=65520,nat(src=%s),exec(set_field:0x40/0xff->ct_mark))", 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[0..7]))", + fmt.Sprintf("ct(commit,table=%d,zone=65520,nat(src=%s-%s),exec(set_field:0x40/0xff->ct_mark))", 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[0..7]))", + fmt.Sprintf("ct(commit,table=%d,zone=65520,nat(dst=%s),exec(set_field:0x40/0xff->ct_mark))", 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[0..7]))", + fmt.Sprintf("ct(commit,table=%d,zone=65520,nat(dst=%s-%s),exec(set_field:0x40/0xff->ct_mark))", table.GetNext(), natedIP1.String(), natedIP2.String()), }, } diff --git a/test/integration/ovs/openflow_test_utils.go b/test/integration/ovs/openflow_test_utils.go index bc48ab4e31d..a5d88c7b777 100644 --- a/test/integration/ovs/openflow_test_utils.go +++ b/test/integration/ovs/openflow_test_utils.go @@ -37,7 +37,7 @@ func PrepareOVSBridge(brName string) error { // using the netdev datapath type does not impact test coverage but // ensures that the integration tests can be run with Docker Desktop on // macOS. - cmdStr := fmt.Sprintf("ovs-vsctl --may-exist add-br %s -- set Bridge %s protocols='OpenFlow10,OpenFlow13' datapath_type=netdev", brName, brName) + cmdStr := fmt.Sprintf("ovs-vsctl --may-exist add-br %s -- set Bridge %s protocols='OpenFlow10,OpenFlow15' datapath_type=netdev", brName, brName) err := exec.Command("/bin/sh", "-c", cmdStr).Run() if err != nil { return err @@ -114,7 +114,12 @@ func CheckGroupExists(t *testing.T, ovsCtlClient ovsctl.OVSCtlClient, groupID bi found := false for _, groupElems := range groupList { groupEntry := fmt.Sprintf("%s,bucket=", groupElems[0]) - groupEntry = fmt.Sprintf("%s%s", groupEntry, strings.Join(groupElems[1:], ",bucket=")) + var groupElemStrs []string + for _, elem := range groupElems[1:] { + elemStr := strings.Join(strings.Split(elem, ",")[1:], ",") + groupElemStrs = append(groupElemStrs, elemStr) + } + groupEntry = fmt.Sprintf("%s%s", groupEntry, strings.Join(groupElemStrs, ",bucket=")) if strings.Contains(groupEntry, groupStr) { found = true break @@ -148,7 +153,7 @@ func formatFlowDump(rawFlows []string) []string { for _, flow := range rawFlows { felem := strings.Fields(flow) if len(felem) > 2 { - felem = append(felem[:1], felem[3:]...) + felem = append(felem[:1], felem[4:]...) fstr := strings.Join(felem, " ") flowList = append(flowList, fstr) }