summaryrefslogtreecommitdiffstats
path: root/tests/py/any
diff options
context:
space:
mode:
Diffstat (limited to 'tests/py/any')
-rw-r--r--tests/py/any/counter.t14
-rw-r--r--tests/py/any/counter.t.json39
-rw-r--r--tests/py/any/counter.t.json.output28
-rw-r--r--tests/py/any/counter.t.payload15
-rw-r--r--tests/py/any/ct.t149
-rw-r--r--tests/py/any/ct.t.json1523
-rw-r--r--tests/py/any/ct.t.json.output666
-rw-r--r--tests/py/any/ct.t.payload518
-rw-r--r--tests/py/any/icmpX.t.netdev9
-rw-r--r--tests/py/any/icmpX.t.netdev.payload36
-rw-r--r--tests/py/any/last.t13
-rw-r--r--tests/py/any/last.t.json16
-rw-r--r--tests/py/any/last.t.json.output14
-rw-r--r--tests/py/any/last.t.payload8
-rw-r--r--tests/py/any/limit.t55
-rw-r--r--tests/py/any/limit.t.json413
-rw-r--r--tests/py/any/limit.t.json.output277
-rw-r--r--tests/py/any/limit.t.payload141
-rw-r--r--tests/py/any/log.t41
-rw-r--r--tests/py/any/log.t.json178
-rw-r--r--tests/py/any/log.t.json.output16
-rw-r--r--tests/py/any/log.t.payload71
-rw-r--r--tests/py/any/meta.t226
-rw-r--r--tests/py/any/meta.t.json2760
-rw-r--r--tests/py/any/meta.t.json.output828
-rw-r--r--tests/py/any/meta.t.payload1074
-rw-r--r--tests/py/any/objects.t16
-rw-r--r--tests/py/any/queue.t33
-rw-r--r--tests/py/any/queue.t.json251
-rw-r--r--tests/py/any/queue.t.json.output9
-rw-r--r--tests/py/any/queue.t.payload81
-rw-r--r--tests/py/any/quota.t25
-rw-r--r--tests/py/any/quota.t.json136
-rw-r--r--tests/py/any/quota.t.payload52
-rw-r--r--tests/py/any/rawpayload.t24
-rw-r--r--tests/py/any/rawpayload.t.json206
-rw-r--r--tests/py/any/rawpayload.t.json.output119
-rw-r--r--tests/py/any/rawpayload.t.payload63
-rw-r--r--tests/py/any/rt.t9
-rw-r--r--tests/py/any/rt.t.json45
-rw-r--r--tests/py/any/rt.t.payload15
-rw-r--r--tests/py/any/tcpopt.t62
-rw-r--r--tests/py/any/tcpopt.t.json622
-rw-r--r--tests/py/any/tcpopt.t.json.output32
-rw-r--r--tests/py/any/tcpopt.t.payload202
45 files changed, 11130 insertions, 0 deletions
diff --git a/tests/py/any/counter.t b/tests/py/any/counter.t
new file mode 100644
index 0000000..1c72742
--- /dev/null
+++ b/tests/py/any/counter.t
@@ -0,0 +1,14 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+*arp;test-arp;input
+*bridge;test-bridge;input
+*netdev;test-netdev;ingress
+
+counter;ok
+counter packets 0 bytes 0;ok;counter
+counter packets 2 bytes 1;ok;counter
+counter bytes 1024 packets 1;ok;counter
diff --git a/tests/py/any/counter.t.json b/tests/py/any/counter.t.json
new file mode 100644
index 0000000..2d1eaa9
--- /dev/null
+++ b/tests/py/any/counter.t.json
@@ -0,0 +1,39 @@
+# counter
+[
+ {
+ "counter": {
+ "bytes": 0,
+ "packets": 0
+ }
+ }
+]
+
+# counter packets 0 bytes 0
+[
+ {
+ "counter": {
+ "bytes": 0,
+ "packets": 0
+ }
+ }
+]
+
+# counter packets 2 bytes 1
+[
+ {
+ "counter": {
+ "bytes": 1,
+ "packets": 2
+ }
+ }
+]
+
+# counter bytes 1024 packets 1
+[
+ {
+ "counter": {
+ "bytes": 1024,
+ "packets": 1
+ }
+ }
+]
diff --git a/tests/py/any/counter.t.json.output b/tests/py/any/counter.t.json.output
new file mode 100644
index 0000000..6a62ffb
--- /dev/null
+++ b/tests/py/any/counter.t.json.output
@@ -0,0 +1,28 @@
+# counter
+[
+ {
+ "counter": null
+ }
+]
+
+# counter packets 0 bytes 0
+[
+ {
+ "counter": null
+ }
+]
+
+# counter packets 2 bytes 1
+[
+ {
+ "counter": null
+ }
+]
+
+# counter bytes 1024 packets 1
+[
+ {
+ "counter": null
+ }
+]
+
diff --git a/tests/py/any/counter.t.payload b/tests/py/any/counter.t.payload
new file mode 100644
index 0000000..23e96ba
--- /dev/null
+++ b/tests/py/any/counter.t.payload
@@ -0,0 +1,15 @@
+# counter
+ip
+ [ counter pkts 0 bytes 0 ]
+
+# counter packets 0 bytes 0
+ip
+ [ counter pkts 0 bytes 0 ]
+
+# counter packets 2 bytes 1
+ip
+ [ counter pkts 2 bytes 1 ]
+
+# counter bytes 1024 packets 1
+ip
+ [ counter pkts 1 bytes 1024 ]
diff --git a/tests/py/any/ct.t b/tests/py/any/ct.t
new file mode 100644
index 0000000..f73fa4e
--- /dev/null
+++ b/tests/py/any/ct.t
@@ -0,0 +1,149 @@
+:output;type filter hook output priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+
+ct state new,established, related, untracked;ok;ct state established,related,new,untracked
+ct state != related;ok
+ct state {new,established, related, untracked};ok
+ct state != {new,established, related, untracked};ok
+ct state invalid drop;ok
+ct state established accept;ok
+ct state 8;ok;ct state new
+ct state xxx;fail
+
+ct direction original;ok
+ct direction != original;ok
+ct direction reply;ok
+ct direction != reply;ok
+ct direction {reply, original};ok
+ct direction != {reply, original};ok
+ct direction xxx;fail
+
+ct status expected;ok
+ct status != expected;ok
+ct status seen-reply;ok
+ct status != seen-reply;ok
+ct status {expected, seen-reply, assured, confirmed, dying};ok
+ct status != {expected, seen-reply, assured, confirmed, dying};ok
+ct status expected,seen-reply,assured,confirmed,snat,dnat,dying;ok
+ct status snat;ok
+ct status dnat;ok
+ct status ! dnat;ok
+ct status xxx;fail
+
+ct mark 0;ok;ct mark 0x00000000
+ct mark or 0x23 == 0x11;ok;ct mark | 0x00000023 == 0x00000011
+ct mark or 0x3 != 0x1;ok;ct mark | 0x00000003 != 0x00000001
+ct mark and 0x23 == 0x11;ok;ct mark & 0x00000023 == 0x00000011
+ct mark and 0x3 != 0x1;ok;ct mark & 0x00000003 != 0x00000001
+ct mark xor 0x23 == 0x11;ok;ct mark 0x00000032
+ct mark xor 0x3 != 0x1;ok;ct mark != 0x00000002
+ct mark set ct mark or 0x00000001;ok;ct mark set ct mark | 0x00000001
+
+ct mark 0x00000032;ok
+ct mark != 0x00000032;ok
+ct mark 0x00000032-0x00000045;ok
+ct mark != 0x00000032-0x00000045;ok
+ct mark {0x32, 0x2222, 0x42de3};ok;ct mark { 0x00042de3, 0x00002222, 0x00000032}
+ct mark {0x32-0x2222, 0x4444-0x42de3};ok;ct mark { 0x00000032-0x00002222, 0x00004444-0x00042de3}
+ct mark != {0x32, 0x2222, 0x42de3};ok;ct mark != { 0x00042de3, 0x00002222, 0x00000032}
+
+# ct mark != {0x32, 0x2222, 0x42de3};ok
+# BUG: invalid expression type set
+# nft: src/evaluate.c:975: expr_evaluate_relational: Assertion '0' failed.
+
+ct mark set 0x11 xor 0x1331;ok;ct mark set 0x00001320
+ct mark set 0x11333 and 0x11;ok;ct mark set 0x00000011
+ct mark set 0x12 or 0x11;ok;ct mark set 0x00000013
+ct mark set 0x11;ok;ct mark set 0x00000011
+ct mark set mark;ok;ct mark set meta mark
+ct mark set (meta mark | 0x10) << 8;ok;ct mark set (meta mark | 0x00000010) << 8
+ct mark set mark map { 1 : 10, 2 : 20, 3 : 30 };ok;ct mark set meta mark map { 0x00000003 : 0x0000001e, 0x00000002 : 0x00000014, 0x00000001 : 0x0000000a}
+
+ct mark set {0x11333, 0x11};fail
+ct zone set {123, 127};fail
+ct label set {123, 127};fail
+ct event set {new, related, destroy, label};fail
+
+ct expiration 30s;ok
+ct expiration 30000ms;ok;ct expiration 30s
+ct expiration 1m-1h;ok;ct expiration 60s-3600s
+ct expiration 1d-1h;fail
+ct expiration > 4d23h59m59s;ok
+ct expiration != 233;ok;ct expiration != 3m53s
+ct expiration 33-45;ok;ct expiration 33s-45s
+ct expiration != 33-45;ok;ct expiration != 33s-45s
+ct expiration {33, 55, 67, 88};ok;ct expiration { 1m7s, 33s, 55s, 1m28s}
+ct expiration != {33, 55, 67, 88};ok;ct expiration != { 1m7s, 33s, 55s, 1m28s}
+ct expiration {33-55, 66-88};ok;ct expiration { 33s-55s, 66s-88s}
+ct expiration != {33-55, 66-88};ok;ct expiration != { 33s-55s, 66s-88s}
+
+ct helper "ftp";ok
+ct helper "12345678901234567";fail
+ct helper "";fail
+
+ct state . ct mark { new . 0x12345678, new . 0x34127856, established . 0x12785634};ok
+ct direction . ct mark { original . 0x12345678, reply . 0x87654321};ok
+ct state . ct mark vmap { new . 0x12345678 : drop, established . 0x87654321 : accept};ok
+
+ct original bytes > 100000;ok
+ct reply packets < 100;ok
+ct bytes > 100000;ok
+
+ct avgpkt > 200;ok
+ct original avgpkt < 500;ok
+
+# bogus direction
+ct both bytes gt 1;fail
+# nonsensical
+ct bytes original reply;fail
+
+# missing direction
+ct ip saddr 1.2.3.4;fail
+
+# wrong base (ip6 but ipv4 address given)
+meta nfproto ipv6 ct original ip saddr 1.2.3.4;fail
+
+# direction, but must be used without
+ct original mark 42;fail
+# swapped key and direction
+ct mark original;fail
+
+ct event set new;ok
+ct event set new or related or destroy or foobar;fail
+ct event set new | related | destroy | label;ok;ct event set new,related,destroy,label
+ct event set new,related,destroy,label;ok
+ct event set new,destroy;ok
+ct event set 1;ok;ct event set new
+ct event set 0x0;ok
+
+ct label 127;ok
+ct label set 127;ok
+ct label 128;fail
+
+ct zone 0;ok
+ct zone 23;ok
+ct zone 65536;fail
+ct both zone 1;fail
+ct original zone 1;ok
+ct reply zone 1;ok
+
+ct id 12345;ok
+
+ct zone set 1;ok
+ct original zone set 1;ok
+ct reply zone set 1;ok
+ct zone set mark map { 1 : 1, 2 : 2 };ok;ct zone set meta mark map { 0x00000001 : 1, 0x00000002 : 2}
+ct both zone set 1;fail
+
+ct invalid;fail
+ct invalid original;fail
+ct set invalid original 42;fail
+ct set invalid 42;fail
+
+notrack;ok
+
+ct count 3;ok
+ct count over 3;ok
diff --git a/tests/py/any/ct.t.json b/tests/py/any/ct.t.json
new file mode 100644
index 0000000..a2a0602
--- /dev/null
+++ b/tests/py/any/ct.t.json
@@ -0,0 +1,1523 @@
+# ct state new,established, related, untracked
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": [
+ "new",
+ "established",
+ "related",
+ "untracked"
+ ]
+ }
+ }
+]
+
+# ct state != related
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "!=",
+ "right": "related"
+ }
+ }
+]
+
+# ct state {new,established, related, untracked}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": {
+ "set": [
+ "new",
+ "established",
+ "related",
+ "untracked"
+ ]
+ }
+ }
+ }
+]
+
+# ct state != {new,established, related, untracked}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "new",
+ "established",
+ "related",
+ "untracked"
+ ]
+ }
+ }
+ }
+]
+
+# ct state invalid drop
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": "invalid"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ct state established accept
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": "established"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ct state 8
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": 8
+ }
+ }
+]
+
+# ct direction original
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "==",
+ "right": "original"
+ }
+ }
+]
+
+# ct direction != original
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "!=",
+ "right": "original"
+ }
+ }
+]
+
+# ct direction reply
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "==",
+ "right": "reply"
+ }
+ }
+]
+
+# ct direction != reply
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "!=",
+ "right": "reply"
+ }
+ }
+]
+
+# ct direction {reply, original}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "in",
+ "right": {
+ "set": [
+ "reply",
+ "original"
+ ]
+ }
+ }
+ }
+]
+
+# ct direction != {reply, original}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "reply",
+ "original"
+ ]
+ }
+ }
+ }
+]
+
+# ct status expected
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "in",
+ "right": "expected"
+ }
+ }
+]
+
+# ct status != expected
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "!=",
+ "right": "expected"
+ }
+ }
+]
+
+# ct status seen-reply
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "in",
+ "right": "seen-reply"
+ }
+ }
+]
+
+# ct status != seen-reply
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "!=",
+ "right": "seen-reply"
+ }
+ }
+]
+
+# ct status {expected, seen-reply, assured, confirmed, dying}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "expected",
+ "seen-reply",
+ "assured",
+ "confirmed",
+ "dying"
+ ]
+ }
+ }
+ }
+]
+
+# ct status != {expected, seen-reply, assured, confirmed, dying}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "expected",
+ "seen-reply",
+ "assured",
+ "confirmed",
+ "dying"
+ ]
+ }
+ }
+ }
+]
+
+# ct status expected,seen-reply,assured,confirmed,snat,dnat,dying
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "in",
+ "right": [
+ "expected",
+ "seen-reply",
+ "assured",
+ "confirmed",
+ "snat",
+ "dnat",
+ "dying"
+ ]
+ }
+ }
+]
+
+# ct status snat
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "in",
+ "right": "snat"
+ }
+ }
+]
+
+# ct status dnat
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "in",
+ "right": "dnat"
+ }
+ }
+]
+
+# ct status ! dnat
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "!",
+ "right": "dnat"
+ }
+ }
+]
+
+# ct mark 0
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# ct mark or 0x23 == 0x11
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "0x23"
+ ]
+ },
+ "op": "==",
+ "right": "0x11"
+ }
+ }
+]
+
+# ct mark or 0x3 != 0x1
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "0x3"
+ ]
+ },
+ "op": "!=",
+ "right": "0x1"
+ }
+ }
+]
+
+# ct mark and 0x23 == 0x11
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "0x23"
+ ]
+ },
+ "op": "==",
+ "right": "0x11"
+ }
+ }
+]
+
+# ct mark and 0x3 != 0x1
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "0x3"
+ ]
+ },
+ "op": "!=",
+ "right": "0x1"
+ }
+ }
+]
+
+# ct mark xor 0x23 == 0x11
+[
+ {
+ "match": {
+ "left": {
+ "^": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "0x23"
+ ]
+ },
+ "op": "==",
+ "right": "0x11"
+ }
+ }
+]
+
+# ct mark xor 0x3 != 0x1
+[
+ {
+ "match": {
+ "left": {
+ "^": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "0x3"
+ ]
+ },
+ "op": "!=",
+ "right": "0x1"
+ }
+ }
+]
+
+# ct mark set ct mark or 0x00000001
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 1
+ ]
+ }
+ }
+ }
+]
+
+# ct mark 0x00000032
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": "0x00000032"
+ }
+ }
+]
+
+# ct mark != 0x00000032
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": "0x00000032"
+ }
+ }
+]
+
+# ct mark 0x00000032-0x00000045
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "0x00000032", "0x00000045" ]
+ }
+ }
+ }
+]
+
+# ct mark != 0x00000032-0x00000045
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ "0x00000032", "0x00000045" ]
+ }
+ }
+ }
+]
+
+# ct mark {0x32, 0x2222, 0x42de3}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "in",
+ "right": {
+ "set": [
+ "0x32",
+ "0x2222",
+ "0x42de3"
+ ]
+ }
+ }
+ }
+]
+
+# ct mark {0x32-0x2222, 0x4444-0x42de3}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "in",
+ "right": {
+ "set": [
+ {
+ "range": [ "0x32", "0x2222" ]
+ },
+ {
+ "range": [ "0x4444", "0x42de3" ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ct mark != {0x32, 0x2222, 0x42de3}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "0x32",
+ "0x2222",
+ "0x42de3"
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set 0x11 xor 0x1331
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": { "^": [ "0x11", "0x1331" ] }
+ }
+ }
+]
+
+# ct mark set 0x11333 and 0x11
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": { "&": [ "0x11333", "0x11" ] }
+ }
+ }
+]
+
+# ct mark set 0x12 or 0x11
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": { "|": [ "0x12", "0x11" ] }
+ }
+ }
+]
+
+# ct mark set 0x11
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": "0x11"
+ }
+ }
+]
+
+# ct mark set mark
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "meta": { "key": "mark" }
+ }
+ }
+ }
+]
+
+# ct mark set (meta mark | 0x10) << 8
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "<<": [
+ {
+ "|": [
+ {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ 16
+ ]
+ },
+ 8
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set mark map { 1 : 10, 2 : 20, 3 : 30 }
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "data": {
+ "set": [
+ [ 1, 10 ],
+ [ 2, 20 ],
+ [ 3, 30 ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# ct expiration 30s
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": "30s"
+ }
+ }
+]
+
+# ct expiration 30000ms
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": "30000ms"
+ }
+ }
+]
+
+# ct expiration 1m-1h
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "1m", "1h" ]
+ }
+ }
+ }
+]
+
+# ct expiration > 4d23h59m59s
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": ">",
+ "right": "4d23h59m59s"
+ }
+ }
+]
+
+# ct expiration != 233
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# ct expiration 33-45
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ct expiration != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# ct expiration {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ct expiration != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# ct expiration {33-55, 66-88}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 66, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# ct expiration != {33-55, 66-88}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 66, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# ct helper "ftp"
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "helper"
+ }
+ },
+ "op": "==",
+ "right": "ftp"
+ }
+ }
+]
+
+# ct state . ct mark { new . 0x12345678, new . 0x34127856, established . 0x12785634}
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "ct": {
+ "key": "state"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "concat": [ "new", "0x12345678" ] },
+ { "concat": [ "new", "0x34127856" ] },
+ { "concat": [ "established", "0x12785634" ] }
+ ]
+ }
+ }
+ }
+]
+
+# ct direction . ct mark { original . 0x12345678, reply . 0x87654321}
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "original",
+ "0x12345678"
+ ]
+ },
+ {
+ "concat": [
+ "reply",
+ "0x87654321"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ct state . ct mark vmap { new . 0x12345678 : drop, established . 0x87654321 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "ct": {
+ "key": "state"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "new",
+ "0x12345678"
+ ]
+ },
+ {
+ "drop": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "established",
+ "0x87654321"
+ ]
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ct original bytes > 100000
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "bytes"
+ }
+ },
+ "op": ">",
+ "right": 100000
+ }
+ }
+]
+
+# ct reply packets < 100
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "reply",
+ "key": "packets"
+ }
+ },
+ "op": "<",
+ "right": 100
+ }
+ }
+]
+
+# ct bytes > 100000
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "bytes"
+ }
+ },
+ "op": ">",
+ "right": 100000
+ }
+ }
+]
+
+# ct avgpkt > 200
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "avgpkt"
+ }
+ },
+ "op": ">",
+ "right": 200
+ }
+ }
+]
+
+# ct original avgpkt < 500
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "avgpkt"
+ }
+ },
+ "op": "<",
+ "right": 500
+ }
+ }
+]
+
+# ct event set new
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": "new"
+ }
+ }
+]
+
+# ct event set new | related | destroy | label
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": [
+ "new",
+ "related",
+ "destroy",
+ "label"
+ ]
+ }
+ }
+]
+
+# ct event set new,related,destroy,label
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": [
+ "new",
+ "related",
+ "destroy",
+ "label"
+ ]
+ }
+ }
+]
+
+# ct event set new,destroy
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": [
+ "new",
+ "destroy"
+ ]
+ }
+ }
+]
+
+# ct event set 1
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": 1
+ }
+ }
+]
+
+# ct event set 0x0
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": "0x0"
+ }
+ }
+]
+
+# ct label 127
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "label"
+ }
+ },
+ "op": "in",
+ "right": 127
+ }
+ }
+]
+
+# ct label set 127
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "label"
+ }
+ },
+ "value": 127
+ }
+ }
+]
+
+# ct zone 0
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "zone"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# ct zone 23
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "zone"
+ }
+ },
+ "op": "==",
+ "right": 23
+ }
+ }
+]
+
+# ct original zone 1
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "original",
+ "key": "zone"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# ct reply zone 1
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "dir": "reply",
+ "key": "zone"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# ct zone set 1
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "zone"
+ }
+ },
+ "value": 1
+ }
+ }
+]
+
+# ct original zone set 1
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "dir": "original",
+ "key": "zone"
+ }
+ },
+ "value": 1
+ }
+ }
+]
+
+# ct reply zone set 1
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "dir": "reply",
+ "key": "zone"
+ }
+ },
+ "value": 1
+ }
+ }
+]
+
+# ct id 12345
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "id"
+ }
+ },
+ "op": "==",
+ "right": 12345
+ }
+ }
+]
+
+# ct zone set mark map { 1 : 1, 2 : 2 }
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "zone"
+ }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "data": {
+ "set": [
+ [ 1, 1 ],
+ [ 2, 2 ]
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# notrack
+[
+ {
+ "notrack": null
+ }
+]
+
+# ct count 3
+[
+ {
+ "ct count": {
+ "val": 3
+ }
+ }
+]
+
+# ct count over 3
+[
+ {
+ "ct count": {
+ "inv": true,
+ "val": 3
+ }
+ }
+]
+
diff --git a/tests/py/any/ct.t.json.output b/tests/py/any/ct.t.json.output
new file mode 100644
index 0000000..70ade7e
--- /dev/null
+++ b/tests/py/any/ct.t.json.output
@@ -0,0 +1,666 @@
+# ct state new,established, related, untracked
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": [
+ "established",
+ "related",
+ "new",
+ "untracked"
+ ]
+ }
+ }
+]
+
+# ct state {new,established, related, untracked}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "established",
+ "related",
+ "new",
+ "untracked"
+ ]
+ }
+ }
+ }
+]
+
+# ct state != {new,established, related, untracked}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "established",
+ "related",
+ "new",
+ "untracked"
+ ]
+ }
+ }
+ }
+]
+
+# ct state 8
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "op": "in",
+ "right": "new"
+ }
+ }
+]
+
+# ct direction {reply, original}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "original",
+ "reply"
+ ]
+ }
+ }
+ }
+]
+
+# ct direction != {reply, original}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "original",
+ "reply"
+ ]
+ }
+ }
+ }
+]
+
+# ct mark or 0x23 == 0x11
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 35
+ ]
+ },
+ "op": "==",
+ "right": 17
+ }
+ }
+]
+
+# ct mark or 0x3 != 0x1
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 3
+ ]
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# ct mark and 0x23 == 0x11
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 35
+ ]
+ },
+ "op": "==",
+ "right": 17
+ }
+ }
+]
+
+# ct mark and 0x3 != 0x1
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 3
+ ]
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# ct mark xor 0x23 == 0x11
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": 50
+ }
+ }
+]
+
+# ct mark xor 0x3 != 0x1
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": 2
+ }
+ }
+]
+
+# ct mark 0x00000032
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": 50
+ }
+ }
+]
+
+# ct mark != 0x00000032
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": 50
+ }
+ }
+]
+
+# ct mark 0x00000032-0x00000045
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 50, 69 ]
+ }
+ }
+ }
+]
+
+# ct mark != 0x00000032-0x00000045
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 50, 69 ]
+ }
+ }
+ }
+]
+
+# ct mark {0x32, 0x2222, 0x42de3}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 50,
+ 8738,
+ 273891
+ ]
+ }
+ }
+ }
+]
+
+# ct mark {0x32-0x2222, 0x4444-0x42de3}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 50, 8738 ] },
+ { "range": [ 17476, 273891 ] }
+ ]
+ }
+ }
+ }
+]
+
+# ct mark != {0x32, 0x2222, 0x42de3}
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 50,
+ 8738,
+ 273891
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set 0x11 xor 0x1331
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": 4896
+ }
+ }
+]
+
+# ct mark set 0x11333 and 0x11
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": 17
+ }
+ }
+]
+
+# ct mark set 0x12 or 0x11
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": 19
+ }
+ }
+]
+
+# ct mark set 0x11
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": 17
+ }
+ }
+]
+
+# ct expiration 30s
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": 30
+ }
+ }
+]
+
+# ct expiration 30000ms
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": 30
+ }
+ }
+]
+
+# ct expiration 1m-1h
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 60, 3600 ]
+ }
+ }
+ }
+]
+
+# ct expiration > 4d23h59m59s
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "expiration"
+ }
+ },
+ "op": ">",
+ "right": 431999
+ }
+ }
+]
+
+# ct state . ct mark { new . 0x12345678}
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "ct": {
+ "key": "state"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "new",
+ 305419896
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ct state . ct mark { new . 0x12345678, new . 0x34127856, established . 0x12785634}
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "ct": {
+ "key": "state"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "new",
+ 305419896
+ ]
+ },
+ {
+ "concat": [
+ "established",
+ 309876276
+ ]
+ },
+ {
+ "concat": [
+ "new",
+ 873625686
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ct direction . ct mark { original . 0x12345678, reply . 0x87654321}
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "ct": {
+ "key": "direction"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "original",
+ 305419896
+ ]
+ },
+ {
+ "concat": [
+ "reply",
+ 2271560481
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ct state . ct mark vmap { new . 0x12345678 : drop, established . 0x87654321 : accept}
+[
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "ct": {
+ "key": "state"
+ }
+ },
+ {
+ "ct": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "new",
+ 305419896
+ ]
+ },
+ {
+ "drop": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "established",
+ 2271560481
+ ]
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# ct event set 1
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": "new"
+ }
+ }
+]
+
+# ct event set 0x0
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "event"
+ }
+ },
+ "value": 0
+ }
+ }
+]
+
diff --git a/tests/py/any/ct.t.payload b/tests/py/any/ct.t.payload
new file mode 100644
index 0000000..ed868e5
--- /dev/null
+++ b/tests/py/any/ct.t.payload
@@ -0,0 +1,518 @@
+# ct state new,established, related, untracked
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000004e ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct state != related
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ cmp neq reg 1 0x00000004 ]
+
+# ct state {new,established, related, untracked}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000040 : 0 [end]
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct state != {new,established, related, untracked}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000040 : 0 [end]
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ct state invalid drop
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+ [ immediate reg 0 drop ]
+
+# ct state established accept
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+ [ immediate reg 0 accept ]
+
+# ct state 8
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000008 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct direction original
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ct direction != original
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct direction reply
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# ct direction != reply
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# ct direction {reply, original}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000000 : 0 [end]
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct direction != {reply, original}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000000 : 0 [end]
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ct status expected
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct status != expected
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# ct status seen-reply
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct status != seen-reply
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# ct status {expected, seen-reply, assured, confirmed, dying}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000008 : 0 [end] element 00000200 : 0 [end]
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct status != {expected, seen-reply, assured, confirmed, dying}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000008 : 0 [end] element 00000200 : 0 [end]
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ct mark 0
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ct mark or 0x23 == 0x11
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffdc ) ^ 0x00000023 ]
+ [ cmp eq reg 1 0x00000011 ]
+
+# ct mark or 0x3 != 0x1
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffc ) ^ 0x00000003 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# ct mark and 0x23 == 0x11
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000023 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000011 ]
+
+# ct mark and 0x3 != 0x1
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# ct mark xor 0x23 == 0x11
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# ct mark xor 0x3 != 0x1
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# ct mark 0x00000032
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# ct mark != 0x00000032
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ cmp neq reg 1 0x00000032 ]
+
+# ct mark 0x00000032-0x00000045
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0x32000000 ]
+ [ cmp lte reg 1 0x45000000 ]
+
+# ct mark != 0x00000032-0x00000045
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0x32000000 0x45000000 ]
+
+# ct mark {0x32, 0x2222, 0x42de3}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000032 : 0 [end] element 00002222 : 0 [end] element 00042de3 : 0 [end]
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct mark {0x32-0x2222, 0x4444-0x42de3}
+__set%d test-ip4 7
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 32000000 : 0 [end] element 23220000 : 1 [end] element 44440000 : 0 [end] element e42d0400 : 1 [end]
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# ct mark != {0x32, 0x2222, 0x42de3}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000032 : 0 [end] element 00002222 : 0 [end] element 00042de3 : 0 [end]
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ct mark set 0x11 xor 0x1331
+ip test-ip4 output
+ [ immediate reg 1 0x00001320 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set 0x11333 and 0x11
+ip test-ip4 output
+ [ immediate reg 1 0x00000011 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set 0x12 or 0x11
+ip test-ip4 output
+ [ immediate reg 1 0x00000013 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set 0x11
+ip test-ip4 output
+ [ immediate reg 1 0x00000011 ]
+ [ ct set mark with reg 1 ]
+
+# ct expiration 30s
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ cmp eq reg 1 0x00007530 ]
+
+# ct expiration 30000ms
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ cmp eq reg 1 0x00007530 ]
+
+# ct expiration 1m-1h
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0x60ea0000 ]
+ [ cmp lte reg 1 0x80ee3600 ]
+
+# ct expiration > 4d23h59m59s
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gt reg 1 0x18c8bf19 ]
+
+# ct expiration != 233
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ cmp neq reg 1 0x00038e28 ]
+
+# ct expiration 33-45
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0xe8800000 ]
+ [ cmp lte reg 1 0xc8af0000 ]
+
+# ct expiration != 33-45
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0xe8800000 0xc8af0000 ]
+
+# ct expiration {33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 000080e8 : 0 [end] element 0000d6d8 : 0 [end] element 000105b8 : 0 [end] element 000157c0 : 0 [end]
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct expiration != {33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 000080e8 : 0 [end] element 0000d6d8 : 0 [end] element 000105b8 : 0 [end] element 000157c0 : 0 [end]
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ct expiration {33-55, 66-88}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element e8800000 : 0 [end] element d9d60000 : 1 [end] element d0010100 : 0 [end] element c1570100 : 1 [end]
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# ct expiration != {33-55, 66-88}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element e8800000 : 0 [end] element d9d60000 : 1 [end] element d0010100 : 0 [end] element c1570100 : 1 [end]
+ip test-ip4 output
+ [ ct load expiration => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# ct helper "ftp"
+ip test-ip4 output
+ [ ct load helper => reg 1 ]
+ [ cmp eq reg 1 0x00707466 0x00000000 0x00000000 0x00000000 ]
+
+# ct state . ct mark { new . 0x12345678, new . 0x34127856, established . 0x12785634}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 12345678 : 0 [end] element 00000008 34127856 : 0 [end] element 00000002 12785634 : 0 [end]
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ ct load mark => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct mark set mark
+ip test-ip4 output
+ [ meta load mark => reg 1 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set (meta mark | 0x10) << 8
+inet test-inet output
+ [ meta load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ bitwise reg 1 = ( reg 1 << 0x00000008 ) ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set mark map { 1 : 10, 2 : 20, 3 : 30 }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 00000001 : 0000000a 0 [end] element 00000002 : 00000014 0 [end] element 00000003 : 0000001e 0 [end]
+ip test-ip4 output
+ [ meta load mark => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ ct set mark with reg 1 ]
+
+# ct original bytes > 100000
+ip test-ip4 output
+ [ ct load bytes => reg 1 , dir original ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp gt reg 1 0x00000000 0xa0860100 ]
+
+# ct reply packets < 100
+ip test-ip4 output
+ [ ct load packets => reg 1 , dir reply ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp lt reg 1 0x00000000 0x64000000 ]
+
+# ct bytes > 100000
+ip test-ip4 output
+ [ ct load bytes => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp gt reg 1 0x00000000 0xa0860100 ]
+
+# ct avgpkt > 200
+ip test-ip4 output
+ [ ct load avgpkt => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp gt reg 1 0x00000000 0xc8000000 ]
+
+# ct original avgpkt < 500
+ip test-ip4 output
+ [ ct load avgpkt => reg 1 , dir original ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp lt reg 1 0x00000000 0xf4010000 ]
+
+# ct status expected,seen-reply,assured,confirmed,snat,dnat,dying
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000023f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct status snat
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct status dnat
+ip test-ip4 output
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000020 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ct event set new
+ip test-ip4 output
+ [ immediate reg 1 0x00000001 ]
+ [ ct set event with reg 1 ]
+
+# ct event set new | related | destroy | label
+ip test-ip4 output
+ [ immediate reg 1 0x00000407 ]
+ [ ct set event with reg 1 ]
+
+# ct event set new,related,destroy,label
+ip test-ip4 output
+ [ immediate reg 1 0x00000407 ]
+ [ ct set event with reg 1 ]
+
+# ct event set new,destroy
+ip test-ip4 output
+ [ immediate reg 1 0x00000005 ]
+ [ ct set event with reg 1 ]
+
+# ct event set 1
+ip test-ip4 output
+ [ immediate reg 1 0x00000001 ]
+ [ ct set event with reg 1 ]
+
+# ct event set 0x0
+ip test-ip4 output
+ [ immediate reg 1 0x00000000 ]
+ [ ct set event with reg 1 ]
+
+# ct label 127
+ip test-ip4 output
+ [ ct load label => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000000 0x00000000 0x00000000 0x80000000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 0x00000000 0x00000000 0x00000000 ]
+
+# ct label set 127
+ip test-ip4 output
+ [ immediate reg 1 0x00000000 0x00000000 0x00000000 0x80000000 ]
+ [ ct set label with reg 1 ]
+
+# ct zone 0
+ip test-ip4 output
+ [ ct load zone => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ct zone 23
+ip test-ip4 output
+ [ ct load zone => reg 1 ]
+ [ cmp eq reg 1 0x00000017 ]
+
+# ct original zone 1
+ip test-ip4 output
+ [ ct load zone => reg 1 , dir original ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# ct reply zone 1
+ip test-ip4 output
+ [ ct load zone => reg 1 , dir reply ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# ct zone set 1
+ip test-ip4 output
+ [ immediate reg 1 0x00000001 ]
+ [ ct set zone with reg 1 ]
+
+# ct original zone set 1
+ip test-ip4 output
+ [ immediate reg 1 0x00000001 ]
+ [ ct set zone with reg 1 , dir original ]
+
+# ct reply zone set 1
+ip test-ip4 output
+ [ immediate reg 1 0x00000001 ]
+ [ ct set zone with reg 1 , dir reply ]
+
+# ct zone set mark map { 1 : 1, 2 : 2 }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 00000001 : 00000001 0 [end] element 00000002 : 00000002 0 [end]
+ip test-ip4 output
+ [ meta load mark => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ ct set zone with reg 1 ]
+
+# notrack
+ip test-ip4 output
+ [ notrack ]
+
+# ct direction . ct mark { original . 0x12345678, reply . 0x87654321}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 00000000 12345678 : 0 [end] element 00000001 87654321 : 0 [end]
+ip test-ip4 output
+ [ ct load direction => reg 1 ]
+ [ ct load mark => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct state . ct mark vmap { new . 0x12345678 : drop, established . 0x87654321 : accept}
+__map%d test-ip4 b size 2
+__map%d test-ip4 0
+ element 00000008 12345678 : drop 0 [end] element 00000002 87654321 : accept 0 [end]
+ip test-ip4 output
+ [ ct load state => reg 1 ]
+ [ ct load mark => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ct mark set ct mark or 0x00000001
+ip test-ip4 output
+ [ ct load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffe ) ^ 0x00000001 ]
+ [ ct set mark with reg 1 ]
+
+# ct id 12345
+ip test-ip4 output
+ [ ct load unknown => reg 1 ]
+ [ cmp eq reg 1 0x39300000 ]
+
+# ct status ! dnat
+ip6
+ [ ct load status => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000020 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# ct count 3
+ip test-ip4 output
+ [ connlimit count 3 flags 0 ]
+
+# ct count over 3
+ip test-ip4 output
+ [ connlimit count 3 flags 1 ]
+
diff --git a/tests/py/any/icmpX.t.netdev b/tests/py/any/icmpX.t.netdev
new file mode 100644
index 0000000..cf40242
--- /dev/null
+++ b/tests/py/any/icmpX.t.netdev
@@ -0,0 +1,9 @@
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*netdev;test-netdev;ingress,egress
+
+ip protocol icmp icmp type echo-request;ok;icmp type echo-request
+icmp type echo-request;ok
+ip6 nexthdr icmpv6 icmpv6 type echo-request;ok;icmpv6 type echo-request
+icmpv6 type echo-request;ok
diff --git a/tests/py/any/icmpX.t.netdev.payload b/tests/py/any/icmpX.t.netdev.payload
new file mode 100644
index 0000000..8b8107c
--- /dev/null
+++ b/tests/py/any/icmpX.t.netdev.payload
@@ -0,0 +1,36 @@
+# ip protocol icmp icmp type echo-request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# icmp type echo-request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# ip6 nexthdr icmpv6 icmpv6 type echo-request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# icmpv6 type echo-request
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 1b @ network header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000080 ]
+
diff --git a/tests/py/any/last.t b/tests/py/any/last.t
new file mode 100644
index 0000000..5c53046
--- /dev/null
+++ b/tests/py/any/last.t
@@ -0,0 +1,13 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+*arp;test-arp;input
+*bridge;test-bridge;input
+*netdev;test-netdev;ingress
+
+last;ok
+last used 300s;ok;last
+last used foo;fail
diff --git a/tests/py/any/last.t.json b/tests/py/any/last.t.json
new file mode 100644
index 0000000..2a2b9e7
--- /dev/null
+++ b/tests/py/any/last.t.json
@@ -0,0 +1,16 @@
+# last
+[
+ {
+ "last": null
+ }
+]
+
+# last used 300s
+[
+ {
+ "last": {
+ "used": 300000
+ }
+ }
+]
+
diff --git a/tests/py/any/last.t.json.output b/tests/py/any/last.t.json.output
new file mode 100644
index 0000000..b8a977e
--- /dev/null
+++ b/tests/py/any/last.t.json.output
@@ -0,0 +1,14 @@
+# last
+[
+ {
+ "last": null
+ }
+]
+
+# last used 300s
+[
+ {
+ "last": null
+ }
+]
+
diff --git a/tests/py/any/last.t.payload b/tests/py/any/last.t.payload
new file mode 100644
index 0000000..ed47d0f
--- /dev/null
+++ b/tests/py/any/last.t.payload
@@ -0,0 +1,8 @@
+# last
+ip
+ [ last never ]
+
+# last used 300s
+ip
+ [ last 300000 ]
+
diff --git a/tests/py/any/limit.t b/tests/py/any/limit.t
new file mode 100644
index 0000000..a04ef42
--- /dev/null
+++ b/tests/py/any/limit.t
@@ -0,0 +1,55 @@
+:output;type filter hook output priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+*arp;test-arp;output
+*bridge;test-bridge;output
+*netdev;test-netdev;ingress,egress
+
+limit rate 400/minute;ok;limit rate 400/minute burst 5 packets
+limit rate 20/second;ok;limit rate 20/second burst 5 packets
+limit rate 400/hour;ok;limit rate 400/hour burst 5 packets
+limit rate 40/day;ok;limit rate 40/day burst 5 packets
+limit rate 400/week;ok;limit rate 400/week burst 5 packets
+limit rate 1023/second burst 10 packets;ok
+limit rate 1023/second burst 10 bytes;fail
+
+limit rate 1 kbytes/second;ok
+limit rate 2 kbytes/second;ok
+limit rate 1025 kbytes/second;ok
+limit rate 1023 mbytes/second;ok
+limit rate 10230 mbytes/second;ok
+limit rate 1023000 mbytes/second;ok
+limit rate 512 kbytes/second burst 5 packets;fail
+
+limit rate 1 bytes / second;ok;limit rate 1 bytes/second
+limit rate 1 kbytes / second;ok;limit rate 1 kbytes/second
+limit rate 1 mbytes / second;ok;limit rate 1 mbytes/second
+limit rate 1 gbytes / second;fail
+
+limit rate 1025 bytes/second burst 512 bytes;ok
+limit rate 1025 kbytes/second burst 1023 kbytes;ok
+limit rate 1025 mbytes/second burst 1025 kbytes;ok
+limit rate 1025000 mbytes/second burst 1023 mbytes;ok
+
+limit rate over 400/minute;ok;limit rate over 400/minute burst 5 packets
+limit rate over 20/second;ok;limit rate over 20/second burst 5 packets
+limit rate over 400/hour;ok;limit rate over 400/hour burst 5 packets
+limit rate over 40/day;ok;limit rate over 40/day burst 5 packets
+limit rate over 400/week;ok;limit rate over 400/week burst 5 packets
+limit rate over 1023/second burst 10 packets;ok
+
+limit rate over 1 kbytes/second;ok
+limit rate over 2 kbytes/second;ok
+limit rate over 1025 kbytes/second;ok
+limit rate over 1023 mbytes/second;ok
+limit rate over 10230 mbytes/second;ok
+limit rate over 1023000 mbytes/second;ok
+
+limit rate over 1025 bytes/second burst 512 bytes;ok
+limit rate over 1025 kbytes/second burst 1023 kbytes;ok
+limit rate over 1025 mbytes/second burst 1025 kbytes;ok
+limit rate over 1025000 mbytes/second burst 1023 mbytes;ok
diff --git a/tests/py/any/limit.t.json b/tests/py/any/limit.t.json
new file mode 100644
index 0000000..e001ba0
--- /dev/null
+++ b/tests/py/any/limit.t.json
@@ -0,0 +1,413 @@
+# limit rate 400/minute
+[
+ {
+ "limit": {
+ "per": "minute",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate 20/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 20
+ }
+ }
+]
+
+# limit rate 400/hour
+[
+ {
+ "limit": {
+ "per": "hour",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate 40/day
+[
+ {
+ "limit": {
+ "per": "day",
+ "rate": 40
+ }
+ }
+]
+
+# limit rate 400/week
+[
+ {
+ "limit": {
+ "per": "week",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate 1023/second burst 10 packets
+[
+ {
+ "limit": {
+ "burst": 10,
+ "per": "second",
+ "rate": 1023
+ }
+ }
+]
+
+# limit rate 1 kbytes/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 2 kbytes/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 2,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 1025 kbytes/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 1023 mbytes/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 1023,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 10230 mbytes/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 10230,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 1023000 mbytes/second
+[
+ {
+ "limit": {
+ "per": "second",
+ "rate": 1023000,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 1 bytes / second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "bytes"
+ }
+ }
+]
+
+# limit rate 1 kbytes / second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 1 mbytes / second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 1025 bytes/second burst 512 bytes
+[
+ {
+ "limit": {
+ "burst": 512,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "bytes"
+ }
+ }
+]
+
+# limit rate 1025 kbytes/second burst 1023 kbytes
+[
+ {
+ "limit": {
+ "burst": 1023,
+ "burst_unit": "kbytes",
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 1025 mbytes/second burst 1025 kbytes
+[
+ {
+ "limit": {
+ "burst": 1025,
+ "burst_unit": "kbytes",
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 1025000 mbytes/second burst 1023 mbytes
+[
+ {
+ "limit": {
+ "burst": 1023,
+ "burst_unit": "mbytes",
+ "per": "second",
+ "rate": 1025000,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 400/minute
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "minute",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate over 20/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 20
+ }
+ }
+]
+
+# limit rate over 400/hour
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "hour",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate over 40/day
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "day",
+ "rate": 40
+ }
+ }
+]
+
+# limit rate over 400/week
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "week",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate over 1023/second burst 10 packets
+[
+ {
+ "limit": {
+ "burst": 10,
+ "inv": true,
+ "per": "second",
+ "rate": 1023
+ }
+ }
+]
+
+# limit rate over 1 kbytes/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 2 kbytes/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 2,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 1025 kbytes/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 1023 mbytes/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 1023,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 10230 mbytes/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 10230,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 1023000 mbytes/second
+[
+ {
+ "limit": {
+ "inv": true,
+ "per": "second",
+ "rate": 1023000,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 1025 bytes/second burst 512 bytes
+[
+ {
+ "limit": {
+ "burst": 512,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "bytes"
+ }
+ }
+]
+
+# limit rate over 1025 kbytes/second burst 1023 kbytes
+[
+ {
+ "limit": {
+ "burst": 1023,
+ "burst_unit": "kbytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 1025 mbytes/second burst 1025 kbytes
+[
+ {
+ "limit": {
+ "burst": 1025,
+ "burst_unit": "kbytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 1025000 mbytes/second burst 1023 mbytes
+[
+ {
+ "limit": {
+ "burst": 1023,
+ "burst_unit": "mbytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1025000,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
diff --git a/tests/py/any/limit.t.json.output b/tests/py/any/limit.t.json.output
new file mode 100644
index 0000000..5a95f5e
--- /dev/null
+++ b/tests/py/any/limit.t.json.output
@@ -0,0 +1,277 @@
+# limit rate 400/minute
+[
+ {
+ "limit": {
+ "burst": 5,
+ "per": "minute",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate 20/second
+[
+ {
+ "limit": {
+ "burst": 5,
+ "per": "second",
+ "rate": 20
+ }
+ }
+]
+
+# limit rate 400/hour
+[
+ {
+ "limit": {
+ "burst": 5,
+ "per": "hour",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate 40/day
+[
+ {
+ "limit": {
+ "burst": 5,
+ "per": "day",
+ "rate": 40
+ }
+ }
+]
+
+# limit rate 400/week
+[
+ {
+ "limit": {
+ "burst": 5,
+ "per": "week",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate 1 kbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 2 kbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 2,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 1025 kbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate 1023 mbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1023,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 10230 mbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 10230,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate 1023000 mbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "per": "second",
+ "rate": 1023000,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 400/minute
+[
+ {
+ "limit": {
+ "burst": 5,
+ "inv": true,
+ "per": "minute",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate over 20/second
+[
+ {
+ "limit": {
+ "burst": 5,
+ "inv": true,
+ "per": "second",
+ "rate": 20
+ }
+ }
+]
+
+# limit rate over 400/hour
+[
+ {
+ "limit": {
+ "burst": 5,
+ "inv": true,
+ "per": "hour",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate over 40/day
+[
+ {
+ "limit": {
+ "burst": 5,
+ "inv": true,
+ "per": "day",
+ "rate": 40
+ }
+ }
+]
+
+# limit rate over 400/week
+[
+ {
+ "limit": {
+ "burst": 5,
+ "inv": true,
+ "per": "week",
+ "rate": 400
+ }
+ }
+]
+
+# limit rate over 1 kbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 2 kbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 2,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 1025 kbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1025,
+ "rate_unit": "kbytes"
+ }
+ }
+]
+
+# limit rate over 1023 mbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1023,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 10230 mbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 10230,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
+# limit rate over 1023000 mbytes/second
+[
+ {
+ "limit": {
+ "burst": 0,
+ "burst_unit": "bytes",
+ "inv": true,
+ "per": "second",
+ "rate": 1023000,
+ "rate_unit": "mbytes"
+ }
+ }
+]
+
diff --git a/tests/py/any/limit.t.payload b/tests/py/any/limit.t.payload
new file mode 100644
index 0000000..0c7ee94
--- /dev/null
+++ b/tests/py/any/limit.t.payload
@@ -0,0 +1,141 @@
+# limit rate 400/minute
+ip test-ip4 output
+ [ limit rate 400/minute burst 5 type packets flags 0x0 ]
+
+# limit rate 20/second
+ip test-ip4 output
+ [ limit rate 20/second burst 5 type packets flags 0x0 ]
+
+# limit rate 400/hour
+ip test-ip4 output
+ [ limit rate 400/hour burst 5 type packets flags 0x0 ]
+
+# limit rate 400/week
+ip test-ip4 output
+ [ limit rate 400/week burst 5 type packets flags 0x0 ]
+
+# limit rate 40/day
+ip test-ip4 output
+ [ limit rate 40/day burst 5 type packets flags 0x0 ]
+
+# limit rate 1023/second burst 10 packets
+ip test-ip4 output
+ [ limit rate 1023/second burst 10 type packets flags 0x0 ]
+
+# limit rate 1 kbytes/second
+ip test-ip4 output
+ [ limit rate 1024/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 2 kbytes/second
+ip test-ip4 output
+ [ limit rate 2048/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 1025 kbytes/second
+ip test-ip4 output
+ [ limit rate 1049600/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 1023 mbytes/second
+ip test-ip4 output
+ [ limit rate 1072693248/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 10230 mbytes/second
+ip test-ip4 output
+ [ limit rate 10726932480/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 1023000 mbytes/second
+ip test-ip4 output
+ [ limit rate 1072693248000/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 1 bytes / second
+ip
+ [ limit rate 1/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 1 kbytes / second
+ip
+ [ limit rate 1024/second burst 0 type bytes flags 0x0 ]
+
+# limit rate 1 mbytes / second
+ip
+ [ limit rate 1048576/second burst 0 type bytes flags 0x0 ]
+
+
+# limit rate 1025 bytes/second burst 512 bytes
+ip test-ip4 output
+ [ limit rate 1025/second burst 512 type bytes flags 0x0 ]
+
+# limit rate 1025 kbytes/second burst 1023 kbytes
+ip test-ip4 output
+ [ limit rate 1049600/second burst 1047552 type bytes flags 0x0 ]
+
+# limit rate 1025 mbytes/second burst 1025 kbytes
+ip test-ip4 output
+ [ limit rate 1074790400/second burst 1049600 type bytes flags 0x0 ]
+
+# limit rate 1025000 mbytes/second burst 1023 mbytes
+ip test-ip4 output
+ [ limit rate 1074790400000/second burst 1072693248 type bytes flags 0x0 ]
+
+# limit rate over 400/minute
+ip test-ip4 output
+ [ limit rate 400/minute burst 5 type packets flags 0x1 ]
+
+# limit rate over 20/second
+ip test-ip4 output
+ [ limit rate 20/second burst 5 type packets flags 0x1 ]
+
+# limit rate over 400/hour
+ip test-ip4 output
+ [ limit rate 400/hour burst 5 type packets flags 0x1 ]
+
+# limit rate over 400/week
+ip test-ip4 output
+ [ limit rate 400/week burst 5 type packets flags 0x1 ]
+
+# limit rate over 40/day
+ip test-ip4 output
+ [ limit rate 40/day burst 5 type packets flags 0x1 ]
+
+# limit rate over 1023/second burst 10 packets
+ip test-ip4 output
+ [ limit rate 1023/second burst 10 type packets flags 0x1 ]
+
+# limit rate over 1 kbytes/second
+ip test-ip4 output
+ [ limit rate 1024/second burst 0 type bytes flags 0x1 ]
+
+# limit rate over 2 kbytes/second
+ip test-ip4 output
+ [ limit rate 2048/second burst 0 type bytes flags 0x1 ]
+
+# limit rate over 1025 kbytes/second
+ip test-ip4 output
+ [ limit rate 1049600/second burst 0 type bytes flags 0x1 ]
+
+# limit rate over 1023 mbytes/second
+ip test-ip4 output
+ [ limit rate 1072693248/second burst 0 type bytes flags 0x1 ]
+
+# limit rate over 10230 mbytes/second
+ip test-ip4 output
+ [ limit rate 10726932480/second burst 0 type bytes flags 0x1 ]
+
+# limit rate over 1023000 mbytes/second
+ip test-ip4 output
+ [ limit rate 1072693248000/second burst 0 type bytes flags 0x1 ]
+
+# limit rate over 1025 bytes/second burst 512 bytes
+ip test-ip4 output
+ [ limit rate 1025/second burst 512 type bytes flags 0x1 ]
+
+# limit rate over 1025 kbytes/second burst 1023 kbytes
+ip test-ip4 output
+ [ limit rate 1049600/second burst 1047552 type bytes flags 0x1 ]
+
+# limit rate over 1025 mbytes/second burst 1025 kbytes
+ip test-ip4 output
+ [ limit rate 1074790400/second burst 1049600 type bytes flags 0x1 ]
+
+# limit rate over 1025000 mbytes/second burst 1023 mbytes
+ip test-ip4 output
+ [ limit rate 1074790400000/second burst 1072693248 type bytes flags 0x1 ]
+
diff --git a/tests/py/any/log.t b/tests/py/any/log.t
new file mode 100644
index 0000000..f4ccaf0
--- /dev/null
+++ b/tests/py/any/log.t
@@ -0,0 +1,41 @@
+:output;type filter hook output priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+*arp;test-arp;output
+*bridge;test-bridge;output
+
+log;ok
+log level emerg;ok
+log level alert;ok
+log level crit;ok
+log level err;ok
+log level warn;ok;log
+log level notice;ok
+log level info;ok
+log level debug;ok
+log level audit;ok
+
+log level emerg group 2;fail
+log level alert group 2 prefix "log test2";fail
+
+# log level audit must reject all other parameters
+log level audit prefix "foo";fail
+log level audit group 42;fail
+log level audit snaplen 23;fail
+log level audit queue-threshold 1337;fail
+log level audit flags all;fail
+
+log prefix aaaaa-aaaaaa group 2 snaplen 33;ok;log prefix "aaaaa-aaaaaa" group 2 snaplen 33
+# TODO: Add an exception: 'queue-threshold' attribute needs 'group' attribute
+# The correct rule is log group 2 queue-threshold 2
+log group 2 queue-threshold 2;ok
+log group 2 snaplen 33;ok
+log group 2 prefix "nft-test: ";ok;log prefix "nft-test: " group 2
+
+log flags all;ok
+log level debug flags ip options flags skuid;ok
+log flags tcp sequence,options;ok
+log flags ip options flags ether flags skuid flags tcp sequence,options;ok;log flags all
+log flags all group 2;fail
diff --git a/tests/py/any/log.t.json b/tests/py/any/log.t.json
new file mode 100644
index 0000000..7bcc20e
--- /dev/null
+++ b/tests/py/any/log.t.json
@@ -0,0 +1,178 @@
+# log
+[
+ {
+ "log": null
+ }
+]
+
+# log level emerg
+[
+ {
+ "log": {
+ "level": "emerg"
+ }
+ }
+]
+
+# log level alert
+[
+ {
+ "log": {
+ "level": "alert"
+ }
+ }
+]
+
+# log level crit
+[
+ {
+ "log": {
+ "level": "crit"
+ }
+ }
+]
+
+# log level err
+[
+ {
+ "log": {
+ "level": "err"
+ }
+ }
+]
+
+# log level warn
+[
+ {
+ "log": {
+ "level": "warn"
+ }
+ }
+]
+
+# log level notice
+[
+ {
+ "log": {
+ "level": "notice"
+ }
+ }
+]
+
+# log level info
+[
+ {
+ "log": {
+ "level": "info"
+ }
+ }
+]
+
+# log level debug
+[
+ {
+ "log": {
+ "level": "debug"
+ }
+ }
+]
+
+# log level audit
+[
+ {
+ "log": {
+ "level": "audit"
+ }
+ }
+]
+
+# log prefix aaaaa-aaaaaa group 2 snaplen 33
+[
+ {
+ "log": {
+ "group": 2,
+ "prefix": "aaaaa-aaaaaa",
+ "snaplen": 33
+ }
+ }
+]
+
+# log group 2 queue-threshold 2
+[
+ {
+ "log": {
+ "group": 2,
+ "queue-threshold": 2
+ }
+ }
+]
+
+# log group 2 snaplen 33
+[
+ {
+ "log": {
+ "group": 2,
+ "snaplen": 33
+ }
+ }
+]
+
+# log group 2 prefix "nft-test: "
+[
+ {
+ "log": {
+ "group": 2,
+ "prefix": "nft-test: "
+ }
+ }
+]
+
+# log flags all
+[
+ {
+ "log": {
+ "flags": "all"
+ }
+ }
+]
+
+# log level debug flags ip options flags skuid
+[
+ {
+ "log": {
+ "flags": [
+ "ip options",
+ "skuid"
+ ],
+ "level": "debug"
+ }
+ }
+]
+
+# log flags tcp sequence,options
+[
+ {
+ "log": {
+ "flags": [
+ "tcp sequence",
+ "tcp options"
+ ]
+ }
+ }
+]
+
+# log flags ip options flags ether flags skuid flags tcp sequence,options
+[
+ {
+ "log": {
+ "flags": [
+ "ip options",
+ "ether",
+ "skuid",
+ "tcp sequence",
+ "tcp options"
+ ]
+ }
+ }
+]
+
diff --git a/tests/py/any/log.t.json.output b/tests/py/any/log.t.json.output
new file mode 100644
index 0000000..051c448
--- /dev/null
+++ b/tests/py/any/log.t.json.output
@@ -0,0 +1,16 @@
+# log level warn
+[
+ {
+ "log": null
+ }
+]
+
+# log flags ip options flags ether flags skuid flags tcp sequence,options
+[
+ {
+ "log": {
+ "flags": "all"
+ }
+ }
+]
+
diff --git a/tests/py/any/log.t.payload b/tests/py/any/log.t.payload
new file mode 100644
index 0000000..1330445
--- /dev/null
+++ b/tests/py/any/log.t.payload
@@ -0,0 +1,71 @@
+# log
+ip test-ip4 output
+ [ log ]
+
+# log level emerg
+ip test-ip4 output
+ [ log level 0 ]
+
+# log level alert
+ip test-ip4 output
+ [ log level 1 ]
+
+# log level crit
+ip test-ip4 output
+ [ log level 2 ]
+
+# log level err
+ip test-ip4 output
+ [ log level 3 ]
+
+# log level warn
+ip test-ip4 output
+ [ log level 4 ]
+
+# log level notice
+ip test-ip4 output
+ [ log level 5 ]
+
+# log level info
+ip test-ip4 output
+ [ log level 6 ]
+
+# log level debug
+ip test-ip4 output
+ [ log level 7 ]
+
+# log level audit
+ip test-ip4 output
+ [ log level 8 ]
+
+# log prefix aaaaa-aaaaaa group 2 snaplen 33
+ip test-ip4 output
+ [ log prefix aaaaa-aaaaaa group 2 snaplen 33 qthreshold 0 ]
+
+# log group 2 queue-threshold 2
+ip test-ip4 output
+ [ log group 2 snaplen 0 qthreshold 2 ]
+
+# log group 2 snaplen 33
+ip test-ip4 output
+ [ log group 2 snaplen 33 qthreshold 0 ]
+
+# log group 2 prefix "nft-test: "
+ip test-ip4 output
+ [ log prefix nft-test: group 2 snaplen 0 qthreshold 0 ]
+
+# log flags all
+ip test-ip4 output
+ [ log tcpseq tcpopt ipopt uid macdecode ]
+
+# log level debug flags ip options flags skuid
+ip test-ip4 output
+ [ log level 7 ipopt uid ]
+
+# log flags tcp sequence,options
+ip test-ip4 output
+ [ log tcpseq tcpopt ]
+
+# log flags ip options flags ether flags skuid flags tcp sequence,options
+ip test-ip4 output
+ [ log tcpseq tcpopt ipopt uid macdecode ]
diff --git a/tests/py/any/meta.t b/tests/py/any/meta.t
new file mode 100644
index 0000000..12fabb7
--- /dev/null
+++ b/tests/py/any/meta.t
@@ -0,0 +1,226 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+*arp;test-arp;input
+*bridge;test-bridge;input
+*netdev;test-netdev;ingress,egress
+
+meta length 1000;ok
+meta length 22;ok
+meta length != 233;ok
+meta length 33-45;ok
+meta length != 33-45;ok
+meta length { 33, 55, 67, 88};ok
+meta length { 33-55, 67-88};ok
+meta length { 33-55, 56-88, 100-120};ok;meta length { 33-88, 100-120}
+meta length != { 33, 55, 67, 88};ok
+meta length { 33-55, 66-88};ok
+meta length != { 33-55, 66-88};ok
+
+meta protocol { ip, arp, ip6, vlan };ok;meta protocol { ip6, ip, 8021q, arp}
+meta protocol != {ip, arp, ip6, 8021q};ok
+meta protocol ip;ok
+meta protocol != ip;ok
+
+meta l4proto 22;ok
+meta l4proto != 233;ok
+meta l4proto 33-45;ok
+meta l4proto != 33-45;ok
+meta l4proto { 33, 55, 67, 88};ok
+meta l4proto != { 33, 55, 67, 88};ok
+meta l4proto { 33-55, 66-88};ok
+meta l4proto != { 33-55, 66-88};ok
+
+meta priority root;ok
+meta priority none;ok
+meta priority 0x87654321;ok;meta priority 8765:4321
+meta priority 2271560481;ok;meta priority 8765:4321
+meta priority 1:1234;ok
+meta priority bcad:dadc;ok
+meta priority aabb:0;ok
+meta priority != bcad:dadc;ok
+meta priority != aabb:0;ok
+meta priority bcad:dada-bcad:dadc;ok
+meta priority != bcad:dada-bcad:dadc;ok
+meta priority {bcad:dada, bcad:dadc, aaaa:bbbb};ok
+meta priority set cafe:beef;ok
+meta priority != {bcad:dada, bcad:dadc, aaaa:bbbb};ok
+
+meta mark 0x4;ok;meta mark 0x00000004
+meta mark 0x32;ok;meta mark 0x00000032
+meta mark and 0x03 == 0x01;ok;meta mark & 0x00000003 == 0x00000001
+meta mark and 0x03 != 0x01;ok;meta mark & 0x00000003 != 0x00000001
+meta mark 0x10;ok;meta mark 0x00000010
+meta mark != 0x10;ok;meta mark != 0x00000010
+meta mark 0xffffff00/24;ok
+
+meta mark or 0x03 == 0x01;ok;meta mark | 0x00000003 == 0x00000001
+meta mark or 0x03 != 0x01;ok;meta mark | 0x00000003 != 0x00000001
+meta mark xor 0x03 == 0x01;ok;meta mark 0x00000002
+meta mark xor 0x03 != 0x01;ok;meta mark != 0x00000002
+
+meta iif "lo" accept;ok;iif "lo" accept
+meta iif != "lo" accept;ok;iif != "lo" accept
+
+meta iifname "dummy0";ok;iifname "dummy0"
+meta iifname != "dummy0";ok;iifname != "dummy0"
+meta iifname {"dummy0", "lo"};ok;iifname {"dummy0", "lo"}
+meta iifname != {"dummy0", "lo"};ok;iifname != {"dummy0", "lo"}
+meta iifname "dummy*";ok;iifname "dummy*"
+meta iifname "dummy\*";ok;iifname "dummy\*"
+meta iifname "";fail
+
+meta iiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre};ok
+meta iiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre};ok
+meta iiftype != ether;ok
+meta iiftype ether;ok
+meta iiftype != ppp;ok
+meta iiftype ppp;ok
+
+meta oif "lo" accept;ok;oif "lo" accept
+meta oif != "lo" accept;ok;oif != "lo" accept
+
+meta oifname "dummy0";ok;oifname "dummy0"
+meta oifname != "dummy0";ok;oifname != "dummy0"
+meta oifname { "dummy0", "lo"};ok;oifname { "dummy0", "lo"}
+meta oifname "dummy*";ok;oifname "dummy*"
+meta oifname "dummy\*";ok;oifname "dummy\*"
+meta oifname "";fail
+
+meta oiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre};ok
+meta oiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre};ok
+meta oiftype != ether;ok
+meta oiftype ether;ok
+
+meta skuid {"bin", "root", "daemon"} accept;ok;meta skuid { 0, 1, 2} accept
+meta skuid != {"bin", "root", "daemon"} accept;ok;meta skuid != { 1, 0, 2} accept
+meta skuid "root";ok;meta skuid 0
+meta skuid != "root";ok;meta skuid != 0
+meta skuid lt 3000 accept;ok;meta skuid < 3000 accept
+meta skuid gt 3000 accept;ok;meta skuid > 3000 accept
+meta skuid eq 3000 accept;ok;meta skuid 3000 accept
+meta skuid 3001-3005 accept;ok
+meta skuid != 2001-2005 accept;ok
+meta skuid { 2001-2005, 3001-3005} accept;ok
+meta skuid != { 2001-2005, 3001-3005} accept;ok
+
+meta skgid {"bin", "root", "daemon"} accept;ok;meta skgid { 0, 1, 2} accept
+meta skgid != {"bin", "root", "daemon"} accept;ok;meta skgid != { 1, 0, 2} accept
+meta skgid "root";ok;meta skgid 0
+meta skgid != "root";ok;meta skgid != 0
+meta skgid lt 3000 accept;ok;meta skgid < 3000 accept
+meta skgid gt 3000 accept;ok;meta skgid > 3000 accept
+meta skgid eq 3000 accept;ok;meta skgid 3000 accept
+meta skgid 2001-2005 accept;ok
+meta skgid != 2001-2005 accept;ok
+
+# BUG: meta nftrace 2 and meta nftrace 1
+# $ sudo nft add rule ip test input meta nftrace 2
+# <cmdline>:1:37-37: Error: Value 2 exceeds valid range 0-1
+# add rule ip test input meta nftrace 2
+# ^
+# $ sudo nft add rule ip test input meta nftrace 1
+# <cmdline>:1:1-37: Error: Could not process rule: Operation not supported
+# add rule ip test input meta nftrace 1
+# -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+meta mark set 0xffffffc8 xor 0x16;ok;meta mark set 0xffffffde
+meta mark set 0x16 and 0x16;ok;meta mark set 0x00000016
+meta mark set 0xffffffe9 or 0x16;ok;meta mark set 0xffffffff
+meta mark set 0xffffffde and 0x16;ok;meta mark set 0x00000016
+meta mark set 0xf045ffde or 0x10;ok;meta mark set 0xf045ffde
+meta mark set 0xffffffde or 0x16;ok;meta mark set 0xffffffde
+meta mark set 0x32 or 0xfffff;ok;meta mark set 0x000fffff
+meta mark set 0xfffe xor 0x16;ok;meta mark set 0x0000ffe8
+
+meta mark set {0xffff, 0xcc};fail
+meta pkttype set {unicast, multicast, broadcast};fail
+
+meta iif "lo";ok;iif "lo"
+meta oif "lo";ok;oif "lo"
+meta oifname "dummy2" accept;ok;oifname "dummy2" accept
+meta skuid 3000;ok
+meta skgid 3000;ok
+# BUG: meta nftrace 1;ok
+# <cmdline>:1:1-37: Error: Could not process rule: Operation not supported
+- meta nftrace 1;ok
+meta rtclassid "cosmos";ok
+
+meta pkttype broadcast;ok
+meta pkttype host;ok
+meta pkttype multicast;ok
+meta pkttype != broadcast;ok
+meta pkttype != host;ok
+meta pkttype != multicast;ok
+meta pkttype broadcastttt;fail
+pkttype { broadcast, multicast} accept;ok;meta pkttype { broadcast, multicast} accept
+
+meta cpu 1;ok
+meta cpu != 1;ok
+meta cpu 1-3;ok
+meta cpu != 1-2;ok
+meta cpu { 2,3};ok
+meta cpu { 2-3, 5-7};ok
+meta cpu != { 2,3};ok
+
+meta iifgroup 0;ok;iifgroup "default"
+meta iifgroup != 0;ok;iifgroup != "default"
+meta iifgroup "default";ok;iifgroup "default"
+meta iifgroup != "default";ok;iifgroup != "default"
+meta iifgroup {"default", 11};ok;iifgroup {"default", 11}
+meta iifgroup != {"default", 11};ok;iifgroup != {"default", 11}
+meta iifgroup { 11,33};ok;iifgroup { 11,33}
+meta iifgroup {11-33, 44-55};ok;iifgroup {11-33, 44-55}
+meta iifgroup != { 11,33};ok;iifgroup != { 11,33}
+meta iifgroup != {11-33, 44-55};ok;iifgroup != {11-33, 44-55}
+meta oifgroup 0;ok;oifgroup "default"
+meta oifgroup != 0;ok;oifgroup != "default"
+meta oifgroup "default";ok;oifgroup "default"
+meta oifgroup != "default";ok;oifgroup != "default"
+meta oifgroup {"default", 11};ok;oifgroup {"default", 11}
+meta oifgroup != {"default", 11};ok;oifgroup != {"default", 11}
+meta oifgroup { 11,33};ok;oifgroup { 11,33}
+meta oifgroup {11-33, 44-55};ok;oifgroup {11-33, 44-55}
+meta oifgroup != { 11,33};ok;oifgroup != { 11,33}
+meta oifgroup != {11-33, 44-55};ok;oifgroup != {11-33, 44-55}
+
+meta cgroup 1048577;ok
+meta cgroup != 1048577;ok
+meta cgroup { 1048577, 1048578 };ok
+meta cgroup != { 1048577, 1048578};ok
+meta cgroup 1048577-1048578;ok
+meta cgroup != 1048577-1048578;ok
+
+meta iif . meta oif { "lo" . "lo" };ok;iif . oif { "lo" . "lo" }
+meta iif . meta oif . meta mark { "lo" . "lo" . 0x0000000a };ok;iif . oif . meta mark { "lo" . "lo" . 0x0000000a }
+meta iif . meta oif vmap { "lo" . "lo" : drop };ok;iif . oif vmap { "lo" . "lo" : drop }
+
+meta random eq 1;ok;meta random 1
+meta random gt 1000000;ok;meta random > 1000000
+
+meta time "1970-05-23 21:07:14" drop;ok
+meta time 12341234 drop;ok;meta time "1970-05-23 22:07:14" drop
+meta time "2019-06-21 17:00:00" drop;ok
+meta time "2019-07-01 00:00:00" drop;ok
+meta time "2019-07-01 00:01:00" drop;ok
+meta time "2019-07-01 00:00:01" drop;ok
+meta time < "2022-07-01 11:00:00" accept;ok
+meta time > "2022-07-01 11:00:00" accept;ok
+meta day "Saturday" drop;ok
+meta day 6 drop;ok;meta day "Saturday" drop
+meta day "Satturday" drop;fail
+meta hour "17:00" drop;ok
+meta hour "17:00:00" drop;ok;meta hour "17:00" drop
+meta hour "17:00:01" drop;ok
+meta hour "00:00" drop;ok
+meta hour "00:01" drop;ok
+time < "2022-07-01 11:00:00" accept;ok;meta time < "2022-07-01 11:00:00" accept
+time > "2022-07-01 11:00:00" accept;ok;meta time > "2022-07-01 11:00:00" accept
+
+meta time "meh";fail
+meta hour "24:00" drop;fail
+meta day 7 drop;fail
diff --git a/tests/py/any/meta.t.json b/tests/py/any/meta.t.json
new file mode 100644
index 0000000..4734bbf
--- /dev/null
+++ b/tests/py/any/meta.t.json
@@ -0,0 +1,2760 @@
+# meta length 1000
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": 1000
+ }
+ }
+]
+
+# meta length 22
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# meta length != 233
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# meta length 33-45
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# meta length != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# meta length { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# meta length { 33-55, 67-88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 67, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta length { 33-55, 56-88, 100-120}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 88 ] },
+ { "range": [ 100, 120 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta length != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# meta length { 33-55, 66-88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 66, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta length != { 33-55, 66-88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "length" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 66, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta protocol { ip, arp, ip6, vlan }
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "protocol" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "ip",
+ "arp",
+ "ip6",
+ "vlan"
+ ]
+ }
+ }
+ }
+]
+
+# meta protocol != {ip, arp, ip6, 8021q}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "protocol" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "ip",
+ "arp",
+ "ip6",
+ "8021q"
+ ]
+ }
+ }
+ }
+]
+
+# meta protocol ip
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "protocol" }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ }
+]
+
+# meta protocol != ip
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "protocol" }
+ },
+ "op": "!=",
+ "right": "ip"
+ }
+ }
+]
+
+# meta l4proto 22
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# meta l4proto != 233
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "!=",
+ "right": 233
+ }
+ }
+]
+
+# meta l4proto 33-45
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# meta l4proto != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 33, 45 ]
+ }
+ }
+ }
+]
+
+# meta l4proto { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# meta l4proto != { 33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# meta l4proto { 33-55, 66-88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 66, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta l4proto != { 33-55, 66-88}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 33, 55 ] },
+ { "range": [ 66, 88 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta priority root
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "root"
+ }
+ }
+]
+
+# meta priority none
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "none"
+ }
+ }
+]
+
+# meta priority 0x87654321
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "0x87654321"
+ }
+ }
+]
+
+# meta priority 2271560481
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": 2271560481
+ }
+ }
+]
+
+# meta priority 1:1234
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "1:1234"
+ }
+ }
+]
+
+# meta priority bcad:dadc
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "bcad:dadc"
+ }
+ }
+]
+
+# meta priority aabb:0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "aabb:0"
+ }
+ }
+]
+
+# meta priority != bcad:dadc
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "!=",
+ "right": "bcad:dadc"
+ }
+ }
+]
+
+# meta priority != aabb:0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "!=",
+ "right": "aabb:0"
+ }
+ }
+]
+
+# meta priority bcad:dada-bcad:dadc
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ "bcad:dada", "bcad:dadc" ]
+ }
+ }
+ }
+]
+
+# meta priority != bcad:dada-bcad:dadc
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ "bcad:dada", "bcad:dadc" ]
+ }
+ }
+ }
+]
+
+# meta priority {bcad:dada, bcad:dadc, aaaa:bbbb}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "bcad:dada",
+ "bcad:dadc",
+ "aaaa:bbbb"
+ ]
+ }
+ }
+ }
+]
+
+# meta priority set cafe:beef
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "priority" }
+ },
+ "value": "cafe:beef"
+ }
+ }
+]
+
+# meta priority != {bcad:dada, bcad:dadc, aaaa:bbbb}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "aaaa:bbbb",
+ "bcad:dada",
+ "bcad:dadc"
+ ]
+ }
+ }
+ }
+]
+
+# meta mark 0x4
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": "0x4"
+ }
+ }
+]
+
+# meta mark 0x32
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": "0x32"
+ }
+ }
+]
+
+# meta mark and 0x03 == 0x01
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "meta": { "key": "mark" }
+ },
+ "0x03"
+ ]
+ },
+ "op": "==",
+ "right": "0x01"
+ }
+ }
+]
+
+# meta mark and 0x03 != 0x01
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "meta": { "key": "mark" }
+ },
+ "0x03"
+ ]
+ },
+ "op": "!=",
+ "right": "0x01"
+ }
+ }
+]
+
+# meta mark 0x10
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": "0x10"
+ }
+ }
+]
+
+# meta mark != 0x10
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "!=",
+ "right": "0x10"
+ }
+ }
+]
+
+# meta mark 0xffffff00/24
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": 4294967040,
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# meta mark or 0x03 == 0x01
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "meta": { "key": "mark" }
+ },
+ "0x03"
+ ]
+ },
+ "op": "==",
+ "right": "0x01"
+ }
+ }
+]
+
+# meta mark or 0x03 != 0x01
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "meta": { "key": "mark" }
+ },
+ "0x03"
+ ]
+ },
+ "op": "!=",
+ "right": "0x01"
+ }
+ }
+]
+
+# meta mark xor 0x03 == 0x01
+[
+ {
+ "match": {
+ "left": {
+ "^": [
+ {
+ "meta": { "key": "mark" }
+ },
+ "0x03"
+ ]
+ },
+ "op": "==",
+ "right": "0x01"
+ }
+ }
+]
+
+# meta mark xor 0x03 != 0x01
+[
+ {
+ "match": {
+ "left": {
+ "^": [
+ {
+ "meta": { "key": "mark" }
+ },
+ "0x03"
+ ]
+ },
+ "op": "!=",
+ "right": "0x01"
+ }
+ }
+]
+
+# meta iif "lo" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta iif != "lo" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "!=",
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta iifname "dummy0"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "dummy0"
+ }
+ }
+]
+
+# meta iifname != "dummy0"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "!=",
+ "right": "dummy0"
+ }
+ }
+]
+
+# meta iifname {"dummy0", "lo"}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "dummy0",
+ "lo"
+ ]
+ }
+ }
+ }
+]
+
+# meta iifname != {"dummy0", "lo"}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "dummy0",
+ "lo"
+ ]
+ }
+ }
+ }
+]
+
+# meta iifname "dummy*"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "dummy*"
+ }
+ }
+]
+
+# meta iifname "dummy\*"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": "dummy\\*"
+ }
+ }
+]
+
+# meta iiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "ether",
+ "ppp",
+ "ipip",
+ "ipip6",
+ "loopback",
+ "sit",
+ "ipgre"
+ ]
+ }
+ }
+ }
+]
+
+# meta iiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "ether",
+ "ppp",
+ "ipip",
+ "ipip6",
+ "loopback",
+ "sit",
+ "ipgre"
+ ]
+ }
+ }
+ }
+]
+
+# meta iiftype != ether
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "!=",
+ "right": "ether"
+ }
+ }
+]
+
+# meta iiftype ether
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "==",
+ "right": "ether"
+ }
+ }
+]
+
+# meta iiftype != ppp
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "!=",
+ "right": "ppp"
+ }
+ }
+]
+
+# meta iiftype ppp
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iiftype" }
+ },
+ "op": "==",
+ "right": "ppp"
+ }
+ }
+]
+
+# meta oif "lo" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta oif != "lo" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oif" }
+ },
+ "op": "!=",
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta oifname "dummy0"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "==",
+ "right": "dummy0"
+ }
+ }
+]
+
+# meta oifname != "dummy0"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "!=",
+ "right": "dummy0"
+ }
+ }
+]
+
+# meta oifname { "dummy0", "lo"}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "dummy0",
+ "lo"
+ ]
+ }
+ }
+ }
+]
+
+# meta oifname "dummy*"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "==",
+ "right": "dummy*"
+ }
+ }
+]
+
+# meta oifname "dummy\*"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "==",
+ "right": "dummy\\*"
+ }
+ }
+]
+
+# meta oiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oiftype" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "ether",
+ "ppp",
+ "ipip",
+ "ipip6",
+ "loopback",
+ "sit",
+ "ipgre"
+ ]
+ }
+ }
+ }
+]
+
+# meta oiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oiftype" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "ether",
+ "ppp",
+ "ipip",
+ "ipip6",
+ "loopback",
+ "sit",
+ "ipgre"
+ ]
+ }
+ }
+ }
+]
+
+# meta oiftype != ether
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oiftype" }
+ },
+ "op": "!=",
+ "right": "ether"
+ }
+ }
+]
+
+# meta oiftype ether
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oiftype" }
+ },
+ "op": "==",
+ "right": "ether"
+ }
+ }
+]
+
+# meta skuid {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "bin",
+ "root",
+ "daemon"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid != {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "bin",
+ "root",
+ "daemon"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": "root"
+ }
+ }
+]
+
+# meta skuid != "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "!=",
+ "right": "root"
+ }
+ }
+]
+
+# meta skuid lt 3000 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "<",
+ "right": 3000
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid gt 3000 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": ">",
+ "right": 3000
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid eq 3000 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": 3000
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid 3001-3005 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 3001, 3005 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid != 2001-2005 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 2001, 2005 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid { 2001-2005, 3001-3005} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 2001, 2005 ] },
+ { "range": [ 3001, 3005 ] }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid != { 2001-2005, 3001-3005} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 2001, 2005 ] },
+ { "range": [ 3001, 3005 ] }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "bin",
+ "root",
+ "daemon"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid != {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "bin",
+ "root",
+ "daemon"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": "root"
+ }
+ }
+]
+
+# meta skgid != "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "!=",
+ "right": "root"
+ }
+ }
+]
+
+# meta skgid lt 3000 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "<",
+ "right": 3000
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid gt 3000 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": ">",
+ "right": 3000
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid eq 3000 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": 3000
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid 2001-2005 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 2001, 2005 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid != 2001-2005 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 2001, 2005 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta mark set 0xffffffc8 xor 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "^": [ "0xffffffc8", "0x16" ] }
+ }
+ }
+]
+
+# meta mark set 0x16 and 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "&": [ "0x16", "0x16" ] }
+ }
+ }
+]
+
+# meta mark set 0xffffffe9 or 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "|": [ "0xffffffe9", "0x16" ] }
+ }
+ }
+]
+
+# meta mark set 0xffffffde and 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "&": [ "0xffffffde", "0x16" ] }
+ }
+ }
+]
+
+# meta mark set 0xf045ffde or 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "|": [ "0xf045ffde", "0x10" ] }
+ }
+ }
+]
+
+# meta mark set 0xffffffde or 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "|": [ "0xffffffde", "0x16" ] }
+ }
+ }
+]
+
+# meta mark set 0x32 or 0xfffff
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "|": [ "0x32", "0xfffff" ] }
+ }
+ }
+]
+
+# meta mark set 0xfffe xor 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": { "^": [ "0xfffe", "0x16" ] }
+ }
+ }
+]
+
+# meta iif "lo"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ }
+]
+
+# meta oif "lo"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oif" }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ }
+]
+
+# meta oifname "dummy2" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "==",
+ "right": "dummy2"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid 3000
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": 3000
+ }
+ }
+]
+
+# meta skgid 3000
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": 3000
+ }
+ }
+]
+
+# meta rtclassid "cosmos"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "rtclassid" }
+ },
+ "op": "==",
+ "right": "cosmos"
+ }
+ }
+]
+
+# meta pkttype broadcast
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "==",
+ "right": "broadcast"
+ }
+ }
+]
+
+# meta pkttype host
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "==",
+ "right": "host"
+ }
+ }
+]
+
+# meta pkttype multicast
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "==",
+ "right": "multicast"
+ }
+ }
+]
+
+# meta pkttype != broadcast
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "!=",
+ "right": "broadcast"
+ }
+ }
+]
+
+# meta pkttype != host
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "!=",
+ "right": "host"
+ }
+ }
+]
+
+# meta pkttype != multicast
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "!=",
+ "right": "multicast"
+ }
+ }
+]
+
+# pkttype { broadcast, multicast} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "pkttype" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "broadcast",
+ "multicast"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta cpu 1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# meta cpu != 1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# meta cpu 1-3
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 1, 3 ]
+ }
+ }
+ }
+]
+
+# meta cpu != 1-2
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 1, 2 ]
+ }
+ }
+ }
+]
+
+# meta cpu { 2,3}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 2,
+ 3
+ ]
+ }
+ }
+ }
+]
+
+# meta cpu { 2-3, 5-7}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 2, 3 ] },
+ { "range": [ 5, 7 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta cpu != { 2,3}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cpu" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 2,
+ 3
+ ]
+ }
+ }
+ }
+]
+
+# meta iifgroup 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# meta iifgroup != 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "!=",
+ "right": 0
+ }
+ }
+]
+
+# meta iifgroup "default"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "==",
+ "right": "default"
+ }
+ }
+]
+
+# meta iifgroup != "default"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "!=",
+ "right": "default"
+ }
+ }
+]
+
+# meta iifgroup {"default", 11}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "default",
+ 11
+ ]
+ }
+ }
+ }
+]
+
+# meta iifgroup != {"default", 11}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "default",
+ 11
+ ]
+ }
+ }
+ }
+]
+
+# meta iifgroup { 11,33}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 11,
+ 33
+ ]
+ }
+ }
+ }
+]
+
+# meta iifgroup {11-33, 44-55}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 11, 33 ] },
+ { "range": [ 44, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta iifgroup != { 11,33}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 11,
+ 33
+ ]
+ }
+ }
+ }
+]
+
+# meta iifgroup != {11-33, 44-55}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 11, 33 ] },
+ { "range": [ 44, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta oifgroup 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# meta oifgroup != 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "!=",
+ "right": 0
+ }
+ }
+]
+
+# meta oifgroup "default"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "==",
+ "right": "default"
+ }
+ }
+]
+
+# meta oifgroup != "default"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "!=",
+ "right": "default"
+ }
+ }
+]
+
+# meta oifgroup {"default", 11}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "default",
+ 11
+ ]
+ }
+ }
+ }
+]
+
+# meta oifgroup != {"default", 11}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "default",
+ 11
+ ]
+ }
+ }
+ }
+]
+
+# meta oifgroup { 11,33}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 11,
+ 33
+ ]
+ }
+ }
+ }
+]
+
+# meta oifgroup {11-33, 44-55}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ { "range": [ 11, 33 ] },
+ { "range": [ 44, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta oifgroup != { 11,33}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 11,
+ 33
+ ]
+ }
+ }
+ }
+]
+
+# meta oifgroup != {11-33, 44-55}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ { "range": [ 11, 33 ] },
+ { "range": [ 44, 55 ] }
+ ]
+ }
+ }
+ }
+]
+
+# meta cgroup 1048577
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "==",
+ "right": 1048577
+ }
+ }
+]
+
+# meta cgroup != 1048577
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "!=",
+ "right": 1048577
+ }
+ }
+]
+
+# meta cgroup { 1048577, 1048578 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 1048577,
+ 1048578
+ ]
+ }
+ }
+ }
+]
+
+# meta cgroup != { 1048577, 1048578}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 1048577,
+ 1048578
+ ]
+ }
+ }
+ }
+]
+
+# meta cgroup 1048577-1048578
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "==",
+ "right": {
+ "range": [ 1048577, 1048578 ]
+ }
+ }
+ }
+]
+
+# meta cgroup != 1048577-1048578
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "range": [ 1048577, 1048578 ]
+ }
+ }
+ }
+]
+
+# meta cgroup {1048577-1048578}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "range": [ 1048577, 1048578 ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# meta cgroup != { 1048577-1048578}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "cgroup" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ {
+ "range": [ 1048577, 1048578 ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# meta iif . meta oif { "lo" . "lo" }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "meta": { "key": "iif" }
+ },
+ {
+ "meta": { "key": "oif" }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "lo",
+ "lo"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# meta iif . meta oif . meta mark { "lo" . "lo" . 0x0000000a }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "meta": { "key": "iif" }
+ },
+ {
+ "meta": { "key": "oif" }
+ },
+ {
+ "meta": { "key": "mark" }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "lo",
+ "lo",
+ "0x0000000a"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# meta iif . meta oif vmap { "lo" . "lo" : drop }
+[
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "meta": { "key": "iif" }
+ },
+ {
+ "meta": { "key": "oif" }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "lo",
+ "lo"
+ ]
+ },
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+]
+
+# meta random eq 1
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "random" }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# meta random gt 1000000
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "random" }
+ },
+ "op": ">",
+ "right": 1000000
+ }
+ }
+]
+
+# meta time "1970-05-23 21:07:14" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "1970-05-23 21:07:14"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time 12341234 drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "12341234"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-06-21 17:00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-06-21 17:00:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-07-01 00:00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-07-01 00:00:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-07-01 00:01:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-07-01 00:01:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-07-01 00:00:01" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-07-01 00:00:01"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time < "2022-07-01 11:00:00" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "<",
+ "right": "2022-07-01 11:00:00"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta time > "2022-07-01 11:00:00" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": ">",
+ "right": "2022-07-01 11:00:00"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta day "Saturday" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "day"
+ }
+ },
+ "op": "==",
+ "right": "Saturday"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta day 6 drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "day"
+ }
+ },
+ "op": "==",
+ "right": "6"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "17:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "17:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "17:00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "17:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "17:00:01" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "17:00:01"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "00:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "00:01" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "00:01"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# time < "2022-07-01 11:00:00" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "<",
+ "right": "2022-07-01 11:00:00"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# time > "2022-07-01 11:00:00" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": ">",
+ "right": "2022-07-01 11:00:00"
+ }
+ },
+ {
+ "accept": null
+ }
+]
diff --git a/tests/py/any/meta.t.json.output b/tests/py/any/meta.t.json.output
new file mode 100644
index 0000000..4e9e669
--- /dev/null
+++ b/tests/py/any/meta.t.json.output
@@ -0,0 +1,828 @@
+# meta protocol { ip, arp, ip6, vlan }
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "protocol" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "ip",
+ "arp",
+ "8021q",
+ "ip6"
+ ]
+ }
+ }
+ }
+]
+
+# meta protocol != {ip, arp, ip6, 8021q}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "protocol" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "ip",
+ "arp",
+ "8021q",
+ "ip6"
+ ]
+ }
+ }
+ }
+]
+
+# meta priority 0x87654321
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "8765:4321"
+ }
+ }
+]
+
+# meta priority 2271560481
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": "8765:4321"
+ }
+ }
+]
+
+# meta priority {bcad:dada, bcad:dadc, aaaa:bbbb}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "priority" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "aaaa:bbbb",
+ "bcad:dada",
+ "bcad:dadc"
+ ]
+ }
+ }
+ }
+]
+
+# meta mark 0x4
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 4
+ }
+ }
+]
+
+# meta mark 0x32
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 50
+ }
+ }
+]
+
+# meta mark and 0x03 == 0x01
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "meta": { "key": "mark" }
+ },
+ 3
+ ]
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# meta mark and 0x03 != 0x01
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "meta": { "key": "mark" }
+ },
+ 3
+ ]
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# meta mark 0x10
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 16
+ }
+ }
+]
+
+# meta mark != 0x10
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "!=",
+ "right": 16
+ }
+ }
+]
+
+# meta mark or 0x03 == 0x01
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "meta": { "key": "mark" }
+ },
+ 3
+ ]
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# meta mark or 0x03 != 0x01
+[
+ {
+ "match": {
+ "left": {
+ "|": [
+ {
+ "meta": { "key": "mark" }
+ },
+ 3
+ ]
+ },
+ "op": "!=",
+ "right": 1
+ }
+ }
+]
+
+# meta mark xor 0x03 == 0x01
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# meta mark xor 0x03 != 0x01
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "mark" }
+ },
+ "op": "!=",
+ "right": 2
+ }
+ }
+]
+
+# meta iifname {"dummy0", "lo"}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "lo",
+ "dummy0"
+ ]
+ }
+ }
+ }
+]
+
+# meta iifname != {"dummy0", "lo"}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifname" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ "lo",
+ "dummy0"
+ ]
+ }
+ }
+ }
+]
+
+# meta oifname { "dummy0", "lo"}
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifname" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "lo",
+ "dummy0"
+ ]
+ }
+ }
+ }
+]
+
+# meta skuid {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": {
+ "set": [ 0, 1, 2 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid != {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [ 0, 1, 2 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skuid "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# meta skuid != "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skuid" }
+ },
+ "op": "!=",
+ "right": 0
+ }
+ }
+]
+
+# meta skgid {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": {
+ "set": [ 0, 1, 2 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid != {"bin", "root", "daemon"} accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "!=",
+ "right": {
+ "set": [ 0, 1, 2 ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta skgid "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# meta skgid != "root"
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "skgid" }
+ },
+ "op": "!=",
+ "right": 0
+ }
+ }
+]
+
+# meta mark set 0xffffffc8 xor 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 4294967262
+ }
+ }
+]
+
+# meta mark set 0x16 and 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 22
+ }
+ }
+]
+
+# meta mark set 0xffffffe9 or 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 4294967295
+ }
+ }
+]
+
+# meta mark set 0xffffffde and 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 22
+ }
+ }
+]
+
+# meta mark set 0xf045ffde or 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 4031119326
+ }
+ }
+]
+
+# meta mark set 0xffffffde or 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 4294967262
+ }
+ }
+]
+
+# meta mark set 0x32 or 0xfffff
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 1048575
+ }
+ }
+]
+
+# meta mark set 0xfffe xor 0x16
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "mark" }
+ },
+ "value": 65512
+ }
+ }
+]
+
+# meta iifgroup 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "==",
+ "right": "default"
+ }
+ }
+]
+
+# meta iifgroup != 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "iifgroup" }
+ },
+ "op": "!=",
+ "right": "default"
+ }
+ }
+]
+
+# meta oifgroup 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "==",
+ "right": "default"
+ }
+ }
+]
+
+# meta oifgroup != 0
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "oifgroup" }
+ },
+ "op": "!=",
+ "right": "default"
+ }
+ }
+]
+
+# meta iif . meta oif . meta mark { "lo" . "lo" . 0x0000000a }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "meta": { "key": "iif" }
+ },
+ {
+ "meta": { "key": "oif" }
+ },
+ {
+ "meta": { "key": "mark" }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "lo",
+ "lo",
+ 10
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# meta time "1970-05-23 21:07:14" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "1970-05-23 21:07:14"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time 12341234 drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "1970-05-23 22:07:14"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-06-21 17:00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-06-21 17:00:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-07-01 00:00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-07-01 00:00:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-07-01 00:01:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-07-01 00:01:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta time "2019-07-01 00:00:01" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "time"
+ }
+ },
+ "op": "==",
+ "right": "2019-07-01 00:00:01"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta day "Saturday" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "day"
+ }
+ },
+ "op": "==",
+ "right": "Saturday"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta day 6 drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "day"
+ }
+ },
+ "op": "==",
+ "right": "Saturday"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "17:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "17:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "17:00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "17:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "17:00:01" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "17:00:01"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "00:00" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "00:00"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# meta hour "00:01" drop
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "hour"
+ }
+ },
+ "op": "==",
+ "right": "00:01"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
diff --git a/tests/py/any/meta.t.payload b/tests/py/any/meta.t.payload
new file mode 100644
index 0000000..16dc121
--- /dev/null
+++ b/tests/py/any/meta.t.payload
@@ -0,0 +1,1074 @@
+# meta length 1000
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ cmp eq reg 1 0x000003e8 ]
+
+# meta length 22
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# meta length != 233
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# meta length 33-45
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0x21000000 ]
+ [ cmp lte reg 1 0x2d000000 ]
+
+# meta length != 33-45
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0x21000000 0x2d000000 ]
+
+# meta length { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta length { 33-55, 67-88}
+__set%d test-ip4 7
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end] element 43000000 : 0 [end] element 59000000 : 1 [end]
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# meta length { 33-55, 56-88, 100-120}
+__set%d test-ip4 7
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 21000000 : 0 [end] element 59000000 : 1 [end] element 64000000 : 0 [end] element 79000000 : 1 [end]
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# meta length != { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta protocol { ip, arp, ip6, vlan }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000608 : 0 [end] element 0000dd86 : 0 [end] element 00000081 : 0 [end]
+ip test-ip4 input
+ [ meta load protocol => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta protocol != {ip, arp, ip6, 8021q}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000608 : 0 [end] element 0000dd86 : 0 [end] element 00000081 : 0 [end]
+ip test-ip4 input
+ [ meta load protocol => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta protocol ip
+ip test-ip4 input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# meta protocol != ip
+ip test-ip4 input
+ [ meta load protocol => reg 1 ]
+ [ cmp neq reg 1 0x00000008 ]
+
+# meta l4proto 22
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# meta l4proto != 233
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# meta l4proto 33-45
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# meta l4proto != 33-45
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# meta l4proto { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta l4proto != { 33, 55, 67, 88}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta mark 0x4
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+
+# meta mark 0x32
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# meta mark and 0x03 == 0x01
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta mark and 0x03 != 0x01
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# meta mark 0x10
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000010 ]
+
+# meta mark != 0x10
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ cmp neq reg 1 0x00000010 ]
+
+# meta mark 0xffffff00/24
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffff00 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0xffffff00 ]
+
+# meta mark or 0x03 == 0x01
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffc ) ^ 0x00000003 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta mark or 0x03 != 0x01
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffc ) ^ 0x00000003 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# meta mark xor 0x03 == 0x01
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# meta mark xor 0x03 != 0x01
+ip test-ip4 input
+ [ meta load mark => reg 1 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# meta iif "lo" accept
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# meta iif != "lo" accept
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# meta iifname "dummy0"
+ip test-ip4 input
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00003079 0x00000000 0x00000000 ]
+
+# meta iifname != "dummy0"
+ip test-ip4 input
+ [ meta load iifname => reg 1 ]
+ [ cmp neq reg 1 0x6d6d7564 0x00003079 0x00000000 0x00000000 ]
+
+# meta iifname {"dummy0", "lo"}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 6d6d7564 00003079 00000000 00000000 : 0 [end] element 00006f6c 00000000 00000000 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load iifname => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iifname != {"dummy0", "lo"}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 6d6d7564 00003079 00000000 00000000 : 0 [end] element 00006f6c 00000000 00000000 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load iifname => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta iifname "dummy*"
+ip test-ip4 input
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00000079 ]
+
+# meta iifname "dummy\*"
+ip test-ip4 input
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00002a79 0x00000000 0x00000000 ]
+
+# meta iiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000200 : 0 [end] element 00000300 : 0 [end] element 00000301 : 0 [end] element 00000304 : 0 [end] element 00000308 : 0 [end] element 0000030a : 0 [end]
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000200 : 0 [end] element 00000300 : 0 [end] element 00000301 : 0 [end] element 00000304 : 0 [end] element 00000308 : 0 [end] element 0000030a : 0 [end]
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta iiftype != ether
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# meta iiftype ether
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta iiftype != ppp
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ cmp neq reg 1 0x00000200 ]
+
+# meta iiftype ppp
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# meta oif "lo" accept
+ip test-ip4 input
+ [ meta load oif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# meta oif != "lo" accept
+ip test-ip4 input
+ [ meta load oif => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# meta oifname "dummy0"
+ip test-ip4 input
+ [ meta load oifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00003079 0x00000000 0x00000000 ]
+
+# meta oifname != "dummy0"
+ip test-ip4 input
+ [ meta load oifname => reg 1 ]
+ [ cmp neq reg 1 0x6d6d7564 0x00003079 0x00000000 0x00000000 ]
+
+# meta oifname { "dummy0", "lo"}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 6d6d7564 00003079 00000000 00000000 : 0 [end] element 00006f6c 00000000 00000000 00000000 : 0 [end]
+ip test-ip4 input
+ [ meta load oifname => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta oifname "dummy*"
+ip test-ip4 input
+ [ meta load oifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00000079 ]
+
+# meta oifname "dummy\*"
+ip test-ip4 input
+ [ meta load oifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00002a79 0x00000000 0x00000000 ]
+
+# meta oiftype {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000200 : 0 [end] element 00000300 : 0 [end] element 00000301 : 0 [end] element 00000304 : 0 [end] element 00000308 : 0 [end] element 0000030a : 0 [end]
+ip test-ip4 input
+ [ meta load oiftype => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta oiftype != {ether, ppp, ipip, ipip6, loopback, sit, ipgre}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000200 : 0 [end] element 00000300 : 0 [end] element 00000301 : 0 [end] element 00000304 : 0 [end] element 00000308 : 0 [end] element 0000030a : 0 [end]
+ip test-ip4 input
+ [ meta load oiftype => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta oiftype != ether
+ip test-ip4 input
+ [ meta load oiftype => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# meta oiftype ether
+ip test-ip4 input
+ [ meta load oiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta skuid {"bin", "root", "daemon"} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000000 : 0 [end] element 00000002 : 0 [end]
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# meta skuid != {"bin", "root", "daemon"} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000000 : 0 [end] element 00000002 : 0 [end]
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# meta skuid "root"
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta skuid != "root"
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta skuid lt 3000 accept
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp lt reg 1 0xb80b0000 ]
+ [ immediate reg 0 accept ]
+
+# meta skuid gt 3000 accept
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gt reg 1 0xb80b0000 ]
+ [ immediate reg 0 accept ]
+
+# meta skuid eq 3000 accept
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ cmp eq reg 1 0x00000bb8 ]
+ [ immediate reg 0 accept ]
+
+# meta skuid 3001-3005 accept
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0xb90b0000 ]
+ [ cmp lte reg 1 0xbd0b0000 ]
+ [ immediate reg 0 accept ]
+
+# meta skuid != 2001-2005 accept
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0xd1070000 0xd5070000 ]
+ [ immediate reg 0 accept ]
+
+# meta skgid {"bin", "root", "daemon"} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000000 : 0 [end] element 00000002 : 0 [end]
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# meta skgid != {"bin", "root", "daemon"} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000000 : 0 [end] element 00000002 : 0 [end]
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# meta skgid "root"
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta skgid != "root"
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta skgid lt 3000 accept
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp lt reg 1 0xb80b0000 ]
+ [ immediate reg 0 accept ]
+
+# meta skgid gt 3000 accept
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gt reg 1 0xb80b0000 ]
+ [ immediate reg 0 accept ]
+
+# meta skgid eq 3000 accept
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ cmp eq reg 1 0x00000bb8 ]
+ [ immediate reg 0 accept ]
+
+# meta skgid 2001-2005 accept
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0xd1070000 ]
+ [ cmp lte reg 1 0xd5070000 ]
+ [ immediate reg 0 accept ]
+
+# meta skgid != 2001-2005 accept
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0xd1070000 0xd5070000 ]
+ [ immediate reg 0 accept ]
+
+# meta mark set 0xffffffc8 xor 0x16
+ip test-ip4 input
+ [ immediate reg 1 0xffffffde ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0x16 and 0x16
+ip test-ip4 input
+ [ immediate reg 1 0x00000016 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0xffffffe9 or 0x16
+ip test-ip4 input
+ [ immediate reg 1 0xffffffff ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0xffffffde and 0x16
+ip test-ip4 input
+ [ immediate reg 1 0x00000016 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0xf045ffde or 0x10
+ip test-ip4 input
+ [ immediate reg 1 0xf045ffde ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0xffffffde or 0x16
+ip test-ip4 input
+ [ immediate reg 1 0xffffffde ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0x32 or 0xfffff
+ip test-ip4 input
+ [ immediate reg 1 0x000fffff ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set 0xfffe xor 0x16
+ip test-ip4 input
+ [ immediate reg 1 0x0000ffe8 ]
+ [ meta set mark with reg 1 ]
+
+# meta iif "lo"
+ip test-ip4 input
+ [ meta load iif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta oif "lo"
+ip test-ip4 input
+ [ meta load oif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta oifname "dummy2" accept
+ip test-ip4 input
+ [ meta load oifname => reg 1 ]
+ [ cmp eq reg 1 0x6d6d7564 0x00003279 0x00000000 0x00000000 ]
+ [ immediate reg 0 accept ]
+
+# meta skuid 3000
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ cmp eq reg 1 0x00000bb8 ]
+
+# meta skgid 3000
+ip test-ip4 input
+ [ meta load skgid => reg 1 ]
+ [ cmp eq reg 1 0x00000bb8 ]
+
+# meta rtclassid "cosmos"
+ip test-ip4 input
+ [ meta load rtclassid => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta pkttype broadcast
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta pkttype host
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta pkttype multicast
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# meta pkttype != broadcast
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# meta pkttype != host
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta pkttype != multicast
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# pkttype { broadcast, multicast} accept
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 : 0 [end] element 00000002 : 0 [end]
+ip test-ip4 input
+ [ meta load pkttype => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# meta cpu 1
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# meta cpu != 1
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# meta cpu 1-3
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0x01000000 ]
+ [ cmp lte reg 1 0x03000000 ]
+
+# meta cpu != 1-2
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0x01000000 0x02000000 ]
+
+# meta cpu { 2,3}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000002 : 0 [end] element 00000003 : 0 [end]
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta cpu != { 2,3}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000002 : 0 [end] element 00000003 : 0 [end]
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta cpu { 2-3, 5-7}
+__set%d test-ip4 7
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 02000000 : 0 [end] element 04000000 : 1 [end] element 05000000 : 0 [end] element 08000000 : 1 [end]
+ip test-ip4 input
+ [ meta load cpu => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iifgroup 0
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta iifgroup != 0
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta iifgroup "default"
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta iifgroup != "default"
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta iifgroup { 11,33}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 0000000b : 0 [end] element 00000021 : 0 [end]
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta oifgroup 0
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta oifgroup != 0
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta oifgroup "default"
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta oifgroup != "default"
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# meta oifgroup { 11,33}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 0000000b : 0 [end] element 00000021 : 0 [end]
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta cgroup 1048577
+ip test-ip4 input
+ [ meta load cgroup => reg 1 ]
+ [ cmp eq reg 1 0x00100001 ]
+
+# meta cgroup != 1048577
+ip test-ip4 input
+ [ meta load cgroup => reg 1 ]
+ [ cmp neq reg 1 0x00100001 ]
+
+# meta cgroup { 1048577, 1048578 }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00100001 : 0 [end] element 00100002 : 0 [end]
+ip test-ip4 input
+ [ meta load cgroup => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta cgroup != { 1048577, 1048578}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00100001 : 0 [end] element 00100002 : 0 [end]
+ip test-ip4 input
+ [ meta load cgroup => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta cgroup 1048577-1048578
+ip test-ip4 input
+ [ meta load cgroup => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0x01001000 ]
+ [ cmp lte reg 1 0x02001000 ]
+
+# meta cgroup != 1048577-1048578
+ip test-ip4 input
+ [ meta load cgroup => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0x01001000 0x02001000 ]
+
+# meta iif . meta oif { "lo" . "lo" }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 00000001 : 0 [end]
+ip test-ip4 output
+ [ meta load iif => reg 1 ]
+ [ meta load oif => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iif . meta oif . meta mark { "lo" . "lo" . 0x0000000a }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000001 00000001 0000000a : 0 [end]
+ip test-ip4 output
+ [ meta load iif => reg 1 ]
+ [ meta load oif => reg 9 ]
+ [ meta load mark => reg 10 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iif . meta oif vmap { "lo" . "lo" : drop }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 00000001 00000001 : drop 0 [end]
+ip test-ip4 output
+ [ meta load iif => reg 1 ]
+ [ meta load oif => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# meta random eq 1
+ip test-ip4 input
+ [ meta load prandom => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# meta random gt 1000000
+ip test-ip4 input
+ [ meta load prandom => reg 1 ]
+ [ cmp gt reg 1 0x40420f00 ]
+
+# meta priority root
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0xffffffff ]
+
+# meta priority none
+netdev test-netdev ingress
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# meta priority 1:1234
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0x00011234 ]
+
+# meta priority bcad:dadc
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0xbcaddadc ]
+
+# meta priority aabb:0
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0xaabb0000 ]
+
+# meta priority != bcad:dadc
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp neq reg 1 0xbcaddadc ]
+
+# meta priority != aabb:0
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp neq reg 1 0xaabb0000 ]
+
+# meta priority bcad:dada-bcad:dadc
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ cmp gte reg 1 0xdadaadbc ]
+ [ cmp lte reg 1 0xdcdaadbc ]
+
+# meta priority != bcad:dada-bcad:dadc
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ range neq reg 1 0xdadaadbc 0xdcdaadbc ]
+
+# meta priority {bcad:dada, bcad:dadc, aaaa:bbbb}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element bcaddada : 0 [end] element bcaddadc : 0 [end] element aaaabbbb : 0 [end]
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta priority set cafe:beef
+ip test-ip4 input
+ [ immediate reg 1 0xcafebeef ]
+ [ meta set priority with reg 1 ]
+
+# meta priority != {bcad:dada, bcad:dadc, aaaa:bbbb}
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element bcaddada : 0 [end] element bcaddadc : 0 [end] element aaaabbbb : 0 [end]
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta priority 0x87654321
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0x87654321 ]
+
+# meta priority 2271560481
+ip test-ip4 input
+ [ meta load priority => reg 1 ]
+ [ cmp eq reg 1 0x87654321 ]
+
+# meta length { 33-55, 66-88}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end] element 42000000 : 0 [end] element 59000000 : 1 [end]
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# meta length != { 33-55, 66-88}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end] element 42000000 : 0 [end] element 59000000 : 1 [end]
+ip test-ip4 input
+ [ meta load len => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta l4proto { 33-55, 66-88}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end] element 00000042 : 0 [end] element 00000059 : 1 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta l4proto != { 33-55, 66-88}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end] element 00000042 : 0 [end] element 00000059 : 1 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta skuid { 2001-2005, 3001-3005} accept
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element d1070000 : 0 [end] element d6070000 : 1 [end] element b90b0000 : 0 [end] element be0b0000 : 1 [end]
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
+# meta iifgroup {"default", 11}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 0000000b : 0 [end]
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iifgroup != {"default", 11}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 0000000b : 0 [end]
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta iifgroup {11-33, 44-55}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 0b000000 : 0 [end] element 22000000 : 1 [end] element 2c000000 : 0 [end] element 38000000 : 1 [end]
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# meta iifgroup != { 11,33}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 0000000b : 0 [end] element 00000021 : 0 [end]
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta iifgroup != {11-33, 44-55}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 0b000000 : 0 [end] element 22000000 : 1 [end] element 2c000000 : 0 [end] element 38000000 : 1 [end]
+ip test-ip4 input
+ [ meta load iifgroup => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta oifgroup {"default", 11}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 0000000b : 0 [end]
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta oifgroup {11-33, 44-55}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 0b000000 : 0 [end] element 22000000 : 1 [end] element 2c000000 : 0 [end] element 38000000 : 1 [end]
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# meta oifgroup != { 11,33}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 0000000b : 0 [end] element 00000021 : 0 [end]
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta oifgroup != {11-33, 44-55}
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element 0b000000 : 0 [end] element 22000000 : 1 [end] element 2c000000 : 0 [end] element 38000000 : 1 [end]
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta skuid != { 2001-2005, 3001-3005} accept
+__set%d test-ip4 7 size 5
+__set%d test-ip4 0
+ element 00000000 : 1 [end] element d1070000 : 0 [end] element d6070000 : 1 [end] element b90b0000 : 0 [end] element be0b0000 : 1 [end]
+ip test-ip4 input
+ [ meta load skuid => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ lookup reg 1 set __set%d 0x1 ]
+ [ immediate reg 0 accept ]
+
+# meta oifgroup != {"default", 11}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 00000000 : 0 [end] element 0000000b : 0 [end]
+ip test-ip4 input
+ [ meta load oifgroup => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# meta time "1970-05-23 21:07:14" drop
+ip meta-test input
+ [ meta load time => reg 1 ]
+ [ cmp eq reg 1 0x43f05400 0x002bd503 ]
+ [ immediate reg 0 drop ]
+
+# meta time 12341234 drop
+ip meta-test input
+ [ meta load time => reg 1 ]
+ [ cmp eq reg 1 0x74a8f400 0x002bd849 ]
+ [ immediate reg 0 drop ]
+
+# meta time "2019-06-21 17:00:00" drop
+ip meta-test input
+ [ meta load time => reg 1 ]
+ [ cmp eq reg 1 0x767d6000 0x15aa3ebc ]
+ [ immediate reg 0 drop ]
+
+# meta time "2019-07-01 00:00:00" drop
+ip meta-test input
+ [ meta load time => reg 1 ]
+ [ cmp eq reg 1 0xe750c000 0x15ad18e0 ]
+ [ immediate reg 0 drop ]
+
+# meta time "2019-07-01 00:01:00" drop
+ip meta-test input
+ [ meta load time => reg 1 ]
+ [ cmp eq reg 1 0xdf981800 0x15ad18ee ]
+ [ immediate reg 0 drop ]
+
+# meta time "2019-07-01 00:00:01" drop
+ip meta-test input
+ [ meta load time => reg 1 ]
+ [ cmp eq reg 1 0x22eb8a00 0x15ad18e1 ]
+ [ immediate reg 0 drop ]
+
+# meta time < "2022-07-01 11:00:00" accept
+ip test-ip4 input
+ [ meta load time => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp lt reg 1 0xf3a8fd16 0x00a07719 ]
+ [ immediate reg 0 accept ]
+
+# meta time > "2022-07-01 11:00:00" accept
+ip test-ip4 input
+ [ meta load time => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp gt reg 1 0xf3a8fd16 0x00a07719 ]
+ [ immediate reg 0 accept ]
+
+# meta day "Saturday" drop
+ip test-ip4 input
+ [ meta load day => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 0 drop ]
+
+# meta day 6 drop
+ip test-ip4 input
+ [ meta load day => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 0 drop ]
+
+# meta hour "17:00" drop
+ip test-ip4 input
+ [ meta load hour => reg 1 ]
+ [ cmp eq reg 1 0x0000d2f0 ]
+ [ immediate reg 0 drop ]
+
+# meta hour "17:00:00" drop
+ip test-ip4 input
+ [ meta load hour => reg 1 ]
+ [ cmp eq reg 1 0x0000d2f0 ]
+ [ immediate reg 0 drop ]
+
+# meta hour "17:00:01" drop
+ip meta-test input
+ [ meta load hour => reg 1 ]
+ [ cmp eq reg 1 0x0000d2f1 ]
+ [ immediate reg 0 drop ]
+
+# meta hour "00:00" drop
+ip meta-test input
+ [ meta load hour => reg 1 ]
+ [ cmp eq reg 1 0x00013560 ]
+ [ immediate reg 0 drop ]
+
+# meta hour "00:01" drop
+ip meta-test input
+ [ meta load hour => reg 1 ]
+ [ cmp eq reg 1 0x0001359c ]
+ [ immediate reg 0 drop ]
+
+# time < "2022-07-01 11:00:00" accept
+ip test-ip4 input
+ [ meta load time => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp lt reg 1 0xf3a8fd16 0x00a07719 ]
+ [ immediate reg 0 accept ]
+
+# time > "2022-07-01 11:00:00" accept
+ip test-ip4 input
+ [ meta load time => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 8, 8) ]
+ [ cmp gt reg 1 0xf3a8fd16 0x00a07719 ]
+ [ immediate reg 0 accept ]
diff --git a/tests/py/any/objects.t b/tests/py/any/objects.t
new file mode 100644
index 0000000..7b51f91
--- /dev/null
+++ b/tests/py/any/objects.t
@@ -0,0 +1,16 @@
+:output;type filter hook output priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+*arp;test-arp;output
+*bridge;test-bridge;output
+*netdev;test-netdev;ingress,egress
+
+%cnt1 type counter;ok
+%qt1 type quota 25 mbytes;ok
+%qt2 type quota over 1 kbytes;ok
+%lim0 type limit rate 400/minute;ok
+%lim2 type limit rate over 1024 bytes/second burst 512 bytes;ok
diff --git a/tests/py/any/queue.t b/tests/py/any/queue.t
new file mode 100644
index 0000000..2e51136
--- /dev/null
+++ b/tests/py/any/queue.t
@@ -0,0 +1,33 @@
+:output;type filter hook output priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+*bridge;test-bridge;output
+
+queue;ok;queue to 0
+queue num 2;ok;queue to 2
+queue num 65535;ok;queue to 65535
+queue num 65536;fail
+queue num 2-3;ok;queue to 2-3
+queue num 1-65535;ok;queue to 1-65535
+queue num 4-5 fanout bypass;ok;queue flags bypass,fanout to 4-5
+queue num 4-5 fanout;ok;queue flags fanout to 4-5
+queue num 4-5 bypass;ok;queue flags bypass to 4-5
+
+queue to symhash mod 2 offset 65536;fail
+queue num symhash mod 65536;fail
+queue to symhash mod 65536;ok
+queue flags fanout to symhash mod 65536;fail
+queue flags bypass,fanout to symhash mod 65536;fail
+queue flags bypass to numgen inc mod 65536;ok
+queue to jhash oif . meta mark mod 32;ok
+queue to 2;ok
+queue to 65535;ok
+queue flags bypass to 65535;ok
+queue flags bypass to 1-65535;ok
+queue flags bypass,fanout to 1-65535;ok
+queue to 1-65535;ok
+queue to oif;fail
+queue num oif;fail
+queue flags bypass to oifname map { "eth0" : 0, "ppp0" : 2, "eth1" : 2 };ok
diff --git a/tests/py/any/queue.t.json b/tests/py/any/queue.t.json
new file mode 100644
index 0000000..5f7f901
--- /dev/null
+++ b/tests/py/any/queue.t.json
@@ -0,0 +1,251 @@
+# queue
+[
+ {
+ "queue": null
+ }
+]
+
+# queue num 2
+[
+ {
+ "queue": {
+ "num": 2
+ }
+ }
+]
+
+# queue num 65535
+[
+ {
+ "queue": {
+ "num": 65535
+ }
+ }
+]
+
+# queue num 2-3
+[
+ {
+ "queue": {
+ "num": {
+ "range": [ 2, 3 ]
+ }
+ }
+ }
+]
+
+# queue num 1-65535
+[
+ {
+ "queue": {
+ "num": {
+ "range": [ 1, 65535 ]
+ }
+ }
+ }
+]
+
+# queue num 4-5 fanout bypass
+[
+ {
+ "queue": {
+ "flags": [
+ "bypass",
+ "fanout"
+ ],
+ "num": {
+ "range": [ 4, 5 ]
+ }
+ }
+ }
+]
+
+# queue num 4-5 fanout
+[
+ {
+ "queue": {
+ "flags": "fanout",
+ "num": {
+ "range": [ 4, 5 ]
+ }
+ }
+ }
+]
+
+# queue num 4-5 bypass
+[
+ {
+ "queue": {
+ "flags": "bypass",
+ "num": {
+ "range": [ 4, 5 ]
+ }
+ }
+ }
+]
+
+# queue to symhash mod 65536
+[
+ {
+ "queue": {
+ "num": {
+ "symhash": {
+ "mod": 65536
+ }
+ }
+ }
+ }
+]
+
+# queue flags bypass to numgen inc mod 65536
+[
+ {
+ "queue": {
+ "flags": "bypass",
+ "num": {
+ "numgen": {
+ "mod": 65536,
+ "mode": "inc",
+ "offset": 0
+ }
+ }
+ }
+ }
+]
+
+# queue to jhash oif . meta mark mod 32
+[
+ {
+ "queue": {
+ "num": {
+ "jhash": {
+ "expr": {
+ "concat": [
+ {
+ "meta": {
+ "key": "oif"
+ }
+ },
+ {
+ "meta": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "mod": 32
+ }
+ }
+ }
+ }
+]
+
+# queue flags bypass to oifname map { "eth0" : 0, "ppp0" : 2, "eth1" : 2 }
+[
+ {
+ "queue": {
+ "flags": "bypass",
+ "num": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "eth0",
+ 0
+ ],
+ [
+ "ppp0",
+ 2
+ ],
+ [
+ "eth1",
+ 2
+ ]
+ ]
+ },
+ "key": {
+ "meta": {
+ "key": "oifname"
+ }
+ }
+ }
+ }
+ }
+ }
+]
+
+# queue to 2
+[
+ {
+ "queue": {
+ "num": 2
+ }
+ }
+]
+
+# queue to 65535
+[
+ {
+ "queue": {
+ "num": 65535
+ }
+ }
+]
+
+# queue flags bypass to 65535
+[
+ {
+ "queue": {
+ "flags": "bypass",
+ "num": 65535
+ }
+ }
+]
+
+# queue flags bypass to 1-65535
+[
+ {
+ "queue": {
+ "flags": "bypass",
+ "num": {
+ "range": [
+ 1,
+ 65535
+ ]
+ }
+ }
+ }
+]
+
+# queue flags bypass,fanout to 1-65535
+[
+ {
+ "queue": {
+ "flags": [
+ "bypass",
+ "fanout"
+ ],
+ "num": {
+ "range": [
+ 1,
+ 65535
+ ]
+ }
+ }
+ }
+]
+
+# queue to 1-65535
+[
+ {
+ "queue": {
+ "num": {
+ "range": [
+ 1,
+ 65535
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/any/queue.t.json.output b/tests/py/any/queue.t.json.output
new file mode 100644
index 0000000..1104d76
--- /dev/null
+++ b/tests/py/any/queue.t.json.output
@@ -0,0 +1,9 @@
+# queue
+[
+ {
+ "queue": {
+ "num": 0
+ }
+ }
+]
+
diff --git a/tests/py/any/queue.t.payload b/tests/py/any/queue.t.payload
new file mode 100644
index 0000000..2f22193
--- /dev/null
+++ b/tests/py/any/queue.t.payload
@@ -0,0 +1,81 @@
+# queue
+ip test-ip4 output
+ [ queue num 0 ]
+
+# queue num 2
+ip test-ip4 output
+ [ queue num 2 ]
+
+# queue num 65535
+ip test-ip4 output
+ [ queue num 65535 ]
+
+# queue num 2-3
+ip test-ip4 output
+ [ queue num 2-3 ]
+
+# queue num 1-65535
+ip test-ip4 output
+ [ queue num 1-65535 ]
+
+# queue num 4-5 fanout bypass
+ip test-ip4 output
+ [ queue num 4-5 bypass fanout ]
+
+# queue num 4-5 fanout
+ip test-ip4 output
+ [ queue num 4-5 fanout ]
+
+# queue num 4-5 bypass
+ip test-ip4 output
+ [ queue num 4-5 bypass ]
+
+# queue to symhash mod 65536
+ip
+ [ hash reg 1 = symhash() % mod 65536 ]
+ [ queue sreg_qnum 1 ]
+
+# queue to jhash oif . meta mark mod 32
+ip
+ [ meta load oif => reg 2 ]
+ [ meta load mark => reg 13 ]
+ [ hash reg 1 = jhash(reg 2, 8, 0x0) % mod 32 ]
+ [ queue sreg_qnum 1 ]
+
+# queue flags bypass to numgen inc mod 65536
+ip
+ [ numgen reg 1 = inc mod 65536 ]
+ [ queue sreg_qnum 1 bypass ]
+
+# queue flags bypass to oifname map { "eth0" : 0, "ppp0" : 2, "eth1" : 2 }
+__map%d test-ip4 b size 3
+__map%d test-ip4 0
+ element 30687465 00000000 00000000 00000000 : 00000000 0 [end] element 30707070 00000000 00000000 00000000 : 00000002 0 [end] element 31687465 00000000 00000000 00000000 : 00000002 0 [end]
+ip
+ [ meta load oifname => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ queue sreg_qnum 1 bypass ]
+
+# queue to 2
+ip
+ [ queue num 2 ]
+
+# queue to 65535
+ip
+ [ queue num 65535 ]
+
+# queue flags bypass to 65535
+ip
+ [ queue num 65535 bypass ]
+
+# queue flags bypass to 1-65535
+ip
+ [ queue num 1-65535 bypass ]
+
+# queue flags bypass,fanout to 1-65535
+ip
+ [ queue num 1-65535 bypass fanout ]
+
+# queue to 1-65535
+ip
+ [ queue num 1-65535 ]
diff --git a/tests/py/any/quota.t b/tests/py/any/quota.t
new file mode 100644
index 0000000..79dd765
--- /dev/null
+++ b/tests/py/any/quota.t
@@ -0,0 +1,25 @@
+:output;type filter hook output priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+*arp;test-arp;output
+*bridge;test-bridge;output
+*netdev;test-netdev;ingress,egress
+
+quota 1025 bytes;ok
+quota 1 kbytes;ok
+quota 2 kbytes;ok
+quota 1025 kbytes;ok
+quota 1023 mbytes;ok
+quota 10230 mbytes;ok
+quota 1023000 mbytes;ok
+
+quota over 1 kbytes;ok
+quota over 2 kbytes;ok
+quota over 1025 kbytes;ok
+quota over 1023 mbytes;ok
+quota over 10230 mbytes;ok
+quota over 1023000 mbytes;ok
diff --git a/tests/py/any/quota.t.json b/tests/py/any/quota.t.json
new file mode 100644
index 0000000..59ccc72
--- /dev/null
+++ b/tests/py/any/quota.t.json
@@ -0,0 +1,136 @@
+# quota 1025 bytes
+[
+ {
+ "quota": {
+ "val": 1025,
+ "val_unit": "bytes"
+ }
+ }
+]
+
+# quota 1 kbytes
+[
+ {
+ "quota": {
+ "val": 1,
+ "val_unit": "kbytes"
+ }
+ }
+]
+
+# quota 2 kbytes
+[
+ {
+ "quota": {
+ "val": 2,
+ "val_unit": "kbytes"
+ }
+ }
+]
+
+# quota 1025 kbytes
+[
+ {
+ "quota": {
+ "val": 1025,
+ "val_unit": "kbytes"
+ }
+ }
+]
+
+# quota 1023 mbytes
+[
+ {
+ "quota": {
+ "val": 1023,
+ "val_unit": "mbytes"
+ }
+ }
+]
+
+# quota 10230 mbytes
+[
+ {
+ "quota": {
+ "val": 10230,
+ "val_unit": "mbytes"
+ }
+ }
+]
+
+# quota 1023000 mbytes
+[
+ {
+ "quota": {
+ "val": 1023000,
+ "val_unit": "mbytes"
+ }
+ }
+]
+
+# quota over 1 kbytes
+[
+ {
+ "quota": {
+ "inv": true,
+ "val": 1,
+ "val_unit": "kbytes"
+ }
+ }
+]
+
+# quota over 2 kbytes
+[
+ {
+ "quota": {
+ "inv": true,
+ "val": 2,
+ "val_unit": "kbytes"
+ }
+ }
+]
+
+# quota over 1025 kbytes
+[
+ {
+ "quota": {
+ "inv": true,
+ "val": 1025,
+ "val_unit": "kbytes"
+ }
+ }
+]
+
+# quota over 1023 mbytes
+[
+ {
+ "quota": {
+ "inv": true,
+ "val": 1023,
+ "val_unit": "mbytes"
+ }
+ }
+]
+
+# quota over 10230 mbytes
+[
+ {
+ "quota": {
+ "inv": true,
+ "val": 10230,
+ "val_unit": "mbytes"
+ }
+ }
+]
+
+# quota over 1023000 mbytes
+[
+ {
+ "quota": {
+ "inv": true,
+ "val": 1023000,
+ "val_unit": "mbytes"
+ }
+ }
+]
+
diff --git a/tests/py/any/quota.t.payload b/tests/py/any/quota.t.payload
new file mode 100644
index 0000000..31cfccb
--- /dev/null
+++ b/tests/py/any/quota.t.payload
@@ -0,0 +1,52 @@
+# quota 1025 bytes
+ip test-ip4 output
+ [ quota bytes 1025 consumed 0 flags 0 ]
+
+# quota 1 kbytes
+ip test-ip4 output
+ [ quota bytes 1024 consumed 0 flags 0 ]
+
+# quota 2 kbytes
+ip test-ip4 output
+ [ quota bytes 2048 consumed 0 flags 0 ]
+
+# quota 1025 kbytes
+ip test-ip4 output
+ [ quota bytes 1049600 consumed 0 flags 0 ]
+
+# quota 1023 mbytes
+ip test-ip4 output
+ [ quota bytes 1072693248 consumed 0 flags 0 ]
+
+# quota 10230 mbytes
+ip test-ip4 output
+ [ quota bytes 10726932480 consumed 0 flags 0 ]
+
+# quota 1023000 mbytes
+ip test-ip4 output
+ [ quota bytes 1072693248000 consumed 0 flags 0 ]
+
+# quota over 1 kbytes
+ip test-ip4 output
+ [ quota bytes 1024 consumed 0 flags 1 ]
+
+# quota over 2 kbytes
+ip test-ip4 output
+ [ quota bytes 2048 consumed 0 flags 1 ]
+
+# quota over 1025 kbytes
+ip test-ip4 output
+ [ quota bytes 1049600 consumed 0 flags 1 ]
+
+# quota over 1023 mbytes
+ip test-ip4 output
+ [ quota bytes 1072693248 consumed 0 flags 1 ]
+
+# quota over 10230 mbytes
+ip test-ip4 output
+ [ quota bytes 10726932480 consumed 0 flags 1 ]
+
+# quota over 1023000 mbytes
+ip test-ip4 output
+ [ quota bytes 1072693248000 consumed 0 flags 1 ]
+
diff --git a/tests/py/any/rawpayload.t b/tests/py/any/rawpayload.t
new file mode 100644
index 0000000..5bc9d35
--- /dev/null
+++ b/tests/py/any/rawpayload.t
@@ -0,0 +1,24 @@
+:input;type filter hook input priority 0
+:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
+
+*inet;test-inet;input
+*netdev;test-netdev;ingress,egress
+
+meta l4proto { tcp, udp, sctp} @th,16,16 { 22, 23, 80 };ok;meta l4proto { 6, 17, 132} th dport { 22, 23, 80}
+meta l4proto tcp @th,16,16 { 22, 23, 80};ok;tcp dport { 22, 23, 80}
+@nh,8,8 0xff;ok
+@nh,8,16 0x0;ok
+
+# out of range (0-1)
+@th,16,1 2;fail
+
+@ll,0,0 2;fail
+@ll,0,1;fail
+@ll,0,1 1;ok;@ll,0,8 & 0x80 == 0x80
+@ll,0,8 & 0x80 == 0x80;ok
+@ll,0,128 0xfedcba987654321001234567890abcde;ok
+
+meta l4proto 91 @th,400,16 0x0 accept;ok
+
+@ih,32,32 0x14000000;ok
diff --git a/tests/py/any/rawpayload.t.json b/tests/py/any/rawpayload.t.json
new file mode 100644
index 0000000..4cae4d4
--- /dev/null
+++ b/tests/py/any/rawpayload.t.json
@@ -0,0 +1,206 @@
+# meta l4proto { tcp, udp, sctp} @th,16,16 { 22, 23, 80 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "tcp",
+ "udp",
+ "sctp"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "th",
+ "len": 16,
+ "offset": 16
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 22,
+ 23,
+ 80
+ ]
+ }
+ }
+ }
+]
+
+# meta l4proto tcp @th,16,16 { 22, 23, 80}
+[
+ {
+ "match": {
+ "left": { "meta": { "key": "l4proto" } },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "th",
+ "len": 16,
+ "offset": 16
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 22,
+ 23,
+ 80
+ ]
+ }
+ }
+ }
+]
+
+# @nh,8,8 0xff
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "nh",
+ "len": 8,
+ "offset": 8
+ }
+ },
+ "op": "==",
+ "right": "0xff"
+ }
+ }
+]
+
+# @nh,8,16 0x0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "nh",
+ "len": 16,
+ "offset": 8
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# @ll,0,1 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "ll",
+ "len": 1,
+ "offset": 0
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# @ll,0,8 & 0x80 == 0x80
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "base": "ll",
+ "len": 8,
+ "offset": 0
+ }
+ },
+ "0x80"
+ ]
+ },
+ "op": "==",
+ "right": "0x80"
+ }
+ }
+]
+
+# @ll,0,128 0xfedcba987654321001234567890abcde
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "ll",
+ "len": 128,
+ "offset": 0
+ }
+ },
+ "op": "==",
+ "right": "0xfedcba987654321001234567890abcde"
+ }
+ }
+]
+
+# meta l4proto 91 @th,400,16 0x0 accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 91
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "th",
+ "len": 16,
+ "offset": 400
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# @ih,32,32 0x14000000
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "ih",
+ "len": 32,
+ "offset": 32
+ }
+ },
+ "op": "==",
+ "right": 335544320
+ }
+ }
+]
+
diff --git a/tests/py/any/rawpayload.t.json.output b/tests/py/any/rawpayload.t.json.output
new file mode 100644
index 0000000..291b237
--- /dev/null
+++ b/tests/py/any/rawpayload.t.json.output
@@ -0,0 +1,119 @@
+# meta l4proto { tcp, udp, sctp} @th,16,16 { 22, 23, 80 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": { "key": "l4proto" }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17,
+ 132
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "th"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 22,
+ 23,
+ 80
+ ]
+ }
+ }
+ }
+]
+
+# meta l4proto tcp @th,16,16 { 22, 23, 80}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 22,
+ 23,
+ 80
+ ]
+ }
+ }
+ }
+]
+
+# @ll,0,1 1
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "base": "ll",
+ "len": 8,
+ "offset": 0
+ }
+ },
+ 128
+ ]
+ },
+ "op": "==",
+ "right": 128
+ }
+ }
+]
+
+# @ll,0,8 & 0x80 == 0x80
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "base": "ll",
+ "len": 8,
+ "offset": 0
+ }
+ },
+ 128
+ ]
+ },
+ "op": "==",
+ "right": 128
+ }
+ }
+]
+
+# @nh,8,8 0xff
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "base": "nh",
+ "len": 8,
+ "offset": 8
+ }
+ },
+ "op": "==",
+ "right": 255
+ }
+ }
+]
diff --git a/tests/py/any/rawpayload.t.payload b/tests/py/any/rawpayload.t.payload
new file mode 100644
index 0000000..fe2377e
--- /dev/null
+++ b/tests/py/any/rawpayload.t.payload
@@ -0,0 +1,63 @@
+# meta l4proto { tcp, udp, sctp} @th,16,16 { 22, 23, 80 }
+__set%d test-inet 3 size 3
+__set%d test-inet 0
+ element 00000006 : 0 [end] element 00000011 : 0 [end] element 00000084 : 0 [end]
+__set%d test-inet 3 size 3
+__set%d test-inet 0
+ element 00001600 : 0 [end] element 00001700 : 0 [end] element 00005000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta l4proto tcp @th,16,16 { 22, 23, 80}
+__set%d test-inet 3 size 3
+__set%d test-inet 0
+ element 00001600 : 0 [end] element 00001700 : 0 [end] element 00005000 : 0 [end]
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# @nh,8,8 0xff
+inet test-inet input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ cmp eq reg 1 0x000000ff ]
+
+# @nh,8,16 0x0
+inet test-inet input
+ [ payload load 2b @ network header + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# @ll,0,1 1
+inet test-inet input
+ [ payload load 1b @ link header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000080 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# @ll,0,8 & 0x80 == 0x80
+inet test-inet input
+ [ payload load 1b @ link header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000080 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000080 ]
+
+# @ll,0,128 0xfedcba987654321001234567890abcde
+inet test-inet input
+ [ payload load 16b @ link header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x98badcfe 0x10325476 0x67452301 0xdebc0a89 ]
+
+# meta l4proto 91 @th,400,16 0x0 accept
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000005b ]
+ [ payload load 2b @ transport header + 50 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+ [ immediate reg 0 accept ]
+
+# @ih,32,32 0x14000000
+inet test-inet input
+ [ payload load 4b @ inner header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000014 ]
+
diff --git a/tests/py/any/rt.t b/tests/py/any/rt.t
new file mode 100644
index 0000000..3ce57e0
--- /dev/null
+++ b/tests/py/any/rt.t
@@ -0,0 +1,9 @@
+:output;type filter hook input priority 0
+
+*ip;test-ip4;output
+*ip6;test-ip6;output
+*inet;test-inet;output
+
+rt classid "cosmos";ok
+rt ipsec exists;ok
+rt ipsec missing;ok
diff --git a/tests/py/any/rt.t.json b/tests/py/any/rt.t.json
new file mode 100644
index 0000000..2ca6fe0
--- /dev/null
+++ b/tests/py/any/rt.t.json
@@ -0,0 +1,45 @@
+# rt classid "cosmos"
+[
+ {
+ "match": {
+ "left": {
+ "rt": {
+ "key": "classid"
+ }
+ },
+ "op": "==",
+ "right": "cosmos"
+ }
+ }
+]
+
+# rt ipsec exists
+[
+ {
+ "match": {
+ "left": {
+ "rt": {
+ "key": "ipsec"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# rt ipsec missing
+[
+ {
+ "match": {
+ "left": {
+ "rt": {
+ "key": "ipsec"
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
diff --git a/tests/py/any/rt.t.payload b/tests/py/any/rt.t.payload
new file mode 100644
index 0000000..e1ecb28
--- /dev/null
+++ b/tests/py/any/rt.t.payload
@@ -0,0 +1,15 @@
+# rt classid "cosmos"
+ip test-ip4 input
+ [ rt load classid => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# rt ipsec exists
+ip test-ip4 input
+ [ rt load ipsec => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# rt ipsec missing
+ip test-ip4 input
+ [ rt load ipsec => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
diff --git a/tests/py/any/tcpopt.t b/tests/py/any/tcpopt.t
new file mode 100644
index 0000000..177f01c
--- /dev/null
+++ b/tests/py/any/tcpopt.t
@@ -0,0 +1,62 @@
+:input;type filter hook input priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+
+tcp option eol exists;ok
+tcp option nop exists;ok
+tcp option maxseg exists;ok
+tcp option maxseg length 1;ok
+tcp option maxseg size 1;ok
+tcp option window length 1;ok
+tcp option window count 1;ok
+tcp option sack-perm exists;ok
+tcp option sack-perm length 1;ok
+tcp option sack exists;ok
+tcp option sack length 1;ok
+tcp option sack left 1;ok
+tcp option sack0 left 1;ok;tcp option sack left 1
+tcp option sack1 left 1;ok
+tcp option sack2 left 1;ok
+tcp option sack3 left 1;ok
+tcp option sack right 1;ok
+tcp option sack0 right 1;ok;tcp option sack right 1
+tcp option sack1 right 1;ok
+tcp option sack2 right 1;ok
+tcp option sack3 right 1;ok
+tcp option timestamp exists;ok
+tcp option timestamp length 1;ok
+tcp option timestamp tsval 1;ok
+tcp option timestamp tsecr 1;ok
+tcp option 255 missing;ok
+tcp option 6 exists;ok
+tcp option @255,8,8 255;ok
+
+tcp option foobar;fail
+tcp option foo bar;fail
+tcp option eol left;fail
+tcp option eol left 1;fail
+tcp option sack window;fail
+tcp option sack window 1;fail
+tcp option 256 exists;fail
+tcp option @255,8,8 256;fail
+
+tcp option window exists;ok
+tcp option window missing;ok
+
+tcp option maxseg size set 1360;ok
+
+tcp option md5sig exists;ok
+tcp option fastopen exists;ok
+tcp option mptcp exists;ok
+
+tcp option mptcp subtype 0;ok
+tcp option mptcp subtype 1;ok
+tcp option mptcp subtype { 0, 2};ok
+
+reset tcp option mptcp;ok
+reset tcp option 2;ok;reset tcp option maxseg
+reset tcp option 123;ok
+reset tcp option meh;fail
+reset tcp option 256;fail
diff --git a/tests/py/any/tcpopt.t.json b/tests/py/any/tcpopt.t.json
new file mode 100644
index 0000000..4466f14
--- /dev/null
+++ b/tests/py/any/tcpopt.t.json
@@ -0,0 +1,622 @@
+# tcp option eol exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "eol"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option nop exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "nop"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option maxseg exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "maxseg"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option maxseg length 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "length",
+ "name": "maxseg"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option maxseg size 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "size",
+ "name": "maxseg"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option window length 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "length",
+ "name": "window"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option window count 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "count",
+ "name": "window"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack-perm exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "sack-perm"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option sack-perm length 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "length",
+ "name": "sack-perm"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option sack length 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "length",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack left 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "left",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack0 left 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "left",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack1 left 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "left",
+ "name": "sack1"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack2 left 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "left",
+ "name": "sack2"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack3 left 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "left",
+ "name": "sack3"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack0 right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack1 right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack1"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack2 right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack2"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack3 right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack3"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option timestamp exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "timestamp"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option timestamp length 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "length",
+ "name": "timestamp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option timestamp tsval 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "tsval",
+ "name": "timestamp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option timestamp tsecr 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "tsecr",
+ "name": "timestamp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option 255 missing
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "base": 255,
+ "len": 8,
+ "offset": 0
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
+# tcp option 6 exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "base": 6,
+ "len": 8,
+ "offset": 0
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option @255,8,8 255
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "base": 255,
+ "len": 8,
+ "offset": 8
+ }
+ },
+ "op": "==",
+ "right": 255
+ }
+ }
+]
+
+# tcp option window exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "window"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option window missing
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "window"
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
+# tcp option maxseg size set 1360
+[
+ {
+ "mangle": {
+ "key": {
+ "tcp option": {
+ "field": "size",
+ "name": "maxseg"
+ }
+ },
+ "value": 1360
+ }
+ }
+]
+
+# tcp option md5sig exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "md5sig"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option fastopen exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "fastopen"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option mptcp exists
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "name": "mptcp"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# tcp option mptcp subtype 0
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "subtype",
+ "name": "mptcp"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# tcp option mptcp subtype 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "subtype",
+ "name": "mptcp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option mptcp subtype { 0, 2}
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "subtype",
+ "name": "mptcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 0,
+ 2
+ ]
+ }
+ }
+ }
+]
+
+# reset tcp option mptcp
+[
+ {
+ "reset": {
+ "tcp option": {
+ "name": "mptcp"
+ }
+ }
+ }
+]
+
+# reset tcp option 2
+[
+ {
+ "reset": {
+ "tcp option": {
+ "name": "maxseg"
+ }
+ }
+ }
+]
+
+# reset tcp option 123
+[
+ {
+ "reset": {
+ "tcp option": {
+ "base": 123,
+ "len": 0,
+ "offset": 0
+ }
+ }
+ }
+]
diff --git a/tests/py/any/tcpopt.t.json.output b/tests/py/any/tcpopt.t.json.output
new file mode 100644
index 0000000..ad0d25f
--- /dev/null
+++ b/tests/py/any/tcpopt.t.json.output
@@ -0,0 +1,32 @@
+# tcp option sack0 left 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "left",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack0 right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
new file mode 100644
index 0000000..99b8985
--- /dev/null
+++ b/tests/py/any/tcpopt.t.payload
@@ -0,0 +1,202 @@
+# tcp option eol exists
+inet
+ [ exthdr load tcpopt 1b @ 0 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option nop exists
+inet
+ [ exthdr load tcpopt 1b @ 1 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg exists
+inet
+ [ exthdr load tcpopt 1b @ 2 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg length 1
+inet
+ [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg size 1
+inet
+ [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# tcp option window length 1
+inet
+ [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window count 1
+inet
+ [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack-perm exists
+inet
+ [ exthdr load tcpopt 1b @ 4 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack-perm length 1
+inet
+ [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack exists
+inet
+ [ exthdr load tcpopt 1b @ 5 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack length 1
+inet
+ [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack left 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack0 left 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack1 left 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack2 left 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack3 left 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack right 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack0 right 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack1 right 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack2 right 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack3 right 1
+inet
+ [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option timestamp exists
+inet
+ [ exthdr load tcpopt 1b @ 8 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option timestamp length 1
+inet
+ [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option timestamp tsval 1
+inet
+ [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option timestamp tsecr 1
+inet
+ [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option 255 missing
+inet
+ [ exthdr load tcpopt 1b @ 255 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp option 6 exists
+inet
+ [ exthdr load tcpopt 1b @ 6 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option @255,8,8 255
+inet
+ [ exthdr load tcpopt 1b @ 255 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x000000ff ]
+
+# tcp option window exists
+inet
+ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window missing
+inet
+ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp option maxseg size set 1360
+inet
+ [ immediate reg 1 0x00005005 ]
+ [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
+
+# tcp option md5sig exists
+inet
+ [ exthdr load tcpopt 1b @ 19 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option fastopen exists
+inet
+ [ exthdr load tcpopt 1b @ 34 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option mptcp exists
+inet
+ [ exthdr load tcpopt 1b @ 30 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option mptcp subtype 0
+inet
+ [ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp option mptcp subtype 1
+inet
+ [ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+
+# tcp option mptcp subtype { 0, 2}
+__set%d test-inet 3 size 2
+__set%d test-inet 0
+ element 00000000 : 0 [end] element 00000020 : 0 [end]
+inet
+ [ exthdr load tcpopt 1b @ 30 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# reset tcp option mptcp
+ip test-ip4 input
+ [ exthdr reset tcpopt 30 ]
+
+# reset tcp option 2
+ip test-ip4 input
+ [ exthdr reset tcpopt 2 ]
+
+# reset tcp option 123
+ip test-ip4 input
+ [ exthdr reset tcpopt 123 ]