Message ID | 20211122112256.2011194-17-amorenoz@redhat.com |
---|---|
State | Changes Requested |
Headers | show |
Series | python: add flow parsing library | expand |
Context | Check | Description |
---|---|---|
ovsrobot/apply-robot | success | apply and check: success |
ovsrobot/github-robot-_Build_and_Test | fail | github build: failed |
Other than ending comments with a dot and an extra newline, it looks fine. Acked-by: Eelco Chaudron <echaudro@redhat.com> On 22 Nov 2021, at 12:22, Adrian Moreno wrote: > Signed-off-by: Adrian Moreno <amorenoz@redhat.com> > --- > python/automake.mk | 3 +- > python/ovs/tests/test_ofp.py | 524 +++++++++++++++++++++++++++++++++++ > 2 files changed, 526 insertions(+), 1 deletion(-) > create mode 100644 python/ovs/tests/test_ofp.py > > diff --git a/python/automake.mk b/python/automake.mk > index 41973797c..713f1d1a4 100644 > --- a/python/automake.mk > +++ b/python/automake.mk > @@ -55,7 +55,8 @@ ovs_pyfiles = \ > > ovs_tests = \ > python/ovs/tests/test_kv.py \ > - python/ovs/tests/test_list.py > + python/ovs/tests/test_list.py \ > + python/ovs/tests/test_ofp.py > > > # These python files are used at build time but not runtime, > diff --git a/python/ovs/tests/test_ofp.py b/python/ovs/tests/test_ofp.py > new file mode 100644 > index 000000000..975be17d1 > --- /dev/null > +++ b/python/ovs/tests/test_ofp.py > @@ -0,0 +1,524 @@ > +import netaddr > +import pytest > + > +from ovs.flows.ofp import OFPFlowFactory > +from ovs.flows.kv import KeyValue > +from ovs.flows.decoders import EthMask, IPMask, decode_mask > + > + > +@pytest.mark.parametrize( > + "input_string,expected", > + [ > + ( > + "actions=local,3,4,5,output:foo", > + [ > + KeyValue("output", {"port": "local"}), > + KeyValue("output", {"port": 3}), > + KeyValue("output", {"port": 4}), > + KeyValue("output", {"port": 5}), > + KeyValue("output", {"port": "foo"}), > + ], > + ), > + ( > + "actions=controller,controller:200", > + [ > + KeyValue("output", "controller"), > + KeyValue("controller", {"max_len": 200}), > + ], > + ), > + ( > + "actions=enqueue(foo,42),enqueue:foo:42,enqueue(bar,4242)", > + [ > + KeyValue("enqueue", {"port": "foo", "queue": 42}), > + KeyValue("enqueue", {"port": "foo", "queue": 42}), > + KeyValue("enqueue", {"port": "bar", "queue": 4242}), > + ], > + ), > + ( > + "actions=bundle(eth_src,0,hrw,ofport,members:4,8)", > + [ > + KeyValue( > + "bundle", > + { > + "fields": "eth_src", > + "basis": 0, > + "algorithm": "hrw", > + "members": [4, 8], > + }, > + ), > + ], > + ), > + ( > + "actions=bundle_load(eth_src,0,hrw,ofport,reg0,members:4,8)", > + [ > + KeyValue( > + "bundle_load", > + { > + "fields": "eth_src", > + "basis": 0, > + "algorithm": "hrw", > + "dst": "reg0", > + "members": [4, 8], > + }, > + ), > + ], > + ), > + ( > + "actions=group:3", > + [KeyValue("group", 3)], > + ), > + ( > + "actions=strip_vlan", > + [KeyValue("strip_vlan", True)], > + ), > + ( > + "actions=pop_vlan", > + [KeyValue("pop_vlan", True)], > + ), > + ( > + "actions=push_vlan:0x8100", > + [KeyValue("push_vlan", 0x8100)], > + ), > + ( > + "actions=push_mpls:0x8848", > + [KeyValue("push_mpls", 0x8848)], > + ), > + ( > + "actions=pop_mpls:0x8848", > + [KeyValue("pop_mpls", 0x8848)], > + ), > + ( > + "actions=pop_mpls:0x8848", > + [KeyValue("pop_mpls", 0x8848)], > + ), > + ( > + "actions=encap(nsh(md_type=2,tlv(0x1000,10,0x12345678)))", > + [ > + KeyValue( > + "encap", > + { > + "nsh": { > + "md_type": 2, > + "tlv": { > + "class": 0x1000, > + "type": 10, > + "value": 0x12345678, > + }, > + } > + }, > + ) > + ], > + ), > + ( > + "actions=encap(0x0800)", > + [ > + KeyValue( > + "encap", > + {"ethernet": 0x800}, > + ) > + ], > + ), > + ( > + "actions=load:0x001122334455->eth_src", > + [ > + KeyValue( > + "load", > + {"value": 0x001122334455, "dst": {"field": "eth_src"}}, > + ) > + ], > + ), > + ( > + "actions=load:1->eth_src[1]", > + [ > + KeyValue( > + "load", > + { > + "value": 1, > + "dst": {"field": "eth_src", "start": 1, "end": 1}, > + }, > + ) > + ], > + ), > + ( > + "actions=learn(load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[])", > + [ > + KeyValue( > + "learn", > + [ > + { > + "load": { > + "src": {"field": "NXM_NX_TUN_ID"}, > + "dst": {"field": "NXM_NX_TUN_ID"}, > + } > + } > + ], > + ), > + ], > + ), > + ( > + "actions=set_field:00:11:22:33:44:55->eth_src", > + [ > + KeyValue( > + "set_field", > + { > + "value": {"eth_src": EthMask("00:11:22:33:44:55")}, > + "dst": {"field": "eth_src"}, > + }, > + ) > + ], > + ), > + ( > + "actions=set_field:01:00:00:00:00:00/01:00:00:00:00:00->eth_src", > + [ > + KeyValue( > + "set_field", > + { > + "value": { > + "eth_src": EthMask( > + "01:00:00:00:00:00/01:00:00:00:00:00" > + ) > + }, > + "dst": {"field": "eth_src"}, > + }, > + ) > + ], > + ), > + ( > + "actions=set_field:0x10ff->vlan_vid", > + [ > + KeyValue( > + "set_field", > + { > + "value": {"vlan_vid": decode_mask(13)("0x10ff")}, > + "dst": {"field": "vlan_vid"}, > + }, > + ) > + ], > + ), > + ( > + "actions=move:reg0[0..5]->reg1[16..31]", > + [ > + KeyValue( > + "move", > + { > + "src": {"field": "reg0", "start": 0, "end": 5}, > + "dst": {"field": "reg1", "start": 16, "end": 31}, > + }, > + ) > + ], > + ), > + ( > + "actions=mod_dl_dst:00:11:22:33:44:55", > + [KeyValue("mod_dl_dst", EthMask("00:11:22:33:44:55"))], > + ), > + ( > + "actions=mod_nw_dst:192.168.1.1", > + [KeyValue("mod_nw_dst", IPMask("192.168.1.1"))], > + ), > + ( > + "actions=mod_nw_dst:fe80::ec17:7bff:fe61:7aac", > + [KeyValue("mod_nw_dst", IPMask("fe80::ec17:7bff:fe61:7aac"))], > + ), > + ( > + "actions=dec_ttl,dec_ttl(1,2,3)", > + [KeyValue("dec_ttl", True), KeyValue("dec_ttl", [1, 2, 3])], > + ), > + ( > + "actions=set_mpls_label:0x100,set_mpls_tc:2,set_mpls_ttl:10", > + [ > + KeyValue("set_mpls_label", 0x100), > + KeyValue("set_mpls_tc", 2), > + KeyValue("set_mpls_ttl", 10), > + ], > + ), > + ( > + "actions=check_pkt_larger(100)->reg0[10]", > + [ > + KeyValue( > + "check_pkt_larger", > + { > + "pkt_len": 100, > + "dst": {"field": "reg0", "start": 10, "end": 10}, > + }, > + ), > + ], > + ), > + ( > + "actions=pop_queue,set_tunnel:0x10,set_tunnel64:0x65000,set_queue=3", # noqa: E501 > + [ > + KeyValue("pop_queue", True), > + KeyValue("set_tunnel", 0x10), > + KeyValue("set_tunnel64", 0x65000), > + KeyValue("set_queue", 3), > + ], > + ), > + ( > + "actions=ct(zone=10,table=2,nat(snat=192.168.0.0-192.168.0.200:1000-2000,random))", # noqa: E501 > + [ > + KeyValue( > + "ct", > + { > + "zone": 10, > + "table": 2, > + "nat": { > + "type": "snat", > + "addrs": { > + "start": netaddr.IPAddress("192.168.0.0"), > + "end": netaddr.IPAddress("192.168.0.200"), > + }, > + "ports": { > + "start": 1000, > + "end": 2000, > + }, > + "random": True, > + }, > + }, > + ) > + ], > + ), > + ( > + "actions=ct(commit,zone=NXM_NX_REG13[0..15],table=2,exec(load:0->NXM_NX_CT_LABEL[0]))", # noqa: E501 > + [ > + KeyValue( > + "ct", > + { > + "commit": True, > + "zone": { > + "field": "NXM_NX_REG13", > + "start": 0, > + "end": 15, > + }, > + "table": 2, > + "exec": [ > + { > + "load": { > + "value": 0, > + "dst": { > + "field": "NXM_NX_CT_LABEL", > + "start": 0, > + "end": 0, > + }, > + }, > + }, > + ], > + }, > + ) > + ], > + ), > + ( > + "actions=load:0x1->NXM_NX_REG10[7],learn(table=69,delete_learned,cookie=0xda6f52b0,OXM_OF_METADATA[],eth_type=0x800,NXM_OF_IP_SRC[],ip_dst=172.30.204.105,nw_proto=6,NXM_OF_TCP_SRC[]=NXM_OF_TCP_DST[],load:0x1->NXM_NX_REG10[7])", # noqa: E501 > + [ > + KeyValue( > + "load", > + { > + "value": 1, > + "dst": {"field": "NXM_NX_REG10", "start": 7, "end": 7}, > + }, > + ), > + KeyValue( > + "learn", > + [ > + {"table": 69}, > + {"delete_learned": True}, > + {"cookie": 3664728752}, > + {"OXM_OF_METADATA[]": True}, > + {"eth_type": 2048}, > + {"NXM_OF_IP_SRC[]": True}, > + {"ip_dst": IPMask("172.30.204.105/32")}, > + {"nw_proto": 6}, > + {"NXM_OF_TCP_SRC[]": "NXM_OF_TCP_DST[]"}, > + { > + "load": { > + "value": 1, > + "dst": { > + "field": "NXM_NX_REG10", > + "start": 7, > + "end": 7, > + }, > + } > + }, > + ], > + ), > + ], > + ), > + ( > + "actions=resubmit(,8),resubmit:3,resubmit(1,2,ct)", > + [ > + KeyValue("resubmit", {"port": "", "table": 8}), > + KeyValue("resubmit", {"port": 3}), > + KeyValue("resubmit", {"port": 1, "table": 2, "ct": True}), > + ], > + ), > + ( > + "actions=clone(ct_clear,load:0->NXM_NX_REG11[],load:0->NXM_NX_REG12[],load:0->NXM_NX_REG13[],load:0x1d->NXM_NX_REG13[],load:0x1f->NXM_NX_REG11[],load:0x1c->NXM_NX_REG12[],load:0x11->OXM_OF_METADATA[],load:0x2->NXM_NX_REG14[],load:0->NXM_NX_REG10[],load:0->NXM_NX_REG15[],load:0->NXM_NX_REG0[],load:0->NXM_NX_REG1[],load:0->NXM_NX_REG2[],load:0->NXM_NX_REG3[],load:0->NXM_NX_REG4[],load:0->NXM_NX_REG5[],load:0->NXM_NX_REG6[],load:0->NXM_NX_REG7[],load:0->NXM_NX_REG8[],load:0->NXM_NX_REG9[],resubmit(,8))", # noqa: E501 > + [ > + KeyValue( > + "clone", > + [ > + {"ct_clear": True}, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG11"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG12"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG13"}, > + } > + }, > + { > + "load": { > + "value": 29, > + "dst": {"field": "NXM_NX_REG13"}, > + } > + }, > + { > + "load": { > + "value": 31, > + "dst": {"field": "NXM_NX_REG11"}, > + } > + }, > + { > + "load": { > + "value": 28, > + "dst": {"field": "NXM_NX_REG12"}, > + } > + }, > + { > + "load": { > + "value": 17, > + "dst": {"field": "OXM_OF_METADATA"}, > + } > + }, > + { > + "load": { > + "value": 2, > + "dst": {"field": "NXM_NX_REG14"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG10"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG15"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG0"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG1"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG2"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG3"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG4"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG5"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG6"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG7"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG8"}, > + } > + }, > + { > + "load": { > + "value": 0, > + "dst": {"field": "NXM_NX_REG9"}, > + } > + }, > + {"resubmit": {"port": "", "table": 8}}, > + ], > + ) > + ], > + ), > + ( > + "actions=conjunction(1234, 1/2),note:00.00.11.22.33.ff,sample(probability=123,collector_set_id=0x123,obs_domain_id=0x123,obs_point_id=0x123,sampling_port=inport0,ingress)", # noqa: E501 > + [ > + KeyValue("conjunction", {"id": 1234, "k": 1, "n": 2}), > + KeyValue("note", "00.00.11.22.33.ff"), > + KeyValue( > + "sample", > + { > + "probability": 123, > + "collector_set_id": 0x123, > + "obs_domain_id": 0x123, > + "obs_point_id": 0x123, > + "sampling_port": "inport0", > + "ingress": True, > + }, > + ), > + ], > + ), > + ], > +) Add new line… (also by other tests?) > +def test_act(input_string, expected): > + ofp = OFPFlowFactory().from_string(input_string) > + actions = ofp.actions_kv > + for i in range(len(expected)): > + assert expected[i].key == actions[i].key > + assert expected[i].value == actions[i].value > + > + # Assert positions relative to action string are OK > + apos = ofp.section("actions").pos > + astring = ofp.section("actions").string > + > + kpos = actions[i].meta.kpos > + kstr = actions[i].meta.kstring > + vpos = actions[i].meta.vpos > + vstr = actions[i].meta.vstring > + assert astring[kpos : kpos + len(kstr)] == kstr > + if vpos != -1: > + assert astring[vpos : vpos + len(vstr)] == vstr > + > + # assert astring meta is correct > + assert input_string[apos : apos + len(astring)] == astring > -- > 2.31.1
On 12/24/21 14:14, Eelco Chaudron wrote: > Other than ending comments with a dot and an extra newline, it looks fine. > > Acked-by: Eelco Chaudron <echaudro@redhat.com> > > On 22 Nov 2021, at 12:22, Adrian Moreno wrote: > >> Signed-off-by: Adrian Moreno <amorenoz@redhat.com> >> --- >> python/automake.mk | 3 +- >> python/ovs/tests/test_ofp.py | 524 +++++++++++++++++++++++++++++++++++ >> 2 files changed, 526 insertions(+), 1 deletion(-) >> create mode 100644 python/ovs/tests/test_ofp.py >> >> diff --git a/python/automake.mk b/python/automake.mk >> index 41973797c..713f1d1a4 100644 >> --- a/python/automake.mk >> +++ b/python/automake.mk >> @@ -55,7 +55,8 @@ ovs_pyfiles = \ >> >> ovs_tests = \ >> python/ovs/tests/test_kv.py \ >> - python/ovs/tests/test_list.py >> + python/ovs/tests/test_list.py \ >> + python/ovs/tests/test_ofp.py >> >> >> # These python files are used at build time but not runtime, >> diff --git a/python/ovs/tests/test_ofp.py b/python/ovs/tests/test_ofp.py >> new file mode 100644 >> index 000000000..975be17d1 >> --- /dev/null >> +++ b/python/ovs/tests/test_ofp.py >> @@ -0,0 +1,524 @@ >> +import netaddr >> +import pytest >> + >> +from ovs.flows.ofp import OFPFlowFactory >> +from ovs.flows.kv import KeyValue >> +from ovs.flows.decoders import EthMask, IPMask, decode_mask >> + >> + >> +@pytest.mark.parametrize( >> + "input_string,expected", >> + [ >> + ( >> + "actions=local,3,4,5,output:foo", >> + [ >> + KeyValue("output", {"port": "local"}), >> + KeyValue("output", {"port": 3}), >> + KeyValue("output", {"port": 4}), >> + KeyValue("output", {"port": 5}), >> + KeyValue("output", {"port": "foo"}), >> + ], >> + ), >> + ( >> + "actions=controller,controller:200", >> + [ >> + KeyValue("output", "controller"), >> + KeyValue("controller", {"max_len": 200}), >> + ], >> + ), >> + ( >> + "actions=enqueue(foo,42),enqueue:foo:42,enqueue(bar,4242)", >> + [ >> + KeyValue("enqueue", {"port": "foo", "queue": 42}), >> + KeyValue("enqueue", {"port": "foo", "queue": 42}), >> + KeyValue("enqueue", {"port": "bar", "queue": 4242}), >> + ], >> + ), >> + ( >> + "actions=bundle(eth_src,0,hrw,ofport,members:4,8)", >> + [ >> + KeyValue( >> + "bundle", >> + { >> + "fields": "eth_src", >> + "basis": 0, >> + "algorithm": "hrw", >> + "members": [4, 8], >> + }, >> + ), >> + ], >> + ), >> + ( >> + "actions=bundle_load(eth_src,0,hrw,ofport,reg0,members:4,8)", >> + [ >> + KeyValue( >> + "bundle_load", >> + { >> + "fields": "eth_src", >> + "basis": 0, >> + "algorithm": "hrw", >> + "dst": "reg0", >> + "members": [4, 8], >> + }, >> + ), >> + ], >> + ), >> + ( >> + "actions=group:3", >> + [KeyValue("group", 3)], >> + ), >> + ( >> + "actions=strip_vlan", >> + [KeyValue("strip_vlan", True)], >> + ), >> + ( >> + "actions=pop_vlan", >> + [KeyValue("pop_vlan", True)], >> + ), >> + ( >> + "actions=push_vlan:0x8100", >> + [KeyValue("push_vlan", 0x8100)], >> + ), >> + ( >> + "actions=push_mpls:0x8848", >> + [KeyValue("push_mpls", 0x8848)], >> + ), >> + ( >> + "actions=pop_mpls:0x8848", >> + [KeyValue("pop_mpls", 0x8848)], >> + ), >> + ( >> + "actions=pop_mpls:0x8848", >> + [KeyValue("pop_mpls", 0x8848)], >> + ), >> + ( >> + "actions=encap(nsh(md_type=2,tlv(0x1000,10,0x12345678)))", >> + [ >> + KeyValue( >> + "encap", >> + { >> + "nsh": { >> + "md_type": 2, >> + "tlv": { >> + "class": 0x1000, >> + "type": 10, >> + "value": 0x12345678, >> + }, >> + } >> + }, >> + ) >> + ], >> + ), >> + ( >> + "actions=encap(0x0800)", >> + [ >> + KeyValue( >> + "encap", >> + {"ethernet": 0x800}, >> + ) >> + ], >> + ), >> + ( >> + "actions=load:0x001122334455->eth_src", >> + [ >> + KeyValue( >> + "load", >> + {"value": 0x001122334455, "dst": {"field": "eth_src"}}, >> + ) >> + ], >> + ), >> + ( >> + "actions=load:1->eth_src[1]", >> + [ >> + KeyValue( >> + "load", >> + { >> + "value": 1, >> + "dst": {"field": "eth_src", "start": 1, "end": 1}, >> + }, >> + ) >> + ], >> + ), >> + ( >> + "actions=learn(load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[])", >> + [ >> + KeyValue( >> + "learn", >> + [ >> + { >> + "load": { >> + "src": {"field": "NXM_NX_TUN_ID"}, >> + "dst": {"field": "NXM_NX_TUN_ID"}, >> + } >> + } >> + ], >> + ), >> + ], >> + ), >> + ( >> + "actions=set_field:00:11:22:33:44:55->eth_src", >> + [ >> + KeyValue( >> + "set_field", >> + { >> + "value": {"eth_src": EthMask("00:11:22:33:44:55")}, >> + "dst": {"field": "eth_src"}, >> + }, >> + ) >> + ], >> + ), >> + ( >> + "actions=set_field:01:00:00:00:00:00/01:00:00:00:00:00->eth_src", >> + [ >> + KeyValue( >> + "set_field", >> + { >> + "value": { >> + "eth_src": EthMask( >> + "01:00:00:00:00:00/01:00:00:00:00:00" >> + ) >> + }, >> + "dst": {"field": "eth_src"}, >> + }, >> + ) >> + ], >> + ), >> + ( >> + "actions=set_field:0x10ff->vlan_vid", >> + [ >> + KeyValue( >> + "set_field", >> + { >> + "value": {"vlan_vid": decode_mask(13)("0x10ff")}, >> + "dst": {"field": "vlan_vid"}, >> + }, >> + ) >> + ], >> + ), >> + ( >> + "actions=move:reg0[0..5]->reg1[16..31]", >> + [ >> + KeyValue( >> + "move", >> + { >> + "src": {"field": "reg0", "start": 0, "end": 5}, >> + "dst": {"field": "reg1", "start": 16, "end": 31}, >> + }, >> + ) >> + ], >> + ), >> + ( >> + "actions=mod_dl_dst:00:11:22:33:44:55", >> + [KeyValue("mod_dl_dst", EthMask("00:11:22:33:44:55"))], >> + ), >> + ( >> + "actions=mod_nw_dst:192.168.1.1", >> + [KeyValue("mod_nw_dst", IPMask("192.168.1.1"))], >> + ), >> + ( >> + "actions=mod_nw_dst:fe80::ec17:7bff:fe61:7aac", >> + [KeyValue("mod_nw_dst", IPMask("fe80::ec17:7bff:fe61:7aac"))], >> + ), >> + ( >> + "actions=dec_ttl,dec_ttl(1,2,3)", >> + [KeyValue("dec_ttl", True), KeyValue("dec_ttl", [1, 2, 3])], >> + ), >> + ( >> + "actions=set_mpls_label:0x100,set_mpls_tc:2,set_mpls_ttl:10", >> + [ >> + KeyValue("set_mpls_label", 0x100), >> + KeyValue("set_mpls_tc", 2), >> + KeyValue("set_mpls_ttl", 10), >> + ], >> + ), >> + ( >> + "actions=check_pkt_larger(100)->reg0[10]", >> + [ >> + KeyValue( >> + "check_pkt_larger", >> + { >> + "pkt_len": 100, >> + "dst": {"field": "reg0", "start": 10, "end": 10}, >> + }, >> + ), >> + ], >> + ), >> + ( >> + "actions=pop_queue,set_tunnel:0x10,set_tunnel64:0x65000,set_queue=3", # noqa: E501 >> + [ >> + KeyValue("pop_queue", True), >> + KeyValue("set_tunnel", 0x10), >> + KeyValue("set_tunnel64", 0x65000), >> + KeyValue("set_queue", 3), >> + ], >> + ), >> + ( >> + "actions=ct(zone=10,table=2,nat(snat=192.168.0.0-192.168.0.200:1000-2000,random))", # noqa: E501 >> + [ >> + KeyValue( >> + "ct", >> + { >> + "zone": 10, >> + "table": 2, >> + "nat": { >> + "type": "snat", >> + "addrs": { >> + "start": netaddr.IPAddress("192.168.0.0"), >> + "end": netaddr.IPAddress("192.168.0.200"), >> + }, >> + "ports": { >> + "start": 1000, >> + "end": 2000, >> + }, >> + "random": True, >> + }, >> + }, >> + ) >> + ], >> + ), >> + ( >> + "actions=ct(commit,zone=NXM_NX_REG13[0..15],table=2,exec(load:0->NXM_NX_CT_LABEL[0]))", # noqa: E501 >> + [ >> + KeyValue( >> + "ct", >> + { >> + "commit": True, >> + "zone": { >> + "field": "NXM_NX_REG13", >> + "start": 0, >> + "end": 15, >> + }, >> + "table": 2, >> + "exec": [ >> + { >> + "load": { >> + "value": 0, >> + "dst": { >> + "field": "NXM_NX_CT_LABEL", >> + "start": 0, >> + "end": 0, >> + }, >> + }, >> + }, >> + ], >> + }, >> + ) >> + ], >> + ), >> + ( >> + "actions=load:0x1->NXM_NX_REG10[7],learn(table=69,delete_learned,cookie=0xda6f52b0,OXM_OF_METADATA[],eth_type=0x800,NXM_OF_IP_SRC[],ip_dst=172.30.204.105,nw_proto=6,NXM_OF_TCP_SRC[]=NXM_OF_TCP_DST[],load:0x1->NXM_NX_REG10[7])", # noqa: E501 >> + [ >> + KeyValue( >> + "load", >> + { >> + "value": 1, >> + "dst": {"field": "NXM_NX_REG10", "start": 7, "end": 7}, >> + }, >> + ), >> + KeyValue( >> + "learn", >> + [ >> + {"table": 69}, >> + {"delete_learned": True}, >> + {"cookie": 3664728752}, >> + {"OXM_OF_METADATA[]": True}, >> + {"eth_type": 2048}, >> + {"NXM_OF_IP_SRC[]": True}, >> + {"ip_dst": IPMask("172.30.204.105/32")}, >> + {"nw_proto": 6}, >> + {"NXM_OF_TCP_SRC[]": "NXM_OF_TCP_DST[]"}, >> + { >> + "load": { >> + "value": 1, >> + "dst": { >> + "field": "NXM_NX_REG10", >> + "start": 7, >> + "end": 7, >> + }, >> + } >> + }, >> + ], >> + ), >> + ], >> + ), >> + ( >> + "actions=resubmit(,8),resubmit:3,resubmit(1,2,ct)", >> + [ >> + KeyValue("resubmit", {"port": "", "table": 8}), >> + KeyValue("resubmit", {"port": 3}), >> + KeyValue("resubmit", {"port": 1, "table": 2, "ct": True}), >> + ], >> + ), >> + ( >> + "actions=clone(ct_clear,load:0->NXM_NX_REG11[],load:0->NXM_NX_REG12[],load:0->NXM_NX_REG13[],load:0x1d->NXM_NX_REG13[],load:0x1f->NXM_NX_REG11[],load:0x1c->NXM_NX_REG12[],load:0x11->OXM_OF_METADATA[],load:0x2->NXM_NX_REG14[],load:0->NXM_NX_REG10[],load:0->NXM_NX_REG15[],load:0->NXM_NX_REG0[],load:0->NXM_NX_REG1[],load:0->NXM_NX_REG2[],load:0->NXM_NX_REG3[],load:0->NXM_NX_REG4[],load:0->NXM_NX_REG5[],load:0->NXM_NX_REG6[],load:0->NXM_NX_REG7[],load:0->NXM_NX_REG8[],load:0->NXM_NX_REG9[],resubmit(,8))", # noqa: E501 >> + [ >> + KeyValue( >> + "clone", >> + [ >> + {"ct_clear": True}, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG11"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG12"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG13"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 29, >> + "dst": {"field": "NXM_NX_REG13"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 31, >> + "dst": {"field": "NXM_NX_REG11"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 28, >> + "dst": {"field": "NXM_NX_REG12"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 17, >> + "dst": {"field": "OXM_OF_METADATA"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 2, >> + "dst": {"field": "NXM_NX_REG14"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG10"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG15"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG0"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG1"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG2"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG3"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG4"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG5"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG6"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG7"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG8"}, >> + } >> + }, >> + { >> + "load": { >> + "value": 0, >> + "dst": {"field": "NXM_NX_REG9"}, >> + } >> + }, >> + {"resubmit": {"port": "", "table": 8}}, >> + ], >> + ) >> + ], >> + ), >> + ( >> + "actions=conjunction(1234, 1/2),note:00.00.11.22.33.ff,sample(probability=123,collector_set_id=0x123,obs_domain_id=0x123,obs_point_id=0x123,sampling_port=inport0,ingress)", # noqa: E501 >> + [ >> + KeyValue("conjunction", {"id": 1234, "k": 1, "n": 2}), >> + KeyValue("note", "00.00.11.22.33.ff"), >> + KeyValue( >> + "sample", >> + { >> + "probability": 123, >> + "collector_set_id": 0x123, >> + "obs_domain_id": 0x123, >> + "obs_point_id": 0x123, >> + "sampling_port": "inport0", >> + "ingress": True, >> + }, >> + ), >> + ], >> + ), >> + ], >> +) > > Add new line… (also by other tests?) > Funny you mention. I kept adding the space and my formatter (I use black[1] for automatic python formatting) kept removing it. Then I figured (rememberd) all this is actually a decorator of the function and I _think_ decorators should be immediatly above the function declaration. [1] https://github.com/psf/black >> +def test_act(input_string, expected): >> + ofp = OFPFlowFactory().from_string(input_string) >> + actions = ofp.actions_kv >> + for i in range(len(expected)): >> + assert expected[i].key == actions[i].key >> + assert expected[i].value == actions[i].value >> + >> + # Assert positions relative to action string are OK >> + apos = ofp.section("actions").pos >> + astring = ofp.section("actions").string >> + >> + kpos = actions[i].meta.kpos >> + kstr = actions[i].meta.kstring >> + vpos = actions[i].meta.vpos >> + vstr = actions[i].meta.vstring >> + assert astring[kpos : kpos + len(kstr)] == kstr >> + if vpos != -1: >> + assert astring[vpos : vpos + len(vstr)] == vstr >> + >> + # assert astring meta is correct >> + assert input_string[apos : apos + len(astring)] == astring >> -- >> 2.31.1 >
On 13 Jan 2022, at 17:23, Adrian Moreno wrote: > On 12/24/21 14:14, Eelco Chaudron wrote: >> Other than ending comments with a dot and an extra newline, it looks fine. >> >> Acked-by: Eelco Chaudron <echaudro@redhat.com> >> >> On 22 Nov 2021, at 12:22, Adrian Moreno wrote: >> >>> Signed-off-by: Adrian Moreno <amorenoz@redhat.com> >>> --- >>> python/automake.mk | 3 +- >>> python/ovs/tests/test_ofp.py | 524 +++++++++++++++++++++++++++++++++++ >>> 2 files changed, 526 insertions(+), 1 deletion(-) >>> create mode 100644 python/ovs/tests/test_ofp.py >>> >>> diff --git a/python/automake.mk b/python/automake.mk >>> index 41973797c..713f1d1a4 100644 >>> --- a/python/automake.mk >>> +++ b/python/automake.mk >>> @@ -55,7 +55,8 @@ ovs_pyfiles = \ >>> >>> ovs_tests = \ >>> python/ovs/tests/test_kv.py \ >>> - python/ovs/tests/test_list.py >>> + python/ovs/tests/test_list.py \ >>> + python/ovs/tests/test_ofp.py >>> >>> >>> # These python files are used at build time but not runtime, >>> diff --git a/python/ovs/tests/test_ofp.py b/python/ovs/tests/test_ofp.py >>> new file mode 100644 >>> index 000000000..975be17d1 >>> --- /dev/null >>> +++ b/python/ovs/tests/test_ofp.py >>> @@ -0,0 +1,524 @@ >>> +import netaddr >>> +import pytest >>> + >>> +from ovs.flows.ofp import OFPFlowFactory >>> +from ovs.flows.kv import KeyValue >>> +from ovs.flows.decoders import EthMask, IPMask, decode_mask >>> + >>> + >>> +@pytest.mark.parametrize( >>> + "input_string,expected", >>> + [ >>> + ( >>> + "actions=local,3,4,5,output:foo", >>> + [ >>> + KeyValue("output", {"port": "local"}), >>> + KeyValue("output", {"port": 3}), >>> + KeyValue("output", {"port": 4}), >>> + KeyValue("output", {"port": 5}), >>> + KeyValue("output", {"port": "foo"}), >>> + ], >>> + ), >>> + ( >>> + "actions=controller,controller:200", >>> + [ >>> + KeyValue("output", "controller"), >>> + KeyValue("controller", {"max_len": 200}), >>> + ], >>> + ), >>> + ( >>> + "actions=enqueue(foo,42),enqueue:foo:42,enqueue(bar,4242)", >>> + [ >>> + KeyValue("enqueue", {"port": "foo", "queue": 42}), >>> + KeyValue("enqueue", {"port": "foo", "queue": 42}), >>> + KeyValue("enqueue", {"port": "bar", "queue": 4242}), >>> + ], >>> + ), >>> + ( >>> + "actions=bundle(eth_src,0,hrw,ofport,members:4,8)", >>> + [ >>> + KeyValue( >>> + "bundle", >>> + { >>> + "fields": "eth_src", >>> + "basis": 0, >>> + "algorithm": "hrw", >>> + "members": [4, 8], >>> + }, >>> + ), >>> + ], >>> + ), >>> + ( >>> + "actions=bundle_load(eth_src,0,hrw,ofport,reg0,members:4,8)", >>> + [ >>> + KeyValue( >>> + "bundle_load", >>> + { >>> + "fields": "eth_src", >>> + "basis": 0, >>> + "algorithm": "hrw", >>> + "dst": "reg0", >>> + "members": [4, 8], >>> + }, >>> + ), >>> + ], >>> + ), >>> + ( >>> + "actions=group:3", >>> + [KeyValue("group", 3)], >>> + ), >>> + ( >>> + "actions=strip_vlan", >>> + [KeyValue("strip_vlan", True)], >>> + ), >>> + ( >>> + "actions=pop_vlan", >>> + [KeyValue("pop_vlan", True)], >>> + ), >>> + ( >>> + "actions=push_vlan:0x8100", >>> + [KeyValue("push_vlan", 0x8100)], >>> + ), >>> + ( >>> + "actions=push_mpls:0x8848", >>> + [KeyValue("push_mpls", 0x8848)], >>> + ), >>> + ( >>> + "actions=pop_mpls:0x8848", >>> + [KeyValue("pop_mpls", 0x8848)], >>> + ), >>> + ( >>> + "actions=pop_mpls:0x8848", >>> + [KeyValue("pop_mpls", 0x8848)], >>> + ), >>> + ( >>> + "actions=encap(nsh(md_type=2,tlv(0x1000,10,0x12345678)))", >>> + [ >>> + KeyValue( >>> + "encap", >>> + { >>> + "nsh": { >>> + "md_type": 2, >>> + "tlv": { >>> + "class": 0x1000, >>> + "type": 10, >>> + "value": 0x12345678, >>> + }, >>> + } >>> + }, >>> + ) >>> + ], >>> + ), >>> + ( >>> + "actions=encap(0x0800)", >>> + [ >>> + KeyValue( >>> + "encap", >>> + {"ethernet": 0x800}, >>> + ) >>> + ], >>> + ), >>> + ( >>> + "actions=load:0x001122334455->eth_src", >>> + [ >>> + KeyValue( >>> + "load", >>> + {"value": 0x001122334455, "dst": {"field": "eth_src"}}, >>> + ) >>> + ], >>> + ), >>> + ( >>> + "actions=load:1->eth_src[1]", >>> + [ >>> + KeyValue( >>> + "load", >>> + { >>> + "value": 1, >>> + "dst": {"field": "eth_src", "start": 1, "end": 1}, >>> + }, >>> + ) >>> + ], >>> + ), >>> + ( >>> + "actions=learn(load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[])", >>> + [ >>> + KeyValue( >>> + "learn", >>> + [ >>> + { >>> + "load": { >>> + "src": {"field": "NXM_NX_TUN_ID"}, >>> + "dst": {"field": "NXM_NX_TUN_ID"}, >>> + } >>> + } >>> + ], >>> + ), >>> + ], >>> + ), >>> + ( >>> + "actions=set_field:00:11:22:33:44:55->eth_src", >>> + [ >>> + KeyValue( >>> + "set_field", >>> + { >>> + "value": {"eth_src": EthMask("00:11:22:33:44:55")}, >>> + "dst": {"field": "eth_src"}, >>> + }, >>> + ) >>> + ], >>> + ), >>> + ( >>> + "actions=set_field:01:00:00:00:00:00/01:00:00:00:00:00->eth_src", >>> + [ >>> + KeyValue( >>> + "set_field", >>> + { >>> + "value": { >>> + "eth_src": EthMask( >>> + "01:00:00:00:00:00/01:00:00:00:00:00" >>> + ) >>> + }, >>> + "dst": {"field": "eth_src"}, >>> + }, >>> + ) >>> + ], >>> + ), >>> + ( >>> + "actions=set_field:0x10ff->vlan_vid", >>> + [ >>> + KeyValue( >>> + "set_field", >>> + { >>> + "value": {"vlan_vid": decode_mask(13)("0x10ff")}, >>> + "dst": {"field": "vlan_vid"}, >>> + }, >>> + ) >>> + ], >>> + ), >>> + ( >>> + "actions=move:reg0[0..5]->reg1[16..31]", >>> + [ >>> + KeyValue( >>> + "move", >>> + { >>> + "src": {"field": "reg0", "start": 0, "end": 5}, >>> + "dst": {"field": "reg1", "start": 16, "end": 31}, >>> + }, >>> + ) >>> + ], >>> + ), >>> + ( >>> + "actions=mod_dl_dst:00:11:22:33:44:55", >>> + [KeyValue("mod_dl_dst", EthMask("00:11:22:33:44:55"))], >>> + ), >>> + ( >>> + "actions=mod_nw_dst:192.168.1.1", >>> + [KeyValue("mod_nw_dst", IPMask("192.168.1.1"))], >>> + ), >>> + ( >>> + "actions=mod_nw_dst:fe80::ec17:7bff:fe61:7aac", >>> + [KeyValue("mod_nw_dst", IPMask("fe80::ec17:7bff:fe61:7aac"))], >>> + ), >>> + ( >>> + "actions=dec_ttl,dec_ttl(1,2,3)", >>> + [KeyValue("dec_ttl", True), KeyValue("dec_ttl", [1, 2, 3])], >>> + ), >>> + ( >>> + "actions=set_mpls_label:0x100,set_mpls_tc:2,set_mpls_ttl:10", >>> + [ >>> + KeyValue("set_mpls_label", 0x100), >>> + KeyValue("set_mpls_tc", 2), >>> + KeyValue("set_mpls_ttl", 10), >>> + ], >>> + ), >>> + ( >>> + "actions=check_pkt_larger(100)->reg0[10]", >>> + [ >>> + KeyValue( >>> + "check_pkt_larger", >>> + { >>> + "pkt_len": 100, >>> + "dst": {"field": "reg0", "start": 10, "end": 10}, >>> + }, >>> + ), >>> + ], >>> + ), >>> + ( >>> + "actions=pop_queue,set_tunnel:0x10,set_tunnel64:0x65000,set_queue=3", # noqa: E501 >>> + [ >>> + KeyValue("pop_queue", True), >>> + KeyValue("set_tunnel", 0x10), >>> + KeyValue("set_tunnel64", 0x65000), >>> + KeyValue("set_queue", 3), >>> + ], >>> + ), >>> + ( >>> + "actions=ct(zone=10,table=2,nat(snat=192.168.0.0-192.168.0.200:1000-2000,random))", # noqa: E501 >>> + [ >>> + KeyValue( >>> + "ct", >>> + { >>> + "zone": 10, >>> + "table": 2, >>> + "nat": { >>> + "type": "snat", >>> + "addrs": { >>> + "start": netaddr.IPAddress("192.168.0.0"), >>> + "end": netaddr.IPAddress("192.168.0.200"), >>> + }, >>> + "ports": { >>> + "start": 1000, >>> + "end": 2000, >>> + }, >>> + "random": True, >>> + }, >>> + }, >>> + ) >>> + ], >>> + ), >>> + ( >>> + "actions=ct(commit,zone=NXM_NX_REG13[0..15],table=2,exec(load:0->NXM_NX_CT_LABEL[0]))", # noqa: E501 >>> + [ >>> + KeyValue( >>> + "ct", >>> + { >>> + "commit": True, >>> + "zone": { >>> + "field": "NXM_NX_REG13", >>> + "start": 0, >>> + "end": 15, >>> + }, >>> + "table": 2, >>> + "exec": [ >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": { >>> + "field": "NXM_NX_CT_LABEL", >>> + "start": 0, >>> + "end": 0, >>> + }, >>> + }, >>> + }, >>> + ], >>> + }, >>> + ) >>> + ], >>> + ), >>> + ( >>> + "actions=load:0x1->NXM_NX_REG10[7],learn(table=69,delete_learned,cookie=0xda6f52b0,OXM_OF_METADATA[],eth_type=0x800,NXM_OF_IP_SRC[],ip_dst=172.30.204.105,nw_proto=6,NXM_OF_TCP_SRC[]=NXM_OF_TCP_DST[],load:0x1->NXM_NX_REG10[7])", # noqa: E501 >>> + [ >>> + KeyValue( >>> + "load", >>> + { >>> + "value": 1, >>> + "dst": {"field": "NXM_NX_REG10", "start": 7, "end": 7}, >>> + }, >>> + ), >>> + KeyValue( >>> + "learn", >>> + [ >>> + {"table": 69}, >>> + {"delete_learned": True}, >>> + {"cookie": 3664728752}, >>> + {"OXM_OF_METADATA[]": True}, >>> + {"eth_type": 2048}, >>> + {"NXM_OF_IP_SRC[]": True}, >>> + {"ip_dst": IPMask("172.30.204.105/32")}, >>> + {"nw_proto": 6}, >>> + {"NXM_OF_TCP_SRC[]": "NXM_OF_TCP_DST[]"}, >>> + { >>> + "load": { >>> + "value": 1, >>> + "dst": { >>> + "field": "NXM_NX_REG10", >>> + "start": 7, >>> + "end": 7, >>> + }, >>> + } >>> + }, >>> + ], >>> + ), >>> + ], >>> + ), >>> + ( >>> + "actions=resubmit(,8),resubmit:3,resubmit(1,2,ct)", >>> + [ >>> + KeyValue("resubmit", {"port": "", "table": 8}), >>> + KeyValue("resubmit", {"port": 3}), >>> + KeyValue("resubmit", {"port": 1, "table": 2, "ct": True}), >>> + ], >>> + ), >>> + ( >>> + "actions=clone(ct_clear,load:0->NXM_NX_REG11[],load:0->NXM_NX_REG12[],load:0->NXM_NX_REG13[],load:0x1d->NXM_NX_REG13[],load:0x1f->NXM_NX_REG11[],load:0x1c->NXM_NX_REG12[],load:0x11->OXM_OF_METADATA[],load:0x2->NXM_NX_REG14[],load:0->NXM_NX_REG10[],load:0->NXM_NX_REG15[],load:0->NXM_NX_REG0[],load:0->NXM_NX_REG1[],load:0->NXM_NX_REG2[],load:0->NXM_NX_REG3[],load:0->NXM_NX_REG4[],load:0->NXM_NX_REG5[],load:0->NXM_NX_REG6[],load:0->NXM_NX_REG7[],load:0->NXM_NX_REG8[],load:0->NXM_NX_REG9[],resubmit(,8))", # noqa: E501 >>> + [ >>> + KeyValue( >>> + "clone", >>> + [ >>> + {"ct_clear": True}, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG11"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG12"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG13"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 29, >>> + "dst": {"field": "NXM_NX_REG13"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 31, >>> + "dst": {"field": "NXM_NX_REG11"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 28, >>> + "dst": {"field": "NXM_NX_REG12"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 17, >>> + "dst": {"field": "OXM_OF_METADATA"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 2, >>> + "dst": {"field": "NXM_NX_REG14"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG10"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG15"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG0"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG1"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG2"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG3"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG4"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG5"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG6"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG7"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG8"}, >>> + } >>> + }, >>> + { >>> + "load": { >>> + "value": 0, >>> + "dst": {"field": "NXM_NX_REG9"}, >>> + } >>> + }, >>> + {"resubmit": {"port": "", "table": 8}}, >>> + ], >>> + ) >>> + ], >>> + ), >>> + ( >>> + "actions=conjunction(1234, 1/2),note:00.00.11.22.33.ff,sample(probability=123,collector_set_id=0x123,obs_domain_id=0x123,obs_point_id=0x123,sampling_port=inport0,ingress)", # noqa: E501 >>> + [ >>> + KeyValue("conjunction", {"id": 1234, "k": 1, "n": 2}), >>> + KeyValue("note", "00.00.11.22.33.ff"), >>> + KeyValue( >>> + "sample", >>> + { >>> + "probability": 123, >>> + "collector_set_id": 0x123, >>> + "obs_domain_id": 0x123, >>> + "obs_point_id": 0x123, >>> + "sampling_port": "inport0", >>> + "ingress": True, >>> + }, >>> + ), >>> + ], >>> + ), >>> + ], >>> +) >> >> Add new line… (also by other tests?) >> > > Funny you mention. I kept adding the space and my formatter (I use black[1] for automatic python formatting) kept removing it. Then I figured (rememberd) all this is actually a decorator of the function and I _think_ decorators should be immediatly above the function declaration. Yes, I’ve seen it before, but I just don’t like some of its parentheses handling, but I guess that is just my personal preference ;) But you are right, as it’s a decorator normally it’s added without a new line. So please leave it as is, and make sure it’s the same for all tests. > [1] https://github.com/psf/black > >>> +def test_act(input_string, expected): >>> + ofp = OFPFlowFactory().from_string(input_string) >>> + actions = ofp.actions_kv >>> + for i in range(len(expected)): >>> + assert expected[i].key == actions[i].key >>> + assert expected[i].value == actions[i].value >>> + >>> + # Assert positions relative to action string are OK >>> + apos = ofp.section("actions").pos >>> + astring = ofp.section("actions").string >>> + >>> + kpos = actions[i].meta.kpos >>> + kstr = actions[i].meta.kstring >>> + vpos = actions[i].meta.vpos >>> + vstr = actions[i].meta.vstring >>> + assert astring[kpos : kpos + len(kstr)] == kstr >>> + if vpos != -1: >>> + assert astring[vpos : vpos + len(vstr)] == vstr >>> + >>> + # assert astring meta is correct >>> + assert input_string[apos : apos + len(astring)] == astring >>> -- >>> 2.31.1 >> > > -- > Adrián Moreno
diff --git a/python/automake.mk b/python/automake.mk index 41973797c..713f1d1a4 100644 --- a/python/automake.mk +++ b/python/automake.mk @@ -55,7 +55,8 @@ ovs_pyfiles = \ ovs_tests = \ python/ovs/tests/test_kv.py \ - python/ovs/tests/test_list.py + python/ovs/tests/test_list.py \ + python/ovs/tests/test_ofp.py # These python files are used at build time but not runtime, diff --git a/python/ovs/tests/test_ofp.py b/python/ovs/tests/test_ofp.py new file mode 100644 index 000000000..975be17d1 --- /dev/null +++ b/python/ovs/tests/test_ofp.py @@ -0,0 +1,524 @@ +import netaddr +import pytest + +from ovs.flows.ofp import OFPFlowFactory +from ovs.flows.kv import KeyValue +from ovs.flows.decoders import EthMask, IPMask, decode_mask + + +@pytest.mark.parametrize( + "input_string,expected", + [ + ( + "actions=local,3,4,5,output:foo", + [ + KeyValue("output", {"port": "local"}), + KeyValue("output", {"port": 3}), + KeyValue("output", {"port": 4}), + KeyValue("output", {"port": 5}), + KeyValue("output", {"port": "foo"}), + ], + ), + ( + "actions=controller,controller:200", + [ + KeyValue("output", "controller"), + KeyValue("controller", {"max_len": 200}), + ], + ), + ( + "actions=enqueue(foo,42),enqueue:foo:42,enqueue(bar,4242)", + [ + KeyValue("enqueue", {"port": "foo", "queue": 42}), + KeyValue("enqueue", {"port": "foo", "queue": 42}), + KeyValue("enqueue", {"port": "bar", "queue": 4242}), + ], + ), + ( + "actions=bundle(eth_src,0,hrw,ofport,members:4,8)", + [ + KeyValue( + "bundle", + { + "fields": "eth_src", + "basis": 0, + "algorithm": "hrw", + "members": [4, 8], + }, + ), + ], + ), + ( + "actions=bundle_load(eth_src,0,hrw,ofport,reg0,members:4,8)", + [ + KeyValue( + "bundle_load", + { + "fields": "eth_src", + "basis": 0, + "algorithm": "hrw", + "dst": "reg0", + "members": [4, 8], + }, + ), + ], + ), + ( + "actions=group:3", + [KeyValue("group", 3)], + ), + ( + "actions=strip_vlan", + [KeyValue("strip_vlan", True)], + ), + ( + "actions=pop_vlan", + [KeyValue("pop_vlan", True)], + ), + ( + "actions=push_vlan:0x8100", + [KeyValue("push_vlan", 0x8100)], + ), + ( + "actions=push_mpls:0x8848", + [KeyValue("push_mpls", 0x8848)], + ), + ( + "actions=pop_mpls:0x8848", + [KeyValue("pop_mpls", 0x8848)], + ), + ( + "actions=pop_mpls:0x8848", + [KeyValue("pop_mpls", 0x8848)], + ), + ( + "actions=encap(nsh(md_type=2,tlv(0x1000,10,0x12345678)))", + [ + KeyValue( + "encap", + { + "nsh": { + "md_type": 2, + "tlv": { + "class": 0x1000, + "type": 10, + "value": 0x12345678, + }, + } + }, + ) + ], + ), + ( + "actions=encap(0x0800)", + [ + KeyValue( + "encap", + {"ethernet": 0x800}, + ) + ], + ), + ( + "actions=load:0x001122334455->eth_src", + [ + KeyValue( + "load", + {"value": 0x001122334455, "dst": {"field": "eth_src"}}, + ) + ], + ), + ( + "actions=load:1->eth_src[1]", + [ + KeyValue( + "load", + { + "value": 1, + "dst": {"field": "eth_src", "start": 1, "end": 1}, + }, + ) + ], + ), + ( + "actions=learn(load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[])", + [ + KeyValue( + "learn", + [ + { + "load": { + "src": {"field": "NXM_NX_TUN_ID"}, + "dst": {"field": "NXM_NX_TUN_ID"}, + } + } + ], + ), + ], + ), + ( + "actions=set_field:00:11:22:33:44:55->eth_src", + [ + KeyValue( + "set_field", + { + "value": {"eth_src": EthMask("00:11:22:33:44:55")}, + "dst": {"field": "eth_src"}, + }, + ) + ], + ), + ( + "actions=set_field:01:00:00:00:00:00/01:00:00:00:00:00->eth_src", + [ + KeyValue( + "set_field", + { + "value": { + "eth_src": EthMask( + "01:00:00:00:00:00/01:00:00:00:00:00" + ) + }, + "dst": {"field": "eth_src"}, + }, + ) + ], + ), + ( + "actions=set_field:0x10ff->vlan_vid", + [ + KeyValue( + "set_field", + { + "value": {"vlan_vid": decode_mask(13)("0x10ff")}, + "dst": {"field": "vlan_vid"}, + }, + ) + ], + ), + ( + "actions=move:reg0[0..5]->reg1[16..31]", + [ + KeyValue( + "move", + { + "src": {"field": "reg0", "start": 0, "end": 5}, + "dst": {"field": "reg1", "start": 16, "end": 31}, + }, + ) + ], + ), + ( + "actions=mod_dl_dst:00:11:22:33:44:55", + [KeyValue("mod_dl_dst", EthMask("00:11:22:33:44:55"))], + ), + ( + "actions=mod_nw_dst:192.168.1.1", + [KeyValue("mod_nw_dst", IPMask("192.168.1.1"))], + ), + ( + "actions=mod_nw_dst:fe80::ec17:7bff:fe61:7aac", + [KeyValue("mod_nw_dst", IPMask("fe80::ec17:7bff:fe61:7aac"))], + ), + ( + "actions=dec_ttl,dec_ttl(1,2,3)", + [KeyValue("dec_ttl", True), KeyValue("dec_ttl", [1, 2, 3])], + ), + ( + "actions=set_mpls_label:0x100,set_mpls_tc:2,set_mpls_ttl:10", + [ + KeyValue("set_mpls_label", 0x100), + KeyValue("set_mpls_tc", 2), + KeyValue("set_mpls_ttl", 10), + ], + ), + ( + "actions=check_pkt_larger(100)->reg0[10]", + [ + KeyValue( + "check_pkt_larger", + { + "pkt_len": 100, + "dst": {"field": "reg0", "start": 10, "end": 10}, + }, + ), + ], + ), + ( + "actions=pop_queue,set_tunnel:0x10,set_tunnel64:0x65000,set_queue=3", # noqa: E501 + [ + KeyValue("pop_queue", True), + KeyValue("set_tunnel", 0x10), + KeyValue("set_tunnel64", 0x65000), + KeyValue("set_queue", 3), + ], + ), + ( + "actions=ct(zone=10,table=2,nat(snat=192.168.0.0-192.168.0.200:1000-2000,random))", # noqa: E501 + [ + KeyValue( + "ct", + { + "zone": 10, + "table": 2, + "nat": { + "type": "snat", + "addrs": { + "start": netaddr.IPAddress("192.168.0.0"), + "end": netaddr.IPAddress("192.168.0.200"), + }, + "ports": { + "start": 1000, + "end": 2000, + }, + "random": True, + }, + }, + ) + ], + ), + ( + "actions=ct(commit,zone=NXM_NX_REG13[0..15],table=2,exec(load:0->NXM_NX_CT_LABEL[0]))", # noqa: E501 + [ + KeyValue( + "ct", + { + "commit": True, + "zone": { + "field": "NXM_NX_REG13", + "start": 0, + "end": 15, + }, + "table": 2, + "exec": [ + { + "load": { + "value": 0, + "dst": { + "field": "NXM_NX_CT_LABEL", + "start": 0, + "end": 0, + }, + }, + }, + ], + }, + ) + ], + ), + ( + "actions=load:0x1->NXM_NX_REG10[7],learn(table=69,delete_learned,cookie=0xda6f52b0,OXM_OF_METADATA[],eth_type=0x800,NXM_OF_IP_SRC[],ip_dst=172.30.204.105,nw_proto=6,NXM_OF_TCP_SRC[]=NXM_OF_TCP_DST[],load:0x1->NXM_NX_REG10[7])", # noqa: E501 + [ + KeyValue( + "load", + { + "value": 1, + "dst": {"field": "NXM_NX_REG10", "start": 7, "end": 7}, + }, + ), + KeyValue( + "learn", + [ + {"table": 69}, + {"delete_learned": True}, + {"cookie": 3664728752}, + {"OXM_OF_METADATA[]": True}, + {"eth_type": 2048}, + {"NXM_OF_IP_SRC[]": True}, + {"ip_dst": IPMask("172.30.204.105/32")}, + {"nw_proto": 6}, + {"NXM_OF_TCP_SRC[]": "NXM_OF_TCP_DST[]"}, + { + "load": { + "value": 1, + "dst": { + "field": "NXM_NX_REG10", + "start": 7, + "end": 7, + }, + } + }, + ], + ), + ], + ), + ( + "actions=resubmit(,8),resubmit:3,resubmit(1,2,ct)", + [ + KeyValue("resubmit", {"port": "", "table": 8}), + KeyValue("resubmit", {"port": 3}), + KeyValue("resubmit", {"port": 1, "table": 2, "ct": True}), + ], + ), + ( + "actions=clone(ct_clear,load:0->NXM_NX_REG11[],load:0->NXM_NX_REG12[],load:0->NXM_NX_REG13[],load:0x1d->NXM_NX_REG13[],load:0x1f->NXM_NX_REG11[],load:0x1c->NXM_NX_REG12[],load:0x11->OXM_OF_METADATA[],load:0x2->NXM_NX_REG14[],load:0->NXM_NX_REG10[],load:0->NXM_NX_REG15[],load:0->NXM_NX_REG0[],load:0->NXM_NX_REG1[],load:0->NXM_NX_REG2[],load:0->NXM_NX_REG3[],load:0->NXM_NX_REG4[],load:0->NXM_NX_REG5[],load:0->NXM_NX_REG6[],load:0->NXM_NX_REG7[],load:0->NXM_NX_REG8[],load:0->NXM_NX_REG9[],resubmit(,8))", # noqa: E501 + [ + KeyValue( + "clone", + [ + {"ct_clear": True}, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG11"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG12"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG13"}, + } + }, + { + "load": { + "value": 29, + "dst": {"field": "NXM_NX_REG13"}, + } + }, + { + "load": { + "value": 31, + "dst": {"field": "NXM_NX_REG11"}, + } + }, + { + "load": { + "value": 28, + "dst": {"field": "NXM_NX_REG12"}, + } + }, + { + "load": { + "value": 17, + "dst": {"field": "OXM_OF_METADATA"}, + } + }, + { + "load": { + "value": 2, + "dst": {"field": "NXM_NX_REG14"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG10"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG15"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG0"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG1"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG2"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG3"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG4"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG5"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG6"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG7"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG8"}, + } + }, + { + "load": { + "value": 0, + "dst": {"field": "NXM_NX_REG9"}, + } + }, + {"resubmit": {"port": "", "table": 8}}, + ], + ) + ], + ), + ( + "actions=conjunction(1234, 1/2),note:00.00.11.22.33.ff,sample(probability=123,collector_set_id=0x123,obs_domain_id=0x123,obs_point_id=0x123,sampling_port=inport0,ingress)", # noqa: E501 + [ + KeyValue("conjunction", {"id": 1234, "k": 1, "n": 2}), + KeyValue("note", "00.00.11.22.33.ff"), + KeyValue( + "sample", + { + "probability": 123, + "collector_set_id": 0x123, + "obs_domain_id": 0x123, + "obs_point_id": 0x123, + "sampling_port": "inport0", + "ingress": True, + }, + ), + ], + ), + ], +) +def test_act(input_string, expected): + ofp = OFPFlowFactory().from_string(input_string) + actions = ofp.actions_kv + for i in range(len(expected)): + assert expected[i].key == actions[i].key + assert expected[i].value == actions[i].value + + # Assert positions relative to action string are OK + apos = ofp.section("actions").pos + astring = ofp.section("actions").string + + kpos = actions[i].meta.kpos + kstr = actions[i].meta.kstring + vpos = actions[i].meta.vpos + vstr = actions[i].meta.vstring + assert astring[kpos : kpos + len(kstr)] == kstr + if vpos != -1: + assert astring[vpos : vpos + len(vstr)] == vstr + + # assert astring meta is correct + assert input_string[apos : apos + len(astring)] == astring
Signed-off-by: Adrian Moreno <amorenoz@redhat.com> --- python/automake.mk | 3 +- python/ovs/tests/test_ofp.py | 524 +++++++++++++++++++++++++++++++++++ 2 files changed, 526 insertions(+), 1 deletion(-) create mode 100644 python/ovs/tests/test_ofp.py