summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore14
-rw-r--r--COPYING8
-rw-r--r--INSTALL55
-rw-r--r--Make_global.am21
-rw-r--r--Makefile.am414
-rw-r--r--configure.ac79
-rw-r--r--doc/Makefile.am31
-rw-r--r--doc/data-types.txt111
-rw-r--r--doc/libnftables-json.adoc93
-rw-r--r--doc/libnftables.adoc77
-rw-r--r--doc/nft.txt376
-rw-r--r--doc/payload-expression.txt318
-rw-r--r--doc/primary-expression.txt139
-rw-r--r--doc/stateful-objects.txt77
-rw-r--r--doc/statements.txt337
-rw-r--r--examples/.gitignore5
-rw-r--r--examples/json-ruleset.nft43
-rw-r--r--examples/nft-buffer.c34
-rw-r--r--examples/nft-json-file.c30
-rw-r--r--files/Makefile.am2
-rwxr-xr-xfiles/examples/secmark.nft87
-rw-r--r--files/nftables/Makefile.am18
-rw-r--r--[-rwxr-xr-x]files/nftables/all-in-one.nft4
-rw-r--r--[-rwxr-xr-x]files/nftables/arp-filter.nft2
-rw-r--r--[-rwxr-xr-x]files/nftables/bridge-filter.nft2
-rw-r--r--[-rwxr-xr-x]files/nftables/inet-filter.nft2
-rw-r--r--[-rwxr-xr-x]files/nftables/inet-nat.nft2
-rw-r--r--[-rwxr-xr-x]files/nftables/ipv4-filter.nft2
-rw-r--r--[-rwxr-xr-x]files/nftables/ipv4-mangle.nft2
-rw-r--r--[-rwxr-xr-x]files/nftables/ipv4-nat.nft2
-rw-r--r--[-rwxr-xr-x]files/nftables/ipv4-raw.nft2
-rw-r--r--[-rwxr-xr-x]files/nftables/ipv6-filter.nft2
-rw-r--r--[-rwxr-xr-x]files/nftables/ipv6-mangle.nft2
-rw-r--r--[-rwxr-xr-x]files/nftables/ipv6-nat.nft2
-rw-r--r--[-rwxr-xr-x]files/nftables/ipv6-raw.nft2
-rw-r--r--[-rwxr-xr-x]files/nftables/netdev-ingress.nft4
-rw-r--r--files/osf/Makefile.am2
-rw-r--r--include/Makefile.am38
-rw-r--r--include/cache.h118
-rw-r--r--include/cli.h5
-rw-r--r--include/cmd.h13
-rw-r--r--include/ct.h2
-rw-r--r--include/datatype.h30
-rw-r--r--include/dccpopt.h41
-rw-r--r--include/erec.h5
-rw-r--r--include/expression.h69
-rw-r--r--include/exthdr.h17
-rw-r--r--include/gmputil.h4
-rw-r--r--include/headers.h2
-rw-r--r--include/intervals.h11
-rw-r--r--include/ipopt.h2
-rw-r--r--include/json.h20
-rw-r--r--include/linux/Makefile.am12
-rw-r--r--include/linux/netfilter.h2
-rw-r--r--include/linux/netfilter/Makefile.am8
-rw-r--r--include/linux/netfilter/nf_log.h3
-rw-r--r--include/linux/netfilter/nf_nat.h15
-rw-r--r--include/linux/netfilter/nf_tables.h196
-rw-r--r--include/linux/netfilter/nfnetlink.h3
-rw-r--r--include/linux/netfilter/nfnetlink_hook.h82
-rw-r--r--include/linux/netfilter_arp/Makefile.am1
-rw-r--r--include/linux/netfilter_bridge/Makefile.am1
-rw-r--r--include/linux/netfilter_ipv4/Makefile.am1
-rw-r--r--include/linux/netfilter_ipv6/Makefile.am1
-rw-r--r--include/list.h18
-rw-r--r--include/meta.h2
-rw-r--r--include/mnl.h61
-rw-r--r--include/netlink.h97
-rw-r--r--include/nft.h18
-rw-r--r--include/nftables.h55
-rw-r--r--include/nftables/Makefile.am1
-rw-r--r--include/nftables/libnftables.h23
-rw-r--r--include/owner.h6
-rw-r--r--include/parser.h75
-rw-r--r--include/payload.h22
-rw-r--r--include/proto.h138
-rw-r--r--include/rbtree.h98
-rw-r--r--include/rule.h188
-rw-r--r--include/sctp_chunk.h87
-rw-r--r--include/socket.h2
-rw-r--r--include/statement.h58
-rw-r--r--include/tcpopt.h96
-rw-r--r--include/utils.h45
-rw-r--r--py/Makefile.am28
-rw-r--r--py/pyproject.toml3
-rw-r--r--py/setup.cfg24
-rwxr-xr-xpy/setup.py25
-rw-r--r--py/src/__init__.py (renamed from py/__init__.py)0
-rw-r--r--py/src/nftables.py (renamed from py/nftables.py)241
-rw-r--r--py/src/schema.json (renamed from py/schema.json)0
-rw-r--r--src/Makefile.am108
-rw-r--r--src/cache.c1170
-rw-r--r--src/cli.c133
-rw-r--r--src/cmd.c501
-rw-r--r--src/ct.c95
-rw-r--r--src/datatype.c623
-rw-r--r--src/dccpopt.c277
-rw-r--r--src/erec.c104
-rw-r--r--src/evaluate.c3046
-rw-r--r--src/expression.c405
-rw-r--r--src/exthdr.c239
-rw-r--r--src/fib.c67
-rw-r--r--src/gmputil.c27
-rw-r--r--src/hash.c78
-rw-r--r--src/iface.c58
-rw-r--r--src/intervals.c755
-rw-r--r--src/ipopt.c30
-rw-r--r--src/json.c549
-rw-r--r--src/libnftables.c410
-rw-r--r--src/libnftables.map17
-rw-r--r--src/main.c453
-rw-r--r--src/mergesort.c80
-rw-r--r--src/meta.c343
-rw-r--r--src/mini-gmp.c4
-rw-r--r--src/misspell.c14
-rw-r--r--src/mnl.c1584
-rw-r--r--src/monitor.c186
-rw-r--r--src/netlink.c1341
-rw-r--r--src/netlink_delinearize.c1503
-rw-r--r--src/netlink_linearize.c601
-rw-r--r--src/nfnl_osf.c4
-rw-r--r--src/nftutils.c100
-rw-r--r--src/nftutils.h20
-rw-r--r--src/numgen.c68
-rw-r--r--src/optimize.c1406
-rw-r--r--src/osf.c24
-rw-r--r--src/owner.c182
-rw-r--r--src/parser_bison.y2761
-rw-r--r--src/parser_json.c1055
-rw-r--r--src/payload.c762
-rw-r--r--src/print.c7
-rw-r--r--src/proto.c334
-rw-r--r--src/rbtree.c388
-rw-r--r--src/rt.c66
-rw-r--r--src/rule.c1254
-rw-r--r--src/scanner.l914
-rw-r--r--src/sctp_chunk.c262
-rw-r--r--src/segtree.c1130
-rw-r--r--src/socket.c79
-rw-r--r--src/statement.c211
-rw-r--r--src/tcpopt.c301
-rw-r--r--src/utils.c24
-rw-r--r--src/xfrm.c72
-rw-r--r--src/xt.c252
-rwxr-xr-xtests/build/run-tests.sh38
-rwxr-xr-xtests/json_echo/run-test.py39
-rwxr-xr-xtests/monitor/run-tests.sh90
-rw-r--r--tests/monitor/testcases/map-expr.t6
-rw-r--r--tests/monitor/testcases/object.t2
-rw-r--r--tests/monitor/testcases/set-concat-interval.t12
-rw-r--r--tests/monitor/testcases/set-interval.t30
-rw-r--r--tests/monitor/testcases/simple.t8
-rw-r--r--tests/py/README31
-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.t14
-rw-r--r--tests/py/any/ct.t.json156
-rw-r--r--tests/py/any/ct.t.json.output20
-rw-r--r--tests/py/any/ct.t.payload67
-rw-r--r--tests/py/any/icmpX.t.netdev3
-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.output7
-rw-r--r--tests/py/any/last.t.payload8
-rw-r--r--tests/py/any/limit.t32
-rw-r--r--tests/py/any/limit.t.json72
-rw-r--r--tests/py/any/limit.t.json.output249
-rw-r--r--tests/py/any/limit.t.payload48
-rw-r--r--tests/py/any/meta.t48
-rw-r--r--tests/py/any/meta.t.json198
-rw-r--r--tests/py/any/meta.t.json.output188
-rw-r--r--tests/py/any/meta.t.payload159
-rw-r--r--tests/py/any/meta.t.payload.bridge20
-rw-r--r--tests/py/any/objects.t3
-rw-r--r--tests/py/any/queue.t35
-rw-r--r--tests/py/any/queue.t.json165
-rw-r--r--tests/py/any/queue.t.payload49
-rw-r--r--tests/py/any/quota.t3
-rw-r--r--tests/py/any/rawpayload.t17
-rw-r--r--tests/py/any/rawpayload.t.json56
-rw-r--r--tests/py/any/rawpayload.t.json.output18
-rw-r--r--tests/py/any/rawpayload.t.payload24
-rw-r--r--tests/py/any/tcpopt.t (renamed from tests/py/inet/tcpopt.t)38
-rw-r--r--tests/py/any/tcpopt.t.json (renamed from tests/py/inet/tcpopt.t.json)305
-rw-r--r--tests/py/any/tcpopt.t.json.output (renamed from tests/py/inet/tcpopt.t.json.output)0
-rw-r--r--tests/py/any/tcpopt.t.payload202
-rw-r--r--tests/py/arp/arp.t14
-rw-r--r--tests/py/arp/arp.t.json204
-rw-r--r--tests/py/arp/arp.t.json.output28
-rw-r--r--tests/py/arp/arp.t.payload68
-rw-r--r--tests/py/arp/arp.t.payload.netdev88
-rw-r--r--tests/py/bridge/chains.t4
-rw-r--r--tests/py/bridge/meta.t7
-rw-r--r--tests/py/bridge/meta.t.json56
-rw-r--r--tests/py/bridge/meta.t.payload18
-rw-r--r--tests/py/bridge/redirect.t5
-rw-r--r--tests/py/bridge/redirect.t.json12
-rw-r--r--tests/py/bridge/redirect.t.payload4
-rw-r--r--tests/py/bridge/reject.t60
-rw-r--r--tests/py/bridge/reject.t.json106
-rw-r--r--tests/py/bridge/reject.t.json.output129
-rw-r--r--tests/py/bridge/reject.t.payload54
-rw-r--r--tests/py/bridge/vlan.t43
-rw-r--r--tests/py/bridge/vlan.t.json388
-rw-r--r--tests/py/bridge/vlan.t.json.output206
-rw-r--r--tests/py/bridge/vlan.t.payload177
-rw-r--r--tests/py/bridge/vlan.t.payload.netdev193
-rw-r--r--tests/py/inet/ah.t13
-rw-r--r--tests/py/inet/ah.t.json160
-rw-r--r--tests/py/inet/ah.t.payload80
-rw-r--r--tests/py/inet/comp.t7
-rw-r--r--tests/py/inet/comp.t.json80
-rw-r--r--tests/py/inet/comp.t.payload40
-rw-r--r--tests/py/inet/ct.t2
-rw-r--r--tests/py/inet/ct.t.json8
-rw-r--r--tests/py/inet/ct.t.payload7
-rw-r--r--tests/py/inet/dccp.t14
-rw-r--r--tests/py/inet/dccp.t.json162
-rw-r--r--tests/py/inet/dccp.t.payload80
-rw-r--r--tests/py/inet/dnat.t6
-rw-r--r--tests/py/inet/dnat.t.json75
-rw-r--r--tests/py/inet/dnat.t.payload42
-rw-r--r--tests/py/inet/esp.t7
-rw-r--r--tests/py/inet/esp.t.json60
-rw-r--r--tests/py/inet/esp.t.payload40
-rw-r--r--tests/py/inet/ether-ip.t3
-rw-r--r--tests/py/inet/ether-ip.t.payload.netdev15
-rw-r--r--tests/py/inet/ether.t9
-rw-r--r--tests/py/inet/ether.t.json32
-rw-r--r--tests/py/inet/ether.t.payload20
-rw-r--r--tests/py/inet/ether.t.payload.bridge33
-rw-r--r--tests/py/inet/ether.t.payload.ip33
-rw-r--r--tests/py/inet/fib.t.payload2
-rw-r--r--tests/py/inet/geneve.t23
-rw-r--r--tests/py/inet/geneve.t.json344
-rw-r--r--tests/py/inet/geneve.t.payload114
-rw-r--r--tests/py/inet/gre.t22
-rw-r--r--tests/py/inet/gre.t.json177
-rw-r--r--tests/py/inet/gre.t.payload78
-rw-r--r--tests/py/inet/gretap.t21
-rw-r--r--tests/py/inet/gretap.t.json195
-rw-r--r--tests/py/inet/gretap.t.payload87
-rw-r--r--tests/py/inet/icmpX.t2
-rw-r--r--tests/py/inet/icmpX.t.json.output9
-rw-r--r--tests/py/inet/ip.t5
-rw-r--r--tests/py/inet/ip.t.payload.bridge2
-rw-r--r--tests/py/inet/ip_tcp.t7
-rw-r--r--tests/py/inet/ip_tcp.t.json.output12
-rw-r--r--tests/py/inet/ipsec.t2
-rw-r--r--tests/py/inet/ipsec.t.json21
-rw-r--r--tests/py/inet/ipsec.t.payload7
-rw-r--r--tests/py/inet/map.t3
-rw-r--r--tests/py/inet/map.t.payload2
-rw-r--r--tests/py/inet/map.t.payload.ip2
-rw-r--r--tests/py/inet/map.t.payload.netdev2
-rw-r--r--tests/py/inet/meta.t15
-rw-r--r--tests/py/inet/meta.t.json354
-rw-r--r--tests/py/inet/meta.t.json.output41
-rw-r--r--tests/py/inet/meta.t.payload114
-rw-r--r--tests/py/inet/osf.t.payload108
-rw-r--r--tests/py/inet/payloadmerge.t14
-rw-r--r--tests/py/inet/payloadmerge.t.json211
-rw-r--r--tests/py/inet/payloadmerge.t.payload66
-rw-r--r--tests/py/inet/reject.t54
-rw-r--r--tests/py/inet/reject.t.json82
-rw-r--r--tests/py/inet/reject.t.json.output194
-rw-r--r--tests/py/inet/reject.t.payload.inet150
-rw-r--r--tests/py/inet/rt.t5
-rw-r--r--tests/py/inet/sctp.t48
-rw-r--r--tests/py/inet/sctp.t.json598
-rw-r--r--tests/py/inet/sctp.t.payload233
-rw-r--r--tests/py/inet/sets.t9
-rw-r--r--tests/py/inet/sets.t.json98
-rw-r--r--tests/py/inet/sets.t.payload.bridge27
-rw-r--r--tests/py/inet/sets.t.payload.inet24
-rw-r--r--tests/py/inet/sets.t.payload.netdev25
-rw-r--r--tests/py/inet/snat.t.payload6
-rw-r--r--tests/py/inet/socket.t4
-rw-r--r--tests/py/inet/socket.t.json29
-rw-r--r--tests/py/inet/socket.t.payload39
-rw-r--r--tests/py/inet/synproxy.t.json32
-rw-r--r--tests/py/inet/synproxy.t.payload48
-rw-r--r--tests/py/inet/tcp.t39
-rw-r--r--tests/py/inet/tcp.t.json647
-rw-r--r--tests/py/inet/tcp.t.json.output47
-rw-r--r--tests/py/inet/tcp.t.payload280
-rw-r--r--tests/py/inet/tcpopt.t.payload200
-rw-r--r--tests/py/inet/tproxy.t2
-rw-r--r--tests/py/inet/tproxy.t.json35
-rw-r--r--tests/py/inet/tproxy.t.payload14
-rw-r--r--tests/py/inet/udp.t11
-rw-r--r--tests/py/inet/udp.t.json166
-rw-r--r--tests/py/inet/udp.t.payload82
-rw-r--r--tests/py/inet/udplite.t11
-rw-r--r--tests/py/inet/udplite.t.json126
-rw-r--r--tests/py/inet/udplite.t.payload62
-rw-r--r--tests/py/inet/vmap.t10
-rw-r--r--tests/py/inet/vmap.t.json144
-rw-r--r--tests/py/inet/vmap.t.payload34
-rw-r--r--tests/py/inet/vmap.t.payload.netdev34
-rw-r--r--tests/py/inet/vxlan.t23
-rw-r--r--tests/py/inet/vxlan.t.json344
-rw-r--r--tests/py/inet/vxlan.t.payload114
-rw-r--r--tests/py/ip/ct.t13
-rw-r--r--tests/py/ip/ct.t.json263
-rw-r--r--tests/py/ip/ct.t.payload82
-rw-r--r--tests/py/ip/dnat.t10
-rw-r--r--tests/py/ip/dnat.t.json479
-rw-r--r--tests/py/ip/dnat.t.payload.ip127
-rw-r--r--tests/py/ip/flowtable.t5
-rw-r--r--tests/py/ip/flowtable.t.json24
-rw-r--r--tests/py/ip/flowtable.t.payload7
-rw-r--r--tests/py/ip/hash.t.payload2
-rw-r--r--tests/py/ip/icmp.t51
-rw-r--r--tests/py/ip/icmp.t.json582
-rw-r--r--tests/py/ip/icmp.t.json.output134
-rw-r--r--tests/py/ip/icmp.t.payload.ip273
-rw-r--r--tests/py/ip/igmp.t2
-rw-r--r--tests/py/ip/igmp.t.json50
-rw-r--r--tests/py/ip/igmp.t.payload248
-rw-r--r--tests/py/ip/ip.t44
-rw-r--r--tests/py/ip/ip.t.json446
-rw-r--r--tests/py/ip/ip.t.json.output31
-rw-r--r--tests/py/ip/ip.t.payload216
-rw-r--r--tests/py/ip/ip.t.payload.bridge238
-rw-r--r--tests/py/ip/ip.t.payload.inet250
-rw-r--r--tests/py/ip/ip.t.payload.netdev354
-rw-r--r--tests/py/ip/ip_tcp.t1
-rw-r--r--tests/py/ip/masquerade.t.payload8
-rw-r--r--tests/py/ip/meta.t10
-rw-r--r--tests/py/ip/meta.t.json129
-rw-r--r--tests/py/ip/meta.t.payload43
-rw-r--r--tests/py/ip/numgen.t2
-rw-r--r--tests/py/ip/numgen.t.json30
-rw-r--r--tests/py/ip/numgen.t.payload15
-rw-r--r--tests/py/ip/redirect.t2
-rw-r--r--tests/py/ip/redirect.t.json14
-rw-r--r--tests/py/ip/redirect.t.payload28
-rw-r--r--tests/py/ip/reject.t19
-rw-r--r--tests/py/ip/reject.t.json24
-rw-r--r--tests/py/ip/reject.t.json.output7
-rw-r--r--tests/py/ip/reject.t.payload18
-rw-r--r--tests/py/ip/sets.t14
-rw-r--r--tests/py/ip/sets.t.json115
-rw-r--r--tests/py/ip/sets.t.payload.inet38
-rw-r--r--tests/py/ip/sets.t.payload.ip31
-rw-r--r--tests/py/ip/sets.t.payload.netdev39
-rw-r--r--tests/py/ip/snat.t11
-rw-r--r--tests/py/ip/snat.t.json362
-rw-r--r--tests/py/ip/snat.t.json.output177
-rw-r--r--tests/py/ip/snat.t.payload102
-rw-r--r--tests/py/ip/tcpopt.t38
-rw-r--r--tests/py/ip/tcpopt.t.json416
-rw-r--r--tests/py/ip/tcpopt.t.json.output16
-rw-r--r--tests/py/ip/tcpopt.t.payload181
-rw-r--r--tests/py/ip6/ct.t9
-rw-r--r--tests/py/ip6/ct.t.json293
-rw-r--r--tests/py/ip6/ct.t.payload46
-rw-r--r--tests/py/ip6/dnat.t6
-rw-r--r--tests/py/ip6/dnat.t.json17
-rw-r--r--tests/py/ip6/dnat.t.payload.ip66
-rw-r--r--tests/py/ip6/dst.t5
-rw-r--r--tests/py/ip6/dst.t.json81
-rw-r--r--tests/py/ip6/dst.t.payload.inet41
-rw-r--r--tests/py/ip6/dst.t.payload.ip634
-rw-r--r--tests/py/ip6/ether.t2
-rw-r--r--tests/py/ip6/exthdr.t.json.output30
-rw-r--r--tests/py/ip6/flowtable.t6
-rw-r--r--tests/py/ip6/flowtable.t.json62
-rw-r--r--tests/py/ip6/flowtable.t.json.output62
-rw-r--r--tests/py/ip6/flowtable.t.payload16
-rw-r--r--tests/py/ip6/frag.t8
-rw-r--r--tests/py/ip6/frag.t.payload.inet88
-rw-r--r--tests/py/ip6/frag.t.payload.ip674
-rw-r--r--tests/py/ip6/frag.t.payload.netdev232
-rw-r--r--tests/py/ip6/hbh.t4
-rw-r--r--tests/py/ip6/hbh.t.json80
-rw-r--r--tests/py/ip6/hbh.t.payload.inet40
-rw-r--r--tests/py/ip6/hbh.t.payload.ip632
-rw-r--r--tests/py/ip6/icmpv6.t79
-rw-r--r--tests/py/ip6/icmpv6.t.json485
-rw-r--r--tests/py/ip6/icmpv6.t.json.output592
-rw-r--r--tests/py/ip6/icmpv6.t.payload.ip6273
-rw-r--r--tests/py/ip6/ip6.t19
-rw-r--r--tests/py/ip6/ip6.t.json208
-rw-r--r--tests/py/ip6/ip6.t.payload.inet173
-rw-r--r--tests/py/ip6/ip6.t.payload.ip6149
-rw-r--r--tests/py/ip6/map.t.payload2
-rw-r--r--tests/py/ip6/masquerade.t.payload.ip68
-rw-r--r--tests/py/ip6/meta.t9
-rw-r--r--tests/py/ip6/meta.t.json206
-rw-r--r--tests/py/ip6/meta.t.json.output16
-rw-r--r--tests/py/ip6/meta.t.payload48
-rw-r--r--tests/py/ip6/mh.t8
-rw-r--r--tests/py/ip6/mh.t.json162
-rw-r--r--tests/py/ip6/mh.t.payload.inet81
-rw-r--r--tests/py/ip6/mh.t.payload.ip665
-rw-r--r--tests/py/ip6/redirect.t2
-rw-r--r--tests/py/ip6/redirect.t.json14
-rw-r--r--tests/py/ip6/redirect.t.payload.ip622
-rw-r--r--tests/py/ip6/reject.t17
-rw-r--r--tests/py/ip6/reject.t.json22
-rw-r--r--tests/py/ip6/reject.t.json.output7
-rw-r--r--tests/py/ip6/reject.t.payload.ip616
-rw-r--r--tests/py/ip6/rt.t8
-rw-r--r--tests/py/ip6/rt.t.json160
-rw-r--r--tests/py/ip6/rt.t.payload.inet80
-rw-r--r--tests/py/ip6/rt.t.payload.ip664
-rw-r--r--tests/py/ip6/sets.t7
-rw-r--r--tests/py/ip6/sets.t.json32
-rw-r--r--tests/py/ip6/sets.t.payload.inet9
-rw-r--r--tests/py/ip6/sets.t.payload.ip67
-rw-r--r--tests/py/ip6/sets.t.payload.netdev9
-rw-r--r--tests/py/ip6/snat.t2
-rw-r--r--tests/py/ip6/snat.t.payload.ip64
-rw-r--r--tests/py/ip6/srh.t.payload6
-rw-r--r--tests/py/ip6/tcpopt.t37
-rw-r--r--tests/py/ip6/tcpopt.t.json416
-rw-r--r--tests/py/ip6/tcpopt.t.json.output16
-rw-r--r--tests/py/ip6/tcpopt.t.payload181
-rw-r--r--tests/py/ip6/vmap.t3
-rw-r--r--tests/py/ip6/vmap.t.payload.inet84
-rw-r--r--tests/py/ip6/vmap.t.payload.ip684
-rw-r--r--tests/py/ip6/vmap.t.payload.netdev84
-rw-r--r--tests/py/netdev/dup.t (renamed from tests/py/any/dup.t)3
-rw-r--r--tests/py/netdev/dup.t.json (renamed from tests/py/any/dup.t.json)0
-rw-r--r--tests/py/netdev/dup.t.payload (renamed from tests/py/any/dup.t.payload)0
-rw-r--r--tests/py/netdev/fwd.t (renamed from tests/py/any/fwd.t)3
-rw-r--r--tests/py/netdev/fwd.t.json (renamed from tests/py/any/fwd.t.json)0
-rw-r--r--tests/py/netdev/fwd.t.json.output (renamed from tests/py/any/fwd.t.json.output)0
-rw-r--r--tests/py/netdev/fwd.t.payload (renamed from tests/py/any/fwd.t.payload)0
-rw-r--r--tests/py/netdev/reject.t40
-rw-r--r--tests/py/netdev/reject.t.json293
-rw-r--r--tests/py/netdev/reject.t.payload142
-rwxr-xr-xtests/py/nft-test.py192
-rwxr-xr-xtests/py/tools/test-sanitizer.sh78
-rw-r--r--tests/shell/README29
-rw-r--r--tests/shell/features/bitshift.nft7
-rw-r--r--tests/shell/features/catchall_element.nft8
-rw-r--r--tests/shell/features/chain_binding.nft7
-rwxr-xr-xtests/shell/features/comment.sh14
-rw-r--r--tests/shell/features/ctexpect.nft10
-rw-r--r--tests/shell/features/cttimeout.nft8
-rw-r--r--tests/shell/features/destroy.nft3
-rw-r--r--tests/shell/features/dynset_op_delete.nft12
-rwxr-xr-xtests/shell/features/flowtable_counter.sh16
-rwxr-xr-xtests/shell/features/flowtable_no_devices.nft8
-rw-r--r--tests/shell/features/inet_ingress.nft7
-rw-r--r--tests/shell/features/inet_nat.nft7
-rw-r--r--tests/shell/features/inner_matching.nft7
-rwxr-xr-xtests/shell/features/json.sh6
-rw-r--r--tests/shell/features/map_lookup.nft11
-rw-r--r--tests/shell/features/meta_time.nft7
-rwxr-xr-xtests/shell/features/netdev_chain_multidevice.sh17
-rw-r--r--tests/shell/features/netdev_chain_without_device.nft7
-rw-r--r--tests/shell/features/netdev_egress.nft7
-rw-r--r--tests/shell/features/netmap.nft8
-rw-r--r--tests/shell/features/osf.nft7
-rw-r--r--tests/shell/features/pipapo.nft9
-rw-r--r--tests/shell/features/prerouting_reject.nft8
-rwxr-xr-xtests/shell/features/reset_rule.sh8
-rwxr-xr-xtests/shell/features/reset_set.sh10
-rw-r--r--tests/shell/features/reset_tcp_options.nft5
-rw-r--r--tests/shell/features/sctp_chunks.nft7
-rw-r--r--tests/shell/features/secmark.nft7
-rwxr-xr-xtests/shell/features/set_expr.sh19
-rw-r--r--tests/shell/features/set_with_two_expressions.nft9
-rwxr-xr-xtests/shell/features/setelem_expiration.sh18
-rwxr-xr-xtests/shell/features/stateful_object_update.sh21
-rw-r--r--tests/shell/features/synproxy.nft9
-rw-r--r--tests/shell/features/table_flag_owner.nft5
-rwxr-xr-xtests/shell/helpers/json-diff-pretty.sh17
-rwxr-xr-xtests/shell/helpers/json-pretty.sh30
-rwxr-xr-xtests/shell/helpers/json-sanitize-ruleset.sh30
-rwxr-xr-xtests/shell/helpers/nft-valgrind-wrapper.sh31
-rwxr-xr-xtests/shell/helpers/random-source.sh40
-rwxr-xr-xtests/shell/helpers/test-wrapper.sh328
-rwxr-xr-xtests/shell/run-tests.sh1014
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_013
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_113
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_213
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_313
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_413
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_513
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_613
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_713
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_813
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_913
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_0.json-nft75
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_0.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_1.json-nft86
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_1.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_2.json-nft65
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_2.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_3.json-nft65
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_3.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_4.json-nft65
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_4.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_5.json-nft65
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_5.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_6.json-nft65
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_6.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_7.json-nft65
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_7.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_8.json-nft65
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_8.nft6
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_9.json-nft65
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_9.nft6
-rwxr-xr-xtests/shell/testcases/bogons/assert_failures12
-rw-r--r--tests/shell/testcases/bogons/dumps/assert_failures.json-nft11
-rw-r--r--tests/shell/testcases/bogons/dumps/assert_failures.nft0
-rw-r--r--tests/shell/testcases/bogons/nft-f/add_to_a_set_crash11
-rw-r--r--tests/shell/testcases/bogons/nft-f/binop_with_different_basetype_assert5
-rw-r--r--tests/shell/testcases/bogons/nft-f/bitwise_masklen_assert5
-rw-r--r--tests/shell/testcases/bogons/nft-f/byteorder_switch_stack_overflow6
-rw-r--r--tests/shell/testcases/bogons/nft-f/counter_objref_crash5
-rw-r--r--tests/shell/testcases/bogons/nft-f/ct_helper_yystate_underflow14
-rw-r--r--tests/shell/testcases/bogons/nft-f/ct_timeout_memleak7
-rw-r--r--tests/shell/testcases/bogons/nft-f/ct_timeout_memleak_objfree5
-rw-r--r--tests/shell/testcases/bogons/nft-f/define_policy_assert3
-rw-r--r--tests/shell/testcases/bogons/nft-f/double-free-on-binop-dtype_assert6
-rw-r--r--tests/shell/testcases/bogons/nft-f/dup_fwd_ranges14
-rw-r--r--tests/shell/testcases/bogons/nft-f/dynamic-stack-buffer-overflow_gen_prefix5
-rw-r--r--tests/shell/testcases/bogons/nft-f/evaluate_conflict_resolution_gen_dependency_base_ll_hdr_assert5
-rw-r--r--tests/shell/testcases/bogons/nft-f/exthdr_with_range_bug1
-rw-r--r--tests/shell/testcases/bogons/nft-f/huge_binop_expr_chain_crash5
-rw-r--r--tests/shell/testcases/bogons/nft-f/huge_chain_name_assert5
-rw-r--r--tests/shell/testcases/bogons/nft-f/huge_chain_name_define_assert7
-rw-r--r--tests/shell/testcases/bogons/nft-f/huge_chain_prio5
-rw-r--r--tests/shell/testcases/bogons/nft-f/huge_shift_assert5
-rw-r--r--tests/shell/testcases/bogons/nft-f/icmp_reject_type_uint8_assert1
-rw-r--r--tests/shell/testcases/bogons/nft-f/include-device1
-rw-r--r--tests/shell/testcases/bogons/nft-f/invalid_mapping_expr_binop_assert1
-rw-r--r--tests/shell/testcases/bogons/nft-f/invalid_range_expr_type_binop12
-rw-r--r--tests/shell/testcases/bogons/nft-f/map_without_key5
-rw-r--r--tests/shell/testcases/bogons/nft-f/mapping_with_invalid_datatype_crash1
-rw-r--r--tests/shell/testcases/bogons/nft-f/memleak_on_hookspec_error21
-rw-r--r--tests/shell/testcases/bogons/nft-f/memleak_on_meta_set_errpath5
-rw-r--r--tests/shell/testcases/bogons/nft-f/nat_prefix_map_with_set_element_assert7
-rw-r--r--tests/shell/testcases/bogons/nft-f/nat_stmt_with_set_instead_of_map10
-rw-r--r--tests/shell/testcases/bogons/nft-f/netlink_gen_stmt_stateful_assert6
-rw-r--r--tests/shell/testcases/bogons/nft-f/no_integer_basetype_crash1
-rw-r--r--tests/shell/testcases/bogons/nft-f/objmap_to_prefix_assert6
-rw-r--r--tests/shell/testcases/bogons/nft-f/payload_expr_pctx_update_assert1
-rw-r--r--tests/shell/testcases/bogons/nft-f/payload_expr_unaligned_store1
-rw-r--r--tests/shell/testcases/bogons/nft-f/payload_expr_with_0_length_assert1
-rw-r--r--tests/shell/testcases/bogons/nft-f/scope_underflow_assert6
-rw-r--r--tests/shell/testcases/bogons/nft-f/set_definition_with_no_key_assert12
-rw-r--r--tests/shell/testcases/bogons/nft-f/set_without_key5
-rw-r--r--tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_concat_expr5
-rw-r--r--tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_raw_expr5
-rw-r--r--tests/shell/testcases/bogons/nft-f/tchandle_type_parse_heap_overflow6
-rw-r--r--tests/shell/testcases/bogons/nft-f/tcp_option_without_template1
-rw-r--r--tests/shell/testcases/bogons/nft-f/tproxy_ranges8
-rw-r--r--tests/shell/testcases/bogons/nft-f/unhandled_key_type_13_assert5
-rw-r--r--tests/shell/testcases/bogons/nft-f/unhandled_key_type_13_assert_map5
-rw-r--r--tests/shell/testcases/bogons/nft-f/unhandled_key_type_13_assert_vmap5
-rw-r--r--tests/shell/testcases/bogons/nft-f/unknown_expr_type_range_assert7
-rw-r--r--tests/shell/testcases/bogons/nft-f/use_after_free_on_chain_removal5
-rw-r--r--tests/shell/testcases/bogons/nft-f/zero_length_devicename2_assert5
-rw-r--r--tests/shell/testcases/bogons/nft-f/zero_length_devicename_assert5
-rw-r--r--tests/shell/testcases/bogons/nft-f/zero_length_devicename_flowtable_assert5
-rwxr-xr-xtests/shell/testcases/cache/0001_cache_handling_02
-rwxr-xr-xtests/shell/testcases/cache/0008_delete_by_handle_025
-rwxr-xr-xtests/shell/testcases/cache/0009_delete_by_handle_incorrect_08
-rwxr-xr-xtests/shell/testcases/cache/0010_implicit_chain_021
-rwxr-xr-xtests/shell/testcases/cache/0011_index_012
-rw-r--r--tests/shell/testcases/cache/dumps/0001_cache_handling_0.json-nft142
-rw-r--r--tests/shell/testcases/cache/dumps/0002_interval_0.json-nft38
-rw-r--r--tests/shell/testcases/cache/dumps/0003_cache_update_0.json-nft137
-rw-r--r--tests/shell/testcases/cache/dumps/0003_cache_update_0.nft18
-rw-r--r--tests/shell/testcases/cache/dumps/0004_cache_update_0.json-nft42
-rw-r--r--tests/shell/testcases/cache/dumps/0004_cache_update_0.nft5
-rw-r--r--tests/shell/testcases/cache/dumps/0005_cache_chain_flush.json-nft77
-rw-r--r--tests/shell/testcases/cache/dumps/0005_cache_chain_flush.nft14
-rw-r--r--tests/shell/testcases/cache/dumps/0006_cache_table_flush.json-nft77
-rw-r--r--tests/shell/testcases/cache/dumps/0006_cache_table_flush.nft14
-rw-r--r--tests/shell/testcases/cache/dumps/0007_echo_cache_init_0.json-nft68
-rw-r--r--tests/shell/testcases/cache/dumps/0008_delete_by_handle_0.json-nft18
-rw-r--r--tests/shell/testcases/cache/dumps/0008_delete_by_handle_0.nft2
-rw-r--r--tests/shell/testcases/cache/dumps/0009_delete_by_handle_incorrect_0.json-nft11
-rw-r--r--tests/shell/testcases/cache/dumps/0009_delete_by_handle_incorrect_0.nft0
-rw-r--r--tests/shell/testcases/cache/dumps/0010_implicit_chain_0.nft7
-rw-r--r--tests/shell/testcases/cache/dumps/0011_index_0.json-nft93
-rw-r--r--tests/shell/testcases/cache/dumps/0011_index_0.nft8
-rwxr-xr-xtests/shell/testcases/chains/0012reject_in_prerouting_111
-rwxr-xr-xtests/shell/testcases/chains/0014rename_02
-rwxr-xr-xtests/shell/testcases/chains/0016delete_handle_04
-rwxr-xr-xtests/shell/testcases/chains/0021prio_06
-rwxr-xr-xtests/shell/testcases/chains/0023prio_inet_srcnat_12
-rwxr-xr-xtests/shell/testcases/chains/0024prio_inet_dstnat_12
-rwxr-xr-xtests/shell/testcases/chains/0026prio_netdev_14
-rwxr-xr-x[-rw-r--r--]tests/shell/testcases/chains/0030create_00
-rwxr-xr-xtests/shell/testcases/chains/0032priority_variable_010
-rwxr-xr-xtests/shell/testcases/chains/0039negative_priority_08
-rwxr-xr-xtests/shell/testcases/chains/0041chain_binding_029
-rwxr-xr-xtests/shell/testcases/chains/0042chain_variable_071
-rwxr-xr-xtests/shell/testcases/chains/0043chain_ingress_019
-rwxr-xr-xtests/shell/testcases/chains/0044chain_destroy_012
-rw-r--r--tests/shell/testcases/chains/dumps/0001jumps_0.json-nft371
-rw-r--r--tests/shell/testcases/chains/dumps/0002jumps_1.json-nft383
-rw-r--r--tests/shell/testcases/chains/dumps/0002jumps_1.nft68
-rw-r--r--tests/shell/testcases/chains/dumps/0003jump_loop_1.json-nft371
-rw-r--r--tests/shell/testcases/chains/dumps/0003jump_loop_1.nft64
-rw-r--r--tests/shell/testcases/chains/dumps/0004busy_1.json-nft49
-rw-r--r--tests/shell/testcases/chains/dumps/0004busy_1.nft8
-rw-r--r--tests/shell/testcases/chains/dumps/0005busy_map_1.json-nft66
-rw-r--r--tests/shell/testcases/chains/dumps/0005busy_map_1.nft8
-rw-r--r--tests/shell/testcases/chains/dumps/0006masquerade_0.json-nft43
-rw-r--r--tests/shell/testcases/chains/dumps/0007masquerade_1.json-nft30
-rw-r--r--tests/shell/testcases/chains/dumps/0007masquerade_1.nft5
-rw-r--r--tests/shell/testcases/chains/dumps/0008masquerade_jump_1.json-nft51
-rw-r--r--tests/shell/testcases/chains/dumps/0008masquerade_jump_1.nft9
-rw-r--r--tests/shell/testcases/chains/dumps/0009masquerade_jump_1.json-nft51
-rw-r--r--tests/shell/testcases/chains/dumps/0009masquerade_jump_1.nft9
-rw-r--r--tests/shell/testcases/chains/dumps/0010endless_jump_loop_1.json-nft26
-rw-r--r--tests/shell/testcases/chains/dumps/0010endless_jump_loop_1.nft4
-rw-r--r--tests/shell/testcases/chains/dumps/0011endless_jump_loop_1.json-nft75
-rw-r--r--tests/shell/testcases/chains/dumps/0011endless_jump_loop_1.nft13
-rw-r--r--tests/shell/testcases/chains/dumps/0013rename_0.json-nft26
-rw-r--r--tests/shell/testcases/chains/dumps/0014rename_0.json-nft34
-rw-r--r--tests/shell/testcases/chains/dumps/0014rename_0.nft7
-rw-r--r--tests/shell/testcases/chains/dumps/0015check_jump_loop_1.json-nft49
-rw-r--r--tests/shell/testcases/chains/dumps/0015check_jump_loop_1.nft8
-rw-r--r--tests/shell/testcases/chains/dumps/0016delete_handle_0.json-nft57
-rw-r--r--tests/shell/testcases/chains/dumps/0017masquerade_jump_1.json-nft53
-rw-r--r--tests/shell/testcases/chains/dumps/0017masquerade_jump_1.nft9
-rw-r--r--tests/shell/testcases/chains/dumps/0018check_jump_loop_1.json-nft49
-rw-r--r--tests/shell/testcases/chains/dumps/0018check_jump_loop_1.nft8
-rw-r--r--tests/shell/testcases/chains/dumps/0019masquerade_jump_1.json-nft70
-rw-r--r--tests/shell/testcases/chains/dumps/0019masquerade_jump_1.nft9
-rw-r--r--tests/shell/testcases/chains/dumps/0020depth_1.json-nft475
-rw-r--r--tests/shell/testcases/chains/dumps/0020depth_1.nft84
-rw-r--r--tests/shell/testcases/chains/dumps/0021prio_0.json-nft4743
-rw-r--r--tests/shell/testcases/chains/dumps/0021prio_0.nft20
-rw-r--r--tests/shell/testcases/chains/dumps/0022prio_dummy_1.json-nft18
-rw-r--r--tests/shell/testcases/chains/dumps/0022prio_dummy_1.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/0023prio_inet_srcnat_1.json-nft32
-rw-r--r--tests/shell/testcases/chains/dumps/0023prio_inet_srcnat_1.nft6
-rw-r--r--tests/shell/testcases/chains/dumps/0024prio_inet_dstnat_1.json-nft32
-rw-r--r--tests/shell/testcases/chains/dumps/0024prio_inet_dstnat_1.nft6
-rw-r--r--tests/shell/testcases/chains/dumps/0025prio_arp_1.json-nft18
-rw-r--r--tests/shell/testcases/chains/dumps/0025prio_arp_1.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/0026prio_netdev_1.json-nft18
-rw-r--r--tests/shell/testcases/chains/dumps/0026prio_netdev_1.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/0027prio_bridge_dstnat_1.json-nft18
-rw-r--r--tests/shell/testcases/chains/dumps/0027prio_bridge_dstnat_1.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/0028prio_bridge_out_1.json-nft18
-rw-r--r--tests/shell/testcases/chains/dumps/0028prio_bridge_out_1.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/0029prio_bridge_srcnat_1.json-nft18
-rw-r--r--tests/shell/testcases/chains/dumps/0029prio_bridge_srcnat_1.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/0030create_0.json-nft26
-rw-r--r--tests/shell/testcases/chains/dumps/0031priority_variable_0.json-nft30
-rw-r--r--tests/shell/testcases/chains/dumps/0031priority_variable_0.nft (renamed from tests/shell/testcases/nft-f/dumps/0021priority_variable_0.nft)0
-rw-r--r--tests/shell/testcases/chains/dumps/0032priority_variable_0.json-nft54
-rw-r--r--tests/shell/testcases/chains/dumps/0032priority_variable_0.nft13
-rw-r--r--tests/shell/testcases/chains/dumps/0033priority_variable_1.json-nft11
-rw-r--r--tests/shell/testcases/chains/dumps/0033priority_variable_1.nft0
-rw-r--r--tests/shell/testcases/chains/dumps/0034priority_variable_1.json-nft11
-rw-r--r--tests/shell/testcases/chains/dumps/0034priority_variable_1.nft0
-rw-r--r--tests/shell/testcases/chains/dumps/0035policy_variable_0.json-nft30
-rw-r--r--tests/shell/testcases/chains/dumps/0035policy_variable_0.nft (renamed from tests/shell/testcases/nft-f/dumps/0025policy_variable_0.nft)0
-rw-r--r--tests/shell/testcases/chains/dumps/0036policy_variable_0.json-nft30
-rw-r--r--tests/shell/testcases/chains/dumps/0036policy_variable_0.nft (renamed from tests/shell/testcases/nft-f/dumps/0026policy_variable_0.nft)0
-rw-r--r--tests/shell/testcases/chains/dumps/0037policy_variable_1.json-nft11
-rw-r--r--tests/shell/testcases/chains/dumps/0037policy_variable_1.nft0
-rw-r--r--tests/shell/testcases/chains/dumps/0038policy_variable_1.json-nft11
-rw-r--r--tests/shell/testcases/chains/dumps/0038policy_variable_1.nft0
-rw-r--r--tests/shell/testcases/chains/dumps/0039negative_priority_0.json-nft30
-rw-r--r--tests/shell/testcases/chains/dumps/0039negative_priority_0.nft5
-rw-r--r--tests/shell/testcases/chains/dumps/0041chain_binding_0.nft12
-rw-r--r--tests/shell/testcases/chains/dumps/0042chain_variable_0.json-nft90
-rw-r--r--tests/shell/testcases/chains/dumps/0042chain_variable_0.nft19
-rw-r--r--tests/shell/testcases/chains/dumps/0043chain_ingress_0.json-nft55
-rw-r--r--tests/shell/testcases/chains/dumps/0043chain_ingress_0.nft13
-rw-r--r--tests/shell/testcases/chains/dumps/0044chain_destroy_0.json-nft18
-rw-r--r--tests/shell/testcases/chains/dumps/0044chain_destroy_0.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/netdev_chain_0.json-nft18
-rw-r--r--tests/shell/testcases/chains/dumps/netdev_chain_0.nft2
-rw-r--r--tests/shell/testcases/chains/dumps/netdev_chain_autoremove.json-nft11
-rw-r--r--tests/shell/testcases/chains/dumps/netdev_chain_autoremove.nft0
-rw-r--r--tests/shell/testcases/chains/dumps/netdev_chain_dev_gone.nodump0
-rw-r--r--tests/shell/testcases/chains/dumps/netdev_chain_multidev_gone.nodump0
-rw-r--r--tests/shell/testcases/chains/dumps/netdev_multidev_netns_gone.nodump0
-rw-r--r--tests/shell/testcases/chains/dumps/netdev_netns_gone.nodump0
-rwxr-xr-xtests/shell/testcases/chains/netdev_chain_029
-rwxr-xr-xtests/shell/testcases/chains/netdev_chain_autoremove9
-rwxr-xr-xtests/shell/testcases/chains/netdev_chain_dev_gone34
-rwxr-xr-xtests/shell/testcases/chains/netdev_chain_multidev_gone41
-rwxr-xr-xtests/shell/testcases/chains/netdev_multidev_netns_gone43
-rwxr-xr-xtests/shell/testcases/chains/netdev_netns_gone37
-rwxr-xr-xtests/shell/testcases/comments/comments_044
-rw-r--r--tests/shell/testcases/comments/dumps/comments_0.json-nft135
-rw-r--r--tests/shell/testcases/comments/dumps/comments_0.nft12
-rwxr-xr-xtests/shell/testcases/flowtable/0006segfault_03
-rwxr-xr-xtests/shell/testcases/flowtable/0010delete_handle_021
-rwxr-xr-xtests/shell/testcases/flowtable/0011deleteafterflush_010
-rwxr-xr-xtests/shell/testcases/flowtable/0012flowtable_variable_037
-rwxr-xr-xtests/shell/testcases/flowtable/0013addafterdelete_025
-rwxr-xr-xtests/shell/testcases/flowtable/0014addafterdelete_038
-rwxr-xr-xtests/shell/testcases/flowtable/0015destroy_020
-rw-r--r--tests/shell/testcases/flowtable/dumps/0001flowtable_0.json-nft53
-rw-r--r--tests/shell/testcases/flowtable/dumps/0002create_flowtable_0.json-nft29
-rw-r--r--tests/shell/testcases/flowtable/dumps/0002create_flowtable_0.nft6
-rw-r--r--tests/shell/testcases/flowtable/dumps/0003add_after_flush_0.json-nft29
-rw-r--r--tests/shell/testcases/flowtable/dumps/0003add_after_flush_0.nft6
-rw-r--r--tests/shell/testcases/flowtable/dumps/0004delete_after_add_0.json-nft18
-rw-r--r--tests/shell/testcases/flowtable/dumps/0004delete_after_add_0.nft2
-rw-r--r--tests/shell/testcases/flowtable/dumps/0005delete_in_use_1.json-nft53
-rw-r--r--tests/shell/testcases/flowtable/dumps/0005delete_in_use_1.nft10
-rw-r--r--tests/shell/testcases/flowtable/dumps/0006segfault_0.json-nft18
-rw-r--r--tests/shell/testcases/flowtable/dumps/0006segfault_0.nft2
-rw-r--r--tests/shell/testcases/flowtable/dumps/0007prio_0.json-nft18
-rw-r--r--tests/shell/testcases/flowtable/dumps/0007prio_0.nft2
-rw-r--r--tests/shell/testcases/flowtable/dumps/0008prio_1.json-nft18
-rw-r--r--tests/shell/testcases/flowtable/dumps/0008prio_1.nft2
-rw-r--r--tests/shell/testcases/flowtable/dumps/0009deleteafterflush_0.json-nft26
-rw-r--r--tests/shell/testcases/flowtable/dumps/0009deleteafterflush_0.nft4
-rw-r--r--tests/shell/testcases/flowtable/dumps/0010delete_handle_0.json-nft18
-rw-r--r--tests/shell/testcases/flowtable/dumps/0010delete_handle_0.nft2
-rw-r--r--tests/shell/testcases/flowtable/dumps/0011deleteafterflush_0.json-nft26
-rw-r--r--tests/shell/testcases/flowtable/dumps/0011deleteafterflush_0.nft4
-rw-r--r--tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.json-nft47
-rw-r--r--tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.nft14
-rw-r--r--tests/shell/testcases/flowtable/dumps/0013addafterdelete_0.json-nft29
-rw-r--r--tests/shell/testcases/flowtable/dumps/0013addafterdelete_0.nft6
-rw-r--r--tests/shell/testcases/flowtable/dumps/0014addafterdelete_0.json-nft63
-rw-r--r--tests/shell/testcases/flowtable/dumps/0014addafterdelete_0.nft12
-rw-r--r--tests/shell/testcases/flowtable/dumps/0015destroy_0.json-nft18
-rw-r--r--tests/shell/testcases/flowtable/dumps/0015destroy_0.nft2
-rwxr-xr-xtests/shell/testcases/include/0003includepath_04
-rwxr-xr-xtests/shell/testcases/include/0016maxdepth_08
-rwxr-xr-xtests/shell/testcases/include/0017glob_more_than_maxdepth_139
-rwxr-xr-xtests/shell/testcases/include/0018include_error_034
-rwxr-xr-xtests/shell/testcases/include/0019include_error_063
-rwxr-xr-xtests/shell/testcases/include/0020include_chain_030
-rw-r--r--tests/shell/testcases/include/dumps/0001absolute_0.json-nft18
-rw-r--r--tests/shell/testcases/include/dumps/0002relative_0.json-nft18
-rw-r--r--tests/shell/testcases/include/dumps/0003includepath_0.json-nft18
-rw-r--r--tests/shell/testcases/include/dumps/0004endlessloop_1.json-nft11
-rw-r--r--tests/shell/testcases/include/dumps/0004endlessloop_1.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0005glob_empty_0.json-nft11
-rw-r--r--tests/shell/testcases/include/dumps/0005glob_empty_0.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0006glob_single_0.json-nft18
-rw-r--r--tests/shell/testcases/include/dumps/0007glob_double_0.json-nft25
-rw-r--r--tests/shell/testcases/include/dumps/0008glob_nofile_wildcard_0.json-nft11
-rw-r--r--tests/shell/testcases/include/dumps/0008glob_nofile_wildcard_0.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0009glob_nofile_1.json-nft11
-rw-r--r--tests/shell/testcases/include/dumps/0009glob_nofile_1.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0010glob_broken_file_1.json-nft11
-rw-r--r--tests/shell/testcases/include/dumps/0010glob_broken_file_1.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0011glob_dependency_0.json-nft26
-rw-r--r--tests/shell/testcases/include/dumps/0012glob_dependency_1.json-nft11
-rw-r--r--tests/shell/testcases/include/dumps/0012glob_dependency_1.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0013glob_dotfile_0.json-nft18
-rw-r--r--tests/shell/testcases/include/dumps/0013input_descriptors_included_files_0.json-nft11
-rw-r--r--tests/shell/testcases/include/dumps/0013input_descriptors_included_files_0.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0014glob_directory_0.json-nft11
-rw-r--r--tests/shell/testcases/include/dumps/0014glob_directory_0.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0015doubleincludepath_0.json-nft26
-rw-r--r--tests/shell/testcases/include/dumps/0016maxdepth_0.json-nft11
-rw-r--r--tests/shell/testcases/include/dumps/0016maxdepth_0.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0017glob_more_than_maxdepth_1.json-nft11
-rw-r--r--tests/shell/testcases/include/dumps/0017glob_more_than_maxdepth_1.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0018include_error_0.json-nft11
-rw-r--r--tests/shell/testcases/include/dumps/0018include_error_0.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0019include_error_0.json-nft11
-rw-r--r--tests/shell/testcases/include/dumps/0019include_error_0.nft0
-rw-r--r--tests/shell/testcases/include/dumps/0020include_chain_0.json-nft128
-rw-r--r--tests/shell/testcases/include/dumps/0020include_chain_0.nft11
-rwxr-xr-xtests/shell/testcases/json/0001set_statements_011
-rwxr-xr-xtests/shell/testcases/json/0002table_map_012
-rwxr-xr-xtests/shell/testcases/json/0003json_schema_version_011
-rwxr-xr-xtests/shell/testcases/json/0004json_schema_version_113
-rwxr-xr-xtests/shell/testcases/json/0005secmark_objref_012
-rwxr-xr-xtests/shell/testcases/json/0006obj_comment_012
-rw-r--r--tests/shell/testcases/json/dumps/0001set_statements_0.json-nft100
-rw-r--r--tests/shell/testcases/json/dumps/0001set_statements_0.nft12
-rw-r--r--tests/shell/testcases/json/dumps/0002table_map_0.json-nft33
-rw-r--r--tests/shell/testcases/json/dumps/0002table_map_0.nft6
-rw-r--r--tests/shell/testcases/json/dumps/0003json_schema_version_0.json-nft11
-rw-r--r--tests/shell/testcases/json/dumps/0003json_schema_version_0.nft0
-rw-r--r--tests/shell/testcases/json/dumps/0004json_schema_version_1.json-nft11
-rw-r--r--tests/shell/testcases/json/dumps/0004json_schema_version_1.nft0
-rw-r--r--tests/shell/testcases/json/dumps/0005secmark_objref_0.json-nft233
-rw-r--r--tests/shell/testcases/json/dumps/0005secmark_objref_0.nft18
-rw-r--r--tests/shell/testcases/json/dumps/0006obj_comment_0.json-nft29
-rw-r--r--tests/shell/testcases/json/dumps/0006obj_comment_0.nft6
-rw-r--r--tests/shell/testcases/json/dumps/netdev.json-nft18
-rw-r--r--tests/shell/testcases/json/dumps/netdev.nft2
-rwxr-xr-xtests/shell/testcases/json/netdev28
-rwxr-xr-xtests/shell/testcases/listing/0003table_06
-rwxr-xr-xtests/shell/testcases/listing/0004table_03
-rwxr-xr-xtests/shell/testcases/listing/0005ruleset_ip_03
-rwxr-xr-xtests/shell/testcases/listing/0006ruleset_ip6_03
-rwxr-xr-xtests/shell/testcases/listing/0007ruleset_inet_03
-rwxr-xr-xtests/shell/testcases/listing/0008ruleset_arp_03
-rwxr-xr-xtests/shell/testcases/listing/0009ruleset_bridge_03
-rwxr-xr-xtests/shell/testcases/listing/0010sets_03
-rwxr-xr-xtests/shell/testcases/listing/0011sets_03
-rwxr-xr-xtests/shell/testcases/listing/0012sets_03
-rwxr-xr-xtests/shell/testcases/listing/0013objects_051
-rwxr-xr-xtests/shell/testcases/listing/0014objects_06
-rwxr-xr-xtests/shell/testcases/listing/0015dynamic_03
-rwxr-xr-xtests/shell/testcases/listing/0017objects_03
-rwxr-xr-xtests/shell/testcases/listing/0018data_03
-rwxr-xr-xtests/shell/testcases/listing/0019set_03
-rwxr-xr-xtests/shell/testcases/listing/0020flowtable_065
-rwxr-xr-xtests/shell/testcases/listing/0021ruleset_json_terse_019
-rwxr-xr-xtests/shell/testcases/listing/0022terse_069
-rw-r--r--tests/shell/testcases/listing/dumps/0001ruleset_0.json-nft18
-rw-r--r--tests/shell/testcases/listing/dumps/0002ruleset_0.json-nft11
-rw-r--r--tests/shell/testcases/listing/dumps/0002ruleset_0.nft0
-rw-r--r--tests/shell/testcases/listing/dumps/0003table_0.json-nft18
-rw-r--r--tests/shell/testcases/listing/dumps/0003table_0.nft2
-rw-r--r--tests/shell/testcases/listing/dumps/0004table_0.json-nft25
-rw-r--r--tests/shell/testcases/listing/dumps/0004table_0.nft4
-rw-r--r--tests/shell/testcases/listing/dumps/0005ruleset_ip_0.json-nft46
-rw-r--r--tests/shell/testcases/listing/dumps/0005ruleset_ip_0.nft10
-rw-r--r--tests/shell/testcases/listing/dumps/0006ruleset_ip6_0.json-nft46
-rw-r--r--tests/shell/testcases/listing/dumps/0006ruleset_ip6_0.nft10
-rw-r--r--tests/shell/testcases/listing/dumps/0007ruleset_inet_0.json-nft46
-rw-r--r--tests/shell/testcases/listing/dumps/0007ruleset_inet_0.nft10
-rw-r--r--tests/shell/testcases/listing/dumps/0008ruleset_arp_0.json-nft46
-rw-r--r--tests/shell/testcases/listing/dumps/0008ruleset_arp_0.nft10
-rw-r--r--tests/shell/testcases/listing/dumps/0009ruleset_bridge_0.json-nft46
-rw-r--r--tests/shell/testcases/listing/dumps/0009ruleset_bridge_0.nft10
-rw-r--r--tests/shell/testcases/listing/dumps/0010sets_0.json-nft124
-rw-r--r--tests/shell/testcases/listing/dumps/0010sets_0.nft39
-rw-r--r--tests/shell/testcases/listing/dumps/0011sets_0.json-nft220
-rw-r--r--tests/shell/testcases/listing/dumps/0011sets_0.nft25
-rw-r--r--tests/shell/testcases/listing/dumps/0012sets_0.json-nft124
-rw-r--r--tests/shell/testcases/listing/dumps/0012sets_0.nft39
-rw-r--r--tests/shell/testcases/listing/dumps/0013objects_0.json-nft75
-rw-r--r--tests/shell/testcases/listing/dumps/0013objects_0.nft27
-rw-r--r--tests/shell/testcases/listing/dumps/0014objects_0.json-nft47
-rw-r--r--tests/shell/testcases/listing/dumps/0014objects_0.nft12
-rw-r--r--tests/shell/testcases/listing/dumps/0015dynamic_0.json-nft38
-rw-r--r--tests/shell/testcases/listing/dumps/0015dynamic_0.nft7
-rw-r--r--tests/shell/testcases/listing/dumps/0016anonymous_0.json-nft85
-rw-r--r--tests/shell/testcases/listing/dumps/0016anonymous_0.nft6
-rw-r--r--tests/shell/testcases/listing/dumps/0017objects_0.json-nft28
-rw-r--r--tests/shell/testcases/listing/dumps/0017objects_0.nft5
-rw-r--r--tests/shell/testcases/listing/dumps/0018data_0.json-nft28
-rw-r--r--tests/shell/testcases/listing/dumps/0018data_0.nft5
-rw-r--r--tests/shell/testcases/listing/dumps/0019set_0.json-nft27
-rw-r--r--tests/shell/testcases/listing/dumps/0019set_0.nft5
-rw-r--r--tests/shell/testcases/listing/dumps/0020flowtable_0.json-nft67
-rw-r--r--tests/shell/testcases/listing/dumps/0020flowtable_0.nft20
-rw-r--r--tests/shell/testcases/listing/dumps/0021ruleset_json_terse_0.json-nft39
-rw-r--r--tests/shell/testcases/listing/dumps/0021ruleset_json_terse_0.nft9
-rw-r--r--tests/shell/testcases/listing/dumps/0022terse_0.json-nft88
-rw-r--r--tests/shell/testcases/listing/dumps/0022terse_0.nft12
-rw-r--r--tests/shell/testcases/listing/dumps/meta_time.nodump0
-rwxr-xr-xtests/shell/testcases/listing/meta_time67
-rwxr-xr-xtests/shell/testcases/maps/0003map_add_many_elements_03
-rwxr-xr-xtests/shell/testcases/maps/0004interval_map_create_once_011
-rwxr-xr-xtests/shell/testcases/maps/0008interval_map_delete_05
-rwxr-xr-xtests/shell/testcases/maps/0009vmap_021
-rwxr-xr-xtests/shell/testcases/maps/0010concat_map_021
-rwxr-xr-xtests/shell/testcases/maps/0011vmap_033
-rwxr-xr-xtests/shell/testcases/maps/0012map_017
-rwxr-xr-xtests/shell/testcases/maps/0012map_concat_024
-rwxr-xr-xtests/shell/testcases/maps/0013map_016
-rwxr-xr-xtests/shell/testcases/maps/0014destroy_012
-rwxr-xr-xtests/shell/testcases/maps/0016map_leak_038
-rwxr-xr-xtests/shell/testcases/maps/0017_map_variable_032
-rwxr-xr-xtests/shell/testcases/maps/0018map_leak_timeout_050
-rwxr-xr-xtests/shell/testcases/maps/0024named_objects_0 (renamed from tests/shell/testcases/sets/0024named_objects_0)12
-rwxr-xr-xtests/shell/testcases/maps/anon_objmap_concat8
-rw-r--r--tests/shell/testcases/maps/dumps/0003map_add_many_elements_0.json-nft3874
-rw-r--r--tests/shell/testcases/maps/dumps/0003map_add_many_elements_0.nft486
-rw-r--r--tests/shell/testcases/maps/dumps/0004interval_map_create_once_0.nodump0
-rw-r--r--tests/shell/testcases/maps/dumps/0005interval_map_add_many_elements_0.json-nft69
-rw-r--r--tests/shell/testcases/maps/dumps/0006interval_map_overlap_0.json-nft51
-rw-r--r--tests/shell/testcases/maps/dumps/0007named_ifname_dtype_0.json-nft102
-rw-r--r--tests/shell/testcases/maps/dumps/0008interval_map_delete_0.json-nft159
-rw-r--r--tests/shell/testcases/maps/dumps/0008interval_map_delete_0.nft15
-rw-r--r--tests/shell/testcases/maps/dumps/0009vmap_0.json-nft117
-rw-r--r--tests/shell/testcases/maps/dumps/0009vmap_0.nft13
-rw-r--r--tests/shell/testcases/maps/dumps/0010concat_map_0.json-nft106
-rw-r--r--tests/shell/testcases/maps/dumps/0010concat_map_0.nft11
-rw-r--r--tests/shell/testcases/maps/dumps/0011vmap_0.json-nft145
-rw-r--r--tests/shell/testcases/maps/dumps/0011vmap_0.nft19
-rw-r--r--tests/shell/testcases/maps/dumps/0012map_0.json-nft97
-rw-r--r--tests/shell/testcases/maps/dumps/0012map_0.nft12
-rw-r--r--tests/shell/testcases/maps/dumps/0012map_concat_0.json-nft132
-rw-r--r--tests/shell/testcases/maps/dumps/0012map_concat_0.nft14
-rw-r--r--tests/shell/testcases/maps/dumps/0013map_0.json-nft128
-rw-r--r--tests/shell/testcases/maps/dumps/0013map_0.nft13
-rw-r--r--tests/shell/testcases/maps/dumps/0014destroy_0.json-nft18
-rw-r--r--tests/shell/testcases/maps/dumps/0014destroy_0.nft2
-rw-r--r--tests/shell/testcases/maps/dumps/0016map_leak_0.json-nft11
-rw-r--r--tests/shell/testcases/maps/dumps/0016map_leak_0.nft0
-rw-r--r--tests/shell/testcases/maps/dumps/0017_map_variable_0.json-nft58
-rw-r--r--tests/shell/testcases/maps/dumps/0017_map_variable_0.nft11
-rw-r--r--tests/shell/testcases/maps/dumps/0018map_leak_timeout_0.json-nft11
-rw-r--r--tests/shell/testcases/maps/dumps/0018map_leak_timeout_0.nft0
-rw-r--r--tests/shell/testcases/maps/dumps/0024named_objects_0.json-nft165
-rw-r--r--tests/shell/testcases/maps/dumps/0024named_objects_0.nft (renamed from tests/shell/testcases/sets/dumps/0024named_objects_0.nft)0
-rw-r--r--tests/shell/testcases/maps/dumps/anon_objmap_concat.json-nft116
-rw-r--r--tests/shell/testcases/maps/dumps/anon_objmap_concat.nft16
-rw-r--r--tests/shell/testcases/maps/dumps/anonymous_snat_map_0.json-nft58
-rw-r--r--tests/shell/testcases/maps/dumps/different_map_types_1.json-nft30
-rw-r--r--tests/shell/testcases/maps/dumps/different_map_types_1.nft5
-rw-r--r--tests/shell/testcases/maps/dumps/map_catchall_double_deactivate.json-nft26
-rw-r--r--tests/shell/testcases/maps/dumps/map_catchall_double_deactivate.nft4
-rw-r--r--tests/shell/testcases/maps/dumps/map_catchall_double_free.nodump0
-rw-r--r--tests/shell/testcases/maps/dumps/map_catchall_double_free_2.json-nft46
-rw-r--r--tests/shell/testcases/maps/dumps/map_catchall_double_free_2.nft9
-rw-r--r--tests/shell/testcases/maps/dumps/map_with_flags_0.json-nft31
-rw-r--r--tests/shell/testcases/maps/dumps/named_ct_objects.nft71
-rw-r--r--tests/shell/testcases/maps/dumps/named_limits.json-nft328
-rw-r--r--tests/shell/testcases/maps/dumps/named_limits.nft55
-rw-r--r--tests/shell/testcases/maps/dumps/named_snat_map_0.json-nft67
-rw-r--r--tests/shell/testcases/maps/dumps/nat_addr_port.nft129
-rw-r--r--tests/shell/testcases/maps/dumps/pipapo_double_flush.json-nft42
-rw-r--r--tests/shell/testcases/maps/dumps/pipapo_double_flush.nft9
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_integer_0.nft20
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_maps_0.nft36
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_maps_add_delete.json-nft283
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_maps_add_delete.nft22
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_maps_concat.nft11
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_maps_concat_update_0.nft13
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_maps_update_0.json-nft110
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_maps_update_0.nft21
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_raw_0.nft13
-rw-r--r--tests/shell/testcases/maps/dumps/vmap_mark_bitwise_0.json-nft158
-rw-r--r--tests/shell/testcases/maps/dumps/vmap_mark_bitwise_0.nft26
-rw-r--r--tests/shell/testcases/maps/dumps/vmap_timeout.json-nft229
-rw-r--r--tests/shell/testcases/maps/dumps/vmap_timeout.nft36
-rw-r--r--tests/shell/testcases/maps/dumps/vmap_unary.nft11
-rwxr-xr-xtests/shell/testcases/maps/map_catchall_double_deactivate13
-rwxr-xr-xtests/shell/testcases/maps/map_catchall_double_free13
-rwxr-xr-xtests/shell/testcases/maps/map_catchall_double_free_227
-rwxr-xr-xtests/shell/testcases/maps/named_ct_objects94
-rwxr-xr-xtests/shell/testcases/maps/named_limits61
-rwxr-xr-xtests/shell/testcases/maps/nat_addr_port207
-rwxr-xr-xtests/shell/testcases/maps/pipapo_double_flush25
-rwxr-xr-xtests/shell/testcases/maps/typeof_integer_029
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_0101
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_add_delete56
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_concat6
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_concat_update_019
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_update_028
-rwxr-xr-xtests/shell/testcases/maps/typeof_raw_018
-rwxr-xr-xtests/shell/testcases/maps/vmap_mark_bitwise_040
-rwxr-xr-xtests/shell/testcases/maps/vmap_timeout53
-rwxr-xr-xtests/shell/testcases/maps/vmap_unary19
-rwxr-xr-xtests/shell/testcases/netns/0001nft-f_03
-rwxr-xr-xtests/shell/testcases/netns/0002loosecommands_03
-rwxr-xr-xtests/shell/testcases/netns/0003many_03
-rw-r--r--tests/shell/testcases/netns/dumps/0001nft-f_0.json-nft11
-rw-r--r--tests/shell/testcases/netns/dumps/0001nft-f_0.nft0
-rw-r--r--tests/shell/testcases/netns/dumps/0002loosecommands_0.json-nft11
-rw-r--r--tests/shell/testcases/netns/dumps/0002loosecommands_0.nft0
-rw-r--r--tests/shell/testcases/netns/dumps/0003many_0.json-nft11
-rw-r--r--tests/shell/testcases/netns/dumps/0003many_0.nft0
-rwxr-xr-xtests/shell/testcases/nft-f/0011manydefines_016
-rwxr-xr-xtests/shell/testcases/nft-f/0012different_defines_07
-rwxr-xr-xtests/shell/testcases/nft-f/0016redefines_13
-rwxr-xr-xtests/shell/testcases/nft-f/0017ct_timeout_obj_02
-rwxr-xr-xtests/shell/testcases/nft-f/0018ct_expectation_obj_02
-rwxr-xr-xtests/shell/testcases/nft-f/0022variables_021
-rwxr-xr-xtests/shell/testcases/nft-f/0023check_112
-rwxr-xr-xtests/shell/testcases/nft-f/0024priority_014
-rwxr-xr-xtests/shell/testcases/nft-f/0025empty_dynset_030
-rwxr-xr-xtests/shell/testcases/nft-f/0026listing_014
-rwxr-xr-xtests/shell/testcases/nft-f/0027split_chains_017
-rwxr-xr-xtests/shell/testcases/nft-f/0028variable_cmdline_017
-rwxr-xr-xtests/shell/testcases/nft-f/0029split_file_025
-rwxr-xr-xtests/shell/testcases/nft-f/0030variable_reuse_019
-rwxr-xr-xtests/shell/testcases/nft-f/0031vmap_string_021
-rwxr-xr-xtests/shell/testcases/nft-f/0032pknock_034
-rw-r--r--tests/shell/testcases/nft-f/dumps/0001define_slash_0.json-nft11
-rw-r--r--tests/shell/testcases/nft-f/dumps/0001define_slash_0.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0002rollback_rule_0.json-nft134
-rw-r--r--tests/shell/testcases/nft-f/dumps/0003rollback_jump_0.json-nft134
-rw-r--r--tests/shell/testcases/nft-f/dumps/0004rollback_set_0.json-nft134
-rw-r--r--tests/shell/testcases/nft-f/dumps/0005rollback_map_0.json-nft134
-rw-r--r--tests/shell/testcases/nft-f/dumps/0006action_object_0.json-nft11
-rw-r--r--tests/shell/testcases/nft-f/dumps/0006action_object_0.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0007action_object_set_segfault_1.json-nft11
-rw-r--r--tests/shell/testcases/nft-f/dumps/0007action_object_set_segfault_1.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0008split_tables_0.json-nft67
-rw-r--r--tests/shell/testcases/nft-f/dumps/0009variable_0.json-nft44
-rw-r--r--tests/shell/testcases/nft-f/dumps/0010variable_0.json-nft30
-rw-r--r--tests/shell/testcases/nft-f/dumps/0011manydefines_0.nodump0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0012different_defines_0.json-nft778
-rw-r--r--tests/shell/testcases/nft-f/dumps/0012different_defines_0.nft7
-rw-r--r--tests/shell/testcases/nft-f/dumps/0013defines_1.json-nft11
-rw-r--r--tests/shell/testcases/nft-f/dumps/0013defines_1.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0014defines_1.json-nft11
-rw-r--r--tests/shell/testcases/nft-f/dumps/0014defines_1.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0015defines_1.json-nft11
-rw-r--r--tests/shell/testcases/nft-f/dumps/0015defines_1.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0016redefines_1.json-nft80
-rw-r--r--tests/shell/testcases/nft-f/dumps/0016redefines_1.nft6
-rw-r--r--tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.json-nft53
-rw-r--r--tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.nft2
-rw-r--r--tests/shell/testcases/nft-f/dumps/0018ct_expectation_obj_0.json-nft52
-rw-r--r--tests/shell/testcases/nft-f/dumps/0018ct_expectation_obj_0.nft13
-rw-r--r--tests/shell/testcases/nft-f/dumps/0018jump_variable_0.json-nft49
-rw-r--r--tests/shell/testcases/nft-f/dumps/0019jump_variable_1.json-nft11
-rw-r--r--tests/shell/testcases/nft-f/dumps/0019jump_variable_1.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0020jump_variable_1.json-nft11
-rw-r--r--tests/shell/testcases/nft-f/dumps/0020jump_variable_1.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0021list_ruleset_0.json-nft30
-rw-r--r--tests/shell/testcases/nft-f/dumps/0022priority_variable_0.nft5
-rw-r--r--tests/shell/testcases/nft-f/dumps/0022variables_0.json-nft115
-rw-r--r--tests/shell/testcases/nft-f/dumps/0022variables_0.nft14
-rw-r--r--tests/shell/testcases/nft-f/dumps/0023check_1.json-nft30
-rw-r--r--tests/shell/testcases/nft-f/dumps/0023check_1.nft5
-rw-r--r--tests/shell/testcases/nft-f/dumps/0024priority_0.json-nft95
-rw-r--r--tests/shell/testcases/nft-f/dumps/0024priority_0.nft10
-rw-r--r--tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.json-nft111
-rw-r--r--tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.nft18
-rw-r--r--tests/shell/testcases/nft-f/dumps/0026listing_0.json-nft56
-rw-r--r--tests/shell/testcases/nft-f/dumps/0026listing_0.nft5
-rw-r--r--tests/shell/testcases/nft-f/dumps/0027split_chains_0.json-nft53
-rw-r--r--tests/shell/testcases/nft-f/dumps/0027split_chains_0.nft9
-rw-r--r--tests/shell/testcases/nft-f/dumps/0028variable_cmdline_0.json-nft34
-rw-r--r--tests/shell/testcases/nft-f/dumps/0028variable_cmdline_0.nft8
-rw-r--r--tests/shell/testcases/nft-f/dumps/0029split_file_0.json-nft61
-rw-r--r--tests/shell/testcases/nft-f/dumps/0029split_file_0.nft10
-rw-r--r--tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.json-nft44
-rw-r--r--tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.nft11
-rw-r--r--tests/shell/testcases/nft-f/dumps/0031vmap_string_0.json-nft11
-rw-r--r--tests/shell/testcases/nft-f/dumps/0031vmap_string_0.nft0
-rw-r--r--tests/shell/testcases/nft-f/dumps/0032pknock_0.json-nft484
-rw-r--r--tests/shell/testcases/nft-f/dumps/0032pknock_0.nft25
-rw-r--r--tests/shell/testcases/nft-f/dumps/sample-ruleset.nft239
-rwxr-xr-xtests/shell/testcases/nft-f/sample-ruleset262
-rwxr-xr-xtests/shell/testcases/nft-i/0001define_022
-rw-r--r--tests/shell/testcases/nft-i/dumps/0001define_0.json-nft11
-rw-r--r--tests/shell/testcases/nft-i/dumps/0001define_0.nft0
-rwxr-xr-xtests/shell/testcases/optimizations/dependency_kill48
-rw-r--r--tests/shell/testcases/optimizations/dumps/dependency_kill.json-nft776
-rw-r--r--tests/shell/testcases/optimizations/dumps/dependency_kill.nft42
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_nat.json-nft379
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_nat.nft21
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_nat_concat.json-nft200
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_nat_concat.nft8
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_nat_inet.json-nft208
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_nat_inet.nft11
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_reject.json-nft320
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_reject.nft13
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts.json-nft63
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts.nft5
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_concat.json-nft374
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft18
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.json-nft167
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.nft9
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.json-nft182
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.nft13
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_vmap_raw.json-nft438
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_vmap_raw.nft31
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_vmaps.json-nft205
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_vmaps.nft20
-rw-r--r--tests/shell/testcases/optimizations/dumps/not_mergeable.json-nft140
-rw-r--r--tests/shell/testcases/optimizations/dumps/not_mergeable.nft19
-rw-r--r--tests/shell/testcases/optimizations/dumps/ruleset.json-nft11
-rw-r--r--tests/shell/testcases/optimizations/dumps/ruleset.nft0
-rw-r--r--tests/shell/testcases/optimizations/dumps/single_anon_set.json-nft360
-rw-r--r--tests/shell/testcases/optimizations/dumps/single_anon_set.nft15
-rw-r--r--tests/shell/testcases/optimizations/dumps/single_anon_set_expr.json-nft59
-rw-r--r--tests/shell/testcases/optimizations/dumps/single_anon_set_expr.nft5
-rw-r--r--tests/shell/testcases/optimizations/dumps/skip_merge.json-nft235
-rw-r--r--tests/shell/testcases/optimizations/dumps/skip_merge.nft23
-rw-r--r--tests/shell/testcases/optimizations/dumps/skip_non_eq.json-nft108
-rw-r--r--tests/shell/testcases/optimizations/dumps/skip_non_eq.nft6
-rw-r--r--tests/shell/testcases/optimizations/dumps/skip_unsupported.json-nft256
-rw-r--r--tests/shell/testcases/optimizations/dumps/skip_unsupported.nft18
-rw-r--r--tests/shell/testcases/optimizations/dumps/variables.json-nft11
-rw-r--r--tests/shell/testcases/optimizations/dumps/variables.nft0
-rwxr-xr-xtests/shell/testcases/optimizations/merge_nat38
-rwxr-xr-xtests/shell/testcases/optimizations/merge_nat_concat18
-rwxr-xr-xtests/shell/testcases/optimizations/merge_nat_inet21
-rwxr-xr-xtests/shell/testcases/optimizations/merge_reject26
-rwxr-xr-xtests/shell/testcases/optimizations/merge_stmts13
-rwxr-xr-xtests/shell/testcases/optimizations/merge_stmts_concat37
-rwxr-xr-xtests/shell/testcases/optimizations/merge_stmts_concat_vmap17
-rwxr-xr-xtests/shell/testcases/optimizations/merge_stmts_vmap23
-rwxr-xr-xtests/shell/testcases/optimizations/merge_vmap_raw34
-rwxr-xr-xtests/shell/testcases/optimizations/merge_vmaps31
-rwxr-xr-xtests/shell/testcases/optimizations/not_mergeable22
-rwxr-xr-xtests/shell/testcases/optimizations/ruleset170
-rwxr-xr-xtests/shell/testcases/optimizations/single_anon_set53
-rwxr-xr-xtests/shell/testcases/optimizations/single_anon_set_expr26
-rwxr-xr-xtests/shell/testcases/optimizations/skip_merge34
-rwxr-xr-xtests/shell/testcases/optimizations/skip_non_eq12
-rwxr-xr-xtests/shell/testcases/optimizations/skip_unsupported25
-rwxr-xr-xtests/shell/testcases/optimizations/variables15
-rwxr-xr-xtests/shell/testcases/optionals/comments_02
-rwxr-xr-xtests/shell/testcases/optionals/comments_chain_014
-rwxr-xr-xtests/shell/testcases/optionals/comments_handles_02
-rwxr-xr-xtests/shell/testcases/optionals/comments_objects_058
-rwxr-xr-xtests/shell/testcases/optionals/comments_objects_dup_097
-rwxr-xr-xtests/shell/testcases/optionals/comments_table_07
-rwxr-xr-xtests/shell/testcases/optionals/delete_object_handles_07
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_0.json-nft58
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_chain_0.json-nft27
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_chain_0.nft5
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_handles_0.json-nft58
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_objects_0.json-nft102
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_objects_0.nft42
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_objects_dup_0.json-nft11
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_objects_dup_0.nft0
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_table_0.json-nft19
-rw-r--r--tests/shell/testcases/optionals/dumps/comments_table_0.nft3
-rw-r--r--tests/shell/testcases/optionals/dumps/delete_object_handles_0.json-nft67
-rw-r--r--tests/shell/testcases/optionals/dumps/delete_object_handles_0.nft18
-rw-r--r--tests/shell/testcases/optionals/dumps/handles_0.json-nft57
-rw-r--r--tests/shell/testcases/optionals/dumps/handles_1.json-nft57
-rw-r--r--tests/shell/testcases/optionals/dumps/handles_1.nft5
-rw-r--r--tests/shell/testcases/optionals/dumps/log_prefix_0.json-nft52
-rw-r--r--tests/shell/testcases/optionals/dumps/log_prefix_0.nft5
-rw-r--r--tests/shell/testcases/optionals/dumps/update_object_handles_0.json-nft39
-rw-r--r--tests/shell/testcases/optionals/dumps/update_object_handles_0.nft9
-rwxr-xr-xtests/shell/testcases/optionals/handles_02
-rwxr-xr-xtests/shell/testcases/optionals/log_prefix_016
-rwxr-xr-xtests/shell/testcases/optionals/update_object_handles_026
-rwxr-xr-xtests/shell/testcases/owner/0001-flowtable-uaf26
-rw-r--r--tests/shell/testcases/owner/dumps/0001-flowtable-uaf.json-nft11
-rw-r--r--tests/shell/testcases/owner/dumps/0001-flowtable-uaf.nft0
-rw-r--r--tests/shell/testcases/owner/dumps/0002-persist.json-nft19
-rw-r--r--tests/shell/testcases/owner/dumps/0002-persist.nft3
-rw-r--r--tests/shell/testcases/packetpath/dumps/payload.nodump0
-rw-r--r--tests/shell/testcases/packetpath/dumps/set_lookups.json-nft674
-rw-r--r--tests/shell/testcases/packetpath/dumps/set_lookups.nft51
-rw-r--r--tests/shell/testcases/packetpath/dumps/tcp_options.nodump0
-rw-r--r--tests/shell/testcases/packetpath/dumps/vlan_8021ad_tag.nodump0
-rwxr-xr-xtests/shell/testcases/packetpath/flowtables96
-rwxr-xr-xtests/shell/testcases/packetpath/payload182
-rwxr-xr-xtests/shell/testcases/packetpath/set_lookups66
-rwxr-xr-xtests/shell/testcases/packetpath/tcp_options57
-rwxr-xr-xtests/shell/testcases/packetpath/vlan_8021ad_tag50
-rwxr-xr-xtests/shell/testcases/parsing/describe7
-rw-r--r--tests/shell/testcases/parsing/dumps/describe.json-nft11
-rw-r--r--tests/shell/testcases/parsing/dumps/describe.nft0
-rw-r--r--tests/shell/testcases/parsing/dumps/large_rule_pipe.json-nft4079
-rw-r--r--tests/shell/testcases/parsing/dumps/large_rule_pipe.nft561
-rw-r--r--tests/shell/testcases/parsing/dumps/log.json-nft11
-rw-r--r--tests/shell/testcases/parsing/dumps/log.nft0
-rw-r--r--tests/shell/testcases/parsing/dumps/octal.json-nft11
-rw-r--r--tests/shell/testcases/parsing/dumps/octal.nft0
-rwxr-xr-xtests/shell/testcases/parsing/large_rule_pipe571
-rwxr-xr-xtests/shell/testcases/parsing/log10
-rwxr-xr-xtests/shell/testcases/parsing/octal13
-rwxr-xr-xtests/shell/testcases/rule_management/0001addinsertposition_012
-rwxr-xr-xtests/shell/testcases/rule_management/0003insert_04
-rwxr-xr-xtests/shell/testcases/rule_management/0010replace_02
-rwxr-xr-xtests/shell/testcases/rule_management/0011reset_0170
-rwxr-xr-xtests/shell/testcases/rule_management/0012destroy_014
-rw-r--r--tests/shell/testcases/rule_management/dumps/0001addinsertposition_0.json-nft65
-rw-r--r--tests/shell/testcases/rule_management/dumps/0001addinsertposition_0.nft7
-rw-r--r--tests/shell/testcases/rule_management/dumps/0002addinsertlocation_1.json-nft52
-rw-r--r--tests/shell/testcases/rule_management/dumps/0002addinsertlocation_1.nft6
-rw-r--r--tests/shell/testcases/rule_management/dumps/0003insert_0.json-nft102
-rw-r--r--tests/shell/testcases/rule_management/dumps/0003insert_0.nft1
-rw-r--r--tests/shell/testcases/rule_management/dumps/0004replace_0.json-nft39
-rw-r--r--tests/shell/testcases/rule_management/dumps/0005replace_1.json-nft26
-rw-r--r--tests/shell/testcases/rule_management/dumps/0005replace_1.nft4
-rw-r--r--tests/shell/testcases/rule_management/dumps/0006replace_1.json-nft26
-rw-r--r--tests/shell/testcases/rule_management/dumps/0006replace_1.nft4
-rw-r--r--tests/shell/testcases/rule_management/dumps/0007delete_0.json-nft39
-rw-r--r--tests/shell/testcases/rule_management/dumps/0008delete_1.json-nft26
-rw-r--r--tests/shell/testcases/rule_management/dumps/0008delete_1.nft4
-rw-r--r--tests/shell/testcases/rule_management/dumps/0009delete_1.json-nft26
-rw-r--r--tests/shell/testcases/rule_management/dumps/0009delete_1.nft4
-rw-r--r--tests/shell/testcases/rule_management/dumps/0010replace_0.json-nft11
-rw-r--r--tests/shell/testcases/rule_management/dumps/0010replace_0.nft0
-rw-r--r--tests/shell/testcases/rule_management/dumps/0011reset_0.json-nft257
-rw-r--r--tests/shell/testcases/rule_management/dumps/0011reset_0.nft31
-rw-r--r--tests/shell/testcases/rule_management/dumps/0012destroy_0.json-nft26
-rw-r--r--tests/shell/testcases/rule_management/dumps/0012destroy_0.nft4
-rwxr-xr-xtests/shell/testcases/sets/0011add_many_elements_015
-rwxr-xr-xtests/shell/testcases/sets/0012add_delete_many_elements_014
-rwxr-xr-xtests/shell/testcases/sets/0013add_delete_many_elements_014
-rwxr-xr-xtests/shell/testcases/sets/0020comments_02
-rwxr-xr-xtests/shell/testcases/sets/0022type_selective_flush_02
-rwxr-xr-xtests/shell/testcases/sets/0024synproxy_031
-rwxr-xr-xtests/shell/testcases/sets/0025anonymous_set_02
-rwxr-xr-xtests/shell/testcases/sets/0028delete_handle_05
-rwxr-xr-xtests/shell/testcases/sets/0029named_ifname_dtype_041
-rwxr-xr-xtests/shell/testcases/sets/0030add_many_elements_interval_014
-rwxr-xr-xtests/shell/testcases/sets/0031set_timeout_size_04
-rwxr-xr-xtests/shell/testcases/sets/0034get_element_064
-rwxr-xr-xtests/shell/testcases/sets/0036add_set_element_expiration_019
-rwxr-xr-xtests/shell/testcases/sets/0038meter_list_034
-rwxr-xr-xtests/shell/testcases/sets/0039delete_interval_017
-rwxr-xr-xtests/shell/testcases/sets/0040get_host_endian_elements_043
-rwxr-xr-xtests/shell/testcases/sets/0041interval_025
-rwxr-xr-xtests/shell/testcases/sets/0042update_set_021
-rwxr-xr-xtests/shell/testcases/sets/0043concatenated_ranges_0195
-rwxr-xr-xtests/shell/testcases/sets/0043concatenated_ranges_125
-rwxr-xr-xtests/shell/testcases/sets/0044interval_overlap_0174
-rwxr-xr-xtests/shell/testcases/sets/0044interval_overlap_138
-rwxr-xr-xtests/shell/testcases/sets/0045concat_ipv4_service16
-rwxr-xr-xtests/shell/testcases/sets/0046netmap_022
-rwxr-xr-xtests/shell/testcases/sets/0047nat_042
-rwxr-xr-xtests/shell/testcases/sets/0048set_counters_020
-rwxr-xr-xtests/shell/testcases/sets/0049set_define_028
-rwxr-xr-xtests/shell/testcases/sets/0050set_define_117
-rwxr-xr-xtests/shell/testcases/sets/0051set_interval_counter_021
-rwxr-xr-xtests/shell/testcases/sets/0052overlap_016
-rwxr-xr-xtests/shell/testcases/sets/0053echo_016
-rwxr-xr-xtests/shell/testcases/sets/0054comments_set_09
-rwxr-xr-xtests/shell/testcases/sets/0055tcpflags_027
-rwxr-xr-xtests/shell/testcases/sets/0056dynamic_limit_019
-rwxr-xr-xtests/shell/testcases/sets/0057set_create_fails_018
-rwxr-xr-xtests/shell/testcases/sets/0058_setupdate_timeout_017
-rwxr-xr-xtests/shell/testcases/sets/0059set_update_multistmt_019
-rwxr-xr-xtests/shell/testcases/sets/0060set_multistmt_052
-rwxr-xr-xtests/shell/testcases/sets/0060set_multistmt_140
-rwxr-xr-xtests/shell/testcases/sets/0061anonymous_automerge_011
-rwxr-xr-xtests/shell/testcases/sets/0062set_connlimit_031
-rwxr-xr-xtests/shell/testcases/sets/0063set_catchall_023
-rwxr-xr-xtests/shell/testcases/sets/0064map_catchall_026
-rwxr-xr-xtests/shell/testcases/sets/0065_icmp_postprocessing13
-rwxr-xr-xtests/shell/testcases/sets/0067nat_concat_interval_058
-rwxr-xr-xtests/shell/testcases/sets/0067nat_interval_018
-rwxr-xr-xtests/shell/testcases/sets/0068interval_stack_overflow_045
-rwxr-xr-xtests/shell/testcases/sets/0069interval_merge_028
-rwxr-xr-xtests/shell/testcases/sets/0070stacked_l2_headers6
-rwxr-xr-xtests/shell/testcases/sets/0071unclosed_prefix_interval_023
-rwxr-xr-xtests/shell/testcases/sets/0072destroy_012
-rwxr-xr-xtests/shell/testcases/sets/0073flat_interval_set11
-rwxr-xr-xtests/shell/testcases/sets/0074nested_interval_set6
-rwxr-xr-xtests/shell/testcases/sets/automerge_0131
-rwxr-xr-xtests/shell/testcases/sets/collapse_elem_019
-rwxr-xr-xtests/shell/testcases/sets/concat_interval_026
-rw-r--r--tests/shell/testcases/sets/dumps/0001named_interval_0.json-nft261
-rw-r--r--tests/shell/testcases/sets/dumps/0002named_interval_automerging_0.json-nft44
-rw-r--r--tests/shell/testcases/sets/dumps/0003named_interval_missing_flag_0.json-nft27
-rw-r--r--tests/shell/testcases/sets/dumps/0004named_interval_shadow_0.json-nft38
-rw-r--r--tests/shell/testcases/sets/dumps/0005named_interval_shadow_0.json-nft38
-rw-r--r--tests/shell/testcases/sets/dumps/0006create_set_0.json-nft27
-rw-r--r--tests/shell/testcases/sets/dumps/0007create_element_0.json-nft30
-rw-r--r--tests/shell/testcases/sets/dumps/0008comments_interval_0.json-nft38
-rw-r--r--tests/shell/testcases/sets/dumps/0008create_verdict_map_0.json-nft78
-rw-r--r--tests/shell/testcases/sets/dumps/0009comments_timeout_0.json-nft38
-rw-r--r--tests/shell/testcases/sets/dumps/0010comments_0.json-nft35
-rw-r--r--tests/shell/testcases/sets/dumps/0011add_many_elements_0.nodump0
-rw-r--r--tests/shell/testcases/sets/dumps/0012add_delete_many_elements_0.json-nft27
-rw-r--r--tests/shell/testcases/sets/dumps/0013add_delete_many_elements_0.json-nft27
-rw-r--r--tests/shell/testcases/sets/dumps/0014malformed_set_is_not_defined_0.json-nft11
-rw-r--r--tests/shell/testcases/sets/dumps/0014malformed_set_is_not_defined_0.nft0
-rw-r--r--tests/shell/testcases/sets/dumps/0015rulesetflush_0.json-nft53
-rw-r--r--tests/shell/testcases/sets/dumps/0016element_leak_0.json-nft31
-rw-r--r--tests/shell/testcases/sets/dumps/0017add_after_flush_0.json-nft31
-rw-r--r--tests/shell/testcases/sets/dumps/0018set_check_size_1.json-nft32
-rw-r--r--tests/shell/testcases/sets/dumps/0018set_check_size_1.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0019set_check_size_0.json-nft32
-rw-r--r--tests/shell/testcases/sets/dumps/0020comments_0.json-nft35
-rw-r--r--tests/shell/testcases/sets/dumps/0021nesting_0.json-nft69
-rw-r--r--tests/shell/testcases/sets/dumps/0022type_selective_flush_0.json-nft101
-rw-r--r--tests/shell/testcases/sets/dumps/0022type_selective_flush_0.nft8
-rw-r--r--tests/shell/testcases/sets/dumps/0023incomplete_add_set_command_0.json-nft18
-rw-r--r--tests/shell/testcases/sets/dumps/0024named_objects_0.json-nft165
-rw-r--r--tests/shell/testcases/sets/dumps/0024synproxy_0.json-nft131
-rw-r--r--tests/shell/testcases/sets/dumps/0024synproxy_0.nft23
-rw-r--r--tests/shell/testcases/sets/dumps/0025anonymous_set_0.json-nft102
-rw-r--r--tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft2
-rw-r--r--tests/shell/testcases/sets/dumps/0026named_limit_0.json-nft75
-rw-r--r--tests/shell/testcases/sets/dumps/0027ipv6_maps_ipv4_0.json-nft38
-rw-r--r--tests/shell/testcases/sets/dumps/0028autoselect_0.json-nft168
-rw-r--r--tests/shell/testcases/sets/dumps/0028autoselect_0.nft26
-rw-r--r--tests/shell/testcases/sets/dumps/0028delete_handle_0.json-nft53
-rw-r--r--tests/shell/testcases/sets/dumps/0028delete_handle_0.nft15
-rw-r--r--tests/shell/testcases/sets/dumps/0029named_ifname_dtype_0.nft44
-rw-r--r--tests/shell/testcases/sets/dumps/0030add_many_elements_interval_0.nodump0
-rw-r--r--tests/shell/testcases/sets/dumps/0031set_timeout_size_0.nodump0
-rw-r--r--tests/shell/testcases/sets/dumps/0032restore_set_simple_0.json-nft49
-rw-r--r--tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.json-nft49
-rw-r--r--tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.nft11
-rw-r--r--tests/shell/testcases/sets/dumps/0034get_element_0.json-nft140
-rw-r--r--tests/shell/testcases/sets/dumps/0034get_element_0.nft23
-rw-r--r--tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.json-nft30
-rw-r--r--tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.nft6
-rw-r--r--tests/shell/testcases/sets/dumps/0036add_set_element_expiration_0.nodump0
-rw-r--r--tests/shell/testcases/sets/dumps/0037_set_with_inet_service_0.json-nft159
-rw-r--r--tests/shell/testcases/sets/dumps/0037_set_with_inet_service_0.nft8
-rw-r--r--tests/shell/testcases/sets/dumps/0038meter_list_0.json-nft96
-rw-r--r--tests/shell/testcases/sets/dumps/0038meter_list_0.nft17
-rw-r--r--tests/shell/testcases/sets/dumps/0039delete_interval_0.json-nft39
-rw-r--r--tests/shell/testcases/sets/dumps/0039delete_interval_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.json-nft39
-rw-r--r--tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0041interval_0.json-nft33
-rw-r--r--tests/shell/testcases/sets/dumps/0041interval_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0042update_set_0.json-nft87
-rw-r--r--tests/shell/testcases/sets/dumps/0042update_set_0.nft15
-rw-r--r--tests/shell/testcases/sets/dumps/0043concatenated_ranges_0.json-nft98
-rw-r--r--tests/shell/testcases/sets/dumps/0043concatenated_ranges_0.nft11
-rw-r--r--tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.json-nft1723
-rw-r--r--tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.nft116
-rw-r--r--tests/shell/testcases/sets/dumps/0044interval_overlap_0.nodump0
-rw-r--r--tests/shell/testcases/sets/dumps/0044interval_overlap_1.json-nft529
-rw-r--r--tests/shell/testcases/sets/dumps/0044interval_overlap_1.nft106
-rw-r--r--tests/shell/testcases/sets/dumps/0045concat_ipv4_service.json-nft95
-rw-r--r--tests/shell/testcases/sets/dumps/0045concat_ipv4_service.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/0046netmap_0.json-nft167
-rw-r--r--tests/shell/testcases/sets/dumps/0046netmap_0.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/0047nat_0.nft30
-rw-r--r--tests/shell/testcases/sets/dumps/0048set_counters_0.json-nft95
-rw-r--r--tests/shell/testcases/sets/dumps/0048set_counters_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0049set_define_0.json-nft94
-rw-r--r--tests/shell/testcases/sets/dumps/0049set_define_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0050set_define_1.json-nft11
-rw-r--r--tests/shell/testcases/sets/dumps/0050set_define_1.nft0
-rw-r--r--tests/shell/testcases/sets/dumps/0051set_interval_counter_0.json-nft85
-rw-r--r--tests/shell/testcases/sets/dumps/0051set_interval_counter_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0052overlap_0.json-nft35
-rw-r--r--tests/shell/testcases/sets/dumps/0052overlap_0.nft8
-rw-r--r--tests/shell/testcases/sets/dumps/0053echo_0.json-nft101
-rw-r--r--tests/shell/testcases/sets/dumps/0053echo_0.nft6
-rw-r--r--tests/shell/testcases/sets/dumps/0054comments_set_0.json-nft45
-rw-r--r--tests/shell/testcases/sets/dumps/0054comments_set_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0055tcpflags_0.json-nft138
-rw-r--r--tests/shell/testcases/sets/dumps/0055tcpflags_0.nft10
-rw-r--r--tests/shell/testcases/sets/dumps/0056dynamic_limit_0.json-nft11
-rw-r--r--tests/shell/testcases/sets/dumps/0056dynamic_limit_0.nft0
-rw-r--r--tests/shell/testcases/sets/dumps/0057set_create_fails_0.json-nft31
-rw-r--r--tests/shell/testcases/sets/dumps/0057set_create_fails_0.nft7
-rw-r--r--tests/shell/testcases/sets/dumps/0058_setupdate_timeout_0.json-nft68
-rw-r--r--tests/shell/testcases/sets/dumps/0058_setupdate_timeout_0.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.json-nft79
-rw-r--r--tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0060set_multistmt_0.json-nft105
-rw-r--r--tests/shell/testcases/sets/dumps/0060set_multistmt_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/0060set_multistmt_1.json-nft105
-rw-r--r--tests/shell/testcases/sets/dumps/0060set_multistmt_1.nft15
-rw-r--r--tests/shell/testcases/sets/dumps/0061anonymous_automerge_0.json-nft57
-rw-r--r--tests/shell/testcases/sets/dumps/0061anonymous_automerge_0.nft5
-rw-r--r--tests/shell/testcases/sets/dumps/0062set_connlimit_0.json-nft52
-rw-r--r--tests/shell/testcases/sets/dumps/0062set_connlimit_0.nft14
-rw-r--r--tests/shell/testcases/sets/dumps/0063set_catchall_0.json-nft94
-rw-r--r--tests/shell/testcases/sets/dumps/0063set_catchall_0.nft14
-rw-r--r--tests/shell/testcases/sets/dumps/0064map_catchall_0.json-nft220
-rw-r--r--tests/shell/testcases/sets/dumps/0064map_catchall_0.nft18
-rw-r--r--tests/shell/testcases/sets/dumps/0065_icmp_postprocessing.json-nft78
-rw-r--r--tests/shell/testcases/sets/dumps/0065_icmp_postprocessing.nft6
-rw-r--r--tests/shell/testcases/sets/dumps/0067nat_concat_interval_0.nft35
-rw-r--r--tests/shell/testcases/sets/dumps/0067nat_interval_0.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/0068interval_stack_overflow_0.nodump0
-rw-r--r--tests/shell/testcases/sets/dumps/0069interval_merge_0.json-nft51
-rw-r--r--tests/shell/testcases/sets/dumps/0069interval_merge_0.nft9
-rw-r--r--tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft28
-rw-r--r--tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.json-nft128
-rw-r--r--tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.nft19
-rw-r--r--tests/shell/testcases/sets/dumps/0072destroy_0.json-nft18
-rw-r--r--tests/shell/testcases/sets/dumps/0072destroy_0.nft2
-rw-r--r--tests/shell/testcases/sets/dumps/0073flat_interval_set.json-nft52
-rw-r--r--tests/shell/testcases/sets/dumps/0073flat_interval_set.nft11
-rw-r--r--tests/shell/testcases/sets/dumps/0074nested_interval_set.json-nft52
-rw-r--r--tests/shell/testcases/sets/dumps/0074nested_interval_set.nft11
-rw-r--r--tests/shell/testcases/sets/dumps/automerge_0.nodump0
-rw-r--r--tests/shell/testcases/sets/dumps/collapse_elem_0.json-nft50
-rw-r--r--tests/shell/testcases/sets/dumps/collapse_elem_0.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/concat_interval_0.json-nft68
-rw-r--r--tests/shell/testcases/sets/dumps/concat_interval_0.nft14
-rw-r--r--tests/shell/testcases/sets/dumps/dynset_missing.json-nft83
-rw-r--r--tests/shell/testcases/sets/dumps/dynset_missing.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/elem_opts_compat_0.nodump0
-rw-r--r--tests/shell/testcases/sets/dumps/errors_0.json-nft11
-rw-r--r--tests/shell/testcases/sets/dumps/errors_0.nft0
-rw-r--r--tests/shell/testcases/sets/dumps/exact_overlap_0.json-nft110
-rw-r--r--tests/shell/testcases/sets/dumps/exact_overlap_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/inner_0.json-nft207
-rw-r--r--tests/shell/testcases/sets/dumps/inner_0.nft18
-rw-r--r--tests/shell/testcases/sets/dumps/meter_0.json-nft203
-rw-r--r--tests/shell/testcases/sets/dumps/meter_0.nft29
-rw-r--r--tests/shell/testcases/sets/dumps/reset_command_0.nodump0
-rw-r--r--tests/shell/testcases/sets/dumps/set_eval_0.json-nft85
-rw-r--r--tests/shell/testcases/sets/dumps/set_eval_0.nft11
-rw-r--r--tests/shell/testcases/sets/dumps/sets_with_ifnames.json-nft551
-rw-r--r--tests/shell/testcases/sets/dumps/sets_with_ifnames.nft62
-rw-r--r--tests/shell/testcases/sets/dumps/type_set_symbol.json-nft114
-rw-r--r--tests/shell/testcases/sets/dumps/type_set_symbol.nft16
-rw-r--r--tests/shell/testcases/sets/dumps/typeof_raw_0.nft12
-rw-r--r--tests/shell/testcases/sets/dumps/typeof_sets_0.nft106
-rw-r--r--tests/shell/testcases/sets/dumps/typeof_sets_1.nft15
-rw-r--r--tests/shell/testcases/sets/dumps/typeof_sets_concat.nft23
-rwxr-xr-xtests/shell/testcases/sets/dynset_missing32
-rwxr-xr-xtests/shell/testcases/sets/elem_opts_compat_031
-rwxr-xr-xtests/shell/testcases/sets/errors_069
-rwxr-xr-xtests/shell/testcases/sets/exact_overlap_022
-rwxr-xr-xtests/shell/testcases/sets/inner_027
-rwxr-xr-xtests/shell/testcases/sets/meter_018
-rwxr-xr-xtests/shell/testcases/sets/reset_command_087
-rwxr-xr-xtests/shell/testcases/sets/set_eval_017
-rwxr-xr-xtests/shell/testcases/sets/sets_with_ifnames152
-rwxr-xr-xtests/shell/testcases/sets/type_set_symbol6
-rwxr-xr-xtests/shell/testcases/sets/typeof_raw_017
-rwxr-xr-xtests/shell/testcases/sets/typeof_sets_0243
-rwxr-xr-xtests/shell/testcases/sets/typeof_sets_122
-rwxr-xr-xtests/shell/testcases/sets/typeof_sets_concat8
-rwxr-xr-xtests/shell/testcases/transactions/0002table_01
-rwxr-xr-xtests/shell/testcases/transactions/0003table_04
-rwxr-xr-xtests/shell/testcases/transactions/0040set_03
-rwxr-xr-xtests/shell/testcases/transactions/0049huge_030
-rwxr-xr-xtests/shell/testcases/transactions/0051map_0122
-rwxr-xr-xtests/shell/testcases/transactions/30s-stress683
-rwxr-xr-xtests/shell/testcases/transactions/anon_chain_loop19
-rwxr-xr-xtests/shell/testcases/transactions/bad_expression38
-rwxr-xr-xtests/shell/testcases/transactions/concat_range_abort28
-rwxr-xr-xtests/shell/testcases/transactions/doubled-set22
-rw-r--r--tests/shell/testcases/transactions/dumps/0001table_0.json-nft25
-rw-r--r--tests/shell/testcases/transactions/dumps/0002table_0.json-nft31
-rw-r--r--tests/shell/testcases/transactions/dumps/0002table_0.nft4
-rw-r--r--tests/shell/testcases/transactions/dumps/0003table_0.json-nft25
-rw-r--r--tests/shell/testcases/transactions/dumps/0003table_0.nft4
-rw-r--r--tests/shell/testcases/transactions/dumps/0010chain_0.json-nft26
-rw-r--r--tests/shell/testcases/transactions/dumps/0011chain_0.json-nft30
-rw-r--r--tests/shell/testcases/transactions/dumps/0012chain_0.json-nft30
-rw-r--r--tests/shell/testcases/transactions/dumps/0013chain_0.json-nft30
-rw-r--r--tests/shell/testcases/transactions/dumps/0014chain_1.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/0014chain_1.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0015chain_0.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/0015chain_0.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0020rule_0.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/0020rule_0.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0021rule_0.json-nft54
-rw-r--r--tests/shell/testcases/transactions/dumps/0022rule_1.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/0022rule_1.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0023rule_1.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/0023rule_1.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0024rule_0.json-nft82
-rw-r--r--tests/shell/testcases/transactions/dumps/0025rule_0.json-nft52
-rw-r--r--tests/shell/testcases/transactions/dumps/0030set_0.json-nft18
-rw-r--r--tests/shell/testcases/transactions/dumps/0031set_0.json-nft27
-rw-r--r--tests/shell/testcases/transactions/dumps/0032set_0.json-nft27
-rw-r--r--tests/shell/testcases/transactions/dumps/0033set_0.json-nft18
-rw-r--r--tests/shell/testcases/transactions/dumps/0034set_0.json-nft27
-rw-r--r--tests/shell/testcases/transactions/dumps/0035set_0.json-nft30
-rw-r--r--tests/shell/testcases/transactions/dumps/0036set_1.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/0036set_1.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0037set_0.json-nft30
-rw-r--r--tests/shell/testcases/transactions/dumps/0038set_0.json-nft38
-rw-r--r--tests/shell/testcases/transactions/dumps/0039set_0.json-nft38
-rw-r--r--tests/shell/testcases/transactions/dumps/0040set_0.json-nft84
-rw-r--r--tests/shell/testcases/transactions/dumps/0041nat_restore_0.json-nft30
-rw-r--r--tests/shell/testcases/transactions/dumps/0041nat_restore_0.nft5
-rw-r--r--tests/shell/testcases/transactions/dumps/0042_stateful_expr_0.json-nft28
-rw-r--r--tests/shell/testcases/transactions/dumps/0042_stateful_expr_0.nft5
-rw-r--r--tests/shell/testcases/transactions/dumps/0043set_1.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/0043set_1.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0044rule_0.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/0044rule_0.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0045anon-unbind_0.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/0045anon-unbind_0.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0046set_0.json-nft18
-rw-r--r--tests/shell/testcases/transactions/dumps/0046set_0.nft2
-rw-r--r--tests/shell/testcases/transactions/dumps/0047set_0.json-nft73
-rw-r--r--tests/shell/testcases/transactions/dumps/0047set_0.nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/0048helpers_0.json-nft18
-rw-r--r--tests/shell/testcases/transactions/dumps/0048helpers_0.nft2
-rw-r--r--tests/shell/testcases/transactions/dumps/0049huge_0.json-nft5121
-rw-r--r--tests/shell/testcases/transactions/dumps/0049huge_0.nft749
-rw-r--r--tests/shell/testcases/transactions/dumps/0050rule_1.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/0050rule_1.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/0051map_0.nodump0
-rw-r--r--tests/shell/testcases/transactions/dumps/30s-stress.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/30s-stress.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/anon_chain_loop.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/anon_chain_loop.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/bad_expression.json-nft11
-rw-r--r--tests/shell/testcases/transactions/dumps/bad_expression.nft0
-rw-r--r--tests/shell/testcases/transactions/dumps/concat_range_abort.json-nft47
-rw-r--r--tests/shell/testcases/transactions/dumps/concat_range_abort.nft8
-rw-r--r--tests/shell/testcases/transactions/dumps/doubled-set.json-nft41
-rw-r--r--tests/shell/testcases/transactions/dumps/doubled-set.nft7
-rw-r--r--tests/shell/testcases/transactions/dumps/table_onoff.json-nft59
-rw-r--r--tests/shell/testcases/transactions/dumps/table_onoff.nft8
-rwxr-xr-xtests/shell/testcases/transactions/table_onoff44
-rwxr-xr-xtools/check-tree.sh134
1479 files changed, 101544 insertions, 16180 deletions
diff --git a/.gitignore b/.gitignore
index 2cb1e2af..a62e31f3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
# Generated by autoconf/configure/automake
*.m4
+.dirstamp
Makefile
Makefile.in
stamp-h1
@@ -14,8 +15,21 @@ build-aux/
libnftables.pc
libtool
+# cscope files
+/cscope.*
+
# Generated by tests
*.payload.got
+tests/build/tests.log
# Debian package build temporary files
build-stamp
+
+# Tag files for Vim and Emacs.
+TAGS
+tags
+
+# Emacs back-up files.
+*~
+\#*\#
+.\#*
diff --git a/COPYING b/COPYING
index bf7f06eb..a0dd81b9 100644
--- a/COPYING
+++ b/COPYING
@@ -1,8 +1,8 @@
+Original author of nftables distributed the code under the terms of the
+GPL version 2 *only*. New code though is moving to GPL version 2 or any
+later which is the preferred license for this project these days.
-nftables is distributed under the terms of the GPL version 2. Note that
-*only* version 2 of the GPL applies, not "any later version".
-
-Patrick McHardy <kaber@trash.net>
+Pablo Neira Ayuso <pablo@netfilter.org>
-------------------------------------------------------------------------------
diff --git a/INSTALL b/INSTALL
index a3f10c37..5d45ec98 100644
--- a/INSTALL
+++ b/INSTALL
@@ -4,7 +4,7 @@ Installation instructions for nftables
Prerequisites
=============
- - standard glibc headers, gcc etc.
+ - build tooling: glibc headers, gcc, autotools, automake, libtool, pkg-config.
- libmnl: git://git.netfilter.org/libmnl.git
@@ -14,17 +14,15 @@ Installation instructions for nftables
- bison
- - libgmp
+ - libgmp: alternatively, see mini-gmp support below.
- - libreadline
-
- - pkg-config
-
- - libtool
+ - libreadline or libedit or linenoise: required by interactive command line
- optional: libxtables: required to interact with iptables-compat
- - optional: docbook2x: required for building man-page
+ - optional: libjansson: required to build JSON support
+
+ - optional: asciidoc: required for building man-page
Configuring and compiling
=========================
@@ -60,17 +58,50 @@ Installation instructions for nftables
For libxtables support to interact with the iptables-compat
utility.
- Suggested configuration options: --prefix=/ --datarootdir=/usr/share
+ --without-cli
+
+ To disable interactive command line support, ie. -i/--interactive.
+
+ --with-cli=readline
+
+ To enable interactive command line support with libreadline.
+
+ --with-cli=linenoise
+
+ To enable interactive command line support with linenoise.
+
+ --with-cli=editline
+
+ To enable interactive command line support with libedit.
+
+ --with-json
+
+ To enable JSON support, this requires libjansson.
Run "make" to compile nftables, "make install" to install it in the
configured paths.
- Other notes
+ Python support
+ ==============
+
+ CPython bindings are available for nftables under the py/ folder. They can be
+ installed using pip:
+
+ python -m pip install py/
+
+ A legacy setup.py script can also be used:
+
+ ( cd py && python setup.py install )
+
+ However, this method is deprecated.
+
+ Source code
===========
- The nftables kernel tree can be found at:
+ Netfilter's Linux kernel tree can be found at:
- git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nftables.git
+ git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git/
+ https://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf.git
The latest version of this code can be found at:
diff --git a/Make_global.am b/Make_global.am
deleted file mode 100644
index 713d9583..00000000
--- a/Make_global.am
+++ /dev/null
@@ -1,21 +0,0 @@
-# This is _NOT_ the library release version, it's an API version.
-# Extracted from Chapter 6 "Library interface versions" of the libtool docs.
-#
-# <snippet>
-# Here are a set of rules to help you update your library version information:
-#
-# 1. Start with version information of `0:0:0' for each libtool library.
-# 2. Update the version information only immediately before a public release
-# of your software. More frequent updates are unnecessary, and only guarantee
-# that the current interface number gets larger faster.
-# 3. If the library source code has changed at all since the last update,
-# then increment revision (`c:r:a' becomes `c:r+1:a').
-# 4. If any interfaces have been added, removed, or changed since the last
-# update, increment current, and set revision to 0.
-# 5. If any interfaces have been added since the last public release, then
-# increment age.
-# 6. If any interfaces have been removed since the last public release, then
-# set age to 0.
-# </snippet>
-#
-libnftables_LIBVERSION=1:0:0
diff --git a/Makefile.am b/Makefile.am
index 4a17424d..fef1d8d1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,15 +1,411 @@
-ACLOCAL_AMFLAGS = -I m4
+# This is _NOT_ the library release version, it's an API version.
+# Extracted from Chapter 6 "Library interface versions" of the libtool docs.
+#
+# <snippet>
+# Here are a set of rules to help you update your library version information:
+#
+# 1. Start with version information of `0:0:0' for each libtool library.
+# 2. Update the version information only immediately before a public release
+# of your software. More frequent updates are unnecessary, and only guarantee
+# that the current interface number gets larger faster.
+# 3. If the library source code has changed at all since the last update,
+# then increment revision (`c:r:a' becomes `c:r+1:a').
+# 4. If any interfaces have been added, removed, or changed since the last
+# update, increment current, and set revision to 0.
+# 5. If any interfaces have been added since the last public release, then
+# increment age.
+# 6. If any interfaces have been removed since the last public release, then
+# set age to 0.
+# </snippet>
+#
+libnftables_LIBVERSION = 2:0:1
-SUBDIRS = src \
- include \
- files \
- doc
-if HAVE_PYTHON
-SUBDIRS += py
+###############################################################################
+
+ACLOCAL_AMFLAGS = -I m4
+
+EXTRA_DIST =
+BUILT_SOURCES =
+LDADD =
+lib_LTLIBRARIES =
+noinst_LTLIBRARIES =
+sbin_PROGRAMS =
+check_PROGRAMS =
+dist_man_MANS =
+CLEANFILES =
+
+###############################################################################
+
+pkginclude_HEADERS = \
+ include/nftables/libnftables.h \
+ $(NULL)
+
+noinst_HEADERS = \
+ \
+ include/linux/netfilter.h \
+ include/linux/netfilter/nf_conntrack_common.h \
+ include/linux/netfilter/nf_conntrack_tuple_common.h \
+ include/linux/netfilter/nf_log.h \
+ include/linux/netfilter/nf_nat.h \
+ include/linux/netfilter/nf_synproxy.h \
+ include/linux/netfilter/nf_tables.h \
+ include/linux/netfilter/nf_tables_compat.h \
+ include/linux/netfilter/nfnetlink.h \
+ include/linux/netfilter/nfnetlink_hook.h \
+ include/linux/netfilter/nfnetlink_osf.h \
+ include/linux/netfilter_arp.h \
+ include/linux/netfilter_arp/arp_tables.h \
+ include/linux/netfilter_bridge.h \
+ include/linux/netfilter_bridge/ebtables.h \
+ include/linux/netfilter_decnet.h \
+ include/linux/netfilter_ipv4.h \
+ include/linux/netfilter_ipv4/ip_tables.h \
+ include/linux/netfilter_ipv6.h \
+ include/linux/netfilter_ipv6/ip6_tables.h \
+ \
+ include/cache.h \
+ include/cli.h \
+ include/cmd.h \
+ include/ct.h \
+ include/datatype.h \
+ include/dccpopt.h \
+ include/erec.h \
+ include/expression.h \
+ include/exthdr.h \
+ include/fib.h \
+ include/gmputil.h \
+ include/hash.h \
+ include/headers.h \
+ include/iface.h \
+ include/intervals.h \
+ include/ipopt.h \
+ include/json.h \
+ include/list.h \
+ include/meta.h \
+ include/mini-gmp.h \
+ include/misspell.h \
+ include/mnl.h \
+ include/netlink.h \
+ include/nft.h \
+ include/nftables.h \
+ include/numgen.h \
+ include/osf.h \
+ include/owner.h \
+ include/parser.h \
+ include/payload.h \
+ include/proto.h \
+ include/rt.h \
+ include/rule.h \
+ include/sctp_chunk.h \
+ include/socket.h \
+ include/statement.h \
+ include/tcpopt.h \
+ include/utils.h \
+ include/xfrm.h \
+ include/xt.h \
+ \
+ $(NULL)
+
+###############################################################################
+
+AM_CPPFLAGS = \
+ "-I$(srcdir)/include" \
+ "-DDEFAULT_INCLUDE_PATH=\"${sysconfdir}\"" \
+ $(LIBMNL_CFLAGS) \
+ $(LIBNFTNL_CFLAGS) \
+ $(NULL)
+
+if BUILD_DEBUG
+AM_CPPFLAGS += -g -DDEBUG
+endif
+if BUILD_XTABLES
+AM_CPPFLAGS += $(XTABLES_CFLAGS)
+endif
+if BUILD_MINIGMP
+AM_CPPFLAGS += -DHAVE_MINIGMP
+endif
+if BUILD_JSON
+AM_CPPFLAGS += -DHAVE_JSON
+endif
+if BUILD_XTABLES
+AM_CPPFLAGS += -DHAVE_XTABLES
+endif
+
+AM_CFLAGS = \
+ -Wall \
+ \
+ -Waggregate-return \
+ -Wbad-function-cast \
+ -Wcast-align \
+ -Wdeclaration-after-statement \
+ -Wformat-nonliteral \
+ -Wformat-security \
+ -Winit-self \
+ -Wmissing-declarations \
+ -Wmissing-format-attribute \
+ -Wmissing-prototypes \
+ -Wsign-compare \
+ -Wstrict-prototypes \
+ -Wundef \
+ -Wunused \
+ -Wwrite-strings \
+ \
+ $(GCC_FVISIBILITY_HIDDEN) \
+ \
+ $(NULL)
+
+AM_YFLAGS = -d -Wno-yacc
+
+###############################################################################
+
+BUILT_SOURCES += src/parser_bison.h
+
+# yacc and lex generate dirty code
+noinst_LTLIBRARIES += src/libparser.la
+
+src_libparser_la_SOURCES = \
+ src/parser_bison.y \
+ src/scanner.l \
+ $(NULL)
+
+src_libparser_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ -Wno-missing-declarations \
+ -Wno-missing-prototypes \
+ -Wno-nested-externs \
+ -Wno-redundant-decls \
+ -Wno-undef \
+ -Wno-unused-but-set-variable \
+ $(NULL)
+
+###############################################################################
+
+if BUILD_MINIGMP
+
+noinst_LTLIBRARIES += src/libminigmp.la
+
+src_libminigmp_la_SOURCES = src/mini-gmp.c
+
+src_libminigmp_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ -Wno-sign-compare \
+ $(NULL)
+
+endif
+
+###############################################################################
+
+lib_LTLIBRARIES += src/libnftables.la
+
+src_libnftables_la_SOURCES = \
+ src/libnftables.map \
+ \
+ src/cache.c \
+ src/cmd.c \
+ src/ct.c \
+ src/datatype.c \
+ src/dccpopt.c \
+ src/erec.c \
+ src/evaluate.c \
+ src/expression.c \
+ src/exthdr.c \
+ src/fib.c \
+ src/gmputil.c \
+ src/hash.c \
+ src/iface.c \
+ src/intervals.c \
+ src/ipopt.c \
+ src/libnftables.c \
+ src/mergesort.c \
+ src/meta.c \
+ src/misspell.c \
+ src/mnl.c \
+ src/monitor.c \
+ src/netlink.c \
+ src/netlink_delinearize.c \
+ src/netlink_linearize.c \
+ src/nfnl_osf.c \
+ src/nftutils.c \
+ src/nftutils.h \
+ src/numgen.c \
+ src/optimize.c \
+ src/osf.c \
+ src/owner.c \
+ src/payload.c \
+ src/print.c \
+ src/proto.c \
+ src/rt.c \
+ src/rule.c \
+ src/sctp_chunk.c \
+ src/segtree.c \
+ src/socket.c \
+ src/statement.c \
+ src/tcpopt.c \
+ src/utils.c \
+ src/xfrm.c \
+ $(NULL)
+
+src_libnftables_la_SOURCES += src/xt.c
+
+if BUILD_JSON
+src_libnftables_la_SOURCES += \
+ src/json.c \
+ src/parser_json.c \
+ $(NULL)
+endif
+
+src_libnftables_la_LDFLAGS = \
+ -version-info "${libnftables_LIBVERSION}" \
+ -Wl,--version-script="$(srcdir)/src//libnftables.map" \
+ $(NULL)
+
+src_libnftables_la_LIBADD = \
+ $(LIBMNL_LIBS) \
+ $(LIBNFTNL_LIBS) \
+ src/libparser.la \
+ $(NULL)
+
+if BUILD_MINIGMP
+src_libnftables_la_LIBADD += src/libminigmp.la
+endif
+
+if BUILD_XTABLES
+src_libnftables_la_LIBADD += $(XTABLES_LIBS)
endif
-EXTRA_DIST = tests \
- files
+if BUILD_JSON
+src_libnftables_la_LIBADD += $(JANSSON_LIBS)
+endif
+
+###############################################################################
+
+sbin_PROGRAMS += src/nft
+
+src_nft_SOURCES = src/main.c
+
+if BUILD_CLI
+src_nft_SOURCES += src/cli.c
+endif
+
+src_nft_LDADD = src/libnftables.la
+
+###############################################################################
+
+check_PROGRAMS += examples/nft-buffer
+
+examples_nft_buffer_AM_CPPFLAGS = -I$(srcdir)/include
+examples_nft_buffer_LDADD = src/libnftables.la
+
+check_PROGRAMS += examples/nft-json-file
+
+examples_nft_json_file_AM_CPPFLAGS = -I$(srcdir)/include
+examples_nft_json_file_LDADD = src/libnftables.la
+
+###############################################################################
+
+if BUILD_MAN
+
+dist_man_MANS += \
+ doc/nft.8 \
+ doc/libnftables-json.5 \
+ doc/libnftables.3 \
+ $(NULL)
+
+A2X_OPTS_MANPAGE = \
+ -L \
+ --doctype manpage \
+ --format manpage \
+ -D "${builddir}/doc" \
+ $(NULL)
+
+ASCIIDOC_MAIN = doc/nft.txt
+
+ASCIIDOC_INCLUDES = \
+ doc/data-types.txt \
+ doc/payload-expression.txt \
+ doc/primary-expression.txt \
+ doc/stateful-objects.txt \
+ doc/statements.txt \
+ $(NULL)
+
+ASCIIDOCS = \
+ $(ASCIIDOC_MAIN) \
+ $(ASCIIDOC_INCLUDES) \
+ $(NULL)
+
+EXTRA_DIST += \
+ $(ASCIIDOCS) \
+ doc/libnftables-json.adoc \
+ doc/libnftables.adoc \
+ $(NULL)
+
+CLEANFILES += doc/*~
+
+doc/nft.8: $(ASCIIDOCS)
+ mkdir -p ${builddir}/doc
+ $(AM_V_GEN)$(A2X) $(A2X_OPTS_MANPAGE) $<
+
+.adoc.3:
+ $(AM_V_GEN)$(A2X) $(A2X_OPTS_MANPAGE) $<
+
+.adoc.5:
+ $(AM_V_GEN)$(A2X) $(A2X_OPTS_MANPAGE) $<
+
+MAINTAINERCLEANFILES = ${dist_man_MANS}
+
+endif
+
+###############################################################################
+
+dist_pkgdata_DATA = \
+ files/nftables/all-in-one.nft \
+ files/nftables/arp-filter.nft \
+ files/nftables/bridge-filter.nft \
+ files/nftables/inet-filter.nft \
+ files/nftables/inet-nat.nft \
+ files/nftables/ipv4-filter.nft \
+ files/nftables/ipv4-mangle.nft \
+ files/nftables/ipv4-nat.nft \
+ files/nftables/ipv4-raw.nft \
+ files/nftables/ipv6-filter.nft \
+ files/nftables/ipv6-mangle.nft \
+ files/nftables/ipv6-nat.nft \
+ files/nftables/ipv6-raw.nft \
+ files/nftables/netdev-ingress.nft \
+ $(NULL)
+
+pkgdocdir = ${docdir}/examples
+
+dist_pkgdoc_SCRIPTS = \
+ files/examples/ct_helpers.nft \
+ files/examples/load_balancing.nft \
+ files/examples/secmark.nft \
+ files/examples/sets_and_maps.nft \
+ $(NULL)
+
+pkgsysconfdir = ${sysconfdir}/nftables/osf
+
+dist_pkgsysconf_DATA = \
+ files/osf/pf.os \
+ $(NULL)
+
+###############################################################################
+
+EXTRA_DIST += \
+ py/pyproject.toml \
+ py/setup.cfg \
+ py/setup.py \
+ py/src/__init__.py \
+ py/src/nftables.py \
+ py/src/schema.json \
+ $(NULL)
+
+###############################################################################
+
+EXTRA_DIST += \
+ files \
+ tests \
+ $(NULL)
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libnftables.pc
diff --git a/configure.ac b/configure.ac
index 170b6093..724a4ae7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,15 +1,15 @@
-AC_INIT([nftables], [0.9.2], [netfilter-devel@vger.kernel.org])
-AC_DEFINE([RELEASE_NAME], ["Scram"], [Release name])
+AC_INIT([nftables], [1.0.9], [netfilter-devel@vger.kernel.org])
+AC_DEFINE([RELEASE_NAME], ["Old Doc Yak #3"], [Release name])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects
- tar-pax no-dist-gzip dist-bzip2 1.6])
+ tar-pax no-dist-gzip dist-xz 1.6])
dnl kernel style compile messages
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
-AC_CONFIG_HEADER([config.h])
+AC_CONFIG_HEADERS([config.h])
AC_ARG_ENABLE([debug],
AS_HELP_STRING([--disable-debug], [Disable debugging symbols]),
@@ -23,19 +23,22 @@ AM_CONDITIONAL([BUILD_MAN], [test "x$enable_man_doc" = "xyes" ])
# Checks for programs.
AC_PROG_CC
+
+AC_USE_SYSTEM_EXTENSIONS
+
AC_PROG_MKDIR_P
AC_PROG_INSTALL
AC_PROG_SED
-AM_PROG_LEX
+AC_PROG_LEX([noyywrap])
AC_PROG_YACC
-if test -z "$ac_cv_prog_YACC"
+if test -z "$ac_cv_prog_YACC" -a ! -f "${srcdir}/src/parser_bison.c"
then
echo "*** Error: No suitable bison/yacc found. ***"
echo " Please install the 'bison' package."
exit 1
fi
-if test -z "$ac_cv_prog_LEX"
+if test -z "$ac_cv_prog_LEX" -a ! -f "${srcdir}/src/scanner.c"
then
echo "*** Error: No suitable flex/lex found. ***"
echo " Please install the 'flex' package."
@@ -43,21 +46,18 @@ then
fi
AM_PROG_AR
-AM_PROG_LIBTOOL
-LT_INIT
-AM_PROG_CC_C_O
+LT_INIT([disable-static])
AC_EXEEXT
-AC_DISABLE_STATIC
CHECK_GCC_FVISIBILITY
AS_IF([test "x$enable_man_doc" = "xyes"], [
AC_CHECK_PROG(A2X, [a2x], [a2x], [no])
- AS_IF([test "$A2X" = "no"],
+ AS_IF([test "$A2X" = "no" -a ! -f "${srcdir}/doc/nft.8"],
[AC_MSG_ERROR([a2x not found, please install asciidoc])])
])
-PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.3])
-PKG_CHECK_MODULES([LIBNFTNL], [libnftnl >= 1.1.4])
+PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.4])
+PKG_CHECK_MODULES([LIBNFTNL], [libnftnl >= 1.2.6])
AC_ARG_WITH([mini-gmp], [AS_HELP_STRING([--with-mini-gmp],
[Use builtin mini-gmp (for embedded builds)])],
@@ -68,8 +68,8 @@ AC_CHECK_LIB([gmp],[__gmpz_init], , AC_MSG_ERROR([No suitable version of libgmp
AM_CONDITIONAL([BUILD_MINIGMP], [test "x$with_mini_gmp" = xyes])
AC_ARG_WITH([cli], [AS_HELP_STRING([--without-cli],
- [disable interactive CLI (libreadline or linenoise support)])],
- [], [with_cli=readline])
+ [disable interactive CLI (libreadline, editline or linenoise support)])],
+ [], [with_cli=editline])
AS_IF([test "x$with_cli" = xreadline], [
AC_CHECK_LIB([readline], [readline], ,
@@ -81,6 +81,11 @@ AC_CHECK_LIB([linenoise], [linenoise], ,
AC_MSG_ERROR([No suitable version of linenoise found]))
AC_DEFINE([HAVE_LIBLINENOISE], [1], [])
],
+ [test "x$with_cli" = xeditline], [
+AC_CHECK_LIB([edit], [readline], ,
+ AC_MSG_ERROR([No suitable version of libedit found]))
+AC_DEFINE([HAVE_LIBEDIT], [1], [])
+],
[test "x$with_cli" != xno], [
AC_MSG_ERROR([unexpected CLI value: $with_cli])
])
@@ -105,42 +110,13 @@ AC_DEFINE([HAVE_LIBJANSSON], [1], [Define if you have libjansson])
])
AM_CONDITIONAL([BUILD_JSON], [test "x$with_json" != xno])
-AC_ARG_ENABLE(python,
- AS_HELP_STRING([--enable-python], [Enable python]),,[enable_python=check]
- )
-
-AC_ARG_WITH([python_bin],
- [AS_HELP_STRING([--with-python-bin], [Specify Python binary to use])],
- [PYTHON_BIN="$withval"], [AC_PATH_PROGS(PYTHON_BIN, python python2 python2.7)]
- )
-
-AS_IF([test "x$PYTHON_BIN" = "x"], [
- AS_IF([test "x$enable_python" = "xyes"], [AC_MSG_ERROR([Python asked but not found])],
- [test "x$enable_python" = "xcheck"], [
- AC_MSG_WARN([Python not found, continuing anyway])
- enable_python=no
- ])
-])
-
-AM_CONDITIONAL([HAVE_PYTHON], [test "$enable_python" != "no"])
+AC_CHECK_DECLS([getprotobyname_r, getprotobynumber_r, getservbyport_r], [], [], [[
+#include <netdb.h>
+]])
AC_CONFIG_FILES([ \
Makefile \
libnftables.pc \
- src/Makefile \
- include/Makefile \
- include/nftables/Makefile \
- include/linux/Makefile \
- include/linux/netfilter/Makefile \
- include/linux/netfilter_arp/Makefile \
- include/linux/netfilter_bridge/Makefile \
- include/linux/netfilter_ipv4/Makefile \
- include/linux/netfilter_ipv6/Makefile \
- files/Makefile \
- files/nftables/Makefile \
- files/osf/Makefile \
- doc/Makefile \
- py/Makefile \
])
AC_OUTPUT
@@ -152,10 +128,3 @@ nft configuration:
enable man page: ${enable_man_doc}
libxtables support: ${with_xtables}
json output support: ${with_json}"
-
-AS_IF([test "$enable_python" != "no"], [
- echo " enable Python: yes (with $PYTHON_BIN)"
- ], [
- echo " enable Python: no"
- ]
- )
diff --git a/doc/Makefile.am b/doc/Makefile.am
deleted file mode 100644
index f0958b33..00000000
--- a/doc/Makefile.am
+++ /dev/null
@@ -1,31 +0,0 @@
-if BUILD_MAN
-man_MANS = nft.8 libnftables-json.5 libnftables.3
-endif
-
-A2X_OPTS_MANPAGE = -L --doctype manpage --format manpage -D ${builddir}
-
-ASCIIDOC_MAIN = nft.txt
-ASCIIDOC_INCLUDES = \
- data-types.txt \
- payload-expression.txt \
- primary-expression.txt \
- stateful-objects.txt \
- statements.txt
-ASCIIDOCS = ${ASCIIDOC_MAIN} ${ASCIIDOC_INCLUDES}
-
-nft.8: ${ASCIIDOCS}
- ${AM_V_GEN}${A2X} ${A2X_OPTS_MANPAGE} $<
-
-.adoc.3:
- ${AM_V_GEN}${A2X} ${A2X_OPTS_MANPAGE} $<
-
-.adoc.5:
- ${AM_V_GEN}${A2X} ${A2X_OPTS_MANPAGE} $<
-
-EXTRA_DIST = ${ASCIIDOCS} libnftables-json.adoc libnftables.adoc
-
-CLEANFILES = \
- nft.8 \
- libnftables-json.5 \
- libnftables.3 \
- *~
diff --git a/doc/data-types.txt b/doc/data-types.txt
index 90e19a8b..6c0e2f94 100644
--- a/doc/data-types.txt
+++ b/doc/data-types.txt
@@ -242,33 +242,13 @@ integer
The ICMP Code type is used to conveniently specify the ICMP header's code field.
-.Keywords may be used when specifying the ICMP code
-[options="header"]
-|==================
-|Keyword | Value
-|net-unreachable |
-0
-|host-unreachable |
-1
-|prot-unreachable|
-2
-|port-unreachable|
-3
-|net-prohibited|
-9
-|host-prohibited|
-10
-|admin-prohibited|
-13
-|===================
-
ICMPV6 TYPE TYPE
~~~~~~~~~~~~~~~~
[options="header"]
|==================
|Name | Keyword | Size | Base type
|ICMPv6 Type |
-icmpx_code |
+icmpv6_type |
8 bit |
integer
|===================
@@ -338,52 +318,6 @@ integer
The ICMPv6 Code type is used to conveniently specify the ICMPv6 header's code field.
-.keywords may be used when specifying the ICMPv6 code
-[options="header"]
-|==================
-|Keyword |Value
-|no-route|
-0
-|admin-prohibited|
-1
-|addr-unreachable|
-3
-|port-unreachable|
-4
-|policy-fail|
-5
-|reject-route|
-6
-|==================
-
-ICMPVX CODE TYPE
-~~~~~~~~~~~~~~~~
-[options="header"]
-|==================
-|Name | Keyword | Size | Base type
-|ICMPvX Code |
-icmpv6_type |
-8 bit |
-integer
-|===================
-
-The ICMPvX Code type abstraction is a set of values which overlap between ICMP
-and ICMPv6 Code types to be used from the inet family.
-
-.keywords may be used when specifying the ICMPvX code
-[options="header"]
-|==================
-|Keyword |Value
-|no-route|
-0
-|port-unreachable|
-1
-|host-unreachable|
-2
-|admin-prohibited|
-3
-|=================
-
CONNTRACK TYPES
~~~~~~~~~~~~~~~
@@ -490,3 +424,46 @@ For each of the types above, keywords are available for convenience:
|==================
Possible keywords for conntrack label type (ct_label) are read at runtime from /etc/connlabel.conf.
+
+DCCP PKTTYPE TYPE
+~~~~~~~~~~~~~~~~
+[options="header"]
+|==================
+|Name | Keyword | Size | Base type
+|DCCP packet type |
+dccp_pkttype |
+4 bit |
+integer
+|===================
+
+The DCCP packet type abstracts the different legal values of the respective
+four bit field in the DCCP header, as stated by RFC4340. Note that possible
+values 10-15 are considered reserved and therefore not allowed to be used. In
+iptables' *dccp* match, these values are aliased 'INVALID'. With nftables, one
+may simply match on the numeric value range, i.e. *10-15*.
+
+.keywords may be used when specifying the DCCP packet type
+[options="header"]
+|==================
+|Keyword |Value
+|request|
+0
+|response|
+1
+|data|
+2
+|ack|
+3
+|dataack|
+4
+|closereq|
+5
+|close|
+6
+|reset|
+7
+|sync|
+8
+|syncack|
+9
+|=================
diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc
index 6877f054..e3b24cc4 100644
--- a/doc/libnftables-json.adoc
+++ b/doc/libnftables-json.adoc
@@ -91,14 +91,15 @@ translates into JSON as such:
{ "add": { "chain": {
"family": "inet",
"table": "mytable",
- "chain": "mychain"
- }}}
+ "name": "mychain"
+ }}},
{ "add": { "rule": {
"family": "inet",
"table": "mytable",
"chain": "mychain",
"expr": [
{ "match": {
+ "op": "==",
"left": { "payload": {
"protocol": "tcp",
"field": "dport"
@@ -117,7 +118,7 @@ ____
*{ "add":* 'ADD_OBJECT' *}*
'ADD_OBJECT' := 'TABLE' | 'CHAIN' | 'RULE' | 'SET' | 'MAP' | 'ELEMENT' |
- 'FLOWTABLE' | 'COUNTER | QUOTA' | 'CT_HELPER' | 'LIMIT' |
+ 'FLOWTABLE' | 'COUNTER' | 'QUOTA' | 'CT_HELPER' | 'LIMIT' |
'CT_TIMEOUT' | 'CT_EXPECTATION'
____
@@ -161,9 +162,9 @@ ____
'LIST_OBJECT' := 'TABLE' | 'TABLES' | 'CHAIN' | 'CHAINS' | 'SET' | 'SETS' |
'MAP' | 'MAPS | COUNTER' | 'COUNTERS' | 'QUOTA' | 'QUOTAS' |
- 'CT_HELPER' | 'CT_HELPERS' | 'LIMIT' | 'LIMITS | RULESET' |
- 'METER' | 'METERS' | 'FLOWTABLES' | 'CT_TIMEOUT' |
- 'CT_EXPECTATION'
+ 'CT_HELPER' | 'CT_HELPERS' | 'LIMIT' | 'LIMITS' | 'RULESET' |
+ 'METER' | 'METERS' | 'FLOWTABLE' | 'FLOWTABLES' |
+ 'CT_TIMEOUT' | 'CT_EXPECTATION'
____
List ruleset elements. The plural forms are used to list all objects of that
@@ -174,7 +175,7 @@ kind, optionally filtered by *family* and for some, also *table*.
____
*{ "reset":* 'RESET_OBJECT' *}*
-'RESET_OBJECT' := 'COUNTER' | 'COUNTERS' | 'QUOTA' | 'QUOTAS'
+'RESET_OBJECT' := 'COUNTER' | 'COUNTERS' | 'QUOTA' | 'QUOTAS' | 'RULE' | 'RULES' | 'SET' | 'MAP' | 'ELEMENT'
____
Reset state in suitable objects, i.e. zero their internal counter.
@@ -311,7 +312,8 @@ ____
"elem":* 'SET_ELEMENTS'*,
"timeout":* 'NUMBER'*,
"gc-interval":* 'NUMBER'*,
- "size":* 'NUMBER'
+ "size":* 'NUMBER'*,
+ "auto-merge":* 'BOOLEAN'
*}}*
*{ "map": {
@@ -326,7 +328,8 @@ ____
"elem":* 'SET_ELEMENTS'*,
"timeout":* 'NUMBER'*,
"gc-interval":* 'NUMBER'*,
- "size":* 'NUMBER'
+ "size":* 'NUMBER'*,
+ "auto-merge":* 'BOOLEAN'
*}}*
'SET_TYPE' := 'STRING' | *[* 'SET_TYPE_LIST' *]*
@@ -365,6 +368,8 @@ that they translate a unique key to a value.
Garbage collector interval in seconds.
*size*::
Maximum number of elements supported.
+*auto-merge*::
+ Automatic merging of adjacent/overlapping set elements in interval sets.
==== TYPE
The set type might be a string, such as *"ipv4_addr"* or an array
@@ -409,6 +414,7 @@ ____
"family":* 'STRING'*,
"table":* 'STRING'*,
"name":* 'STRING'*,
+ "handle":* 'NUMBER'*,
"hook":* 'STRING'*,
"prio":* 'NUMBER'*,
"dev":* 'FT_INTERFACE'
@@ -426,6 +432,8 @@ This object represents a named flowtable.
The table's name.
*name*::
The flow table's name.
+*handle*::
+ The flow table's handle. In input, it is used by the *delete* command only.
*hook*::
The flow table's hook.
*prio*::
@@ -678,11 +686,6 @@ processing continues with the next rule in the same chain.
==== OPERATORS
[horizontal]
-*&*:: Binary AND
-*|*:: Binary OR
-*^*:: Binary XOR
-*<<*:: Left shift
-*>>*:: Right shift
*==*:: Equal
*!=*:: Not equal
*<*:: Less than
@@ -901,7 +904,7 @@ Reject the packet and send the given error reply.
*type*::
Type of reject, either *"tcp reset"*, *"icmpx"*, *"icmp"* or *"icmpv6"*.
*expr*::
- ICMP type to reject with.
+ ICMP code to reject with.
All properties are optional.
@@ -1055,10 +1058,22 @@ Assign connection tracking expectation.
=== XT
[verse]
-*{ "xt": null }*
+____
+*{ "xt": {
+ "type":* 'TYPENAME'*,
+ "name":* 'STRING'
+*}}*
-This represents an xt statement from xtables compat interface. Sadly, at this
-point, it is not possible to provide any further information about its content.
+'TYPENAME' := *match* | *target* | *watcher*
+____
+
+This represents an xt statement from xtables compat interface. It is a
+fallback if translation is not available or not complete.
+
+Seeing this means the ruleset (or parts of it) were created by *iptables-nft*
+and one should use that to manage it.
+
+*BEWARE:* nftables won't restore these statements.
== EXPRESSIONS
Expressions are the building blocks of (most) statements. In their most basic
@@ -1168,7 +1183,7 @@ point (*base*). The following *base* values are accepted:
*"th"*::
The offset is relative to Transport Layer header start offset.
-The second form allows to reference a field by name (*field*) in a named packet
+The second form allows one to reference a field by name (*field*) in a named packet
header (*protocol*).
=== EXTHDR
@@ -1197,6 +1212,30 @@ Create a reference to a field (*field*) of a TCP option header (*name*).
If the *field* property is not given, the expression is to be used as a TCP option
existence check in a *match* statement with a boolean on the right hand side.
+=== SCTP CHUNK
+[verse]
+*{ "sctp chunk": {
+ "name":* 'STRING'*,
+ "field":* 'STRING'
+*}}*
+
+Create a reference to a field (*field*) of an SCTP chunk (*name*).
+
+If the *field* property is not given, the expression is to be used as an SCTP
+chunk existence check in a *match* statement with a boolean on the right hand
+side.
+
+=== DCCP OPTION
+[verse]
+*{ "dccp option": {
+ "type":* 'NUMBER'*
+*}}*
+
+Create a reference to a DCCP option (*type*).
+
+The expression is to be used as a DCCP option existence check in a *match*
+statement with a boolean on the right hand side.
+
=== META
[verse]
____
@@ -1304,15 +1343,17 @@ Perform kernel Forwarding Information Base lookups.
=== BINARY OPERATION
[verse]
-*{ "|": [* 'EXPRESSION'*,* 'EXPRESSION' *] }*
-*{ "^": [* 'EXPRESSION'*,* 'EXPRESSION' *] }*
-*{ "&": [* 'EXPRESSION'*,* 'EXPRESSION' *] }*
-*{ "+<<+": [* 'EXPRESSION'*,* 'EXPRESSION' *] }*
-*{ ">>": [* 'EXPRESSION'*,* 'EXPRESSION' *] }*
+*{ "|": [* 'EXPRESSION'*,* 'EXPRESSIONS' *] }*
+*{ "^": [* 'EXPRESSION'*,* 'EXPRESSIONS' *] }*
+*{ "&": [* 'EXPRESSION'*,* 'EXPRESSIONS' *] }*
+*{ "+<<+": [* 'EXPRESSION'*,* 'EXPRESSIONS' *] }*
+*{ ">>": [* 'EXPRESSION'*,* 'EXPRESSIONS' *] }*
+'EXPRESSIONS' := 'EXPRESSION' | 'EXPRESSION'*,* 'EXPRESSIONS'
-All binary operations expect an array of exactly two expressions, of which the
+All binary operations expect an array of at least two expressions, of which the
first element denotes the left hand side and the second one the right hand
-side.
+side. Extra elements are accepted in the given array and appended to the term
+accordingly.
=== VERDICT
[verse]
diff --git a/doc/libnftables.adoc b/doc/libnftables.adoc
index ea9626af..2cf78d7a 100644
--- a/doc/libnftables.adoc
+++ b/doc/libnftables.adoc
@@ -18,6 +18,9 @@ void nft_ctx_free(struct nft_ctx* '\*ctx'*);
bool nft_ctx_get_dry_run(struct nft_ctx* '\*ctx'*);
void nft_ctx_set_dry_run(struct nft_ctx* '\*ctx'*, bool* 'dry'*);
+unsigned int nft_ctx_input_get_flags(struct nft_ctx* '\*ctx'*);
+unsigned int nft_ctx_input_set_flags(struct nft_ctx* '\*ctx'*, unsigned int* 'flags'*);
+
unsigned int nft_ctx_output_get_flags(struct nft_ctx* '\*ctx'*);
void nft_ctx_output_set_flags(struct nft_ctx* '\*ctx'*, unsigned int* 'flags'*);
@@ -37,6 +40,9 @@ const char *nft_ctx_get_error_buffer(struct nft_ctx* '\*ctx'*);
int nft_ctx_add_include_path(struct nft_ctx* '\*ctx'*, const char* '\*path'*);
void nft_ctx_clear_include_paths(struct nft_ctx* '\*ctx'*);
+int nft_ctx_add_var(struct nft_ctx* '\*ctx'*, const char* '\*var'*);
+void nft_ctx_clear_vars(struct nft_ctx '\*ctx'*);
+
int nft_run_cmd_from_buffer(struct nft_ctx* '\*nft'*, const char* '\*buf'*);
int nft_run_cmd_from_filename(struct nft_ctx* '\*nft'*,
const char* '\*filename'*);*
@@ -68,28 +74,58 @@ The *nft_ctx_free*() function frees the context object pointed to by 'ctx', incl
=== nft_ctx_get_dry_run() and nft_ctx_set_dry_run()
Dry-run setting controls whether ruleset changes are actually committed on kernel side or not.
-It allows to check whether a given operation would succeed without making actual changes to the ruleset.
+It allows one to check whether a given operation would succeed without making actual changes to the ruleset.
The default setting is *false*.
The *nft_ctx_get_dry_run*() function returns the dry-run setting's value contained in 'ctx'.
The *nft_ctx_set_dry_run*() function sets the dry-run setting in 'ctx' to the value of 'dry'.
+=== nft_ctx_input_get_flags() and nft_ctx_input_set_flags()
+The flags setting controls the input format.
+
+----
+enum {
+ NFT_CTX_INPUT_NO_DNS = (1 << 0),
+ NFT_CTX_INPUT_JSON = (1 << 1),
+};
+----
+
+NFT_CTX_INPUT_NO_DNS::
+ Avoid resolving IP addresses with blocking getaddrinfo(). In that case,
+ only plain IP addresses are accepted.
+
+NFT_CTX_INPUT_JSON:
+ When parsing the input, first try to interpret the input as JSON before
+ falling back to the nftables format. This behavior is implied when setting
+ the NFT_CTX_OUTPUT_JSON flag.
+
+The *nft_ctx_input_get_flags*() function returns the input flags setting's value in 'ctx'.
+
+The *nft_ctx_input_set_flags*() function sets the input flags setting in 'ctx' to the value of 'val'
+and returns the previous flags.
+
=== nft_ctx_output_get_flags() and nft_ctx_output_set_flags()
The flags setting controls the output format.
----
enum {
- NFT_CTX_OUTPUT_REVERSEDNS = (1 << 0),
- NFT_CTX_OUTPUT_SERVICE = (1 << 1),
- NFT_CTX_OUTPUT_STATELESS = (1 << 2),
- NFT_CTX_OUTPUT_HANDLE = (1 << 3),
- NFT_CTX_OUTPUT_JSON = (1 << 4),
- NFT_CTX_OUTPUT_ECHO = (1 << 5),
- NFT_CTX_OUTPUT_GUID = (1 << 6),
- NFT_CTX_OUTPUT_NUMERIC_PROTO = (1 << 7),
- NFT_CTX_OUTPUT_NUMERIC_PRIO = (1 << 8),
+ NFT_CTX_OUTPUT_REVERSEDNS = (1 << 0),
+ NFT_CTX_OUTPUT_SERVICE = (1 << 1),
+ NFT_CTX_OUTPUT_STATELESS = (1 << 2),
+ NFT_CTX_OUTPUT_HANDLE = (1 << 3),
+ NFT_CTX_OUTPUT_JSON = (1 << 4),
+ NFT_CTX_OUTPUT_ECHO = (1 << 5),
+ NFT_CTX_OUTPUT_GUID = (1 << 6),
+ NFT_CTX_OUTPUT_NUMERIC_PROTO = (1 << 7),
+ NFT_CTX_OUTPUT_NUMERIC_PRIO = (1 << 8),
NFT_CTX_OUTPUT_NUMERIC_SYMBOL = (1 << 9),
+ NFT_CTX_OUTPUT_NUMERIC_TIME = (1 << 10),
+ NFT_CTX_OUTPUT_NUMERIC_ALL = (NFT_CTX_OUTPUT_NUMERIC_PROTO |
+ NFT_CTX_OUTPUT_NUMERIC_PRIO |
+ NFT_CTX_OUTPUT_NUMERIC_SYMBOL |
+ NFT_CTX_OUTPUT_NUMERIC_TIME),
+ NFT_CTX_OUTPUT_TERSE = (1 << 11),
};
----
@@ -109,10 +145,11 @@ NFT_CTX_OUTPUT_HANDLE::
NFT_CTX_OUTPUT_JSON::
If enabled at compile-time, libnftables accepts input in JSON format and is able to print output in JSON format as well.
See *libnftables-json*(5) for a description of the supported schema.
- This flag controls JSON output format, input is auto-detected.
+ This flag enables JSON output format. If the flag is set, the input will first be tried as JSON format,
+ before falling back to nftables format. This flag implies NFT_CTX_INPUT_JSON.
NFT_CTX_OUTPUT_ECHO::
The echo setting makes libnftables print the changes once they are committed to the kernel, just like a running instance of *nft monitor* would.
- Amongst other things, this allows to retrieve an added rule's handle atomically.
+ Amongst other things, this allows one to retrieve an added rule's handle atomically.
NFT_CTX_OUTPUT_GUID::
Display UID and GID as described in the /etc/passwd and /etc/group files.
NFT_CTX_OUTPUT_NUMERIC_PROTO::
@@ -121,8 +158,12 @@ NFT_CTX_OUTPUT_NUMERIC_PRIO::
Display base chain priority numerically.
NFT_CTX_OUTPUT_NUMERIC_SYMBOL::
Display expression datatype as numeric value.
+NFT_CTX_OUTPUT_NUMERIC_TIME::
+ Display time, day and hour values in numeric format.
NFT_CTX_OUTPUT_NUMERIC_ALL::
Display all numerically.
+NFT_CTX_OUTPUT_TERSE::
+ If terse output has been requested, then the contents of sets are not printed.
The *nft_ctx_output_get_flags*() function returns the output flags setting's value in 'ctx'.
@@ -186,9 +227,9 @@ On failure, the functions return non-zero which may only happen if buffering was
The *nft_ctx_get_output_buffer*() and *nft_ctx_get_error_buffer*() functions return a pointer to the buffered output (which may be empty).
=== nft_ctx_add_include_path() and nft_ctx_clear_include_path()
-The *include* command in nftables rulesets allows to outsource parts of the ruleset into a different file.
+The *include* command in nftables rulesets allows one to outsource parts of the ruleset into a different file.
The include path defines where these files are searched for.
-Libnftables allows to have a list of those paths which are searched in order.
+Libnftables allows one to have a list of those paths which are searched in order.
The default include path list contains a single compile-time defined entry (typically '/etc/').
The *nft_ctx_add_include_path*() function extends the list of include paths in 'ctx' by the one given in 'path'.
@@ -196,6 +237,14 @@ The function returns zero on success or non-zero if memory allocation failed.
The *nft_ctx_clear_include_paths*() function removes all include paths, even the built-in default one.
+=== nft_ctx_add_var() and nft_ctx_clear_vars()
+The *define* command in nftables ruleset allows one to define variables.
+
+The *nft_ctx_add_var*() function extends the list of variables in 'ctx'. The variable must be given in the format 'key=value'.
+The function returns zero on success or non-zero if the variable is malformed.
+
+The *nft_ctx_clear_vars*() function removes all variables.
+
=== nft_run_cmd_from_buffer() and nft_run_cmd_from_filename()
These functions perform the actual work of parsing user input into nftables commands and executing them.
diff --git a/doc/nft.txt b/doc/nft.txt
index 9bc5986b..248b29af 100644
--- a/doc/nft.txt
+++ b/doc/nft.txt
@@ -9,7 +9,7 @@ nft - Administration tool of the nftables framework for packet filtering and cla
SYNOPSIS
--------
[verse]
-*nft* [ *-nNscaeSupyjt* ] [ *-I* 'directory' ] [ *-f* 'filename' | *-i* | 'cmd' ...]
+*nft* [ *-nNscaeSupyjtT* ] [ *-I* 'directory' ] [ *-f* 'filename' | *-i* | 'cmd' ...]
*nft* *-h*
*nft* *-v*
@@ -22,7 +22,10 @@ for Netfilter.
OPTIONS
-------
-For a full summary of options, run *nft --help*.
+The command accepts several different options which are documented here in groups for better
+understanding of their meaning. You can get information about options by running *nft --help*.
+
+.General options:
*-h*::
*--help*::
@@ -32,42 +35,82 @@ For a full summary of options, run *nft --help*.
*--version*::
Show version.
-*-n*::
-*--numeric*::
- Print fully numerical output.
+*-V*::
+ Show long version information, including compile-time configuration.
+
+.Ruleset input handling options that specify to how to load rulesets:
+
+*-f*::
+*--file 'filename'*::
+ Read input from 'filename'. If 'filename' is -, read from stdin.
+
+*-D*::
+*--define 'name=value'*::
+ Define a variable. You can only combine this option with '-f'.
+
+*-i*::
+*--interactive*::
+ Read input from an interactive readline CLI. You can use quit to exit, or use the EOF marker,
+ normally this is CTRL-D.
+
+*-I*::
+*--includepath directory*::
+ Add the directory 'directory' to the list of directories to be searched for included files. This
+ option may be specified multiple times.
+
+*-c*::
+*--check*::
+ Check commands validity without actually applying the changes.
+
+*-o*::
+*--optimize*::
+ Optimize your ruleset. You can combine this option with '-c' to inspect
+ the proposed optimizations.
+
+.Ruleset list output formatting that modify the output of the list ruleset command:
+
+*-a*::
+*--handle*::
+ Show object handles in output.
*-s*::
*--stateless*::
Omit stateful information of rules and stateful objects.
-*-N*::
-*--reversedns*::
- Translate IP address to names via reverse DNS lookup. This may slow down
- your listing since it generates network traffic.
+*-t*::
+*--terse*::
+ Omit contents of sets from output.
*-S*::
*--service*::
Translate ports to service names as defined by /etc/services.
+*-N*::
+*--reversedns*::
+ Translate IP address to names via reverse DNS lookup. This may slow down
+ your listing since it generates network traffic.
+
*-u*::
*--guid*::
Translate numeric UID/GID to names as defined by /etc/passwd and /etc/group.
-*-p*::
-*--numeric-protocol*::
- Display layer 4 protocol numerically.
+*-n*::
+*--numeric*::
+ Print fully numerical output.
*-y*::
*--numeric-priority*::
Display base chain priority numerically.
-*-c*::
-*--check*::
- Check commands validity without actually applying the changes.
+*-p*::
+*--numeric-protocol*::
+ Display layer 4 protocol numerically.
-*-a*::
-*--handle*::
- Show object handles in output.
+*-T*::
+*--numeric-time*::
+ Show time, day and hour values in numeric format.
+
+.Command output formatting:
*-e*::
*--echo*::
@@ -78,24 +121,11 @@ For a full summary of options, run *nft --help*.
*--json*::
Format output in JSON. See libnftables-json(5) for a schema description.
-*-I*::
-*--includepath directory*::
- Add the directory 'directory' to the list of directories to be searched for included files. This
- option may be specified multiple times.
-
-*-f*::
-*--file 'filename'*::
- Read input from 'filename'. If 'filename' is -, read from stdin. +
- nft scripts must start *#!/usr/sbin/nft -f*
-
-*-i*::
-*--interactive*::
- Read input from an interactive readline CLI. You can use quit to exit, or use the EOF marker,
- normally this is CTRL-D.
-
-*-t*::
-*--numeric-time*::
- Show time, day and hour values in numeric format.
+*-d*::
+*--debug* 'level'::
+ Enable debugging output. The debug level can be any of *scanner*, *parser*, *eval*,
+ *netlink*, *mnl*, *proto-ctx*, *segtree*, *all*. You can combine more than one by
+ separating by the ',' symbol, for example '-d eval,mnl'.
INPUT FILE FORMATS
------------------
@@ -109,7 +139,7 @@ semicolon (;). +
A hash sign (#) begins a comment. All following characters on the same line are
ignored. +
-Identifiers begin with an alphabetic character (a-z,A-Z), followed zero or more
+Identifiers begin with an alphabetic character (a-z,A-Z), followed by zero or more
alphanumeric characters (a-z,A-Z,0-9) and the characters slash (/), backslash
(\), underscore (_) and dot (.). Identifiers using different characters or
clashing with a keyword need to be enclosed in double quotes (").
@@ -127,12 +157,12 @@ relative path) or / for file location expressed as an absolute path. +
If *-I*/*--includepath* is not specified, then nft relies on the default
directory that is specified at compile time. You can retrieve this default
-directory via *-h*/*--help* option. +
+directory via the *-h*/*--help* option. +
-Include statements support the usual shell wildcard symbols (\*,?,[]). Having no
+Include statements support the usual shell wildcard symbols (*,?,[]). Having no
matches for an include statement is not an error, if wildcard symbols are used
in the include statement. This allows having potentially empty include
-directories for statements like **include "/etc/firewall/rules/"**. The wildcard
+directories for statements like **include "/etc/firewall/rules/*"**. The wildcard
matches are loaded in alphabetical order. Files beginning with dot (.) are not
matched by include statements.
@@ -140,17 +170,23 @@ SYMBOLIC VARIABLES
~~~~~~~~~~~~~~~~~~
[verse]
*define* 'variable' *=* 'expr'
+*undefine* 'variable'
+*redefine* 'variable' *=* 'expr'
*$variable*
Symbolic variables can be defined using the *define* statement. Variable
-references are expressions and can be used initialize other variables. The scope
+references are expressions and can be used to initialize other variables. The scope
of a definition is the current block and all blocks contained within.
+Symbolic variables can be undefined using the *undefine* statement, and modified
+using the *redefine* statement.
.Using symbolic variables
---------------------------------------
define int_if1 = eth0
define int_if2 = eth1
define int_ifs = { $int_if1, $int_if2 }
+redefine int_if2 = wlan0
+undefine int_if2
filter input iif $int_ifs accept
---------------------------------------
@@ -168,7 +204,7 @@ packet processing paths, which invoke nftables if rules for these hooks exist.
*inet*:: Internet (IPv4/IPv6) address family.
*arp*:: ARP address family, handling IPv4 ARP packets.
*bridge*:: Bridge address family, handling packets which traverse a bridge device.
-*netdev*:: Netdev address family, handling packets from ingress.
+*netdev*:: Netdev address family, handling packets on ingress and egress.
All nftables objects exist in address family specific namespaces, therefore all
identifiers include an address family. If an identifier is specified without an
@@ -196,6 +232,11 @@ Packets forwarded to a different host are processed by the forward hook.
Packets sent by local processes are processed by the output hook.
|postrouting |
All packets leaving the system are processed by the postrouting hook.
+|ingress |
+All packets entering the system are processed by this hook. It is invoked before
+layer 3 protocol handlers, hence before the prerouting hook, and it can be used
+for filtering and policing. Ingress is only available for Inet family (since
+Linux kernel 5.10).
|===================
ARP ADDRESS FAMILY
@@ -221,17 +262,39 @@ The list of supported hooks is identical to IPv4/IPv6/Inet address families abov
NETDEV ADDRESS FAMILY
~~~~~~~~~~~~~~~~~~~~
-The Netdev address family handles packets from ingress.
+The Netdev address family handles packets from the device ingress and egress
+path. This family allows you to filter packets of any ethertype such as ARP,
+VLAN 802.1q, VLAN 802.1ad (Q-in-Q) as well as IPv4 and IPv6 packets.
.Netdev address family hooks
[options="header"]
|=================
|Hook | Description
|ingress |
-All packets entering the system are processed by this hook. It is invoked before
-layer 3 protocol handlers and it can be used for early filtering and policing.
+All packets entering the system are processed by this hook. It is invoked after
+the network taps (ie. *tcpdump*), right after *tc* ingress and before layer 3
+protocol handlers, it can be used for early filtering and policing.
+|egress |
+All packets leaving the system are processed by this hook. It is invoked after
+layer 3 protocol handlers and before *tc* egress. It can be used for late
+filtering and policing.
|=================
+Tunneled packets (such as *vxlan*) are processed by netdev family hooks both
+in decapsulated and encapsulated (tunneled) form. So a packet can be filtered
+on the overlay network as well as on the underlying network.
+
+Note that the order of netfilter and *tc* is mirrored on ingress versus egress.
+This ensures symmetry for NAT and other packet mangling.
+
+Ingress packets which are redirected out some other interface are only
+processed by netfilter on egress if they have passed through netfilter ingress
+processing before. Thus, ingress packets which are redirected by *tc* are not
+subjected to netfilter. But they are if they are redirected by *netfilter* on
+ingress. Conceptually, tc and netfilter can be thought of as layers, with
+netfilter layered above tc: If the packet hasn't been passed up from the
+tc layer to the netfilter layer, it's not subjected to netfilter on egress.
+
RULESET
-------
[verse]
@@ -258,10 +321,11 @@ Effectively, this is the nft-equivalent of *iptables-save* and
TABLES
------
[verse]
-{*add* | *create*} *table* ['family'] 'table' [*{ flags* 'flags' *; }*]
-{*delete* | *list* | *flush*} *table* ['family'] 'table'
-*list tables*
+{*add* | *create*} *table* ['family'] 'table' [*{* [*comment* 'comment' *;*] [*flags* 'flags' *;*] *}*]
+{*delete* | *destroy* | *list* | *flush*} *table* ['family'] 'table'
+*list tables* ['family']
*delete table* ['family'] *handle* 'handle'
+*destroy table* ['family'] *handle* 'handle'
Tables are containers for chains, sets and stateful objects. They are identified
by their address family and their name. The address family must be one of *ip*,
@@ -290,7 +354,7 @@ nft --interactive
create table inet mytable
# add a new base chain: get input packets
-add chain inet mytable myin { type filter hook input priority 0; }
+add chain inet mytable myin { type filter hook input priority filter; }
# add a single counter to the chain
add rule inet mytable myin counter
@@ -305,16 +369,18 @@ add table inet mytable
[horizontal]
*add*:: Add a new table for the given family with the given name.
*delete*:: Delete the specified table.
+*destroy*:: Delete the specified table, it does not fail if it does not exist.
*list*:: List all chains and rules of the specified table.
*flush*:: Flush all chains and rules of the specified table.
CHAINS
------
[verse]
-{*add* | *create*} *chain* ['family'] 'table' 'chain' [*{ type* 'type' *hook* 'hook' [*device* 'device'] *priority* 'priority' *;* [*policy* 'policy' *;*] *}*]
-{*delete* | *list* | *flush*} *chain* ['family'] 'table' 'chain'
-*list chains*
+{*add* | *create*} *chain* ['family'] 'table' 'chain' [*{ type* 'type' *hook* 'hook' [*device* 'device'] *priority* 'priority' *;* [*policy* 'policy' *;*] [*comment* 'comment' *;*] *}*]
+{*delete* | *destroy* | *list* | *flush*} *chain* ['family'] 'table' 'chain'
+*list chains* ['family']
*delete chain* ['family'] 'table' *handle* 'handle'
+*destroy chain* ['family'] 'table' *handle* 'handle'
*rename chain* ['family'] 'table' 'chain' 'newname'
Chains are containers for rules. They exist in two kinds, base chains and
@@ -327,6 +393,7 @@ organization.
are specified, the chain is created as a base chain and hooked up to the networking stack.
*create*:: Similar to the *add* command, but returns an error if the chain already exists.
*delete*:: Delete the specified chain. The chain must not contain any rules or be used as jump target.
+*destroy*:: Delete the specified chain, it does not fail if it does not exist. The chain must not contain any rules or be used as jump target.
*rename*:: Rename the specified chain.
*list*:: List all rules of the specified chain.
*flush*:: Flush all rules of the specified chain.
@@ -348,24 +415,38 @@ statements for instance).
|route | ip, ip6 | output |
If a packet has traversed a chain of this type and is about to be accepted, a
new route lookup is performed if relevant parts of the IP header have changed.
-This allows to e.g. implement policy routing selectors in nftables.
+This allows one to e.g. implement policy routing selectors in nftables.
|=================
Apart from the special cases illustrated above (e.g. *nat* type not supporting
-*forward* hook or *route* type only supporting *output* hook), there are two
+*forward* hook or *route* type only supporting *output* hook), there are three
further quirks worth noticing:
-* The netdev family supports merely a single combination, namely *filter* type and
- *ingress* hook. Base chains in this family also require the *device* parameter
- to be present since they exist per incoming interface only.
+* The netdev family supports merely two combinations, namely *filter* type with
+ *ingress* hook and *filter* type with *egress* hook. Base chains in this
+ family also require the *device* parameter to be present since they exist per
+ interface only.
* The arp family supports only the *input* and *output* hooks, both in chains of type
*filter*.
+* The inet family also supports the *ingress* hook (since Linux kernel 5.10),
+ to filter IPv4 and IPv6 packet at the same location as the netdev *ingress*
+ hook. This inet hook allows you to share sets and maps between the usual
+ *prerouting*, *input*, *forward*, *output*, *postrouting* and this *ingress*
+ hook.
+
+The *device* parameter accepts a network interface name as a string, and is
+required when adding a base chain that filters traffic on the ingress or
+egress hooks. Any ingress or egress chains will only filter traffic from the
+interface specified in the *device* parameter.
The *priority* parameter accepts a signed integer value or a standard priority
-name which specifies the order in which chains with same *hook* value are
+name which specifies the order in which chains with the same *hook* value are
traversed. The ordering is ascending, i.e. lower priority values have precedence
over higher ones.
+With *nat* type chains, there's a lower excluding limit of -200 for *priority*
+values, because conntrack hooks at this priority and NAT requires it.
+
Standard priority values can be replaced with easily memorizable names. Not all
names make sense in every family with every hook (see the compatibility matrices
below) but their numerical value can still be used for prioritizing chains.
@@ -401,9 +482,9 @@ the others. See the following tables that describe the values and compatibility.
Basic arithmetic expressions (addition and subtraction) can also be achieved
with these standard names to ease relative prioritizing, e.g. *mangle - 5* stands
for *-155*. Values will also be printed like this until the value is not
-further than 10 form the standard value.
+further than 10 from the standard value.
-Base chains also allow to set the chain's *policy*, i.e. what happens to
+Base chains also allow one to set the chain's *policy*, i.e. what happens to
packets not explicitly accepted or refused in contained rules. Supported policy
values are *accept* (which is the default) or *drop*.
@@ -412,7 +493,9 @@ RULES
[verse]
{*add* | *insert*} *rule* ['family'] 'table' 'chain' [*handle* 'handle' | *index* 'index'] 'statement' ... [*comment* 'comment']
*replace rule* ['family'] 'table' 'chain' *handle* 'handle' 'statement' ... [*comment* 'comment']
-*delete rule* ['family'] 'table' 'chain' *handle* 'handle'
+{*delete* | *reset*} *rule* ['family'] 'table' 'chain' *handle* 'handle'
+*destroy rule* ['family'] 'table' 'chain' *handle* 'handle'
+*reset rules* ['family'] ['table' ['chain']]
Rules are added to chains in the given table. If the family is not specified, the
ip family is used. Rules are constructed from two kinds of components according
@@ -440,8 +523,10 @@ case the rule is inserted after the specified rule.
beginning of the chain or before the specified rule.
*replace*:: Similar to *add*, but the rule replaces the specified rule.
*delete*:: Delete the specified rule.
+*destroy*:: Delete the specified rule, it does not fail if it does not exist.
+*reset*:: Reset rule-contained state, e.g. counter and quota statement values.
-.*add a rule to ip table input chain*
+.*add a rule to ip table output chain*
-------------
nft add rule filter output ip daddr 192.168.0.0/24 accept # 'ip filter' is assumed
# same command, slightly more verbose
@@ -453,12 +538,12 @@ nft add rule ip filter output ip daddr 192.168.0.0/24 accept
# nft -a list ruleset
table inet filter {
chain input {
- type filter hook input priority 0; policy accept;
+ type filter hook input priority filter; policy accept;
ct state established,related accept # handle 4
ip saddr 10.1.1.1 tcp dport ssh accept # handle 5
...
# delete the rule with handle 5
-# nft delete rule inet filter input handle 5
+nft delete rule inet filter input handle 5
-------------------------
SETS
@@ -489,23 +574,23 @@ The sets allowed_hosts and allowed_ports need to be created first. The next
section describes nft set syntax in more detail.
[verse]
-*add set* ['family'] 'table' 'set' *{ type* 'type' *;* [*flags* 'flags' *;*] [*timeout* 'timeout' *;*] [*gc-interval* 'gc-interval' *;*] [*elements = {* 'element'[*,* ...] *} ;*] [*size* 'size' *;*] [*policy* 'policy' *;*] [*auto-merge ;*] *}*
-{*delete* | *list* | *flush*} *set* ['family'] 'table' 'set'
-*list sets*
+*add set* ['family'] 'table' 'set' *{ type* 'type' | *typeof* 'expression' *;* [*flags* 'flags' *;*] [*timeout* 'timeout' *;*] [*gc-interval* 'gc-interval' *;*] [*elements = {* 'element'[*,* ...] *} ;*] [*size* 'size' *;*] [*comment* 'comment' *;*'] [*policy* 'policy' *;*] [*auto-merge ;*] *}*
+{*delete* | *destroy* | *list* | *flush* | *reset* } *set* ['family'] 'table' 'set'
+*list sets* ['family']
*delete set* ['family'] 'table' *handle* 'handle'
-{*add* | *delete*} *element* ['family'] 'table' 'set' *{* 'element'[*,* ...] *}*
+{*add* | *delete* | *destroy* } *element* ['family'] 'table' 'set' *{* 'element'[*,* ...] *}*
Sets are element containers of a user-defined data type, they are uniquely
identified by a user-defined name and attached to tables. Their behaviour can
be tuned with the flags that can be specified at set creation time.
[horizontal]
-*add*:: Add a new set in the specified table. See the Set specification table below for more information about how to specify a sets properties.
+*add*:: Add a new set in the specified table. See the Set specification table below for more information about how to specify properties of a set.
*delete*:: Delete the specified set.
+*destroy*:: Delete the specified set, it does not fail if it does not exist.
*list*:: Display the elements in the specified set.
*flush*:: Remove all elements from the specified set.
-*add element*:: Comma-separated list of elements to add into the specified set.
-*delete element*:: Comma-separated list of elements to delete from the specified set.
+*reset*:: Reset state in all contained elements, e.g. counter and quota statement values.
.Set specifications
[options="header"]
@@ -514,11 +599,13 @@ be tuned with the flags that can be specified at set creation time.
|type |
data type of set elements |
string: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark
+|typeof |
+data type of set element |
+expression to derive the data type from
|flags |
-set flags |
-string: constant, dynamic, interval, timeout
+set flags | string: constant, dynamic, interval, timeout. Used to describe the sets properties.
|timeout |
-time an element stays in the set, mandatory if set is added to from the packet path (ruleset).|
+time an element stays in the set, mandatory if set is added to from the packet path (ruleset)|
string, decimal followed by unit. Units are: d, h, m, s
|gc-interval |
garbage collection interval, only available when timeout or flag timeout are
@@ -528,7 +615,7 @@ string, decimal followed by unit. Units are: d, h, m, s
elements contained by the set |
set data type
|size |
-maximum number of elements in the set, mandatory if set is added to from the packet path (ruleset).|
+maximum number of elements in the set, mandatory if set is added to from the packet path (ruleset)|
unsigned integer (64 bit)
|policy |
set policy |
@@ -541,20 +628,19 @@ automatic merge of adjacent/overlapping set elements (only for interval sets) |
MAPS
-----
[verse]
-*add map* ['family'] 'table' 'map' *{ type* 'type' [*flags* 'flags' *;*] [*elements = {* 'element'[*,* ...] *} ;*] [*size* 'size' *;*] [*policy* 'policy' *;*] *}*
-{*delete* | *list* | *flush*} *map* ['family'] 'table' 'map'
-*list maps*
-{*add* | *delete*} *element* ['family'] 'table' 'map' *{ elements = {* 'element'[*,* ...] *} ; }*
+*add map* ['family'] 'table' 'map' *{ type* 'type' | *typeof* 'expression' [*flags* 'flags' *;*] [*elements = {* 'element'[*,* ...] *} ;*] [*size* 'size' *;*] [*comment* 'comment' *;*'] [*policy* 'policy' *;*] *}*
+{*delete* | *destroy* | *list* | *flush* | *reset* } *map* ['family'] 'table' 'map'
+*list maps* ['family']
Maps store data based on some specific key used as input. They are uniquely identified by a user-defined name and attached to tables.
[horizontal]
*add*:: Add a new map in the specified table.
*delete*:: Delete the specified map.
+*destroy*:: Delete the specified map, it does not fail if it does not exist.
*list*:: Display the elements in the specified map.
*flush*:: Remove all elements from the specified map.
-*add element*:: Comma-separated list of elements to add into the specified map.
-*delete element*:: Comma-separated list of element keys to delete from the specified map.
+*reset*:: Reset state in all contained elements, e.g. counter and quota statement values.
.Map specifications
[options="header"]
@@ -562,10 +648,13 @@ Maps store data based on some specific key used as input. They are uniquely iden
|Keyword | Description | Type
|type |
data type of map elements |
-string `:' string: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark, counter, quota. Counter and quota can't be used as keys
+string: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark, counter, quota. Counter and quota can't be used as keys
+|typeof |
+data type of set element |
+expression to derive the data type from
|flags |
map flags |
-string: constant, interval
+string, same as set flags
|elements |
elements contained by the map |
map data type
@@ -577,12 +666,70 @@ map policy |
string: performance [default], memory
|=================
+Users can specifiy the properties/features that the set/map must support.
+This allows the kernel to pick an optimal internal representation.
+If a required flag is missing, the ruleset might still work, as
+nftables will auto-enable features if it can infer this from the ruleset.
+This may not work for all cases, however, so it is recommended to
+specify all required features in the set/map definition manually.
+
+.Set and Map flags
+[options="header"]
+|=================
+|Flag | Description
+|constant | Set contents will never change after creation
+|dynamic | Set must support updates from the packet path with the *add*, *update* or *delete* keywords.
+|interval | Set must be able to store intervals (ranges)
+|timeout | Set must support element timeouts (auto-removal of elements once they expire).
+|=================
+
+ELEMENTS
+--------
+[verse]
+____
+{*add* | *create* | *delete* | *destroy* | *get* | *reset* } *element* ['family'] 'table' 'set' *{* 'ELEMENT'[*,* ...] *}*
+
+'ELEMENT' := 'key_expression' 'OPTIONS' [*:* 'value_expression']
+'OPTIONS' := [*timeout* 'TIMESPEC'] [*expires* 'TIMESPEC'] [*comment* 'string']
+'TIMESPEC' := ['num'*d*]['num'*h*]['num'*m*]['num'[*s*]]
+____
+Element-related commands allow one to change contents of named sets and maps.
+'key_expression' is typically a value matching the set type.
+'value_expression' is not allowed in sets but mandatory when adding to maps, where it
+matches the data part in its type definition. When deleting from maps, it may
+be specified but is optional as 'key_expression' uniquely identifies the
+element.
+
+*create* command is similar to *add* with the exception that none of the
+listed elements may already exist.
+
+*get* command is useful to check if an element is contained in a set which may
+be non-trivial in very large and/or interval sets. In the latter case, the
+containing interval is returned instead of just the element itself.
+
+*reset* command resets state attached to the given element(s), e.g. counter and
+quota statement values.
+
+.Element options
+[options="header"]
+|=================
+|Option | Description
+|timeout |
+timeout value for sets/maps with flag *timeout*
+|expires |
+the time until given element expires, useful for ruleset replication only
+|comment |
+per element comment field
+|=================
+
FLOWTABLES
-----------
[verse]
{*add* | *create*} *flowtable* ['family'] 'table' 'flowtable' *{ hook* 'hook' *priority* 'priority' *; devices = {* 'device'[*,* ...] *} ; }*
-{*delete* | *list*} *flowtable* ['family'] 'table' 'flowtable'
+*list flowtables* ['family']
+{*delete* | *destroy* | *list*} *flowtable* ['family'] 'table' 'flowtable'
+*delete* *flowtable* ['family'] 'table' *handle* 'handle'
Flowtables allow you to accelerate packet forwarding in software. Flowtables
entries are represented through a tuple that is composed of the input interface,
@@ -605,24 +752,48 @@ and subtraction can be used to set relative priority, e.g. filter + 5 equals to
[horizontal]
*add*:: Add a new flowtable for the given family with the given name.
*delete*:: Delete the specified flowtable.
+*destroy*:: Delete the specified flowtable, it does not fail if it does not exist.
*list*:: List all flowtables.
+LISTING
+-------
+[verse]
+*list { secmarks | synproxys | flow tables | meters | hooks }* ['family']
+*list { secmarks | synproxys | flow tables | meters | hooks } table* ['family'] 'table'
+*list ct { timeout | expectation | helper | helpers } table* ['family'] 'table'
+
+Inspect configured objects.
+*list hooks* shows the full hook pipeline, including those registered by
+kernel modules, such as nf_conntrack.
STATEFUL OBJECTS
----------------
[verse]
-{*add* | *delete* | *list* | *reset*} 'type' ['family'] 'table' 'object'
-*delete* 'type' ['family'] 'table' *handle* 'handle'
-*list counters*
-*list quotas*
-
-Stateful objects are attached to tables and are identified by an unique name.
+{*add* | *delete* | *destroy* | *list* | *reset*} *counter* ['family'] 'table' 'object'
+{*add* | *delete* | *destroy* | *list* | *reset*} *quota* ['family'] 'table' 'object'
+{*add* | *delete* | *destroy* | *list*} *limit* ['family'] 'table' 'object'
+*delete* 'counter' ['family'] 'table' *handle* 'handle'
+*delete* 'quota' ['family'] 'table' *handle* 'handle'
+*delete* 'limit' ['family'] 'table' *handle* 'handle'
+*destroy* 'counter' ['family'] 'table' *handle* 'handle'
+*destroy* 'quota' ['family'] 'table' *handle* 'handle'
+*destroy* 'limit' ['family'] 'table' *handle* 'handle'
+*list counters* ['family']
+*list quotas* ['family']
+*list limits* ['family']
+*reset counters* ['family']
+*reset quotas* ['family']
+*reset counters* ['family'] 'table'
+*reset quotas* ['family'] 'table'
+
+Stateful objects are attached to tables and are identified by a unique name.
They group stateful information from rules, to reference them in rules the
keywords "type name" are used e.g. "counter name".
[horizontal]
*add*:: Add a new stateful object in the specified table.
*delete*:: Delete the specified object.
+*destroy*:: Delete the specified object, it does not fail if it does not exist.
*list*:: Display stateful information the object holds.
*reset*:: List-and-reset stateful object.
@@ -729,13 +900,26 @@ These are some additional commands included in nft.
MONITOR
~~~~~~~~
The monitor command allows you to listen to Netlink events produced by the
-nf_tables subsystem, related to creation and deletion of objects. When they
+nf_tables subsystem. These are either related to creation and deletion of
+objects or to packets for which *meta nftrace* was enabled. When they
occur, nft will print to stdout the monitored events in either JSON or
native nft format. +
-To filter events related to a concrete object, use one of the keywords 'tables', 'chains', 'sets', 'rules', 'elements', 'ruleset'. +
+[verse]
+____
+*monitor* [*new* | *destroy*] 'MONITOR_OBJECT'
+*monitor* *trace*
+
+'MONITOR_OBJECT' := *tables* | *chains* | *sets* | *rules* | *elements* | *ruleset*
+____
-To filter events related to a concrete action, use keyword 'new' or 'destroy'.
+To filter events related to a concrete object, use one of the keywords in
+'MONITOR_OBJECT'.
+
+To filter events related to a concrete action, use keyword *new* or *destroy*.
+
+The second form of invocation takes no further options and exclusively prints
+events generated for packets with *nftrace* enabled.
Hit ^C to finish the monitor operation.
@@ -759,6 +943,12 @@ Hit ^C to finish the monitor operation.
% nft monitor ruleset
---------------------
+.Trace incoming packets from host 10.0.0.1
+------------------------------------------
+% nft add rule filter input ip saddr 10.0.0.1 meta nftrace set 1
+% nft monitor trace
+------------------------------------------
+
ERROR REPORTING
---------------
When an error is detected, nft shows the line(s) containing the error, the
diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt
index dba42fd5..c7c267da 100644
--- a/doc/payload-expression.txt
+++ b/doc/payload-expression.txt
@@ -21,7 +21,15 @@ ether_type
VLAN HEADER EXPRESSION
~~~~~~~~~~~~~~~~~~~~~~
[verse]
-*vlan* {*id* | *cfi* | *pcp* | *type*}
+*vlan* {*id* | *dei* | *pcp* | *type*}
+
+The vlan expression is used to match on the vlan header fields.
+This expression will not work in the *ip*, *ip6* and *inet* families,
+unless the vlan interface is configured with the *reorder_hdr off* setting.
+The default is *reorder_hdr on* which will automatically remove the vlan tag
+from the packet. See ip-link(8) for more information.
+For these families its easier to match the vlan interface name
+instead, using the *meta iif* or *meta iifname* expression.
.VLAN header expression
[options="header"]
@@ -30,8 +38,8 @@ VLAN HEADER EXPRESSION
|id|
VLAN ID (VID) |
integer (12 bit)
-|cfi|
-Canonical Format Indicator|
+|dei|
+Drop Eligible Indicator|
integer (1 bit)
|pcp|
Priority code point|
@@ -126,6 +134,14 @@ Destination address |
ipv4_addr
|======================
+Careful with matching on *ip length*: If GRO/GSO is enabled, then the Linux
+kernel might aggregate several packets into one big packet that is larger than
+MTU. Moreover, if GRO/GSO maximum size is larger than 65535 (see man ip-link(8),
+specifically gro_ipv6_max_size and gso_ipv6_max_size), then *ip length* might
+be 0 for such jumbo packets. *meta length* allows you to match on the packet
+length including the IP header size. If you want to perform heuristics on the
+*ip length* field, then disable GRO/GSO.
+
ICMP HEADER EXPRESSION
~~~~~~~~~~~~~~~~~~~~~~
[verse]
@@ -184,7 +200,7 @@ igmp_type
IGMP maximum response time field |
integer (8 bit)
|checksum|
-ICMP checksum field |
+IGMP checksum field |
integer (16 bit)
|group|
Group address|
@@ -236,6 +252,14 @@ Destination address |
ipv6_addr
|=======================
+Careful with matching on *ip6 length*: If GRO/GSO is enabled, then the Linux
+kernel might aggregate several packets into one big packet that is larger than
+MTU. Moreover, if GRO/GSO maximum size is larger than 65535 (see man ip-link(8),
+specifically gro_ipv6_max_size and gso_ipv6_max_size), then *ip6 length* might
+be 0 for such jumbo packets. *meta length* allows you to match on the packet
+length including the IP header size. If you want to perform heuristics on the
+*ip6 length* field, then disable GRO/GSO.
+
.Using ip6 header expressions
-----------------------------
# matching if first extension header indicates a fragment
@@ -245,7 +269,7 @@ ip6 nexthdr ipv6-frag
ICMPV6 HEADER EXPRESSION
~~~~~~~~~~~~~~~~~~~~~~~~
[verse]
-*icmpv6* {*type* | *code* | *checksum* | *parameter-problem* | *packet-too-big* | *id* | *sequence* | *max-delay*}
+*icmpv6* {*type* | *code* | *checksum* | *parameter-problem* | *packet-too-big* | *id* | *sequence* | *max-delay* | *taddr* | *daddr*}
This expression refers to ICMPv6 header fields. When using it in *inet*,
*bridge* or *netdev* families, it will cause an implicit dependency on IPv6 to
@@ -280,6 +304,12 @@ integer (16 bit)
|max-delay|
maximum response delay of MLD queries|
integer (16 bit)
+|taddr|
+target address of neighbor solicit/advert, redirect or MLD|
+ipv6_addr
+|daddr|
+destination address of redirect|
+ipv6_addr
|==============================
TCP HEADER EXPRESSION
@@ -369,7 +399,33 @@ integer (16 bit)
SCTP HEADER EXPRESSION
~~~~~~~~~~~~~~~~~~~~~~~
[verse]
+____
*sctp* {*sport* | *dport* | *vtag* | *checksum*}
+*sctp chunk* 'CHUNK' [ 'FIELD' ]
+
+'CHUNK' := *data* | *init* | *init-ack* | *sack* | *heartbeat* |
+ *heartbeat-ack* | *abort* | *shutdown* | *shutdown-ack* | *error* |
+ *cookie-echo* | *cookie-ack* | *ecne* | *cwr* | *shutdown-complete*
+ | *asconf-ack* | *forward-tsn* | *asconf*
+
+'FIELD' := 'COMMON_FIELD' | 'DATA_FIELD' | 'INIT_FIELD' | 'INIT_ACK_FIELD' |
+ 'SACK_FIELD' | 'SHUTDOWN_FIELD' | 'ECNE_FIELD' | 'CWR_FIELD' |
+ 'ASCONF_ACK_FIELD' | 'FORWARD_TSN_FIELD' | 'ASCONF_FIELD'
+
+'COMMON_FIELD' := *type* | *flags* | *length*
+'DATA_FIELD' := *tsn* | *stream* | *ssn* | *ppid*
+'INIT_FIELD' := *init-tag* | *a-rwnd* | *num-outbound-streams* |
+ *num-inbound-streams* | *initial-tsn*
+'INIT_ACK_FIELD' := 'INIT_FIELD'
+'SACK_FIELD' := *cum-tsn-ack* | *a-rwnd* | *num-gap-ack-blocks* |
+ *num-dup-tsns*
+'SHUTDOWN_FIELD' := *cum-tsn-ack*
+'ECNE_FIELD' := *lowest-tsn*
+'CWR_FIELD' := *lowest-tsn*
+'ASCONF_ACK_FIELD' := *seqno*
+'FORWARD_TSN_FIELD' := *new-cum-tsn*
+'ASCONF_FIELD' := *seqno*
+____
.SCTP header expression
[options="header"]
@@ -387,12 +443,39 @@ integer (32 bit)
|checksum|
Checksum|
integer (32 bit)
+|chunk|
+Search chunk in packet|
+without 'FIELD', boolean indicating existence
|================
+.SCTP chunk fields
+[options="header"]
+|==================
+|Name| Width in bits | Chunk | Notes
+|type| 8 | all | not useful, defined by chunk type
+|flags| 8 | all | semantics defined on per-chunk basis
+|length| 16 | all | length of this chunk in bytes excluding padding
+|tsn| 32 | data | transmission sequence number
+|stream| 16 | data | stream identifier
+|ssn| 16 | data | stream sequence number
+|ppid| 32 | data | payload protocol identifier
+|init-tag| 32 | init, init-ack | initiate tag
+|a-rwnd| 32 | init, init-ack, sack | advertised receiver window credit
+|num-outbound-streams| 16 | init, init-ack | number of outbound streams
+|num-inbound-streams| 16 | init, init-ack | number of inbound streams
+|initial-tsn| 32 | init, init-ack | initial transmit sequence number
+|cum-tsn-ack| 32 | sack, shutdown | cumulative transmission sequence number acknowledged
+|num-gap-ack-blocks| 16 | sack | number of Gap Ack Blocks included
+|num-dup-tsns| 16 | sack | number of duplicate transmission sequence numbers received
+|lowest-tsn| 32 | ecne, cwr | lowest transmission sequence number
+|seqno| 32 | asconf-ack, asconf | sequence number
+|new-cum-tsn| 32 | forward-tsn | new cumulative transmission sequence number
+|==================
+
DCCP HEADER EXPRESSION
~~~~~~~~~~~~~~~~~~~~~~
[verse]
-*dccp* {*sport* | *dport*}
+*dccp* {*sport* | *dport* | *type*}
.DCCP header expression
[options="header"]
@@ -404,6 +487,9 @@ inet_service
|dport|
Destination port|
inet_service
+|type|
+Packet type|
+dccp_pkttype
|========================
AUTHENTICATION HEADER EXPRESSION
@@ -468,6 +554,160 @@ compression Parameter Index |
integer (16 bit)
|============================
+GRE HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*gre* {*flags* | *version* | *protocol*}
+*gre* *ip* {*version* | *hdrlength* | *dscp* | *ecn* | *length* | *id* | *frag-off* | *ttl* | *protocol* | *checksum* | *saddr* | *daddr* }
+*gre* *ip6* {*version* | *dscp* | *ecn* | *flowlabel* | *length* | *nexthdr* | *hoplimit* | *saddr* | *daddr*}
+
+The gre expression is used to match on the gre header fields. This expression
+also allows to match on the IPv4 or IPv6 packet within the gre header.
+
+.GRE header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|flags|
+checksum, routing, key, sequence and strict source route flags|
+integer (5 bit)
+|version|
+gre version field, 0 for GRE and 1 for PPTP|
+integer (3 bit)
+|protocol|
+EtherType of encapsulated packet|
+integer (16 bit)
+|==================
+
+.Matching inner IPv4 destination address encapsulated in gre
+------------------------------------------------------------
+netdev filter ingress gre ip daddr 9.9.9.9 counter
+------------------------------------------------------------
+
+GENEVE HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*geneve* {*vni* | *flags*}
+*geneve* *ether* {*daddr* | *saddr* | *type*}
+*geneve* *vlan* {*id* | *dei* | *pcp* | *type*}
+*geneve* *ip* {*version* | *hdrlength* | *dscp* | *ecn* | *length* | *id* | *frag-off* | *ttl* | *protocol* | *checksum* | *saddr* | *daddr* }
+*geneve* *ip6* {*version* | *dscp* | *ecn* | *flowlabel* | *length* | *nexthdr* | *hoplimit* | *saddr* | *daddr*}
+*geneve* *tcp* {*sport* | *dport* | *sequence* | *ackseq* | *doff* | *reserved* | *flags* | *window* | *checksum* | *urgptr*}
+*geneve* *udp* {*sport* | *dport* | *length* | *checksum*}
+
+The geneve expression is used to match on the geneve header fields. The geneve
+header encapsulates a ethernet frame within a *udp* packet. This expression
+requires that you restrict the matching to *udp* packets (usually at
+port 6081 according to IANA-assigned ports).
+
+.GENEVE header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|protocol|
+EtherType of encapsulated packet|
+integer (16 bit)
+|vni|
+Virtual Network ID (VNI)|
+integer (24 bit)
+|==================
+
+.Matching inner TCP destination port encapsulated in geneve
+----------------------------------------------------------
+netdev filter ingress udp dport 4789 geneve tcp dport 80 counter
+----------------------------------------------------------
+
+GRETAP HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*gretap* {*vni* | *flags*}
+*gretap* *ether* {*daddr* | *saddr* | *type*}
+*gretap* *vlan* {*id* | *dei* | *pcp* | *type*}
+*gretap* *ip* {*version* | *hdrlength* | *dscp* | *ecn* | *length* | *id* | *frag-off* | *ttl* | *protocol* | *checksum* | *saddr* | *daddr* }
+*gretap* *ip6* {*version* | *dscp* | *ecn* | *flowlabel* | *length* | *nexthdr* | *hoplimit* | *saddr* | *daddr*}
+*gretap* *tcp* {*sport* | *dport* | *sequence* | *ackseq* | *doff* | *reserved* | *flags* | *window* | *checksum* | *urgptr*}
+*gretap* *udp* {*sport* | *dport* | *length* | *checksum*}
+
+The gretap expression is used to match on the encapsulated ethernet frame
+within the gre header. Use the *gre* expression to match on the *gre* header
+fields.
+
+.Matching inner TCP destination port encapsulated in gretap
+----------------------------------------------------------
+netdev filter ingress gretap tcp dport 80 counter
+----------------------------------------------------------
+
+VXLAN HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*vxlan* {*vni* | *flags*}
+*vxlan* *ether* {*daddr* | *saddr* | *type*}
+*vxlan* *vlan* {*id* | *dei* | *pcp* | *type*}
+*vxlan* *ip* {*version* | *hdrlength* | *dscp* | *ecn* | *length* | *id* | *frag-off* | *ttl* | *protocol* | *checksum* | *saddr* | *daddr* }
+*vxlan* *ip6* {*version* | *dscp* | *ecn* | *flowlabel* | *length* | *nexthdr* | *hoplimit* | *saddr* | *daddr*}
+*vxlan* *tcp* {*sport* | *dport* | *sequence* | *ackseq* | *doff* | *reserved* | *flags* | *window* | *checksum* | *urgptr*}
+*vxlan* *udp* {*sport* | *dport* | *length* | *checksum*}
+
+The vxlan expression is used to match on the vxlan header fields. The vxlan
+header encapsulates a ethernet frame within a *udp* packet. This expression
+requires that you restrict the matching to *udp* packets (usually at
+port 4789 according to IANA-assigned ports).
+
+.VXLAN header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|flags|
+vxlan flags|
+integer (8 bit)
+|vni|
+Virtual Network ID (VNI)|
+integer (24 bit)
+|==================
+
+.Matching inner TCP destination port encapsulated in vxlan
+----------------------------------------------------------
+netdev filter ingress udp dport 4789 vxlan tcp dport 80 counter
+----------------------------------------------------------
+
+ARP HEADER EXPRESSION
+~~~~~~~~~~~~~~~~~~~~~
+[verse]
+*arp* {*htype* | *ptype* | *hlen* | *plen* | *operation* | *saddr* { *ip* | *ether* } | *daddr* { *ip* | *ether* }
+
+.ARP header expression
+[options="header"]
+|==================
+|Keyword| Description| Type
+|htype|
+ARP hardware type|
+integer (16 bit)
+|ptype|
+EtherType|
+ether_type
+|hlen|
+Hardware address len|
+integer (8 bit)
+|plen|
+Protocol address len |
+integer (8 bit)
+|operation|
+Operation |
+arp_op
+|saddr ether|
+Ethernet sender address|
+ether_addr
+|daddr ether|
+Ethernet target address|
+ether_addr
+|saddr ip|
+IPv4 sender address|
+ipv4_addr
+|daddr ip|
+IPv4 target address|
+ipv4_addr
+|======================
+
RAW PAYLOAD EXPRESSION
~~~~~~~~~~~~~~~~~~~~~~
[verse]
@@ -492,6 +732,8 @@ Link layer, for example the Ethernet header
Network header, for example IPv4 or IPv6
|th|
Transport Header, for example TCP
+|ih|
+Inner Header / Payload, i.e. after the L4 transport level header
|==============================
.Matching destination port of both UDP and TCP
@@ -525,14 +767,15 @@ nftables currently supports matching (finding) a given ipv6 extension header, TC
*dst* {*nexthdr* | *hdrlength*}
*mh* {*nexthdr* | *hdrlength* | *checksum* | *type*}
*srh* {*flags* | *tag* | *sid* | *seg-left*}
-*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-permitted* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field'
+*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*} 'tcp_option_field'
*ip option* { lsrr | ra | rr | ssrr } 'ip_option_field'
The following syntaxes are valid only in a relational expression with boolean type on right-hand side for checking header existence only:
[verse]
*exthdr* {*hbh* | *frag* | *rt* | *dst* | *mh*}
-*tcp option* {*eol* | *noop* | *maxseg* | *window* | *sack-permitted* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*}
+*tcp option* {*eol* | *nop* | *maxseg* | *window* | *sack-perm* | *sack* | *sack0* | *sack1* | *sack2* | *sack3* | *timestamp*}
*ip option* { lsrr | ra | rr | ssrr }
+*dccp option* 'dccp_option_type'
.IPv6 extension headers
[options="header"]
@@ -558,39 +801,45 @@ Segment Routing Header
|Keyword| Description | TCP option fields
|eol|
End if option list|
-kind
-|noop|
-1 Byte TCP No-op options |
-kind
+-
+|nop|
+1 Byte TCP Nop padding option |
+-
|maxseg|
TCP Maximum Segment Size|
-kind, length, size
+length, size
|window|
TCP Window Scaling |
-kind, length, count
-|sack-permitted|
+length, count
+|sack-perm |
TCP SACK permitted |
-kind, length
+length
|sack|
TCP Selective Acknowledgement (alias of block 0) |
-kind, length, left, right
+length, left, right
|sack0|
TCP Selective Acknowledgement (block 0) |
-kind, length, left, right
+length, left, right
|sack1|
TCP Selective Acknowledgement (block 1) |
-kind, length, left, right
+length, left, right
|sack2|
TCP Selective Acknowledgement (block 2) |
-kind, length, left, right
+length, left, right
|sack3|
TCP Selective Acknowledgement (block 3) |
-kind, length, left, right
+length, left, right
|timestamp|
TCP Timestamps |
-kind, length, tsval, tsecr
+length, tsval, tsecr
|============================
+TCP option matching also supports raw expression syntax to access arbitrary options:
+[verse]
+*tcp option*
+[verse]
+*tcp option* *@*'number'*,*'offset'*,*'length'
+
.IP Options
[options="header"]
|==================
@@ -611,7 +860,12 @@ type, length, ptr, addr
.finding TCP options
--------------------
-filter input tcp option sack-permitted kind 1 counter
+filter input tcp option sack-perm exists counter
+--------------------
+
+.matching TCP options
+--------------------
+filter input tcp option maxseg size lt 536
--------------------
.matching IPv6 exthdr
@@ -624,6 +878,11 @@ ip6 filter input frag more-fragments 1 counter
filter input ip option lsrr exists counter
---------------------------------------
+.finding DCCP option
+------------------
+filter input dccp option 40 exists counter
+---------------------------------------
+
CONNTRACK EXPRESSIONS
~~~~~~~~~~~~~~~~~~~~~
Conntrack expressions refer to meta data of the connection tracking entry associated with a packet. +
@@ -637,11 +896,13 @@ is true for the *zone*, if a direction is given, the zone is only matched if the
zone id is tied to the given direction. +
[verse]
-*ct* {*state* | *direction* | *status* | *mark* | *expiration* | *helper* | *label*}
+*ct* {*state* | *direction* | *status* | *mark* | *expiration* | *helper* | *label* | *count* | *id*}
*ct* [*original* | *reply*] {*l3proto* | *protocol* | *bytes* | *packets* | *avgpkt* | *zone*}
*ct* {*original* | *reply*} {*proto-src* | *proto-dst*}
*ct* {*original* | *reply*} {*ip* | *ip6*} {*saddr* | *daddr*}
+The conntrack-specific types in this table are described in the sub-section CONNTRACK TYPES above.
+
.Conntrack expressions
[options="header"]
|==================
@@ -698,12 +959,15 @@ integer (64 bit)
conntrack zone |
integer (16 bit)
|count|
-count number of connections
+number of current connections|
integer (32 bit)
+|id|
+Connection id|
+ct_id|
|==========================================
-A description of conntrack-specific types listed above can be found sub-section CONNTRACK TYPES above.
.restrict the number of parallel connections to a server
--------------------
-filter input tcp dport 22 meter test { ip saddr ct count over 2 } reject
+nft add set filter ssh_flood '{ type ipv4_addr; flags dynamic; }'
+nft add rule filter input tcp dport 22 add @ssh_flood '{ ip saddr ct count over 2 }' reject
--------------------
diff --git a/doc/primary-expression.txt b/doc/primary-expression.txt
index 0316a7e1..782494bd 100644
--- a/doc/primary-expression.txt
+++ b/doc/primary-expression.txt
@@ -36,6 +36,13 @@ add such a rule, it will stop matching if the interface gets renamed and it
will match again in case interface gets deleted and later a new interface
with the same name is created.
+Like with iptables, wildcard matching on interface name prefixes is available for
+*iifname* and *oifname* matches by appending an asterisk (*) character. Note
+however that unlike iptables, nftables does not accept interface names
+consisting of the wildcard character only - users are supposed to just skip
+those always matching expressions. In order to match on literal asterisk
+character, one may escape it using backslash (\).
+
.Meta expression types
[options="header"]
|==================
@@ -76,6 +83,12 @@ ifname
|oiftype|
Output interface hardware type|
iface_type
+|sdif|
+Slave device input interface index |
+iface_index
+|sdifname|
+Slave device interface name|
+ifname
|skuid|
UID associated with originating socket|
uid
@@ -110,7 +123,7 @@ integer (32 bit)
pseudo-random number|
integer (32 bit)
|ipsec|
-boolean|
+true if packet was ipsec encrypted |
boolean (1 bit)
|iifkind|
Input interface kind |
@@ -149,43 +162,54 @@ Device group (32 bit number). Can be specified numerically or as symbolic name d
Packet type: *host* (addressed to local host), *broadcast* (to all),
*multicast* (to group), *other* (addressed to another host).
|ifkind|
-Interface kind (16 byte string). Does not have to exist.
+Interface kind (16 byte string). See TYPES in ip-link(8) for a list.
|time|
Either an integer or a date in ISO format. For example: "2019-06-06 17:00".
Hour and seconds are optional and can be omitted if desired. If omitted,
midnight will be assumed.
The following three would be equivalent: "2019-06-06", "2019-06-06 00:00"
-and "2019-06-06 00:00:00".
+and "2019-06-06 00:00:00". Use a range expression such as
+"2019-06-06 10:00"-"2019-06-10 14:00" for matching a time range.
When an integer is given, it is assumed to be a UNIX timestamp.
|day|
Either a day of week ("Monday", "Tuesday", etc.), or an integer between 0 and 6.
Strings are matched case-insensitively, and a full match is not expected (e.g. "Mon" would match "Monday").
-When an integer is given, 0 is Sunday and 6 is Saturday.
+When an integer is given, 0 is Sunday and 6 is Saturday. Use a range expression
+such as "Monday"-"Wednesday" for matching a week day range.
|hour|
A string representing an hour in 24-hour format. Seconds can optionally be specified.
-For example, 17:00 and 17:00:00 would be equivalent.
+For example, 17:00 and 17:00:00 would be equivalent. Use a range expression such
+as "17:00"-"19:00" for matching a time range.
|=============================
.Using meta expressions
-----------------------
# qualified meta expression
filter output meta oif eth0
+filter forward meta iifkind { "tun", "veth" }
# unqualified meta expression
filter output oif eth0
-# packet was subject to ipsec processing
+# incoming packet was subject to ipsec processing
raw prerouting meta ipsec exists accept
+
+# match incoming packet from 03:00 to 14:00 local time
+raw prerouting meta hour "03:00"-"14:00" counter accept
-----------------------
SOCKET EXPRESSION
~~~~~~~~~~~~~~~~~
[verse]
-*socket* {*transparent* | *mark*}
+*socket* {*transparent* | *mark* | *wildcard*}
+*socket* *cgroupv2* *level* 'NUM'
Socket expression can be used to search for an existing open TCP/UDP socket and
its attributes that can be associated with a packet. It looks for an established
-or non-zero bound listening socket (possibly with a non-local address).
+or non-zero bound listening socket (possibly with a non-local address). You can
+also use it to match on the socket cgroupv2 at a given ancestor level, e.g. if
+the socket belongs to cgroupv2 'a/b', ancestor level 1 checks for a matching on
+cgroup 'a' and ancestor level 2 checks for a matching on cgroup 'b'.
.Available socket attributes
[options="header"]
@@ -195,22 +219,30 @@ or non-zero bound listening socket (possibly with a non-local address).
Value of the IP_TRANSPARENT socket option in the found socket. It can be 0 or 1.|
boolean (1 bit)
|mark| Value of the socket mark (SOL_SOCKET, SO_MARK). | mark
+|wildcard|
+Indicates whether the socket is wildcard-bound (e.g. 0.0.0.0 or ::0). |
+boolean (1 bit)
+|cgroupv2|
+cgroup version 2 for this socket (path from /sys/fs/cgroup)|
+cgroupv2
|==================
.Using socket expression
------------------------
-# Mark packets that correspond to a transparent socket
+# Mark packets that correspond to a transparent socket. "socket wildcard 0"
+# means that zero-bound listener sockets are NOT matched (which is usually
+# exactly what you want).
table inet x {
chain y {
- type filter hook prerouting priority -150; policy accept;
- socket transparent 1 mark set 0x00000001 accept
+ type filter hook prerouting priority mangle; policy accept;
+ socket transparent 1 socket wildcard 0 mark set 0x00000001 accept
}
}
# Trace packets that corresponds to a socket with a mark value of 15
table inet x {
chain y {
- type filter hook prerouting priority -150; policy accept;
+ type filter hook prerouting priority mangle; policy accept;
socket mark 0x0000000f nftrace set 1
}
}
@@ -218,10 +250,18 @@ table inet x {
# Set packet mark to socket mark
table inet x {
chain y {
- type filter hook prerouting priority -150; policy accept;
+ type filter hook prerouting priority mangle; policy accept;
tcp dport 8080 mark set socket mark
}
}
+
+# Count packets for cgroupv2 "user.slice" at level 1
+table inet x {
+ chain y {
+ type filter hook input priority filter; policy accept;
+ socket cgroupv2 level 1 "user.slice" counter
+ }
+}
----------------------
OSF EXPRESSION
@@ -261,7 +301,7 @@ If no TTL attribute is passed, make a true IP header and fingerprint TTL true co
# Accept packets that match the "Linux" OS genre signature without comparing TTL.
table inet x {
chain y {
- type filter hook input priority 0; policy accept;
+ type filter hook input priority filter; policy accept;
osf ttl skip name "Linux"
}
}
@@ -305,13 +345,7 @@ If no route was found for the source address/input interface combination, the ou
In case the input interface is specified as part of the input key, the output interface index is always the same as the input interface index or zero.
If only 'saddr oif' is given, then oif can be any interface index or zero.
-In this example, 'saddr . iif' lookups up routing information based on the source address and the input interface.
-oif picks the output interface index from the routing information.
-If no route was found for the source address/input interface combination, the output interface index is zero.
-In case the input interface is specified as part of the input key, the output interface index is always the same as the input interface index or zero.
-If only 'saddr oif' is given, then oif can be any interface index or zero.
-
-# drop packets to address not configured on ininterface
+# drop packets to address not configured on incoming interface
filter prerouting fib daddr . iif type != { local, broadcast, multicast } drop
# perform lookup in a specific 'blackhole' table (0xdead, needs ip appropriate ip rule)
@@ -355,13 +389,15 @@ Routing Realm (32 bit number). Can be specified numerically or as symbolic name
--------------------------
# IP family independent rt expression
filter output rt classid 10
-filter output rt ipsec missing
# IP family dependent rt expressions
ip filter output rt nexthop 192.168.0.1
ip6 filter output rt nexthop fd00::1
inet filter output rt ip nexthop 192.168.0.1
inet filter output rt ip6 nexthop fd00::1
+
+# outgoing packet will be encapsulated/encrypted by ipsec
+filter output rt ipsec exists
--------------------------
IPSEC EXPRESSIONS
@@ -397,3 +433,62 @@ ipv4_addr/ipv6_addr
Destination address of the tunnel|
ipv4_addr/ipv6_addr
|=================================
+
+*Note:* When using xfrm_interface, this expression is not useable in output
+hook as the plain packet does not traverse it with IPsec info attached - use a
+chain in postrouting hook instead.
+
+NUMGEN EXPRESSION
+~~~~~~~~~~~~~~~~~
+
+[verse]
+*numgen* {*inc* | *random*} *mod* 'NUM' [ *offset* 'NUM' ]
+
+Create a number generator. The *inc* or *random* keywords control its
+operation mode: In *inc* mode, the last returned value is simply incremented.
+In *random* mode, a new random number is returned. The value after *mod*
+keyword specifies an upper boundary (read: modulus) which is not reached by
+returned numbers. The optional *offset* allows one to increment the returned value
+by a fixed offset.
+
+A typical use-case for *numgen* is load-balancing:
+
+.Using numgen expression
+------------------------
+# round-robin between 192.168.10.100 and 192.168.20.200:
+add rule nat prerouting dnat to numgen inc mod 2 map \
+ { 0 : 192.168.10.100, 1 : 192.168.20.200 }
+
+# probability-based with odd bias using intervals:
+add rule nat prerouting dnat to numgen random mod 10 map \
+ { 0-2 : 192.168.10.100, 3-9 : 192.168.20.200 }
+------------------------
+
+HASH EXPRESSIONS
+~~~~~~~~~~~~~~~~
+
+[verse]
+*jhash* {*ip saddr* | *ip6 daddr* | *tcp dport* | *udp sport* | *ether saddr*} [*.* ...] *mod* 'NUM' [ *seed* 'NUM' ] [ *offset* 'NUM' ]
+*symhash* *mod* 'NUM' [ *offset* 'NUM' ]
+
+Use a hashing function to generate a number. The functions available are
+*jhash*, known as Jenkins Hash, and *symhash*, for Symmetric Hash. The
+*jhash* requires an expression to determine the parameters of the packet
+header to apply the hashing, concatenations are possible as well. The value
+after *mod* keyword specifies an upper boundary (read: modulus) which is
+not reached by returned numbers. The optional *seed* is used to specify an
+init value used as seed in the hashing function. The optional *offset*
+allows one to increment the returned value by a fixed offset.
+
+A typical use-case for *jhash* and *symhash* is load-balancing:
+
+.Using hash expressions
+------------------------
+# load balance based on source ip between 2 ip addresses:
+add rule nat prerouting dnat to jhash ip saddr mod 2 map \
+ { 0 : 192.168.10.100, 1 : 192.168.20.200 }
+
+# symmetric load balancing between 2 ip addresses:
+add rule nat prerouting dnat to symhash mod 2 map \
+ { 0 : 192.168.10.100, 1 : 192.168.20.200 }
+------------------------
diff --git a/doc/stateful-objects.txt b/doc/stateful-objects.txt
index 32a3a5c8..00d3c5f1 100644
--- a/doc/stateful-objects.txt
+++ b/doc/stateful-objects.txt
@@ -1,7 +1,9 @@
CT HELPER
~~~~~~~~~
[verse]
-*ct helper* 'helper' *{ type* 'type' *protocol* 'protocol' *;* [*l3proto* 'family' *;*] *}*
+*add* *ct helper* ['family'] 'table' 'name' *{ type* 'type' *protocol* 'protocol' *;* [*l3proto* 'family' *;*] *}*
+*delete* *ct helper* ['family'] 'table' 'name'
+*list* *ct helpers*
Ct helper is used to define connection tracking helpers that can then be used in
combination with the *ct helper set* statement. 'type' and 'protocol' are
@@ -22,6 +24,9 @@ string (e.g. ip)
|l3proto |
layer 3 protocol of the helper |
address family (e.g. ip)
+|comment |
+per ct helper comment field |
+string
|=================
.defining and assigning ftp helper
@@ -34,7 +39,7 @@ table inet myhelpers {
type "ftp" protocol tcp
}
chain prerouting {
- type filter hook prerouting priority 0;
+ type filter hook prerouting priority filter;
tcp dport 21 ct helper set "ftp-standard"
}
}
@@ -43,7 +48,9 @@ table inet myhelpers {
CT TIMEOUT
~~~~~~~~~~
[verse]
-*ct timeout* 'name' *{ protocol* 'protocol' *; policy = {* 'state'*:* 'value' [*,* ...] *} ;* [*l3proto* 'family' *;*] *}*
+*add* *ct timeout* ['family'] 'table' 'name' *{ protocol* 'protocol' *; policy = {* 'state'*:* 'value' [*,* ...] *} ;* [*l3proto* 'family' *;*] *}*
+*delete* *ct timeout* ['family'] 'table' 'name'
+*list* *ct timeouts*
Ct timeout is used to update connection tracking timeout values.Timeout policies are assigned
with the *ct timeout set* statement. 'protocol' and 'policy' are
@@ -65,15 +72,29 @@ unsigned integer
|l3proto |
layer 3 protocol of the timeout object |
address family (e.g. ip)
+|comment |
+per ct timeout comment field |
+string
|=================
+tcp connection state names that can have a specific timeout value are:
+
+'close', 'close_wait', 'established', 'fin_wait', 'last_ack', 'retrans', 'syn_recv', 'syn_sent', 'time_wait' and 'unack'.
+
+You can use 'sysctl -a |grep net.netfilter.nf_conntrack_tcp_timeout_' to view and change the system-wide defaults.
+'ct timeout' allows for flow-specific settings, without changing the global timeouts.
+
+For example, tcp port 53 could have much lower settings than other traffic.
+
+udp state names that can have a specific timeout value are 'replied' and 'unreplied'.
+
.defining and assigning ct timeout policy
----------------------------------
table ip filter {
ct timeout customtimeout {
protocol tcp;
l3proto ip
- policy = { established: 120, close: 20 }
+ policy = { established: 2m, close: 20s }
}
chain output {
@@ -98,7 +119,9 @@ sport=41360 dport=22
CT EXPECTATION
~~~~~~~~~~~~~~
[verse]
-*ct expectation* 'name' *{ protocol* 'protocol' *; dport* 'dport' *; timeout* 'timeout' *; size* 'size' *; [*l3proto* 'family' *;*] *}*
+*add* *ct expectation* ['family'] 'table' 'name' *{ protocol* 'protocol' *; dport* 'dport' *; timeout* 'timeout' *; size* 'size' *; [*l3proto* 'family' *;*] *}*
+*delete* *ct expectation* ['family'] 'table' 'name'
+*list* *ct expectations*
Ct expectation is used to create connection expectations. Expectations are
assigned with the *ct expectation set* statement. 'protocol', 'dport',
@@ -124,6 +147,9 @@ unsigned integer
|l3proto |
layer 3 protocol of the expectation object |
address family (e.g. ip)
+|comment |
+per ct expectation comment field |
+string
|=================
.defining and assigning ct expectation policy
@@ -147,7 +173,9 @@ table ip filter {
COUNTER
~~~~~~~
[verse]
-*counter* ['packets bytes']
+*add* *counter* ['family'] 'table' 'name' [*{* [ *packets* 'packets' *bytes* 'bytes' ';' ] [ *comment* 'comment' ';' *}*]
+*delete* *counter* ['family'] 'table' 'name'
+*list* *counters*
.Counter specifications
[options="header"]
@@ -159,12 +187,31 @@ unsigned integer (64 bit)
|bytes |
initial count of bytes |
unsigned integer (64 bit)
+|comment |
+per counter comment field |
+string
|=================
+.*Using named counters*
+------------------
+nft add counter filter http
+nft add rule filter input tcp dport 80 counter name \"http\"
+------------------
+
+.*Using named counters with maps*
+------------------
+nft add counter filter http
+nft add counter filter https
+nft add rule filter input counter name tcp dport map { 80 : \"http\", 443 : \"https\" }
+------------------
+
QUOTA
~~~~~
[verse]
-*quota* [*over* | *until*] ['used']
+*add* *quota* ['family'] 'table' 'name' *{* [*over*|*until*] 'bytes' 'BYTE_UNIT' [ *used* 'bytes' 'BYTE_UNIT' ] ';' [ *comment* 'comment' ';' ] *}*
+BYTE_UNIT := bytes | kbytes | mbytes
+*delete* *quota* ['family'] 'table' 'name'
+*list* *quotas*
.Quota specifications
[options="header"]
@@ -177,4 +224,20 @@ Two arguments, unsigned integer (64 bit) and string: bytes, kbytes, mbytes.
|used |
initial value of used quota |
Two arguments, unsigned integer (64 bit) and string: bytes, kbytes, mbytes
+|comment |
+per quota comment field |
+string
|=================
+
+.*Using named quotas*
+------------------
+nft add quota filter user123 { over 20 mbytes }
+nft add rule filter input ip saddr 192.168.10.123 quota name \"user123\"
+------------------
+
+.*Using named quotas with maps*
+------------------
+nft add quota filter user123 { over 20 mbytes }
+nft add quota filter user124 { over 20 mbytes }
+nft add rule filter input quota name ip saddr map { 192.168.10.123 : \"user123\", 192.168.10.124 : \"user124\" }
+------------------
diff --git a/doc/statements.txt b/doc/statements.txt
index e17068a8..39b31fd2 100644
--- a/doc/statements.txt
+++ b/doc/statements.txt
@@ -11,7 +11,7 @@ The verdict statement alters control flow in the ruleset and issues policy decis
[horizontal]
*accept*:: Terminate ruleset evaluation and accept the packet.
The packet can still be dropped later by another hook, for instance accept
-in the forward hook still allows to drop the packet later in the postrouting hook,
+in the forward hook still allows one to drop the packet later in the postrouting hook,
or another forward base chain that has a higher priority number and is evaluated
afterwards in the processing pipeline.
*drop*:: Terminate ruleset evaluation and drop the packet.
@@ -71,7 +71,7 @@ EXTENSION HEADER STATEMENT
The extension header statement alters packet content in variable-sized headers.
This can currently be used to alter the TCP Maximum segment size of packets,
-similar to TCPMSS.
+similar to the TCPMSS target in iptables.
.change tcp mss
---------------
@@ -80,6 +80,13 @@ tcp flags syn tcp option maxseg size set 1360
tcp flags syn tcp option maxseg size set rt mtu
---------------
+You can also remove tcp options via reset keyword.
+
+.remove tcp option
+---------------
+tcp flags syn reset tcp option sack-perm
+---------------
+
LOG STATEMENT
~~~~~~~~~~~~~
[verse]
@@ -93,10 +100,11 @@ packets, such as header fields, via the kernel log (where it can be read with
dmesg(1) or read in the syslog).
In the second form of invocation (if 'nflog_group' is specified), the Linux
-kernel will pass the packet to nfnetlink_log which will multicast the packet
-through a netlink socket to the specified multicast group. One or more userspace
-processes may subscribe to the group to receive the packets, see
-libnetfilter_queue documentation for details.
+kernel will pass the packet to nfnetlink_log which will send the log through a
+netlink socket to the specified group. One userspace process may subscribe to
+the group to receive the logs, see man(8) ulogd for the Netfilter userspace log
+daemon and libnetfilter_log documentation for details in case you would like to
+develop a custom program to digest your logs.
In the third form of invocation (if level audit is specified), the Linux
kernel writes a message into the audit buffer suitably formatted for reading
@@ -163,36 +171,77 @@ REJECT STATEMENT
____
*reject* [ *with* 'REJECT_WITH' ]
-'REJECT_WITH' := *icmp type* 'icmp_code' |
- *icmpv6 type* 'icmpv6_code' |
- *icmpx type* 'icmpx_code' |
+'REJECT_WITH' := *icmp* 'icmp_reject_code' |
+ *icmpv6* 'icmpv6_reject_code' |
+ *icmpx* 'icmpx_reject_code' |
*tcp reset*
____
A reject statement is used to send back an error packet in response to the
matched packet otherwise it is equivalent to drop so it is a terminating
-statement, ending rule traversal. This statement is only valid in the input,
-forward and output chains, and user-defined chains which are only called from
+statement, ending rule traversal. This statement is only valid in base chains
+using the *prerouting*, *input*,
+*forward* or *output* hooks, and user-defined chains which are only called from
those chains.
-.different ICMP reject variants are meant for use in different table families
+.Keywords may be used to reject when specifying the ICMP code
+[options="header"]
+|==================
+|Keyword | Value
+|net-unreachable |
+0
+|host-unreachable |
+1
+|prot-unreachable|
+2
+|port-unreachable|
+3
+|frag-needed|
+4
+|net-prohibited|
+9
+|host-prohibited|
+10
+|admin-prohibited|
+13
+|===================
+
+.keywords may be used to reject when specifying the ICMPv6 code
[options="header"]
|==================
-|Variant |Family | Type
-|icmp|
-ip|
-icmp_code
-|icmpv6|
-ip6|
-icmpv6_code
-|icmpx|
-inet|
-icmpx_code
+|Keyword |Value
+|no-route|
+0
+|admin-prohibited|
+1
+|addr-unreachable|
+3
+|port-unreachable|
+4
+|policy-fail|
+5
+|reject-route|
+6
|==================
-For a description of the different types and a list of supported keywords refer
-to DATA TYPES section above. The common default reject value is
-*port-unreachable*. +
+The ICMPvX Code type abstraction is a set of values which overlap between ICMP
+and ICMPv6 Code types to be used from the inet family.
+
+.keywords may be used when specifying the ICMPvX code
+[options="header"]
+|==================
+|Keyword |Value
+|no-route|
+0
+|port-unreachable|
+1
+|host-unreachable|
+2
+|admin-prohibited|
+3
+|=================
+
+The common default ICMP code to reject is *port-unreachable*.
Note that in bridge family, reject statement is only allowed in base chains
which hook into input or prerouting.
@@ -215,7 +264,12 @@ The conntrack statement can be used to set the conntrack mark and conntrack labe
The ct statement sets meta data associated with a connection. The zone id
has to be assigned before a conntrack lookup takes place, i.e. this has to be
done in prerouting and possibly output (if locally generated packets need to be
-placed in a distinct zone), with a hook priority of -300.
+placed in a distinct zone), with a hook priority of *raw* (-300).
+
+Unlike iptables, where the helper assignment happens in the raw table,
+the helper needs to be assigned after a conntrack entry has been
+found, i.e. it will not work when used with hook priorities equal or before
+-200.
.Conntrack statement types
[options="header"]
@@ -247,11 +301,11 @@ ct mark set meta mark
------------------------------
table inet raw {
chain prerouting {
- type filter hook prerouting priority -300;
+ type filter hook prerouting priority raw;
ct zone set iif map { "eth1" : 1, "veth1" : 2 }
}
chain output {
- type filter hook output priority -300;
+ type filter hook output priority raw;
ct zone set oif map { "eth1" : 1, "veth1" : 2 }
}
}
@@ -262,13 +316,27 @@ table inet raw {
ct event set new,related,destroy
--------------------------------------
+NOTRACK STATEMENT
+~~~~~~~~~~~~~~~~~
+The notrack statement allows one to disable connection tracking for certain
+packets.
+
+[verse]
+*notrack*
+
+Note that for this statement to be effective, it has to be applied to packets
+before a conntrack lookup happens. Therefore, it needs to sit in a chain with
+either prerouting or output hook and a hook priority of -300 (*raw*) or less.
+
+See SYNPROXY STATEMENT for an example usage.
+
META STATEMENT
~~~~~~~~~~~~~~
A meta statement sets the value of a meta expression. The existing meta fields
are: priority, mark, pkttype, nftrace. +
[verse]
-*meta* {*mark* | *priority* | *pkttype* | *nftrace*} *set* 'value'
+*meta* {*mark* | *priority* | *pkttype* | *nftrace* | *broute*} *set* 'value'
A meta statement sets meta data associated with a packet. +
@@ -288,6 +356,9 @@ pkt_type
|nftrace |
ruleset packet tracing on/off. Use *monitor trace* command to watch traces|
0, 1
+|broute |
+broute on/off. packets are routed instead of being bridged|
+0, 1
|==========================
LIMIT STATEMENT
@@ -306,6 +377,12 @@ using this statement will match until this limit is reached. It can be used in
combination with the log statement to give limited logging. The optional
*over* keyword makes it match over the specified rate.
+The *burst* value influences the bucket size, i.e. jitter tolerance. With
+packet-based *limit*, the bucket holds exactly *burst* packets, by default
+five. If you specify packet *burst*, it must be a non-zero value. With
+byte-based *limit*, the bucket's minimum size is the given rate's byte value
+and the *burst* value adds to that, by default zero bytes.
+
.limit statement values
[options="header"]
|==================
@@ -322,21 +399,16 @@ NAT STATEMENTS
~~~~~~~~~~~~~~
[verse]
____
-*snat to* 'address' [*:*'port'] ['PRF_FLAGS']
-*snat to* 'address' *-* 'address' [*:*'port' *-* 'port'] ['PRF_FLAGS']
-*snat to* { *ip* | *ip6* } 'address' *-* 'address' [*:*'port' *-* 'port'] ['PR_FLAGS']
-*dnat to* 'address' [*:*'port'] ['PRF_FLAGS']
-*dnat to* 'address' [*:*'port' *-* 'port'] ['PR_FLAGS']
-*dnat to* { *ip* | *ip6* } 'address' [*:*'port' *-* 'port'] ['PR_FLAGS']
-*masquerade to* [*:*'port'] ['PRF_FLAGS']
-*masquerade to* [*:*'port' *-* 'port'] ['PRF_FLAGS']
-*redirect to* [*:*'port'] ['PRF_FLAGS']
-*redirect to* [*:*'port' *-* 'port'] ['PRF_FLAGS']
-
-'PRF_FLAGS' := 'PRF_FLAG' [*,* 'PRF_FLAGS']
-'PR_FLAGS' := 'PR_FLAG' [*,* 'PR_FLAGS']
-'PRF_FLAG' := 'PR_FLAG' | *fully-random*
-'PR_FLAG' := *persistent* | *random*
+*snat* [[*ip* | *ip6*] [ *prefix* ] *to*] 'ADDR_SPEC' [*:*'PORT_SPEC'] ['FLAGS']
+*dnat* [[*ip* | *ip6*] [ *prefix* ] *to*] 'ADDR_SPEC' [*:*'PORT_SPEC'] ['FLAGS']
+*masquerade* [*to :*'PORT_SPEC'] ['FLAGS']
+*redirect* [*to :*'PORT_SPEC'] ['FLAGS']
+
+'ADDR_SPEC' := 'address' | 'address' *-* 'address'
+'PORT_SPEC' := 'port' | 'port' *-* 'port'
+
+'FLAGS' := 'FLAG' [*,* 'FLAGS']
+'FLAG' := *persistent* | *random* | *fully-random*
____
The nat statements are only valid from nat chain types. +
@@ -366,6 +438,9 @@ Before kernel 4.18 nat statements require both prerouting and postrouting base c
to be present since otherwise packets on the return path won't be seen by
netfilter and therefore no reverse translation will take place.
+The optional *prefix* keyword allows to map to map *n* source addresses to *n*
+destination addresses. See 'Advanced NAT examples' below.
+
.NAT statement values
[options="header"]
|==================
@@ -376,7 +451,7 @@ You may specify a mapping to relate a list of tuples composed of arbitrary
expression key with address value. |
ipv4_addr, ipv6_addr, e.g. abcd::1234, or you can use a mapping, e.g. meta mark map { 10 : 192.168.1.2, 20 : 192.168.1.3 }
|port|
-Specifies that the source/destination address of the packet should be modified. |
+Specifies that the source/destination port of the packet should be modified. |
port number (16 bit)
|===============================
@@ -399,8 +474,8 @@ If used then port mapping is generated based on a 32-bit pseudo-random algorithm
---------------------
# create a suitable table/chain setup for all further examples
add table nat
-add chain nat prerouting { type nat hook prerouting priority 0; }
-add chain nat postrouting { type nat hook postrouting priority 100; }
+add chain nat prerouting { type nat hook prerouting priority dstnat; }
+add chain nat postrouting { type nat hook postrouting priority srcnat; }
# translate source addresses of all packets leaving via eth0 to address 1.2.3.4
add rule nat postrouting oif eth0 snat to 1.2.3.4
@@ -425,6 +500,52 @@ add rule inet nat postrouting meta oif ppp0 masquerade
------------------------
+.Advanced NAT examples
+----------------------
+
+# map prefixes in one network to that of another, e.g. 10.141.11.4 is mangled to 192.168.2.4,
+# 10.141.11.5 is mangled to 192.168.2.5 and so on.
+add rule nat postrouting snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 }
+
+# map a source address, source port combination to a pool of destination addresses and ports:
+add rule nat postrouting dnat to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.2-10.141.10.5 . 8888-8999 }
+
+# The above example generates the following NAT expression:
+#
+# [ nat dnat ip addr_min reg 1 addr_max reg 10 proto_min reg 9 proto_max reg 11 ]
+#
+# which expects to obtain the following tuple:
+# IP address (min), source port (min), IP address (max), source port (max)
+# to be obtained from the map. The given addresses and ports are inclusive.
+
+# This also works with named maps and in combination with both concatenations and ranges:
+table ip nat {
+ map ipportmap {
+ typeof ip saddr : interval ip daddr . tcp dport
+ flags interval
+ elements = { 192.168.1.2 : 10.141.10.1-10.141.10.3 . 8888-8999, 192.168.2.0/24 : 10.141.11.5-10.141.11.20 . 8888-8999 }
+ }
+
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ ip protocol tcp dnat ip to ip saddr map @ipportmap
+ }
+}
+
+@ipportmap maps network prefixes to a range of hosts and ports.
+The new destination is taken from the range provided by the map element.
+Same for the destination port.
+
+Note the use of the "interval" keyword in the typeof description.
+This is required so nftables knows that it has to ask for twice the
+amount of storage for each key-value pair in the map.
+
+": ipv4_addr . inet_service" would allow associating one address and one port
+with each key. But for this case, for each key, two addresses and two ports
+(The minimum and maximum values for both) have to be stored.
+
+------------------------
+
TPROXY STATEMENT
~~~~~~~~~~~~~~~~
Tproxy redirects the packet to a local socket without changing the packet header
@@ -461,21 +582,21 @@ this case the rule will match for both families.
-------------------------------------
table ip x {
chain y {
- type filter hook prerouting priority -150; policy accept;
+ type filter hook prerouting priority mangle; policy accept;
tcp dport ntp tproxy to 1.1.1.1
udp dport ssh tproxy to :2222
}
}
table ip6 x {
chain y {
- type filter hook prerouting priority -150; policy accept;
+ type filter hook prerouting priority mangle; policy accept;
tcp dport ntp tproxy to [dead::beef]
udp dport ssh tproxy to :2222
}
}
table inet x {
chain y {
- type filter hook prerouting priority -150; policy accept;
+ type filter hook prerouting priority mangle; policy accept;
tcp dport 321 tproxy to :ssh
tcp dport 99 tproxy ip to 1.1.1.1:999
udp dport 155 tproxy ip6 to [dead::beef]:smux
@@ -546,28 +667,13 @@ drop incorrect cookies. Flags combinations not expected during 3WHS will not
match and continue (e.g. SYN+FIN, SYN+ACK). Finally, drop invalid packets, this
will be out-of-flow packets that were not matched by SYNPROXY.
- table ip foo {
+ table ip x {
chain z {
type filter hook input priority filter; policy accept;
- ct state { invalid, untracked } synproxy mss 1460 wscale 9 timestamp sack-perm
+ ct state invalid, untracked synproxy mss 1460 wscale 9 timestamp sack-perm
ct state invalid drop
}
}
-
-The outcome ruleset of the steps above should be similar to the one below.
-
- table ip x {
- chain y {
- type filter hook prerouting priority raw; policy accept;
- tcp flags syn notrack
- }
-
- chain z {
- type filter hook input priority filter; policy accept;
- ct state { invalid, untracked } synproxy mss 1460 wscale 9 timestamp sack-perm
- ct state invalid drop
- }
- }
---------------------------------------
FLOW STATEMENT
@@ -588,13 +694,19 @@ for details.
[verse]
____
-*queue* [*num* 'queue_number'] [*bypass*]
-*queue* [*num* 'queue_number_from' - 'queue_number_to'] ['QUEUE_FLAGS']
+*queue* [*flags* 'QUEUE_FLAGS'] [*to* 'queue_number']
+*queue* [*flags* 'QUEUE_FLAGS'] [*to* 'queue_number_from' - 'queue_number_to']
+*queue* [*flags* 'QUEUE_FLAGS'] [*to* 'QUEUE_EXPRESSION' ]
'QUEUE_FLAGS' := 'QUEUE_FLAG' [*,* 'QUEUE_FLAGS']
'QUEUE_FLAG' := *bypass* | *fanout*
+'QUEUE_EXPRESSION' := *numgen* | *hash* | *symhash* | *MAP STATEMENT*
____
+QUEUE_EXPRESSION can be used to compute a queue number
+at run-time with the hash or numgen expressions. It also
+allows one to use the map statement to assign fixed queue numbers
+based on external inputs such as the source ip address or interface names.
.queue statement values
[options="header"]
@@ -650,7 +762,7 @@ string
ip filter forward dup to 10.2.3.4 device "eth0"
# copy raw frame to another interface
-netdetv ingress dup to "eth0"
+netdev ingress dup to "eth0"
dup to "eth0"
# combine with map dst addr to gateways
@@ -660,27 +772,62 @@ dup to ip daddr map { 192.168.7.1 : "eth0", 192.168.7.2 : "eth1" }
FWD STATEMENT
~~~~~~~~~~~~~
The fwd statement is used to redirect a raw packet to another interface. It is
-only available in the netdev family ingress hook. It is similar to the dup
-statement except that no copy is made.
+only available in the netdev family ingress and egress hooks. It is similar to
+the dup statement except that no copy is made.
+
+You can also specify the address of the next hop and the device to forward the
+packet to. This updates the source and destination MAC address of the packet by
+transmitting it through the neighboring layer. This also decrements the ttl
+field of the IP packet. This provides a way to effectively bypass the classical
+forwarding path, thus skipping the fib (forwarding information base) lookup.
+[verse]
*fwd to* 'device'
+*fwd* [*ip* | *ip6*] *to* 'address' *device* 'device'
+
+.Using the fwd statement
+------------------------
+# redirect raw packet to device
+netdev ingress fwd to "eth0"
+
+# forward packet to next hop 192.168.200.1 via eth0 device
+netdev ingress ether saddr set fwd ip to 192.168.200.1 device "eth0"
+-----------------------------------
SET STATEMENT
~~~~~~~~~~~~~
The set statement is used to dynamically add or update elements in a set from
the packet path. The set setname must already exist in the given table and must
-have been created with the dynamic flag. Furthermore, these sets must specify
-both a maximum set size (to prevent memory exhaustion) and a timeout (so that
-number of entries in set will not grow indefinitely). The set statement can be
-used to e.g. create dynamic blacklists.
+have been created with one or both of the dynamic and the timeout flags. The
+dynamic flag is required if the set statement expression includes a stateful
+object. The timeout flag is implied if the set is created with a timeout, and is
+required if the set statement updates elements, rather than adding them.
+Furthermore, these sets should specify both a maximum set size (to prevent
+memory exhaustion), and their elements should have a timeout (so their number
+will not grow indefinitely) either from the set definition or from the statement
+that adds or updates them. The set statement can be used to e.g. create dynamic
+blacklists.
+
+Dynamic updates are also supported with maps. In this case, the *add* or
+*update* rule needs to provide both the key and the data element (value),
+separated via ':'.
[verse]
{*add* | *update*} *@*'setname' *{* 'expression' [*timeout* 'timeout'] [*comment* 'string'] *}*
.Example for simple blacklist
-----------------------------
-# declare a set, bound to table "filter", in family "ip". Timeout and size are mandatory because we will add elements from packet path.
-nft add set ip filter blackhole "{ type ipv4_addr; flags timeout; size 65536; }"
+# declare a set, bound to table "filter", in family "ip".
+# Timeout and size are mandatory because we will add elements from packet path.
+# Entries will timeout after one minute, after which they might be
+# re-added if limit condition persists.
+nft add set ip filter blackhole \
+ "{ type ipv4_addr; flags dynamic; timeout 1m; size 65536; }"
+
+# declare a set to store the limit per saddr.
+# This must be separate from blackhole since the timeout is different
+nft add set ip filter flood \
+ "{ type ipv4_addr; flags dynamic; timeout 10s; size 128000; }"
# whitelist internal interface.
nft add rule ip filter input meta iifname "internal" accept
@@ -688,17 +835,18 @@ nft add rule ip filter input meta iifname "internal" accept
# drop packets coming from blacklisted ip addresses.
nft add rule ip filter input ip saddr @blackhole counter drop
-# add source ip addresses to the blacklist if more than 10 tcp connection requests occurred per second and ip address.
-# entries will timeout after one minute, after which they might be re-added if limit condition persists.
-nft add rule ip filter input tcp flags syn tcp dport ssh meter flood size 128000 { ip saddr timeout 10s limit rate over 10/second} add @blackhole { ip saddr timeout 1m } drop
-
-# inspect state of the rate limit meter:
-nft list meter ip filter flood
+# add source ip addresses to the blacklist if more than 10 tcp connection
+# requests occurred per second and ip address.
+nft add rule ip filter input tcp flags syn tcp dport ssh \
+ add @flood { ip saddr limit rate over 10/second } \
+ add @blackhole { ip saddr } \
+ drop
-# inspect content of blackhole:
+# inspect state of the sets.
+nft list set ip filter flood
nft list set ip filter blackhole
-# manually add two addresses to the set:
+# manually add two addresses to the blackhole.
nft add element filter blackhole { 10.2.3.4, 10.23.1.42 }
-----------------------------------------------
@@ -748,3 +896,20 @@ ____
# jump to different chains depending on layer 4 protocol type:
nft add rule ip filter input ip protocol vmap { tcp : jump tcp-chain, udp : jump udp-chain , icmp : jump icmp-chain }
------------------------
+
+XT STATEMENT
+~~~~~~~~~~~~
+This represents an xt statement from xtables compat interface. It is a
+fallback if translation is not available or not complete.
+
+[verse]
+____
+*xt* 'TYPE' 'NAME'
+
+'TYPE' := *match* | *target* | *watcher*
+____
+
+Seeing this means the ruleset (or parts of it) were created by *iptables-nft*
+and one should use that to manage it.
+
+*BEWARE:* nftables won't restore these statements.
diff --git a/examples/.gitignore b/examples/.gitignore
new file mode 100644
index 00000000..7b1a583c
--- /dev/null
+++ b/examples/.gitignore
@@ -0,0 +1,5 @@
+/.deps/
+/.libs/
+/nft-buffer
+/nft-json-file
+/*.o
diff --git a/examples/json-ruleset.nft b/examples/json-ruleset.nft
new file mode 100644
index 00000000..acea1786
--- /dev/null
+++ b/examples/json-ruleset.nft
@@ -0,0 +1,43 @@
+{
+ "nftables": [
+ {
+ "flush": {
+ "ruleset": {
+ "family": "ip"
+ }
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/examples/nft-buffer.c b/examples/nft-buffer.c
new file mode 100644
index 00000000..1c4b1e04
--- /dev/null
+++ b/examples/nft-buffer.c
@@ -0,0 +1,34 @@
+/* gcc nft-buffer.c -o nft-buffer -lnftables */
+#include <stdlib.h>
+#include <nftables/libnftables.h>
+
+const char ruleset[] =
+ "flush ruleset;"
+ "add table x;"
+ "add chain x y { type filter hook input priority 0; };"
+ "add rule x y counter;";
+
+int main(void)
+{
+ struct nft_ctx *ctx;
+ int err;
+
+ ctx = nft_ctx_new(0);
+ if (!ctx) {
+ perror("cannot allocate nft context");
+ return EXIT_FAILURE;
+ }
+
+ /* create ruleset: all commands in the buffer are atomically applied */
+ err = nft_run_cmd_from_buffer(ctx, ruleset);
+ if (err < 0)
+ fprintf(stderr, "failed to run nftables command\n");
+
+ err = nft_run_cmd_from_buffer(ctx, "list ruleset");
+ if (err < 0)
+ fprintf(stderr, "failed to run nftables command\n");
+
+ nft_ctx_free(ctx);
+
+ return EXIT_SUCCESS;
+}
diff --git a/examples/nft-json-file.c b/examples/nft-json-file.c
new file mode 100644
index 00000000..0c832f22
--- /dev/null
+++ b/examples/nft-json-file.c
@@ -0,0 +1,30 @@
+/* gcc nft-json-file.c -o nft-json-file -lnftables */
+#include <stdlib.h>
+#include <nftables/libnftables.h>
+
+int main(void)
+{
+ struct nft_ctx *ctx;
+ int err;
+
+ ctx = nft_ctx_new(0);
+ if (!ctx) {
+ perror("cannot allocate nft context");
+ return EXIT_FAILURE;
+ }
+
+ nft_ctx_output_set_flags(ctx, NFT_CTX_OUTPUT_JSON);
+
+ /* create ruleset: all commands in the buffer are atomically applied */
+ err = nft_run_cmd_from_filename(ctx, "json-ruleset.nft");
+ if (err < 0)
+ fprintf(stderr, "failed to run nftables command\n");
+
+ err = nft_run_cmd_from_buffer(ctx, "list ruleset");
+ if (err < 0)
+ fprintf(stderr, "failed to run nftables command\n");
+
+ nft_ctx_free(ctx);
+
+ return EXIT_SUCCESS;
+}
diff --git a/files/Makefile.am b/files/Makefile.am
deleted file mode 100644
index 4f41b664..00000000
--- a/files/Makefile.am
+++ /dev/null
@@ -1,2 +0,0 @@
-SUBDIRS = nftables \
- osf
diff --git a/files/examples/secmark.nft b/files/examples/secmark.nft
new file mode 100755
index 00000000..c923cebb
--- /dev/null
+++ b/files/examples/secmark.nft
@@ -0,0 +1,87 @@
+#!/usr/sbin/nft -f
+
+# This example file shows how to use secmark labels with the nftables framework.
+# This script is meant to be loaded with `nft -f <file>`
+# You require linux kernel >= 4.20 and nft >= 0.9.3
+# This example is SELinux based, for the secmark objects you require
+# SELinux enabled and a SELinux policy defining the stated contexts
+# For up-to-date information please visit https://wiki.nftables.org
+
+
+flush ruleset
+
+table inet x {
+ secmark ssh_server {
+ "system_u:object_r:ssh_server_packet_t:s0"
+ }
+
+ secmark dns_client {
+ "system_u:object_r:dns_client_packet_t:s0"
+ }
+
+ secmark http_client {
+ "system_u:object_r:http_client_packet_t:s0"
+ }
+
+ secmark https_client {
+ "system_u:object_r:http_client_packet_t:s0"
+ }
+
+ secmark ntp_client {
+ "system_u:object_r:ntp_client_packet_t:s0"
+ }
+
+ secmark icmp_client {
+ "system_u:object_r:icmp_client_packet_t:s0"
+ }
+
+ secmark icmp_server {
+ "system_u:object_r:icmp_server_packet_t:s0"
+ }
+
+ secmark ssh_client {
+ "system_u:object_r:ssh_client_packet_t:s0"
+ }
+
+ secmark git_client {
+ "system_u:object_r:git_client_packet_t:s0"
+ }
+
+ map secmapping_in {
+ type inet_service : secmark
+ elements = { 22 : "ssh_server" }
+ }
+
+ map secmapping_out {
+ type inet_service : secmark
+ elements = { 22 : "ssh_client", 53 : "dns_client", 80 : "http_client", 123 : "ntp_client", 443 : "http_client", 9418 : "git_client" }
+ }
+
+ chain y {
+ type filter hook input priority -225;
+
+ # label new incoming packets and add to connection
+ ct state new meta secmark set tcp dport map @secmapping_in
+ ct state new meta secmark set udp dport map @secmapping_in
+ ct state new ip protocol icmp meta secmark set "icmp_server"
+ ct state new ip6 nexthdr icmpv6 meta secmark set "icmp_server"
+ ct state new ct secmark set meta secmark
+
+ # set label for est/rel packets from connection
+ ct state established,related meta secmark set ct secmark
+ }
+
+ chain z {
+ type filter hook output priority 225;
+
+ # label new outgoing packets and add to connection
+ ct state new meta secmark set tcp dport map @secmapping_out
+ ct state new meta secmark set udp dport map @secmapping_out
+ ct state new ip protocol icmp meta secmark set "icmp_client"
+ ct state new ip6 nexthdr icmpv6 meta secmark set "icmp_client"
+ ct state new ct secmark set meta secmark
+
+ # set label for est/rel packets from connection
+ ct state established,related meta secmark set ct secmark
+ }
+}
diff --git a/files/nftables/Makefile.am b/files/nftables/Makefile.am
deleted file mode 100644
index 2a511cd1..00000000
--- a/files/nftables/Makefile.am
+++ /dev/null
@@ -1,18 +0,0 @@
-pkgsysconfdir = ${sysconfdir}/nftables
-dist_pkgsysconf_DATA = all-in-one.nft \
- arp-filter.nft \
- bridge-filter.nft \
- inet-filter.nft \
- inet-nat.nft \
- ipv4-filter.nft \
- ipv4-mangle.nft \
- ipv4-nat.nft \
- ipv4-raw.nft \
- ipv6-filter.nft \
- ipv6-mangle.nft \
- ipv6-nat.nft \
- ipv6-raw.nft \
- netdev-ingress.nft
-
-install-data-hook:
- ${SED} -i 's|@sbindir[@]|${sbindir}/|g' ${DESTDIR}${pkgsysconfdir}/*.nft
diff --git a/files/nftables/all-in-one.nft b/files/nftables/all-in-one.nft
index d3aa7f37..15ac22e2 100755..100644
--- a/files/nftables/all-in-one.nft
+++ b/files/nftables/all-in-one.nft
@@ -1,12 +1,10 @@
-#!@sbindir@nft -f
-
# Here is an example of different families, hooks and priorities in the
# nftables framework, all mixed together.
#
# more examples are located in files/examples in nftables source.
# For up-to-date information please visit https://wiki.nftables.org
#
-# This script is mean to be loaded with `nft -f <file>`
+# This script is meant to be loaded with `nft -f <file>`
# clear all prior state
flush ruleset
diff --git a/files/nftables/arp-filter.nft b/files/nftables/arp-filter.nft
index 8a350b1e..6e4c6248 100755..100644
--- a/files/nftables/arp-filter.nft
+++ b/files/nftables/arp-filter.nft
@@ -1,5 +1,3 @@
-#!@sbindir@nft -f
-
table arp filter {
chain input { type filter hook input priority 0; }
chain output { type filter hook output priority 0; }
diff --git a/files/nftables/bridge-filter.nft b/files/nftables/bridge-filter.nft
index 93efe864..f071205e 100755..100644
--- a/files/nftables/bridge-filter.nft
+++ b/files/nftables/bridge-filter.nft
@@ -1,5 +1,3 @@
-#!@sbindir@nft -f
-
table bridge filter {
chain input { type filter hook input priority -200; }
chain forward { type filter hook forward priority -200; }
diff --git a/files/nftables/inet-filter.nft b/files/nftables/inet-filter.nft
index 7be447fd..bfe43b4f 100755..100644
--- a/files/nftables/inet-filter.nft
+++ b/files/nftables/inet-filter.nft
@@ -1,5 +1,3 @@
-#!@sbindir@nft -f
-
table inet filter {
chain input { type filter hook input priority 0; }
chain forward { type filter hook forward priority 0; }
diff --git a/files/nftables/inet-nat.nft b/files/nftables/inet-nat.nft
index 52fcdb54..babd7f00 100755..100644
--- a/files/nftables/inet-nat.nft
+++ b/files/nftables/inet-nat.nft
@@ -1,5 +1,3 @@
-#!@sbindir@nft -f
-
table inet nat {
chain prerouting { type nat hook prerouting priority -100; }
chain input { type nat hook input priority 100; }
diff --git a/files/nftables/ipv4-filter.nft b/files/nftables/ipv4-filter.nft
index 51c060f6..ab62024f 100755..100644
--- a/files/nftables/ipv4-filter.nft
+++ b/files/nftables/ipv4-filter.nft
@@ -1,5 +1,3 @@
-#!@sbindir@nft -f
-
table filter {
chain input { type filter hook input priority 0; }
chain forward { type filter hook forward priority 0; }
diff --git a/files/nftables/ipv4-mangle.nft b/files/nftables/ipv4-mangle.nft
index dba8888c..07da5bd9 100755..100644
--- a/files/nftables/ipv4-mangle.nft
+++ b/files/nftables/ipv4-mangle.nft
@@ -1,5 +1,3 @@
-#!@sbindir@nft -f
-
table mangle {
chain output { type route hook output priority -150; }
}
diff --git a/files/nftables/ipv4-nat.nft b/files/nftables/ipv4-nat.nft
index 6754e5ee..2c9ce7c5 100755..100644
--- a/files/nftables/ipv4-nat.nft
+++ b/files/nftables/ipv4-nat.nft
@@ -1,5 +1,3 @@
-#!@sbindir@nft -f
-
table nat {
chain prerouting { type nat hook prerouting priority -100; }
chain input { type nat hook input priority 100; }
diff --git a/files/nftables/ipv4-raw.nft b/files/nftables/ipv4-raw.nft
index c3fed191..2318e875 100755..100644
--- a/files/nftables/ipv4-raw.nft
+++ b/files/nftables/ipv4-raw.nft
@@ -1,5 +1,3 @@
-#!@sbindir@nft -f
-
table raw {
chain prerouting { type filter hook prerouting priority -300; }
chain output { type filter hook output priority -300; }
diff --git a/files/nftables/ipv6-filter.nft b/files/nftables/ipv6-filter.nft
index 266bed36..383d075d 100755..100644
--- a/files/nftables/ipv6-filter.nft
+++ b/files/nftables/ipv6-filter.nft
@@ -1,5 +1,3 @@
-#!@sbindir@nft -f
-
table ip6 filter {
chain input { type filter hook input priority 0; }
chain forward { type filter hook forward priority 0; }
diff --git a/files/nftables/ipv6-mangle.nft b/files/nftables/ipv6-mangle.nft
index 6b3e20dc..88c51e52 100755..100644
--- a/files/nftables/ipv6-mangle.nft
+++ b/files/nftables/ipv6-mangle.nft
@@ -1,5 +1,3 @@
-#!@sbindir@nft -f
-
table ip6 mangle {
chain output { type route hook output priority -150; }
}
diff --git a/files/nftables/ipv6-nat.nft b/files/nftables/ipv6-nat.nft
index ce0391df..6a356f1e 100755..100644
--- a/files/nftables/ipv6-nat.nft
+++ b/files/nftables/ipv6-nat.nft
@@ -1,5 +1,3 @@
-#!@sbindir@nft -f
-
table ip6 nat {
chain prerouting { type nat hook prerouting priority -100; }
chain input { type nat hook input priority 100; }
diff --git a/files/nftables/ipv6-raw.nft b/files/nftables/ipv6-raw.nft
index 504fb3e5..f92668be 100755..100644
--- a/files/nftables/ipv6-raw.nft
+++ b/files/nftables/ipv6-raw.nft
@@ -1,5 +1,3 @@
-#!@sbindir@nft -f
-
table ip6 raw {
chain prerouting { type filter hook prerouting priority -300; }
chain output { type filter hook output priority -300; }
diff --git a/files/nftables/netdev-ingress.nft b/files/nftables/netdev-ingress.nft
index 9e46b15a..3ed881af 100755..100644
--- a/files/nftables/netdev-ingress.nft
+++ b/files/nftables/netdev-ingress.nft
@@ -1,6 +1,4 @@
-#!@sbindir@nft -f
-
-# mind the NIC, it must exists
+# mind the NIC, it must exist
table netdev filter {
chain loinput { type filter hook ingress device lo priority 0; }
}
diff --git a/files/osf/Makefile.am b/files/osf/Makefile.am
deleted file mode 100644
index d80196dd..00000000
--- a/files/osf/Makefile.am
+++ /dev/null
@@ -1,2 +0,0 @@
-pkgsysconfdir = ${sysconfdir}/nftables/osf
-dist_pkgsysconf_DATA = pf.os
diff --git a/include/Makefile.am b/include/Makefile.am
deleted file mode 100644
index 04a4a619..00000000
--- a/include/Makefile.am
+++ /dev/null
@@ -1,38 +0,0 @@
-SUBDIRS = linux \
- nftables
-
-noinst_HEADERS = cli.h \
- cache.h \
- datatype.h \
- expression.h \
- fib.h \
- hash.h \
- ipopt.h \
- json.h \
- mini-gmp.h \
- gmputil.h \
- iface.h \
- mnl.h \
- nftables.h \
- payload.h \
- rbtree.h \
- tcpopt.h \
- statement.h \
- ct.h \
- erec.h \
- exthdr.h \
- headers.h \
- list.h \
- meta.h \
- misspell.h \
- numgen.h \
- netlink.h \
- osf.h \
- parser.h \
- proto.h \
- socket.h \
- rule.h \
- rt.h \
- utils.h \
- xfrm.h \
- xt.h
diff --git a/include/cache.h b/include/cache.h
index 86a7eff7..8ca4a9a7 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -1,6 +1,10 @@
#ifndef _NFT_CACHE_H_
#define _NFT_CACHE_H_
+#include <list.h>
+
+struct handle;
+
enum cache_level_bits {
NFT_CACHE_TABLE_BIT = (1 << 0),
NFT_CACHE_CHAIN_BIT = (1 << 1),
@@ -30,8 +34,122 @@ enum cache_level_flags {
NFT_CACHE_CHAIN_BIT |
NFT_CACHE_RULE_BIT,
NFT_CACHE_FULL = __NFT_CACHE_MAX_BIT - 1,
+ NFT_CACHE_TERSE = (1 << 27),
+ NFT_CACHE_SETELEM_MAYBE = (1 << 28),
+ NFT_CACHE_REFRESH = (1 << 29),
NFT_CACHE_UPDATE = (1 << 30),
NFT_CACHE_FLUSHED = (1 << 31),
};
+struct nft_filter_obj {
+ struct list_head list;
+ uint32_t family;
+ const char *table;
+ const char *set;
+};
+
+#define NFT_CACHE_HSIZE 8192
+
+struct nft_cache_filter {
+ struct {
+ uint32_t family;
+ const char *table;
+ const char *chain;
+ const char *set;
+ const char *ft;
+ uint64_t rule_handle;
+ } list;
+
+ struct {
+ struct list_head head;
+ } obj[NFT_CACHE_HSIZE];
+};
+
+struct nft_cache;
+struct nft_ctx;
+enum cmd_ops;
+
+int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
+ struct list_head *msgs, struct nft_cache_filter *filter,
+ unsigned int *flags);
+int nft_cache_update(struct nft_ctx *ctx, unsigned int flags,
+ struct list_head *msgs,
+ const struct nft_cache_filter *filter);
+bool nft_cache_needs_update(struct nft_cache *cache);
+void nft_cache_release(struct nft_cache *cache);
+
+static inline uint32_t djb_hash(const char *key)
+{
+ uint32_t i, hash = 5381;
+
+ for (i = 0; i < strlen(key); i++)
+ hash = ((hash << 5) + hash) + key[i];
+
+ return hash;
+}
+
+struct nft_cache_filter *nft_cache_filter_init(void);
+void nft_cache_filter_fini(struct nft_cache_filter *filter);
+
+struct table;
+struct chain;
+
+void chain_cache_add(struct chain *chain, struct table *table);
+void chain_cache_del(struct chain *chain);
+struct chain *chain_cache_find(const struct table *table, const char *name);
+
+struct set;
+
+void set_cache_add(struct set *set, struct table *table);
+void set_cache_del(struct set *set);
+struct set *set_cache_find(const struct table *table, const char *name);
+
+struct cache {
+ struct list_head *ht;
+ struct list_head list;
+};
+
+struct cache_item {
+ struct list_head hlist;
+ struct list_head list;
+};
+
+void cache_init(struct cache *cache);
+void cache_free(struct cache *cache);
+void cache_add(struct cache_item *item, struct cache *cache, uint32_t hash);
+void cache_del(struct cache_item *item);
+
+void table_cache_add(struct table *table, struct nft_cache *cache);
+void table_cache_del(struct table *table);
+struct table *table_cache_find(const struct cache *cache, const char *name,
+ uint32_t family);
+
+struct obj;
+
+void obj_cache_add(struct obj *obj, struct table *table);
+void obj_cache_del(struct obj *obj);
+struct obj *obj_cache_find(const struct table *table, const char *name,
+ uint32_t obj_type);
+
+struct flowtable;
+void ft_cache_add(struct flowtable *ft, struct table *table);
+void ft_cache_del(struct flowtable *ft);
+struct flowtable *ft_cache_find(const struct table *table, const char *name);
+
+struct nft_cache {
+ uint32_t genid;
+ struct cache table_cache;
+ uint32_t seqnum;
+ uint32_t flags;
+};
+
+struct netlink_ctx;
+
+void nft_chain_cache_update(struct netlink_ctx *ctx, struct table *table,
+ const char *chain);
+
+int rule_cache_dump(struct netlink_ctx *ctx, const struct handle *h,
+ const struct nft_cache_filter *filter,
+ bool dump, bool reset);
+
#endif /* _NFT_CACHE_H_ */
diff --git a/include/cli.h b/include/cli.h
index d8251775..f0a0d47a 100644
--- a/include/cli.h
+++ b/include/cli.h
@@ -2,9 +2,8 @@
#define _NFT_CLI_H_
#include <nftables/libnftables.h>
-#include <config.h>
-#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBLINENOISE)
+#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) || defined(HAVE_LIBLINENOISE)
extern int cli_init(struct nft_ctx *nft);
#else
static inline int cli_init(struct nft_ctx *nft)
@@ -12,6 +11,6 @@ static inline int cli_init(struct nft_ctx *nft)
return -1;
}
#endif
-extern void cli_exit(void);
+extern void cli_exit(int rc);
#endif
diff --git a/include/cmd.h b/include/cmd.h
new file mode 100644
index 00000000..92a4152b
--- /dev/null
+++ b/include/cmd.h
@@ -0,0 +1,13 @@
+#ifndef _NFT_CMD_H_
+#define _NFT_CMD_H_
+
+void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc);
+void nft_cmd_error(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct mnl_err *err);
+
+void nft_cmd_expand(struct cmd *cmd);
+void nft_cmd_post_expand(struct cmd *cmd);
+bool nft_cmd_collapse(struct list_head *cmds);
+void nft_cmd_uncollapse(struct list_head *cmds);
+
+#endif
diff --git a/include/ct.h b/include/ct.h
index efb2d418..0a705fd0 100644
--- a/include/ct.h
+++ b/include/ct.h
@@ -39,5 +39,7 @@ extern const char *ct_label2str(const struct symbol_table *tbl,
extern const struct datatype ct_dir_type;
extern const struct datatype ct_state_type;
extern const struct datatype ct_status_type;
+extern const struct datatype ct_label_type;
+extern const struct datatype ct_event_type;
#endif /* NFTABLES_CT_H */
diff --git a/include/datatype.h b/include/datatype.h
index 49b8f608..d4b4737c 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -22,7 +22,7 @@
* @TYPE_INET_SERVICE: internet service (integer subtype)
* @TYPE_ICMP_TYPE: ICMP type codes (integer subtype)
* @TYPE_TCP_FLAG: TCP flag (bitmask subtype)
- * @TCPE_DCCP_PKTTYPE: DCCP packet type (integer subtype)
+ * @TYPE_DCCP_PKTTYPE: DCCP packet type (integer subtype)
* @TYPE_MH_TYPE: Mobility Header type (integer subtype)
* @TYPE_TIME: relative time
* @TYPE_MARK: packet mark (integer subtype)
@@ -48,6 +48,7 @@
* @TYPE_TIME_DATA Date type (integer subtype)
* @TYPE_TIME_HOUR Hour type (integer subtype)
* @TYPE_TIME_DAY Day type (integer subtype)
+ * @TYPE_CGROUPV2 cgroups v2 (integer subtype)
*/
enum datatypes {
TYPE_INVALID,
@@ -96,6 +97,7 @@ enum datatypes {
TYPE_TIME_DATE,
TYPE_TIME_HOUR,
TYPE_TIME_DAY,
+ TYPE_CGROUPV2,
__TYPE_MAX
};
#define TYPE_MAX (__TYPE_MAX - 1)
@@ -164,18 +166,23 @@ struct datatype {
struct error_record *(*parse)(struct parse_ctx *ctx,
const struct expr *sym,
struct expr **res);
+ struct error_record *(*err)(const struct expr *sym);
+ void (*describe)(struct output_ctx *octx);
const struct symbol_table *sym_tbl;
unsigned int refcnt;
};
extern const struct datatype *datatype_lookup(enum datatypes type);
extern const struct datatype *datatype_lookup_byname(const char *name);
-extern struct datatype *datatype_get(const struct datatype *dtype);
+extern const struct datatype *datatype_get(const struct datatype *dtype);
extern void datatype_set(struct expr *expr, const struct datatype *dtype);
+extern void __datatype_set(struct expr *expr, const struct datatype *dtype);
extern void datatype_free(const struct datatype *dtype);
+struct datatype *datatype_clone(const struct datatype *orig_dtype);
struct parse_ctx {
struct symbol_tables *tbl;
+ const struct input_ctx *input;
};
extern struct error_record *symbol_parse(struct parse_ctx *ctx,
@@ -245,12 +252,16 @@ extern void symbol_table_print(const struct symbol_table *tbl,
extern struct symbol_table *rt_symbol_table_init(const char *filename);
extern void rt_symbol_table_free(const struct symbol_table *tbl);
+extern void rt_symbol_table_describe(struct output_ctx *octx, const char *name,
+ const struct symbol_table *tbl,
+ const struct datatype *type);
extern const struct datatype invalid_type;
extern const struct datatype verdict_type;
extern const struct datatype nfproto_type;
extern const struct datatype bitmask_type;
extern const struct datatype integer_type;
+extern const struct datatype xinteger_type;
extern const struct datatype string_type;
extern const struct datatype lladdr_type;
extern const struct datatype ipaddr_type;
@@ -270,6 +281,12 @@ extern const struct datatype time_type;
extern const struct datatype boolean_type;
extern const struct datatype priority_type;
extern const struct datatype policy_type;
+extern const struct datatype cgroupv2_type;
+
+/* private datatypes for reject statement. */
+extern const struct datatype reject_icmp_code_type;
+extern const struct datatype reject_icmpv6_code_type;
+extern const struct datatype reject_icmpx_code_type;
void inet_service_type_print(const struct expr *expr, struct output_ctx *octx);
@@ -292,8 +309,7 @@ concat_subtype_lookup(uint32_t type, unsigned int n)
}
extern const struct datatype *
-set_datatype_alloc(const struct datatype *orig_dtype, unsigned int byteorder);
-extern void set_datatype_destroy(const struct datatype *dtype);
+set_datatype_alloc(const struct datatype *orig_dtype, enum byteorder byteorder);
extern void time_print(uint64_t msec, struct output_ctx *octx);
extern struct error_record *time_parse(const struct location *loc,
@@ -306,4 +322,10 @@ extern struct error_record *rate_parse(const struct location *loc,
extern struct error_record *data_unit_parse(const struct location *loc,
const char *str, uint64_t *rate);
+struct limit_rate {
+ uint64_t rate, unit;
+};
+
+extern void expr_chain_export(const struct expr *e, char *chain);
+
#endif /* NFTABLES_DATATYPE_H */
diff --git a/include/dccpopt.h b/include/dccpopt.h
new file mode 100644
index 00000000..3617fc1a
--- /dev/null
+++ b/include/dccpopt.h
@@ -0,0 +1,41 @@
+#ifndef NFTABLES_DCCPOPT_H
+#define NFTABLES_DCCPOPT_H
+
+#include <nftables.h>
+
+#define DCCPOPT_TYPE_MIN 0
+#define DCCPOPT_TYPE_MAX UINT8_MAX
+
+enum dccpopt_fields {
+ DCCPOPT_FIELD_INVALID,
+ DCCPOPT_FIELD_TYPE,
+};
+
+enum dccpopt_types {
+ DCCPOPT_PADDING = 0,
+ DCCPOPT_MANDATORY = 1,
+ DCCPOPT_SLOW_RECEIVER = 2,
+ DCCPOPT_RESERVED_SHORT = 3,
+ DCCPOPT_CHANGE_L = 32,
+ DCCPOPT_CONFIRM_L = 33,
+ DCCPOPT_CHANGE_R = 34,
+ DCCPOPT_CONFIRM_R = 35,
+ DCCPOPT_INIT_COOKIE = 36,
+ DCCPOPT_NDP_COUNT = 37,
+ DCCPOPT_ACK_VECTOR_NONCE_0 = 38,
+ DCCPOPT_ACK_VECTOR_NONCE_1 = 39,
+ DCCPOPT_DATA_DROPPED = 40,
+ DCCPOPT_TIMESTAMP = 41,
+ DCCPOPT_TIMESTAMP_ECHO = 42,
+ DCCPOPT_ELAPSED_TIME = 43,
+ DCCPOPT_DATA_CHECKSUM = 44,
+ DCCPOPT_RESERVED_LONG = 45,
+ DCCPOPT_CCID_SPECIFIC = 128,
+};
+
+const struct exthdr_desc *dccpopt_find_desc(uint8_t type);
+struct expr *dccpopt_expr_alloc(const struct location *loc, uint8_t type);
+void dccpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
+ unsigned int len);
+
+#endif /* NFTABLES_DCCPOPT_H */
diff --git a/include/erec.h b/include/erec.h
index 79a16290..c17f5def 100644
--- a/include/erec.h
+++ b/include/erec.h
@@ -76,4 +76,9 @@ extern int __fmtstring(4, 5) __stmt_binary_error(struct eval_ctx *ctx,
#define stmt_binary_error(ctx, s1, s2, fmt, args...) \
__stmt_binary_error(ctx, &(s1)->location, &(s2)->location, fmt, ## args)
+void print_location(FILE *f, const struct input_descriptor *indesc,
+ const struct location *loc);
+const char *line_location(const struct input_descriptor *indesc,
+ const struct location *loc, char *buf, size_t bufsiz);
+
#endif /* NFTABLES_EREC_H */
diff --git a/include/expression.h b/include/expression.h
index 717b6755..01b45b7c 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -1,7 +1,6 @@
#ifndef NFTABLES_EXPRESSION_H
#define NFTABLES_EXPRESSION_H
-#include <stdbool.h>
#include <gmputil.h>
#include <linux/netfilter/nf_tables.h>
@@ -10,6 +9,11 @@
#include <utils.h>
#include <list.h>
#include <json.h>
+#include <libnftnl/udata.h>
+
+#define NFT_MAX_EXPR_LEN_BYTES (NFT_REG32_COUNT * sizeof(uint32_t))
+#define NFT_MAX_EXPR_LEN_BITS (NFT_MAX_EXPR_LEN_BYTES * BITS_PER_BYTE)
+#define NFT_MAX_EXPR_RECURSION 16
/**
* enum expr_types
@@ -40,6 +44,10 @@
* @EXPR_NUMGEN: number generation expression
* @EXPR_HASH: hash expression
* @EXPR_RT: routing expression
+ * @EXPR_FIB forward information base expression
+ * @EXPR_XFRM XFRM (ipsec) expression
+ * @EXPR_SET_ELEM_CATCHALL catchall element expression
+ * @EXPR_FLAGCMP flagcmp expression
*/
enum expr_types {
EXPR_INVALID,
@@ -70,6 +78,10 @@ enum expr_types {
EXPR_RT,
EXPR_FIB,
EXPR_XFRM,
+ EXPR_SET_ELEM_CATCHALL,
+ EXPR_FLAGCMP,
+
+ EXPR_MAX = EXPR_FLAGCMP
};
enum ops {
@@ -91,6 +103,7 @@ enum ops {
OP_GT,
OP_LTE,
OP_GTE,
+ OP_NEG,
__OP_MAX
};
#define OP_MAX (__OP_MAX - 1)
@@ -111,10 +124,15 @@ enum symbol_types {
* @maxval: expected maximum value
*/
struct expr_ctx {
+ /* expr_ctx does not own the reference to dtype. The caller must ensure
+ * the valid lifetime.
+ */
const struct datatype *dtype;
+
enum byteorder byteorder;
unsigned int len;
unsigned int maxval;
+ const struct expr *key;
};
static inline void __expr_set_context(struct expr_ctx *ctx,
@@ -126,6 +144,7 @@ static inline void __expr_set_context(struct expr_ctx *ctx,
ctx->byteorder = byteorder;
ctx->len = len;
ctx->maxval = maxval;
+ ctx->key = NULL;
}
static inline void expr_set_context(struct expr_ctx *ctx,
@@ -165,10 +184,16 @@ struct expr_ops {
bool (*cmp)(const struct expr *e1,
const struct expr *e2);
void (*pctx_update)(struct proto_ctx *ctx,
+ const struct location *loc,
+ const struct expr *left,
+ const struct expr *right);
+ int (*build_udata)(struct nftnl_udata_buf *udbuf,
const struct expr *expr);
+ struct expr * (*parse_udata)(const struct nftnl_udata *ud);
};
const struct expr_ops *expr_ops(const struct expr *e);
+const struct expr_ops *expr_ops_by_type_u32(uint32_t value);
/**
* enum expr_flags
@@ -178,6 +203,8 @@ const struct expr_ops *expr_ops(const struct expr *e);
* @EXPR_F_PROTOCOL: expressions describes upper layer protocol
* @EXPR_F_INTERVAL_END: set member ends an open interval
* @EXPR_F_BOOLEAN: expression is boolean (set by relational expr on LHS)
+ * @EXPR_F_INTERVAL: expression describes a interval
+ * @EXPR_F_KERNEL: expression resides in the kernel
*/
enum expr_flags {
EXPR_F_CONSTANT = 0x1,
@@ -185,6 +212,9 @@ enum expr_flags {
EXPR_F_PROTOCOL = 0x4,
EXPR_F_INTERVAL_END = 0x8,
EXPR_F_BOOLEAN = 0x10,
+ EXPR_F_INTERVAL = 0x20,
+ EXPR_F_KERNEL = 0x40,
+ EXPR_F_REMOVE = 0x80,
};
#include <payload.h>
@@ -225,6 +255,7 @@ struct expr {
enum expr_types etype:8;
enum ops op:8;
unsigned int len;
+ struct cmd *cmd;
union {
struct {
@@ -241,6 +272,7 @@ struct expr {
/* EXPR_VERDICT */
int verdict;
struct expr *chain;
+ uint32_t chain_id;
};
struct {
/* EXPR_VALUE */
@@ -256,6 +288,8 @@ struct expr {
struct list_head expressions;
unsigned int size;
uint32_t set_flags;
+ uint8_t field_len[NFT_REG32_COUNT];
+ uint8_t field_count;
};
struct {
/* EXPR_SET_REF */
@@ -267,7 +301,7 @@ struct expr {
uint64_t timeout;
uint64_t expiration;
const char *comment;
- struct stmt *stmt;
+ struct list_head stmt_list;
uint32_t elem_flags;
};
struct {
@@ -289,15 +323,18 @@ struct expr {
/* EXPR_PAYLOAD */
const struct proto_desc *desc;
const struct proto_hdr_template *tmpl;
+ const struct proto_desc *inner_desc;
enum proto_bases base;
unsigned int offset;
bool is_raw;
+ bool evaluated;
} payload;
struct {
/* EXPR_EXTHDR */
const struct exthdr_desc *desc;
const struct proto_hdr_template *tmpl;
- unsigned int offset;
+ uint16_t offset;
+ uint8_t raw_type;
enum nft_exthdr_op op;
unsigned int flags;
} exthdr;
@@ -305,10 +342,12 @@ struct expr {
/* EXPR_META */
enum nft_meta_keys key;
enum proto_bases base;
+ const struct proto_desc *inner_desc;
} meta;
struct {
/* SOCKET */
enum nft_socket_keys key;
+ uint32_t level;
} socket;
struct {
/* EXPR_RT */
@@ -352,6 +391,12 @@ struct expr {
uint8_t ttl;
uint32_t flags;
} osf;
+ struct {
+ /* EXPR_FLAGCMP */
+ struct expr *expr;
+ struct expr *mask;
+ struct expr *value;
+ } flagcmp;
};
};
@@ -370,6 +415,8 @@ extern const struct datatype *expr_basetype(const struct expr *expr);
extern void expr_set_type(struct expr *expr, const struct datatype *dtype,
enum byteorder byteorder);
+void expr_to_string(const struct expr *expr, char *string);
+
struct eval_ctx;
extern int expr_binary_error(struct list_head *msgs,
const struct expr *e1, const struct expr *e2,
@@ -441,12 +488,14 @@ extern struct expr *prefix_expr_alloc(const struct location *loc,
extern struct expr *range_expr_alloc(const struct location *loc,
struct expr *low, struct expr *high);
+struct expr *range_expr_to_prefix(struct expr *range);
extern struct expr *compound_expr_alloc(const struct location *loc,
enum expr_types etypes);
extern void compound_expr_add(struct expr *compound, struct expr *expr);
extern void compound_expr_remove(struct expr *compound, struct expr *expr);
extern void list_expr_sort(struct list_head *head);
+extern void list_splice_sorted(struct list_head *list, struct list_head *head);
extern struct expr *concat_expr_alloc(const struct location *loc);
@@ -454,16 +503,13 @@ extern struct expr *list_expr_alloc(const struct location *loc);
extern struct expr *set_expr_alloc(const struct location *loc,
const struct set *set);
-extern int set_to_intervals(struct list_head *msgs, struct set *set,
- struct expr *init, bool add,
- unsigned int debug_mask, bool merge,
- struct output_ctx *octx);
+extern void concat_range_aggregate(struct expr *set);
extern void interval_map_decompose(struct expr *set);
extern struct expr *get_set_intervals(const struct set *set,
const struct expr *init);
struct table;
-extern int get_set_decompose(struct table *table, struct set *set);
+extern int get_set_decompose(struct set *cache_set, struct set *set);
extern struct expr *mapping_expr_alloc(const struct location *loc,
struct expr *from, struct expr *to);
@@ -476,7 +522,14 @@ extern struct expr *set_ref_expr_alloc(const struct location *loc,
extern struct expr *set_elem_expr_alloc(const struct location *loc,
struct expr *key);
+struct expr *set_elem_catchall_expr_alloc(const struct location *loc);
+
+struct expr *flagcmp_expr_alloc(const struct location *loc, enum ops op,
+ struct expr *expr, struct expr *mask,
+ struct expr *value);
+
extern void range_expr_value_low(mpz_t rop, const struct expr *expr);
extern void range_expr_value_high(mpz_t rop, const struct expr *expr);
+void range_expr_swap_values(struct expr *range);
#endif /* NFTABLES_EXPRESSION_H */
diff --git a/include/exthdr.h b/include/exthdr.h
index 3959a65c..084daba5 100644
--- a/include/exthdr.h
+++ b/include/exthdr.h
@@ -4,6 +4,21 @@
#include <proto.h>
#include <tcpopt.h>
#include <ipopt.h>
+#include <dccpopt.h>
+
+enum exthdr_desc_id {
+ EXTHDR_DESC_UNKNOWN = 0,
+ EXTHDR_DESC_HBH,
+ EXTHDR_DESC_RT,
+ EXTHDR_DESC_RT0,
+ EXTHDR_DESC_RT2,
+ EXTHDR_DESC_SRH,
+ EXTHDR_DESC_FRAG,
+ EXTHDR_DESC_DST,
+ EXTHDR_DESC_MH,
+ __EXTHDR_DESC_MAX
+};
+#define EXTHDR_DESC_MAX (__EXTHDR_DESC_MAX - 1)
/**
* struct exthdr_desc - extension header description
@@ -14,8 +29,8 @@
*/
struct exthdr_desc {
const char *name;
+ enum exthdr_desc_id id;
uint8_t type;
- int proto_key;
struct proto_hdr_template templates[10];
};
diff --git a/include/gmputil.h b/include/gmputil.h
index 0cb85a7d..d1f4dcd2 100644
--- a/include/gmputil.h
+++ b/include/gmputil.h
@@ -1,8 +1,6 @@
#ifndef NFTABLES_GMPUTIL_H
#define NFTABLES_GMPUTIL_H
-#include <config.h>
-
#ifdef HAVE_LIBGMP
#include <gmp.h>
#else
@@ -79,4 +77,6 @@ extern void __mpz_switch_byteorder(mpz_t rop, unsigned int len);
__mpz_switch_byteorder(rop, len); \
}
+void nft_gmp_free(void *ptr);
+
#endif /* NFTABLES_GMPUTIL_H */
diff --git a/include/headers.h b/include/headers.h
index 759f93bf..13324c72 100644
--- a/include/headers.h
+++ b/include/headers.h
@@ -1,6 +1,8 @@
#ifndef NFTABLES_HEADERS_H
#define NFTABLES_HEADERS_H
+#include <netinet/in.h>
+
#ifndef IPPROTO_UDPLITE
# define IPPROTO_UDPLITE 136
#endif
diff --git a/include/intervals.h b/include/intervals.h
new file mode 100644
index 00000000..ef0fb53e
--- /dev/null
+++ b/include/intervals.h
@@ -0,0 +1,11 @@
+#ifndef NFTABLES_INTERVALS_H
+#define NFTABLES_INTERVALS_H
+
+int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
+ struct expr *init, unsigned int debug_mask);
+int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set,
+ struct expr *init, unsigned int debug_mask);
+int set_overlap(struct list_head *msgs, struct set *set, struct expr *init);
+int set_to_intervals(const struct set *set, struct expr *init, bool add);
+
+#endif
diff --git a/include/ipopt.h b/include/ipopt.h
index d8d48066..03420dc6 100644
--- a/include/ipopt.h
+++ b/include/ipopt.h
@@ -6,7 +6,7 @@
#include <statement.h>
extern struct expr *ipopt_expr_alloc(const struct location *loc,
- uint8_t type, uint8_t field, uint8_t ptr);
+ uint8_t type, uint8_t field);
extern void ipopt_init_raw(struct expr *expr, uint8_t type,
unsigned int offset, unsigned int len,
diff --git a/include/json.h b/include/json.h
index 20d6c2a4..39be8928 100644
--- a/include/json.h
+++ b/include/json.h
@@ -28,6 +28,7 @@ struct list_head;
json_t *binop_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *relational_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *flagcmp_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *range_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *meta_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *payload_expr_json(const struct expr *expr, struct output_ctx *octx);
@@ -36,6 +37,7 @@ json_t *concat_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *set_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *set_ref_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *set_elem_expr_json(const struct expr *expr, struct output_ctx *octx);
+json_t *set_elem_catchall_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *prefix_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *list_expr_json(const struct expr *expr, struct output_ctx *octx);
json_t *unary_expr_json(const struct expr *expr, struct output_ctx *octx);
@@ -67,10 +69,12 @@ json_t *uid_type_json(const struct expr *expr, struct output_ctx *octx);
json_t *gid_type_json(const struct expr *expr, struct output_ctx *octx);
json_t *expr_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *flow_offload_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *payload_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *exthdr_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *quota_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *ct_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *last_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *limit_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *fwd_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *notrack_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
@@ -80,6 +84,7 @@ json_t *nat_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *reject_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *counter_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *set_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *map_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *log_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *objref_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *meter_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
@@ -88,6 +93,8 @@ json_t *verdict_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *connlimit_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *tproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
json_t *synproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *optstrip_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
+json_t *xt_stmt_json(const struct stmt *stmt, struct output_ctx *octx);
int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd);
@@ -111,6 +118,7 @@ void monitor_print_rule_json(struct netlink_mon_handler *monh,
int json_events_cb(const struct nlmsghdr *nlh,
struct netlink_mon_handler *monh);
+void json_alloc_echo(struct nft_ctx *ctx);
void json_print_echo(struct nft_ctx *ctx);
#else /* ! HAVE_LIBJANSSON */
@@ -126,6 +134,7 @@ static inline json_t *name##_json(arg1_t arg1, arg2_t arg2) { return NULL; }
JSON_PRINT_STUB(name##_stmt, const struct stmt *, struct output_ctx *)
EXPR_PRINT_STUB(binop_expr)
+EXPR_PRINT_STUB(flagcmp_expr)
EXPR_PRINT_STUB(relational_expr)
EXPR_PRINT_STUB(range_expr)
EXPR_PRINT_STUB(meta_expr)
@@ -143,6 +152,7 @@ EXPR_PRINT_STUB(map_expr)
EXPR_PRINT_STUB(exthdr_expr)
EXPR_PRINT_STUB(verdict_expr)
EXPR_PRINT_STUB(rt_expr)
+EXPR_PRINT_STUB(set_elem_catchall_expr)
EXPR_PRINT_STUB(numgen_expr)
EXPR_PRINT_STUB(hash_expr)
EXPR_PRINT_STUB(fib_expr)
@@ -164,10 +174,12 @@ EXPR_PRINT_STUB(uid_type)
EXPR_PRINT_STUB(gid_type)
STMT_PRINT_STUB(expr)
+STMT_PRINT_STUB(flow_offload)
STMT_PRINT_STUB(payload)
STMT_PRINT_STUB(exthdr)
STMT_PRINT_STUB(quota)
STMT_PRINT_STUB(ct)
+STMT_PRINT_STUB(last)
STMT_PRINT_STUB(limit)
STMT_PRINT_STUB(fwd)
STMT_PRINT_STUB(notrack)
@@ -177,6 +189,7 @@ STMT_PRINT_STUB(nat)
STMT_PRINT_STUB(reject)
STMT_PRINT_STUB(counter)
STMT_PRINT_STUB(set)
+STMT_PRINT_STUB(map)
STMT_PRINT_STUB(log)
STMT_PRINT_STUB(objref)
STMT_PRINT_STUB(meter)
@@ -185,6 +198,8 @@ STMT_PRINT_STUB(verdict)
STMT_PRINT_STUB(connlimit)
STMT_PRINT_STUB(tproxy)
STMT_PRINT_STUB(synproxy)
+STMT_PRINT_STUB(optstrip)
+STMT_PRINT_STUB(xt)
#undef STMT_PRINT_STUB
#undef EXPR_PRINT_STUB
@@ -251,6 +266,11 @@ static inline int json_events_cb(const struct nlmsghdr *nlh,
return -1;
}
+static inline void json_alloc_echo(struct nft_ctx *ctx)
+{
+ /* empty */
+}
+
static inline void json_print_echo(struct nft_ctx *ctx)
{
/* empty */
diff --git a/include/linux/Makefile.am b/include/linux/Makefile.am
deleted file mode 100644
index eb9fc4e4..00000000
--- a/include/linux/Makefile.am
+++ /dev/null
@@ -1,12 +0,0 @@
-SUBDIRS = netfilter \
- netfilter_arp \
- netfilter_bridge \
- netfilter_ipv4 \
- netfilter_ipv6
-
-noinst_HEADERS = netfilter_arp.h \
- netfilter_bridge.h \
- netfilter_decnet.h \
- netfilter.h \
- netfilter_ipv4.h \
- netfilter_ipv6.h
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index 18075f95..9e078880 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -48,11 +48,13 @@ enum nf_inet_hooks {
NF_INET_FORWARD,
NF_INET_LOCAL_OUT,
NF_INET_POST_ROUTING,
+ NF_INET_INGRESS,
NF_INET_NUMHOOKS
};
enum nf_dev_hooks {
NF_NETDEV_INGRESS,
+ NF_NETDEV_EGRESS,
NF_NETDEV_NUMHOOKS
};
diff --git a/include/linux/netfilter/Makefile.am b/include/linux/netfilter/Makefile.am
deleted file mode 100644
index 3227d4e8..00000000
--- a/include/linux/netfilter/Makefile.am
+++ /dev/null
@@ -1,8 +0,0 @@
-noinst_HEADERS = nf_conntrack_common.h \
- nf_conntrack_tuple_common.h \
- nf_log.h \
- nf_nat.h \
- nf_tables.h \
- nf_synproxy.h \
- nfnetlink_osf.h \
- nfnetlink.h
diff --git a/include/linux/netfilter/nf_log.h b/include/linux/netfilter/nf_log.h
index 8be21e02..2ae00932 100644
--- a/include/linux/netfilter/nf_log.h
+++ b/include/linux/netfilter/nf_log.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _NETFILTER_NF_LOG_H
#define _NETFILTER_NF_LOG_H
@@ -9,4 +10,6 @@
#define NF_LOG_MACDECODE 0x20 /* Decode MAC header */
#define NF_LOG_MASK 0x2f
+#define NF_LOG_PREFIXLEN 128
+
#endif /* _NETFILTER_NF_LOG_H */
diff --git a/include/linux/netfilter/nf_nat.h b/include/linux/netfilter/nf_nat.h
index 0880781a..a64586e7 100644
--- a/include/linux/netfilter/nf_nat.h
+++ b/include/linux/netfilter/nf_nat.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _NETFILTER_NF_NAT_H
#define _NETFILTER_NF_NAT_H
@@ -9,6 +10,8 @@
#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2)
#define NF_NAT_RANGE_PERSISTENT (1 << 3)
#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
+#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5)
+#define NF_NAT_RANGE_NETMAP (1 << 6)
#define NF_NAT_RANGE_PROTO_RANDOM_ALL \
(NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
@@ -16,7 +19,8 @@
#define NF_NAT_RANGE_MASK \
(NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \
NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \
- NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+ NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \
+ NF_NAT_RANGE_NETMAP)
struct nf_nat_ipv4_range {
unsigned int flags;
@@ -39,4 +43,13 @@ struct nf_nat_range {
union nf_conntrack_man_proto max_proto;
};
+struct nf_nat_range2 {
+ unsigned int flags;
+ union nf_inet_addr min_addr;
+ union nf_inet_addr max_addr;
+ union nf_conntrack_man_proto min_proto;
+ union nf_conntrack_man_proto max_proto;
+ union nf_conntrack_man_proto base_proto;
+};
+
#endif /* _NETFILTER_NF_NAT_H */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index ed8881ad..c62e6ac5 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -48,6 +48,7 @@ enum nft_registers {
#define NFT_REG_SIZE 16
#define NFT_REG32_SIZE 4
+#define NFT_REG32_COUNT (NFT_REG32_15 - NFT_REG32_00 + 1)
/**
* enum nft_verdicts - nf_tables internal verdicts
@@ -96,6 +97,15 @@ enum nft_verdicts {
* @NFT_MSG_NEWFLOWTABLE: add new flow table (enum nft_flowtable_attributes)
* @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes)
* @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes)
+ * @NFT_MSG_GETRULE_RESET: get rules and reset stateful expressions (enum nft_obj_attributes)
+ * @NFT_MSG_DESTROYTABLE: destroy a table (enum nft_table_attributes)
+ * @NFT_MSG_DESTROYCHAIN: destroy a chain (enum nft_chain_attributes)
+ * @NFT_MSG_DESTROYRULE: destroy a rule (enum nft_rule_attributes)
+ * @NFT_MSG_DESTROYSET: destroy a set (enum nft_set_attributes)
+ * @NFT_MSG_DESTROYSETELEM: destroy a set element (enum nft_set_elem_attributes)
+ * @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum nft_object_attributes)
+ * @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum nft_flowtable_attributes)
+ * @NFT_MSG_GETSETELEM_RESET: get set elements and reset attached stateful expressio ns (enum nft_set_elem_attributes)
*/
enum nf_tables_msg_types {
NFT_MSG_NEWTABLE,
@@ -123,6 +133,15 @@ enum nf_tables_msg_types {
NFT_MSG_NEWFLOWTABLE,
NFT_MSG_GETFLOWTABLE,
NFT_MSG_DELFLOWTABLE,
+ NFT_MSG_GETRULE_RESET,
+ NFT_MSG_DESTROYTABLE,
+ NFT_MSG_DESTROYCHAIN,
+ NFT_MSG_DESTROYRULE,
+ NFT_MSG_DESTROYSET,
+ NFT_MSG_DESTROYSETELEM,
+ NFT_MSG_DESTROYOBJ,
+ NFT_MSG_DESTROYFLOWTABLE,
+ NFT_MSG_GETSETELEM_RESET,
NFT_MSG_MAX,
};
@@ -132,7 +151,7 @@ enum nf_tables_msg_types {
* @NFTA_LIST_ELEM: list element (NLA_NESTED)
*/
enum nft_list_attributes {
- NFTA_LIST_UNPEC,
+ NFTA_LIST_UNSPEC,
NFTA_LIST_ELEM,
__NFTA_LIST_MAX
};
@@ -144,12 +163,14 @@ enum nft_list_attributes {
* @NFTA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
* @NFTA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
* @NFTA_HOOK_DEV: netdevice name (NLA_STRING)
+ * @NFTA_HOOK_DEVS: list of netdevices (NLA_NESTED)
*/
enum nft_hook_attributes {
NFTA_HOOK_UNSPEC,
NFTA_HOOK_HOOKNUM,
NFTA_HOOK_PRIORITY,
NFTA_HOOK_DEV,
+ NFTA_HOOK_DEVS,
__NFTA_HOOK_MAX
};
#define NFTA_HOOK_MAX (__NFTA_HOOK_MAX - 1)
@@ -161,7 +182,10 @@ enum nft_hook_attributes {
*/
enum nft_table_flags {
NFT_TABLE_F_DORMANT = 0x1,
+ NFT_TABLE_F_OWNER = 0x2,
};
+#define NFT_TABLE_F_MASK (NFT_TABLE_F_DORMANT | \
+ NFT_TABLE_F_OWNER)
/**
* enum nft_table_attributes - nf_tables table netlink attributes
@@ -169,6 +193,8 @@ enum nft_table_flags {
* @NFTA_TABLE_NAME: name of the table (NLA_STRING)
* @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32)
* @NFTA_TABLE_USE: number of chains in this table (NLA_U32)
+ * @NFTA_TABLE_USERDATA: user data (NLA_BINARY)
+ * @NFTA_TABLE_OWNER: owner of this table through netlink portID (NLA_U32)
*/
enum nft_table_attributes {
NFTA_TABLE_UNSPEC,
@@ -177,10 +203,21 @@ enum nft_table_attributes {
NFTA_TABLE_USE,
NFTA_TABLE_HANDLE,
NFTA_TABLE_PAD,
+ NFTA_TABLE_USERDATA,
+ NFTA_TABLE_OWNER,
__NFTA_TABLE_MAX
};
#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
+enum nft_chain_flags {
+ NFT_CHAIN_BASE = (1 << 0),
+ NFT_CHAIN_HW_OFFLOAD = (1 << 1),
+ NFT_CHAIN_BINDING = (1 << 2),
+};
+#define NFT_CHAIN_FLAGS (NFT_CHAIN_BASE | \
+ NFT_CHAIN_HW_OFFLOAD | \
+ NFT_CHAIN_BINDING)
+
/**
* enum nft_chain_attributes - nf_tables chain netlink attributes
*
@@ -193,6 +230,8 @@ enum nft_table_attributes {
* @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING)
* @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes)
* @NFTA_CHAIN_FLAGS: chain flags
+ * @NFTA_CHAIN_ID: uniquely identifies a chain in a transaction (NLA_U32)
+ * @NFTA_CHAIN_USERDATA: user data (NLA_BINARY)
*/
enum nft_chain_attributes {
NFTA_CHAIN_UNSPEC,
@@ -206,6 +245,8 @@ enum nft_chain_attributes {
NFTA_CHAIN_COUNTERS,
NFTA_CHAIN_PAD,
NFTA_CHAIN_FLAGS,
+ NFTA_CHAIN_ID,
+ NFTA_CHAIN_USERDATA,
__NFTA_CHAIN_MAX
};
#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
@@ -235,6 +276,7 @@ enum nft_rule_attributes {
NFTA_RULE_PAD,
NFTA_RULE_ID,
NFTA_RULE_POSITION_ID,
+ NFTA_RULE_CHAIN_ID,
__NFTA_RULE_MAX
};
#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
@@ -273,6 +315,8 @@ enum nft_rule_compat_attributes {
* @NFT_SET_TIMEOUT: set uses timeouts
* @NFT_SET_EVAL: set can be updated from the evaluation path
* @NFT_SET_OBJECT: set contains stateful objects
+ * @NFT_SET_CONCAT: set contains a concatenation
+ * @NFT_SET_EXPR: set contains expressions
*/
enum nft_set_flags {
NFT_SET_ANONYMOUS = 0x1,
@@ -282,6 +326,8 @@ enum nft_set_flags {
NFT_SET_TIMEOUT = 0x10,
NFT_SET_EVAL = 0x20,
NFT_SET_OBJECT = 0x40,
+ NFT_SET_CONCAT = 0x80,
+ NFT_SET_EXPR = 0x100,
};
/**
@@ -299,15 +345,29 @@ enum nft_set_policies {
* enum nft_set_desc_attributes - set element description
*
* @NFTA_SET_DESC_SIZE: number of elements in set (NLA_U32)
+ * @NFTA_SET_DESC_CONCAT: description of field concatenation (NLA_NESTED)
*/
enum nft_set_desc_attributes {
NFTA_SET_DESC_UNSPEC,
NFTA_SET_DESC_SIZE,
+ NFTA_SET_DESC_CONCAT,
__NFTA_SET_DESC_MAX
};
#define NFTA_SET_DESC_MAX (__NFTA_SET_DESC_MAX - 1)
/**
+ * enum nft_set_field_attributes - attributes of concatenated fields
+ *
+ * @NFTA_SET_FIELD_LEN: length of single field, in bits (NLA_U32)
+ */
+enum nft_set_field_attributes {
+ NFTA_SET_FIELD_UNSPEC,
+ NFTA_SET_FIELD_LEN,
+ __NFTA_SET_FIELD_MAX
+};
+#define NFTA_SET_FIELD_MAX (__NFTA_SET_FIELD_MAX - 1)
+
+/**
* enum nft_set_attributes - nf_tables set netlink attributes
*
* @NFTA_SET_TABLE: table name (NLA_STRING)
@@ -325,6 +385,8 @@ enum nft_set_desc_attributes {
* @NFTA_SET_USERDATA: user data (NLA_BINARY)
* @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
* @NFTA_SET_HANDLE: set handle (NLA_U64)
+ * @NFTA_SET_EXPR: set expression (NLA_NESTED: nft_expr_attributes)
+ * @NFTA_SET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
*/
enum nft_set_attributes {
NFTA_SET_UNSPEC,
@@ -344,6 +406,8 @@ enum nft_set_attributes {
NFTA_SET_PAD,
NFTA_SET_OBJ_TYPE,
NFTA_SET_HANDLE,
+ NFTA_SET_EXPR,
+ NFTA_SET_EXPRESSIONS,
__NFTA_SET_MAX
};
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
@@ -352,9 +416,11 @@ enum nft_set_attributes {
* enum nft_set_elem_flags - nf_tables set element flags
*
* @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval
+ * @NFT_SET_ELEM_CATCHALL: special catch-all element
*/
enum nft_set_elem_flags {
NFT_SET_ELEM_INTERVAL_END = 0x1,
+ NFT_SET_ELEM_CATCHALL = 0x2,
};
/**
@@ -368,6 +434,8 @@ enum nft_set_elem_flags {
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
* @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING)
+ * @NFTA_SET_ELEM_KEY_END: closing key value (NLA_NESTED: nft_data)
+ * @NFTA_SET_ELEM_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
*/
enum nft_set_elem_attributes {
NFTA_SET_ELEM_UNSPEC,
@@ -380,6 +448,8 @@ enum nft_set_elem_attributes {
NFTA_SET_ELEM_EXPR,
NFTA_SET_ELEM_PAD,
NFTA_SET_ELEM_OBJREF,
+ NFTA_SET_ELEM_KEY_END,
+ NFTA_SET_ELEM_EXPRESSIONS,
__NFTA_SET_ELEM_MAX
};
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
@@ -445,11 +515,13 @@ enum nft_data_attributes {
*
* @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts)
* @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING)
+ * @NFTA_VERDICT_CHAIN_ID: jump target chain ID (NLA_U32)
*/
enum nft_verdict_attributes {
NFTA_VERDICT_UNSPEC,
NFTA_VERDICT_CODE,
NFTA_VERDICT_CHAIN,
+ NFTA_VERDICT_CHAIN_ID,
__NFTA_VERDICT_MAX
};
#define NFTA_VERDICT_MAX (__NFTA_VERDICT_MAX - 1)
@@ -483,6 +555,20 @@ enum nft_immediate_attributes {
#define NFTA_IMMEDIATE_MAX (__NFTA_IMMEDIATE_MAX - 1)
/**
+ * enum nft_bitwise_ops - nf_tables bitwise operations
+ *
+ * @NFT_BITWISE_BOOL: mask-and-xor operation used to implement NOT, AND, OR and
+ * XOR boolean operations
+ * @NFT_BITWISE_LSHIFT: left-shift operation
+ * @NFT_BITWISE_RSHIFT: right-shift operation
+ */
+enum nft_bitwise_ops {
+ NFT_BITWISE_BOOL,
+ NFT_BITWISE_LSHIFT,
+ NFT_BITWISE_RSHIFT,
+};
+
+/**
* enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes
*
* @NFTA_BITWISE_SREG: source register (NLA_U32: nft_registers)
@@ -490,16 +576,20 @@ enum nft_immediate_attributes {
* @NFTA_BITWISE_LEN: length of operands (NLA_U32)
* @NFTA_BITWISE_MASK: mask value (NLA_NESTED: nft_data_attributes)
* @NFTA_BITWISE_XOR: xor value (NLA_NESTED: nft_data_attributes)
+ * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops)
+ * @NFTA_BITWISE_DATA: argument for non-boolean operations
+ * (NLA_NESTED: nft_data_attributes)
*
- * The bitwise expression performs the following operation:
+ * The bitwise expression supports boolean and shift operations. It implements
+ * the boolean operations by performing the following operation:
*
* dreg = (sreg & mask) ^ xor
*
- * which allow to express all bitwise operations:
+ * with these mask and xor values:
*
* mask xor
* NOT: 1 1
- * OR: 0 x
+ * OR: ~x x
* XOR: 1 x
* AND: x 0
*/
@@ -510,6 +600,8 @@ enum nft_bitwise_attributes {
NFTA_BITWISE_LEN,
NFTA_BITWISE_MASK,
NFTA_BITWISE_XOR,
+ NFTA_BITWISE_OP,
+ NFTA_BITWISE_DATA,
__NFTA_BITWISE_MAX
};
#define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1)
@@ -641,6 +733,7 @@ enum nft_dynset_ops {
enum nft_dynset_flags {
NFT_DYNSET_F_INV = (1 << 0),
+ NFT_DYNSET_F_EXPR = (1 << 1),
};
/**
@@ -654,6 +747,7 @@ enum nft_dynset_flags {
* @NFTA_DYNSET_TIMEOUT: timeout value for the new element (NLA_U64)
* @NFTA_DYNSET_EXPR: expression (NLA_NESTED: nft_expr_attributes)
* @NFTA_DYNSET_FLAGS: flags (NLA_U32)
+ * @NFTA_DYNSET_EXPRESSIONS: list of expressions (NLA_NESTED: nft_list_attributes)
*/
enum nft_dynset_attributes {
NFTA_DYNSET_UNSPEC,
@@ -666,6 +760,7 @@ enum nft_dynset_attributes {
NFTA_DYNSET_EXPR,
NFTA_DYNSET_PAD,
NFTA_DYNSET_FLAGS,
+ NFTA_DYNSET_EXPRESSIONS,
__NFTA_DYNSET_MAX,
};
#define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1)
@@ -676,11 +771,14 @@ enum nft_dynset_attributes {
* @NFT_PAYLOAD_LL_HEADER: link layer header
* @NFT_PAYLOAD_NETWORK_HEADER: network header
* @NFT_PAYLOAD_TRANSPORT_HEADER: transport header
+ * @NFT_PAYLOAD_INNER_HEADER: inner header / payload
*/
enum nft_payload_bases {
NFT_PAYLOAD_LL_HEADER,
NFT_PAYLOAD_NETWORK_HEADER,
NFT_PAYLOAD_TRANSPORT_HEADER,
+ NFT_PAYLOAD_INNER_HEADER,
+ NFT_PAYLOAD_TUN_HEADER,
};
/**
@@ -688,16 +786,44 @@ enum nft_payload_bases {
*
* @NFT_PAYLOAD_CSUM_NONE: no checksumming
* @NFT_PAYLOAD_CSUM_INET: internet checksum (RFC 791)
+ * @NFT_PAYLOAD_CSUM_SCTP: CRC-32c, for use in SCTP header (RFC 3309)
*/
enum nft_payload_csum_types {
NFT_PAYLOAD_CSUM_NONE,
NFT_PAYLOAD_CSUM_INET,
+ NFT_PAYLOAD_CSUM_SCTP,
};
enum nft_payload_csum_flags {
NFT_PAYLOAD_L4CSUM_PSEUDOHDR = (1 << 0),
};
+enum nft_inner_type {
+ NFT_INNER_UNSPEC = 0,
+ NFT_INNER_VXLAN,
+ NFT_INNER_GENEVE,
+};
+
+enum nft_inner_flags {
+ NFT_INNER_HDRSIZE = (1 << 0),
+ NFT_INNER_LL = (1 << 1),
+ NFT_INNER_NH = (1 << 2),
+ NFT_INNER_TH = (1 << 3),
+};
+#define NFT_INNER_MASK (NFT_INNER_HDRSIZE | NFT_INNER_LL | \
+ NFT_INNER_NH | NFT_INNER_TH)
+
+enum nft_inner_attributes {
+ NFTA_INNER_UNSPEC,
+ NFTA_INNER_NUM,
+ NFTA_INNER_TYPE,
+ NFTA_INNER_FLAGS,
+ NFTA_INNER_HDRSIZE,
+ NFTA_INNER_EXPR,
+ __NFTA_INNER_MAX
+};
+#define NFTA_INNER_MAX (__NFTA_INNER_MAX - 1)
+
/**
* enum nft_payload_attributes - nf_tables payload expression netlink attributes
*
@@ -734,11 +860,15 @@ enum nft_exthdr_flags {
* @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers
* @NFT_EXTHDR_OP_TCP: match against tcp options
* @NFT_EXTHDR_OP_IPV4: match against ipv4 options
+ * @NFT_EXTHDR_OP_SCTP: match against sctp chunks
+ * @NFT_EXTHDR_OP_DCCP: match against dccp options
*/
enum nft_exthdr_op {
NFT_EXTHDR_OP_IPV6,
NFT_EXTHDR_OP_TCPOPT,
NFT_EXTHDR_OP_IPV4,
+ NFT_EXTHDR_OP_SCTP,
+ NFT_EXTHDR_OP_DCCP,
__NFT_EXTHDR_OP_MAX
};
#define NFT_EXTHDR_OP_MAX (__NFT_EXTHDR_OP_MAX - 1)
@@ -803,6 +933,9 @@ enum nft_exthdr_attributes {
* @NFT_META_TIME_NS: time since epoch (in nanoseconds)
* @NFT_META_TIME_DAY: day of week (from 0 = Sunday to 6 = Saturday)
* @NFT_META_TIME_HOUR: hour of day (in seconds)
+ * @NFT_META_SDIF: slave device interface index
+ * @NFT_META_SDIFNAME: slave device interface name
+ * @NFT_META_BRI_BROUTE: packet br_netfilter_broute bit
*/
enum nft_meta_keys {
NFT_META_LEN,
@@ -813,7 +946,8 @@ enum nft_meta_keys {
NFT_META_OIF,
NFT_META_IIFNAME,
NFT_META_OIFNAME,
- NFT_META_IIFTYPE,
+ NFT_META_IFTYPE,
+#define NFT_META_IIFTYPE NFT_META_IFTYPE
NFT_META_OIFTYPE,
NFT_META_SKUID,
NFT_META_SKGID,
@@ -838,6 +972,10 @@ enum nft_meta_keys {
NFT_META_TIME_NS,
NFT_META_TIME_DAY,
NFT_META_TIME_HOUR,
+ NFT_META_SDIF,
+ NFT_META_SDIFNAME,
+ NFT_META_BRI_BROUTE,
+ __NFT_META_IIFTYPE,
};
/**
@@ -933,11 +1071,13 @@ enum nft_rt_attributes {
*
* @NFTA_SOCKET_KEY: socket key to match
* @NFTA_SOCKET_DREG: destination register
+ * @NFTA_SOCKET_LEVEL: cgroups2 ancestor level (only for cgroupsv2)
*/
enum nft_socket_attributes {
NFTA_SOCKET_UNSPEC,
NFTA_SOCKET_KEY,
NFTA_SOCKET_DREG,
+ NFTA_SOCKET_LEVEL,
__NFTA_SOCKET_MAX
};
#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1)
@@ -947,10 +1087,14 @@ enum nft_socket_attributes {
*
* @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option
* @NFT_SOCKET_MARK: Value of the socket mark
+ * @NFT_SOCKET_WILDCARD: Whether the socket is zero-bound (e.g. 0.0.0.0 or ::0)
+ * @NFT_SOCKET_CGROUPV2: Match on cgroups version 2
*/
enum nft_socket_keys {
NFT_SOCKET_TRANSPARENT,
NFT_SOCKET_MARK,
+ NFT_SOCKET_WILDCARD,
+ NFT_SOCKET_CGROUPV2,
__NFT_SOCKET_MAX
};
#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1)
@@ -1105,6 +1249,21 @@ enum nft_counter_attributes {
#define NFTA_COUNTER_MAX (__NFTA_COUNTER_MAX - 1)
/**
+ * enum nft_last_attributes - nf_tables last expression netlink attributes
+ *
+ * @NFTA_LAST_SET: last update has been set, zero means never updated (NLA_U32)
+ * @NFTA_LAST_MSECS: milliseconds since last update (NLA_U64)
+ */
+enum nft_last_attributes {
+ NFTA_LAST_UNSPEC,
+ NFTA_LAST_SET,
+ NFTA_LAST_MSECS,
+ NFTA_LAST_PAD,
+ __NFTA_LAST_MAX
+};
+#define NFTA_LAST_MAX (__NFTA_LAST_MAX - 1)
+
+/**
* enum nft_log_attributes - nf_tables log expression netlink attributes
*
* @NFTA_LOG_GROUP: netlink group to send messages to (NLA_U32)
@@ -1494,6 +1653,7 @@ enum nft_ct_expectation_attributes {
* @NFTA_OBJ_DATA: stateful object data (NLA_NESTED)
* @NFTA_OBJ_USE: number of references to this expression (NLA_U32)
* @NFTA_OBJ_HANDLE: object handle (NLA_U64)
+ * @NFTA_OBJ_USERDATA: user data (NLA_BINARY)
*/
enum nft_object_attributes {
NFTA_OBJ_UNSPEC,
@@ -1504,11 +1664,25 @@ enum nft_object_attributes {
NFTA_OBJ_USE,
NFTA_OBJ_HANDLE,
NFTA_OBJ_PAD,
+ NFTA_OBJ_USERDATA,
__NFTA_OBJ_MAX
};
#define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1)
/**
+ * enum nft_flowtable_flags - nf_tables flowtable flags
+ *
+ * @NFT_FLOWTABLE_HW_OFFLOAD: flowtable hardware offload is enabled
+ * @NFT_FLOWTABLE_COUNTER: enable flow counters
+ */
+enum nft_flowtable_flags {
+ NFT_FLOWTABLE_HW_OFFLOAD = 0x1,
+ NFT_FLOWTABLE_COUNTER = 0x2,
+ NFT_FLOWTABLE_MASK = (NFT_FLOWTABLE_HW_OFFLOAD |
+ NFT_FLOWTABLE_COUNTER)
+};
+
+/**
* enum nft_flowtable_attributes - nf_tables flow table netlink attributes
*
* @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING)
@@ -1516,6 +1690,7 @@ enum nft_object_attributes {
* @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32)
* @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32)
* @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64)
+ * @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32)
*/
enum nft_flowtable_attributes {
NFTA_FLOWTABLE_UNSPEC,
@@ -1525,6 +1700,7 @@ enum nft_flowtable_attributes {
NFTA_FLOWTABLE_USE,
NFTA_FLOWTABLE_HANDLE,
NFTA_FLOWTABLE_PAD,
+ NFTA_FLOWTABLE_FLAGS,
__NFTA_FLOWTABLE_MAX
};
#define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1)
@@ -1725,6 +1901,7 @@ enum nft_tunnel_opts_attributes {
NFTA_TUNNEL_KEY_OPTS_UNSPEC,
NFTA_TUNNEL_KEY_OPTS_VXLAN,
NFTA_TUNNEL_KEY_OPTS_ERSPAN,
+ NFTA_TUNNEL_KEY_OPTS_GENEVE,
__NFTA_TUNNEL_KEY_OPTS_MAX
};
#define NFTA_TUNNEL_KEY_OPTS_MAX (__NFTA_TUNNEL_KEY_OPTS_MAX - 1)
@@ -1746,6 +1923,15 @@ enum nft_tunnel_opts_erspan_attributes {
};
#define NFTA_TUNNEL_KEY_ERSPAN_MAX (__NFTA_TUNNEL_KEY_ERSPAN_MAX - 1)
+enum nft_tunnel_opts_geneve_attributes {
+ NFTA_TUNNEL_KEY_GENEVE_UNSPEC,
+ NFTA_TUNNEL_KEY_GENEVE_CLASS,
+ NFTA_TUNNEL_KEY_GENEVE_TYPE,
+ NFTA_TUNNEL_KEY_GENEVE_DATA,
+ __NFTA_TUNNEL_KEY_GENEVE_MAX
+};
+#define NFTA_TUNNEL_KEY_GENEVE_MAX (__NFTA_TUNNEL_KEY_GENEVE_MAX - 1)
+
enum nft_tunnel_flags {
NFT_TUNNEL_F_ZERO_CSUM_TX = (1 << 0),
NFT_TUNNEL_F_DONT_FRAGMENT = (1 << 1),
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index 454f78d0..49e2b2c5 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -59,7 +59,8 @@ struct nfgenmsg {
#define NFNL_SUBSYS_CTHELPER 9
#define NFNL_SUBSYS_NFTABLES 10
#define NFNL_SUBSYS_NFT_COMPAT 11
-#define NFNL_SUBSYS_COUNT 12
+#define NFNL_SUBSYS_HOOK 12
+#define NFNL_SUBSYS_COUNT 13
/* Reserved control nfnetlink messages */
#define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE
diff --git a/include/linux/netfilter/nfnetlink_hook.h b/include/linux/netfilter/nfnetlink_hook.h
new file mode 100644
index 00000000..84a561a7
--- /dev/null
+++ b/include/linux/netfilter/nfnetlink_hook.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _NFNL_HOOK_H_
+#define _NFNL_HOOK_H_
+
+enum nfnl_hook_msg_types {
+ NFNL_MSG_HOOK_GET,
+ NFNL_MSG_HOOK_MAX,
+};
+
+/**
+ * enum nfnl_hook_attributes - netfilter hook netlink attributes
+ *
+ * @NFNLA_HOOK_HOOKNUM: netfilter hook number (NLA_U32)
+ * @NFNLA_HOOK_PRIORITY: netfilter hook priority (NLA_U32)
+ * @NFNLA_HOOK_DEV: netdevice name (NLA_STRING)
+ * @NFNLA_HOOK_FUNCTION_NAME: hook function name (NLA_STRING)
+ * @NFNLA_HOOK_MODULE_NAME: kernel module that registered this hook (NLA_STRING)
+ * @NFNLA_HOOK_CHAIN_INFO: basechain hook metadata (NLA_NESTED)
+ */
+enum nfnl_hook_attributes {
+ NFNLA_HOOK_UNSPEC,
+ NFNLA_HOOK_HOOKNUM,
+ NFNLA_HOOK_PRIORITY,
+ NFNLA_HOOK_DEV,
+ NFNLA_HOOK_FUNCTION_NAME,
+ NFNLA_HOOK_MODULE_NAME,
+ NFNLA_HOOK_CHAIN_INFO,
+ __NFNLA_HOOK_MAX
+};
+#define NFNLA_HOOK_MAX (__NFNLA_HOOK_MAX - 1)
+
+/**
+ * enum nfnl_hook_chain_info_attributes - chain description
+ *
+ * @NFNLA_HOOK_INFO_DESC: nft chain and table name (NLA_NESTED)
+ * @NFNLA_HOOK_INFO_TYPE: chain type (enum nfnl_hook_chaintype) (NLA_U32)
+ *
+ * NFNLA_HOOK_INFO_DESC depends on NFNLA_HOOK_INFO_TYPE value:
+ * NFNL_HOOK_TYPE_NFTABLES: enum nft_table_attributes
+ * NFNL_HOOK_TYPE_BPF: enum nfnl_hook_bpf_attributes
+ */
+enum nfnl_hook_chain_info_attributes {
+ NFNLA_HOOK_INFO_UNSPEC,
+ NFNLA_HOOK_INFO_DESC,
+ NFNLA_HOOK_INFO_TYPE,
+ __NFNLA_HOOK_INFO_MAX,
+};
+#define NFNLA_HOOK_INFO_MAX (__NFNLA_HOOK_INFO_MAX - 1)
+
+enum nfnl_hook_chain_desc_attributes {
+ NFNLA_CHAIN_UNSPEC,
+ NFNLA_CHAIN_TABLE,
+ NFNLA_CHAIN_FAMILY,
+ NFNLA_CHAIN_NAME,
+ __NFNLA_CHAIN_MAX,
+};
+#define NFNLA_CHAIN_MAX (__NFNLA_CHAIN_MAX - 1)
+
+/**
+ * enum nfnl_hook_chaintype - chain type
+ *
+ * @NFNL_HOOK_TYPE_NFTABLES: nf_tables base chain
+ * @NFNL_HOOK_TYPE_BPF: bpf program
+ */
+enum nfnl_hook_chaintype {
+ NFNL_HOOK_TYPE_NFTABLES = 0x1,
+ NFNL_HOOK_TYPE_BPF,
+};
+
+/**
+ * enum nfnl_hook_bpf_attributes - bpf prog description
+ *
+ * @NFNLA_HOOK_BPF_ID: bpf program id (NLA_U32)
+ */
+enum nfnl_hook_bpf_attributes {
+ NFNLA_HOOK_BPF_UNSPEC,
+ NFNLA_HOOK_BPF_ID,
+ __NFNLA_HOOK_BPF_MAX,
+};
+#define NFNLA_HOOK_BPF_MAX (__NFNLA_HOOK_BPF_MAX - 1)
+
+#endif /* _NFNL_HOOK_H */
diff --git a/include/linux/netfilter_arp/Makefile.am b/include/linux/netfilter_arp/Makefile.am
deleted file mode 100644
index 0a16c1ab..00000000
--- a/include/linux/netfilter_arp/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-noinst_HEADERS = arp_tables.h
diff --git a/include/linux/netfilter_bridge/Makefile.am b/include/linux/netfilter_bridge/Makefile.am
deleted file mode 100644
index d2e8b38b..00000000
--- a/include/linux/netfilter_bridge/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-noinst_HEADERS = ebtables.h
diff --git a/include/linux/netfilter_ipv4/Makefile.am b/include/linux/netfilter_ipv4/Makefile.am
deleted file mode 100644
index fec42533..00000000
--- a/include/linux/netfilter_ipv4/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-noinst_HEADERS = ip_tables.h
diff --git a/include/linux/netfilter_ipv6/Makefile.am b/include/linux/netfilter_ipv6/Makefile.am
deleted file mode 100644
index bec6c3f1..00000000
--- a/include/linux/netfilter_ipv6/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-noinst_HEADERS = ip6_tables.h
diff --git a/include/list.h b/include/list.h
index 75d29212..857921e3 100644
--- a/include/list.h
+++ b/include/list.h
@@ -33,6 +33,17 @@ static inline void init_list_head(struct list_head *list)
list->prev = list;
}
+/**
+ * list_is_first -- tests whether @list is the first entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_first(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->prev == head;
+}
+
/*
* Insert a new entry between two known consecutive entries.
*
@@ -337,6 +348,13 @@ static inline void list_splice_tail_init(struct list_head *list,
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
+/**
+ * list_next_entry - get the next element in list
+ * @pos: the type * to cursor
+ * @member: the name of the list_head within the struct.
+ */
+#define list_next_entry(pos, member) \
+ list_entry((pos)->member.next, typeof(*(pos)), member)
/**
* list_for_each_entry - iterate over list of given type
diff --git a/include/meta.h b/include/meta.h
index 1478902e..af2d772b 100644
--- a/include/meta.h
+++ b/include/meta.h
@@ -45,4 +45,6 @@ extern const struct datatype date_type;
extern const struct datatype hour_type;
extern const struct datatype day_type;
+bool lhs_is_meta_hour(const struct expr *meta);
+
#endif /* NFTABLES_META_H */
diff --git a/include/mnl.h b/include/mnl.h
index eeba7379..cd5a2053 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -7,7 +7,6 @@
#include <libmnl/libmnl.h>
struct mnl_socket *nft_mnl_socket_open(void);
-struct mnl_socket *nft_mnl_socket_reopen(struct mnl_socket *nf_sock);
uint32_t mnl_seqnum_alloc(uint32_t *seqnum);
uint32_t mnl_genid_get(struct netlink_ctx *ctx);
@@ -16,6 +15,7 @@ struct mnl_err {
struct list_head head;
int err;
uint32_t seqnum;
+ uint32_t offset;
};
void mnl_err_list_free(struct mnl_err *err);
@@ -28,59 +28,70 @@ void mnl_batch_end(struct nftnl_batch *batch, uint32_t seqnum);
int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
uint32_t num_cmds);
-int mnl_nft_rule_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_rule_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
-int mnl_nft_rule_del(struct netlink_ctx *ctx, const struct cmd *cmd);
-int mnl_nft_rule_replace(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_rule_del(struct netlink_ctx *ctx, struct cmd *cmd);
+int mnl_nft_rule_replace(struct netlink_ctx *ctx, struct cmd *cmd);
-struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx,
- int family);
+struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
+ const char *table, const char *chain,
+ uint64_t rule_handle,
+ bool dump, bool reset);
-int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
-int mnl_nft_chain_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_chain_del(struct netlink_ctx *ctx, struct cmd *cmd);
int mnl_nft_chain_rename(struct netlink_ctx *ctx, const struct cmd *cmd,
const struct chain *chain);
struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
- int family);
+ int family, const char *table,
+ const char *chain);
-int mnl_nft_table_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_table_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
-int mnl_nft_table_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_table_del(struct netlink_ctx *ctx, struct cmd *cmd);
struct nftnl_table_list *mnl_nft_table_dump(struct netlink_ctx *ctx,
- int family);
+ int family, const char *table);
-int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_set_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
-int mnl_nft_set_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_set_del(struct netlink_ctx *ctx, struct cmd *cmd);
struct nftnl_set_list *mnl_nft_set_dump(struct netlink_ctx *ctx, int family,
- const char *table);
+ const char *table, const char *set);
-int mnl_nft_setelem_add(struct netlink_ctx *ctx, const struct set *set,
- const struct expr *expr, unsigned int flags);
-int mnl_nft_setelem_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_setelem_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ const struct set *set, const struct expr *expr,
+ unsigned int flags);
+int mnl_nft_setelem_del(struct netlink_ctx *ctx, struct cmd *cmd,
+ const struct handle *h, const struct expr *init);
int mnl_nft_setelem_flush(struct netlink_ctx *ctx, const struct cmd *cmd);
-int mnl_nft_setelem_get(struct netlink_ctx *ctx, struct nftnl_set *nls);
+int mnl_nft_setelem_get(struct netlink_ctx *ctx, struct nftnl_set *nls,
+ bool reset);
struct nftnl_set *mnl_nft_setelem_get_one(struct netlink_ctx *ctx,
- struct nftnl_set *nls);
+ struct nftnl_set *nls,
+ bool reset);
struct nftnl_obj_list *mnl_nft_obj_dump(struct netlink_ctx *ctx, int family,
const char *table,
const char *name, uint32_t type,
bool dump, bool reset);
-int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_obj_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
-int mnl_nft_obj_del(struct netlink_ctx *ctx, const struct cmd *cmd, int type);
+int mnl_nft_obj_del(struct netlink_ctx *ctx, struct cmd *cmd, int type);
struct nftnl_flowtable_list *
-mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table);
+mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family,
+ const char *table, const char *ft);
-int mnl_nft_flowtable_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
-int mnl_nft_flowtable_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd);
+
+int mnl_nft_dump_nf_hooks(struct netlink_ctx *ctx, int family, int hook,
+ const char *devname);
int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
struct output_ctx *octx,
diff --git a/include/netlink.h b/include/netlink.h
index 279723f3..27a62462 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -16,6 +16,22 @@
#define MAX_REGS (1 + NFT_REG32_15 - NFT_REG32_00)
+#ifndef NETLINK_EXT_ACK
+#define NETLINK_EXT_ACK 11
+
+enum nlmsgerr_attrs {
+ NLMSGERR_ATTR_UNUSED,
+ NLMSGERR_ATTR_MSG,
+ NLMSGERR_ATTR_OFFS,
+ NLMSGERR_ATTR_COOKIE,
+
+ __NLMSGERR_ATTR_MAX,
+ NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+#define NLM_F_CAPPED 0x100 /* request was capped */
+#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
+#endif
+
struct netlink_parse_ctx {
struct list_head *msgs;
struct table *table;
@@ -23,12 +39,29 @@ struct netlink_parse_ctx {
struct stmt *stmt;
struct expr *registers[MAX_REGS + 1];
unsigned int debug_mask;
+ struct netlink_ctx *nlctx;
+ bool inner;
+ uint8_t inner_reg;
};
-struct rule_pp_ctx {
+
+#define RULE_PP_IN_CONCATENATION (1 << 0)
+#define RULE_PP_IN_SET_ELEM (1 << 1)
+
+#define RULE_PP_REMOVE_OP_AND (RULE_PP_IN_CONCATENATION | \
+ RULE_PP_IN_SET_ELEM)
+
+struct dl_proto_ctx {
struct proto_ctx pctx;
struct payload_dep_ctx pdctx;
+};
+
+struct rule_pp_ctx {
+ struct dl_proto_ctx _dl[2];
+ struct dl_proto_ctx *dl;
struct stmt *stmt;
+ unsigned int flags;
+ struct set *set;
};
extern const struct input_descriptor indesc_netlink;
@@ -52,10 +85,13 @@ struct netlink_ctx {
const void *data;
uint32_t seqnum;
struct nftnl_batch *batch;
+ int maybe_emsgsize;
};
extern struct nftnl_expr *alloc_nft_expr(const char *name);
extern void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls);
+struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
+ const struct expr *expr);
extern struct nftnl_table *netlink_table_alloc(const struct nlmsghdr *nlh);
extern struct nftnl_chain *netlink_chain_alloc(const struct nlmsghdr *nlh);
@@ -65,8 +101,9 @@ extern struct nftnl_rule *netlink_rule_alloc(const struct nlmsghdr *nlh);
struct nft_data_linearize {
uint32_t len;
- uint32_t value[4];
+ uint32_t value[NFT_REG32_COUNT];
char chain[NFT_CHAIN_MAXNAMELEN];
+ uint32_t chain_id;
int verdict;
};
@@ -97,6 +134,7 @@ extern void netlink_gen_data(const struct expr *expr,
extern void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
unsigned int len,
struct nft_data_linearize *data);
+extern struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt);
extern struct expr *netlink_alloc_value(const struct location *loc,
const struct nft_data_delinearize *nld);
@@ -104,10 +142,10 @@ extern struct expr *netlink_alloc_data(const struct location *loc,
const struct nft_data_delinearize *nld,
enum nft_registers dreg);
-extern int netlink_list_rules(struct netlink_ctx *ctx, const struct handle *h);
+struct netlink_linearize_ctx;
extern void netlink_linearize_rule(struct netlink_ctx *ctx,
- struct nftnl_rule *nlr,
- const struct rule *rule);
+ const struct rule *rule,
+ struct netlink_linearize_ctx *lctx);
extern struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
struct nftnl_rule *r);
@@ -115,11 +153,11 @@ extern int netlink_list_chains(struct netlink_ctx *ctx, const struct handle *h);
extern struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
const struct nftnl_chain *nlc);
-extern int netlink_list_tables(struct netlink_ctx *ctx, const struct handle *h);
+extern int netlink_list_tables(struct netlink_ctx *ctx, const struct handle *h,
+ const struct nft_cache_filter *filter);
extern struct table *netlink_delinearize_table(struct netlink_ctx *ctx,
const struct nftnl_table *nlt);
-extern int netlink_list_sets(struct netlink_ctx *ctx, const struct handle *h);
extern struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
const struct nftnl_set *nls);
@@ -128,12 +166,13 @@ extern struct stmt *netlink_parse_set_expr(const struct set *set,
const struct nftnl_expr *nle);
extern int netlink_list_setelems(struct netlink_ctx *ctx,
- const struct handle *h, struct set *set);
+ const struct handle *h, struct set *set,
+ bool reset);
extern int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h,
- const struct location *loc, struct table *table,
- struct set *set, struct expr *init);
+ const struct location *loc, struct set *cache_set,
+ struct set *set, struct expr *init, bool reset);
extern int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
- const struct set *set,
+ struct set *set,
struct nft_cache *cache);
extern int netlink_list_objs(struct netlink_ctx *ctx, const struct handle *h);
@@ -144,6 +183,11 @@ extern struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
extern int netlink_list_flowtables(struct netlink_ctx *ctx,
const struct handle *h);
+extern struct flowtable *netlink_delinearize_flowtable(struct netlink_ctx *ctx,
+ struct nftnl_flowtable *nlo);
+
+extern int netlink_reset_rules(struct netlink_ctx *ctx, const struct cmd *cmd,
+ bool dump);
extern void netlink_dump_chain(const struct nftnl_chain *nlc,
struct netlink_ctx *ctx);
@@ -160,7 +204,7 @@ extern void netlink_dump_flowtable(struct nftnl_flowtable *flo, struct netlink_c
__netlink_abi_error(__FILE__, __LINE__, strerror(errno));
extern void __noreturn __netlink_abi_error(const char *file, int line, const char *reason);
extern int netlink_io_error(struct netlink_ctx *ctx,
- const struct location *loc, const char *fmt, ...);
+ const struct location *loc, const char *fmt, ...) __attribute__((format(printf, 3, 4)));
#define netlink_init_error() \
__netlink_init_error(__FILE__, __LINE__, strerror(errno));
extern void __noreturn __netlink_init_error(const char *file, int line, const char *reason);
@@ -171,12 +215,15 @@ struct netlink_mon_handler {
struct netlink_ctx *ctx;
const struct location *loc;
unsigned int debug_mask;
- bool cache_needed;
struct nft_cache *cache;
};
extern int netlink_monitor(struct netlink_mon_handler *monhandler,
struct mnl_socket *nf_sock);
+struct netlink_cb_data {
+ struct netlink_ctx *nl_ctx;
+ struct list_head *err_list;
+};
int netlink_echo_callback(const struct nlmsghdr *nlh, void *data);
struct ruleset_parse {
@@ -190,6 +237,28 @@ int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
struct netlink_mon_handler *monh);
enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype);
-const struct datatype *dtype_map_from_kernel(enum nft_data_types type);
+
+void netlink_linearize_init(struct netlink_linearize_ctx *lctx,
+ struct nftnl_rule *nlr);
+void netlink_linearize_fini(struct netlink_linearize_ctx *lctx);
+
+struct netlink_linearize_ctx {
+ struct nftnl_rule *nlr;
+ unsigned int reg_low;
+ struct list_head *expr_loc_htable;
+};
+
+#define NFT_EXPR_LOC_HSIZE 128
+
+struct nft_expr_loc {
+ struct list_head hlist;
+ const struct nftnl_expr *nle;
+ const struct location *loc;
+};
+
+struct nft_expr_loc *nft_expr_loc_find(const struct nftnl_expr *nle,
+ struct netlink_linearize_ctx *ctx);
+
+struct dl_proto_ctx *dl_proto_ctx(struct rule_pp_ctx *ctx);
#endif /* NFTABLES_NETLINK_H */
diff --git a/include/nft.h b/include/nft.h
new file mode 100644
index 00000000..a2d62dbf
--- /dev/null
+++ b/include/nft.h
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef NFTABLES_NFT_H
+#define NFTABLES_NFT_H
+
+#include <config.h>
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Just free(), but casts to a (void*). This is for places where
+ * we have a const pointer that we know we want to free. We could just
+ * do the (void*) cast, but free_const() makes it clear that this is
+ * something we frequently need to do and it's intentional. */
+#define free_const(ptr) free((void *)(ptr))
+
+#endif /* NFTABLES_NFT_H */
diff --git a/include/nftables.h b/include/nftables.h
index 1ecf5ef5..4b7c3359 100644
--- a/include/nftables.h
+++ b/include/nftables.h
@@ -1,10 +1,10 @@
#ifndef NFTABLES_NFTABLES_H
#define NFTABLES_NFTABLES_H
-#include <stdbool.h>
#include <stdarg.h>
#include <limits.h>
#include <utils.h>
+#include <cache.h>
#include <nftables/libnftables.h>
struct cookie {
@@ -22,6 +22,20 @@ struct symbol_tables {
const struct symbol_table *realm;
};
+struct input_ctx {
+ unsigned int flags;
+};
+
+static inline bool nft_input_no_dns(const struct input_ctx *ictx)
+{
+ return ictx->flags & NFT_CTX_INPUT_NO_DNS;
+}
+
+static inline bool nft_input_json(const struct input_ctx *ictx)
+{
+ return ictx->flags & NFT_CTX_INPUT_JSON;
+}
+
struct output_ctx {
unsigned int flags;
union {
@@ -90,15 +104,19 @@ static inline bool nft_output_numeric_symbol(const struct output_ctx *octx)
return octx->flags & NFT_CTX_OUTPUT_NUMERIC_SYMBOL;
}
-struct nft_cache {
- uint32_t genid;
- struct list_head list;
- uint32_t seqnum;
- uint32_t flags;
-};
+static inline bool nft_output_terse(const struct output_ctx *octx)
+{
+ return octx->flags & NFT_CTX_OUTPUT_TERSE;
+}
struct mnl_socket;
struct parser_state;
+struct scope;
+
+struct nft_vars {
+ const char *key;
+ const char *value;
+};
#define MAX_INCLUDE_DEPTH 16
@@ -106,16 +124,26 @@ struct nft_ctx {
struct mnl_socket *nf_sock;
char **include_paths;
unsigned int num_include_paths;
+ struct nft_vars *vars;
+ struct {
+ const char *buf;
+ struct list_head indesc_list;
+ } vars_ctx;
+ unsigned int num_vars;
unsigned int parser_max_errors;
unsigned int debug_mask;
+ struct input_ctx input;
struct output_ctx output;
bool check;
struct nft_cache cache;
uint32_t flags;
+ uint32_t optimize_flags;
struct parser_state *state;
void *scanner;
+ struct scope *top_scope;
void *json_root;
- FILE *f[MAX_INCLUDE_DEPTH];
+ json_t *json_echo;
+ const char *stdin_buf;
};
enum nftables_exit_codes {
@@ -163,12 +191,15 @@ enum input_descriptor_types {
INDESC_FILE,
INDESC_CLI,
INDESC_NETLINK,
+ INDESC_STDIN,
};
/**
* struct input_descriptor
*
* @location: location, used for include statements
+ * @f: file descriptor
+ * @depth: include depth of the descriptor
* @type: input descriptor type
* @name: name describing the input
* @union: buffer or file descriptor, depending on type
@@ -179,6 +210,8 @@ enum input_descriptor_types {
*/
struct input_descriptor {
struct list_head list;
+ FILE *f;
+ unsigned int depth;
struct location location;
enum input_descriptor_types type;
const char *name;
@@ -191,7 +224,6 @@ struct input_descriptor {
void ct_label_table_init(struct nft_ctx *ctx);
void mark_table_init(struct nft_ctx *ctx);
-void gmp_init(void);
void realm_table_rt_init(struct nft_ctx *ctx);
void devgroup_table_init(struct nft_ctx *ctx);
void xt_init(void);
@@ -203,8 +235,9 @@ void realm_table_rt_exit(struct nft_ctx *ctx);
int nft_print(struct output_ctx *octx, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
-int nft_gmp_print(struct output_ctx *octx, const char *fmt, ...)
- __attribute__((format(printf, 2, 0)));
+int nft_gmp_print(struct output_ctx *octx, const char *fmt, ...);
+
+int nft_optimize(struct nft_ctx *nft, struct list_head *cmds);
#define __NFT_OUTPUT_NOTSUPP UINT_MAX
diff --git a/include/nftables/Makefile.am b/include/nftables/Makefile.am
deleted file mode 100644
index 5cfb0c6c..00000000
--- a/include/nftables/Makefile.am
+++ /dev/null
@@ -1 +0,0 @@
-pkginclude_HEADERS = libnftables.h
diff --git a/include/nftables/libnftables.h b/include/nftables/libnftables.h
index 7a7a46f3..c1d48d76 100644
--- a/include/nftables/libnftables.h
+++ b/include/nftables/libnftables.h
@@ -9,7 +9,6 @@
#ifndef LIB_NFTABLES_H
#define LIB_NFTABLES_H
-#define _GNU_SOURCE
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
@@ -41,6 +40,21 @@ void nft_ctx_free(struct nft_ctx *ctx);
bool nft_ctx_get_dry_run(struct nft_ctx *ctx);
void nft_ctx_set_dry_run(struct nft_ctx *ctx, bool dry);
+enum nft_optimize_flags {
+ NFT_OPTIMIZE_ENABLED = 0x1,
+};
+
+uint32_t nft_ctx_get_optimize(struct nft_ctx *ctx);
+void nft_ctx_set_optimize(struct nft_ctx *ctx, uint32_t flags);
+
+enum {
+ NFT_CTX_INPUT_NO_DNS = (1 << 0),
+ NFT_CTX_INPUT_JSON = (1 << 1),
+};
+
+unsigned int nft_ctx_input_get_flags(struct nft_ctx *ctx);
+unsigned int nft_ctx_input_set_flags(struct nft_ctx *ctx, unsigned int flags);
+
enum {
NFT_CTX_OUTPUT_REVERSEDNS = (1 << 0),
NFT_CTX_OUTPUT_SERVICE = (1 << 1),
@@ -55,7 +69,9 @@ enum {
NFT_CTX_OUTPUT_NUMERIC_TIME = (1 << 10),
NFT_CTX_OUTPUT_NUMERIC_ALL = (NFT_CTX_OUTPUT_NUMERIC_PROTO |
NFT_CTX_OUTPUT_NUMERIC_PRIO |
- NFT_CTX_OUTPUT_NUMERIC_SYMBOL),
+ NFT_CTX_OUTPUT_NUMERIC_SYMBOL |
+ NFT_CTX_OUTPUT_NUMERIC_TIME),
+ NFT_CTX_OUTPUT_TERSE = (1 << 11),
};
unsigned int nft_ctx_output_get_flags(struct nft_ctx *ctx);
@@ -77,6 +93,9 @@ const char *nft_ctx_get_error_buffer(struct nft_ctx *ctx);
int nft_ctx_add_include_path(struct nft_ctx *ctx, const char *path);
void nft_ctx_clear_include_paths(struct nft_ctx *ctx);
+int nft_ctx_add_var(struct nft_ctx *ctx, const char *var);
+void nft_ctx_clear_vars(struct nft_ctx *ctx);
+
int nft_run_cmd_from_buffer(struct nft_ctx *nft, const char *buf);
int nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename);
diff --git a/include/owner.h b/include/owner.h
new file mode 100644
index 00000000..85d821cc
--- /dev/null
+++ b/include/owner.h
@@ -0,0 +1,6 @@
+#ifndef _NFT_OWNER_H_
+#define _NFT_OWNER_H_
+
+char *get_progname(uint32_t portid);
+
+#endif
diff --git a/include/parser.h b/include/parser.h
index 39a75212..f79a22f3 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -11,28 +11,91 @@
#define YYLTYPE_IS_TRIVIAL 0
#define YYENABLE_NLS 0
-#define SCOPE_NEST_MAX 3
+#define SCOPE_NEST_MAX 4
struct parser_state {
struct input_descriptor *indesc;
- struct input_descriptor *indescs[MAX_INCLUDE_DEPTH];
- unsigned int indesc_idx;
struct list_head indesc_list;
struct list_head *msgs;
unsigned int nerrs;
- struct scope top_scope;
struct scope *scopes[SCOPE_NEST_MAX];
unsigned int scope;
+ bool scope_err;
+ unsigned int flex_state_pop;
+ unsigned int startcond_type;
struct list_head *cmds;
+ unsigned int *startcond_active;
+};
+
+enum startcond_type {
+ PARSER_SC_BEGIN,
+ PARSER_SC_ARP,
+ PARSER_SC_AT,
+ PARSER_SC_CT,
+ PARSER_SC_COUNTER,
+ PARSER_SC_ETH,
+ PARSER_SC_GRE,
+ PARSER_SC_ICMP,
+ PARSER_SC_IGMP,
+ PARSER_SC_IP,
+ PARSER_SC_IP6,
+ PARSER_SC_LAST,
+ PARSER_SC_LIMIT,
+ PARSER_SC_META,
+ PARSER_SC_POLICY,
+ PARSER_SC_QUOTA,
+ PARSER_SC_SCTP,
+ PARSER_SC_SECMARK,
+ PARSER_SC_TCP,
+ PARSER_SC_TYPE,
+ PARSER_SC_VLAN,
+ PARSER_SC_XT,
+ PARSER_SC_CMD_DESTROY,
+ PARSER_SC_CMD_EXPORT,
+ PARSER_SC_CMD_IMPORT,
+ PARSER_SC_CMD_LIST,
+ PARSER_SC_CMD_MONITOR,
+ PARSER_SC_CMD_RESET,
+ PARSER_SC_EXPR_AH,
+ PARSER_SC_EXPR_COMP,
+ PARSER_SC_EXPR_DCCP,
+ PARSER_SC_EXPR_DST,
+ PARSER_SC_EXPR_ESP,
+ PARSER_SC_EXPR_FIB,
+ PARSER_SC_EXPR_FRAG,
+ PARSER_SC_EXPR_HASH,
+ PARSER_SC_EXPR_HBH,
+ PARSER_SC_EXPR_IPSEC,
+ PARSER_SC_EXPR_MH,
+ PARSER_SC_EXPR_NUMGEN,
+ PARSER_SC_EXPR_OSF,
+ PARSER_SC_EXPR_QUEUE,
+ PARSER_SC_EXPR_RT,
+ PARSER_SC_EXPR_SCTP_CHUNK,
+ PARSER_SC_EXPR_SOCKET,
+ PARSER_SC_EXPR_TH,
+ PARSER_SC_EXPR_UDP,
+ PARSER_SC_EXPR_UDPLITE,
+
+ PARSER_SC_STMT_DUP,
+ PARSER_SC_STMT_FWD,
+ PARSER_SC_STMT_LOG,
+ PARSER_SC_STMT_NAT,
+ PARSER_SC_STMT_REJECT,
+ PARSER_SC_STMT_SYNPROXY,
+ PARSER_SC_STMT_TPROXY,
+
+ __SC_MAX
};
struct mnl_socket;
extern void parser_init(struct nft_ctx *nft, struct parser_state *state,
- struct list_head *msgs, struct list_head *cmds);
+ struct list_head *msgs, struct list_head *cmds,
+ struct scope *top_scope);
extern int nft_parse(struct nft_ctx *ctx, void *, struct parser_state *state);
extern void *scanner_init(struct parser_state *state);
@@ -47,4 +110,6 @@ extern void scanner_push_buffer(void *scanner,
const struct input_descriptor *indesc,
const char *buffer);
+extern void scanner_pop_start_cond(void *scanner, enum startcond_type sc);
+
#endif /* NFTABLES_PARSER_H */
diff --git a/include/payload.h b/include/payload.h
index a914d239..08e45f7f 100644
--- a/include/payload.h
+++ b/include/payload.h
@@ -15,6 +15,11 @@ struct eval_ctx;
struct stmt;
extern int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
struct stmt **res);
+int payload_gen_inner_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ struct stmt **res);
+extern int payload_gen_icmp_dependency(struct eval_ctx *ctx,
+ const struct expr *expr,
+ struct stmt **res);
extern int exthdr_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
const struct proto_desc *dependency,
enum proto_bases pb, struct stmt **res);
@@ -22,14 +27,14 @@ extern int exthdr_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
/**
* struct payload_dep_ctx - payload protocol dependency tracking
*
- * @pbase: protocol base of last dependency match
- * @pdep: last dependency match
+ * @icmp_type: extra info for icmp(6) decoding
* @prev: previous statement
+ * @pdeps: last dependency match per protocol layer
*/
struct payload_dep_ctx {
- enum proto_bases pbase;
- struct stmt *pdep;
- struct stmt *prev;
+ uint8_t icmp_type;
+ struct stmt *prev;
+ struct stmt *pdeps[PROTO_BASE_MAX + 1];
};
extern bool payload_is_known(const struct expr *expr);
@@ -42,7 +47,10 @@ extern void payload_dependency_store(struct payload_dep_ctx *ctx,
enum proto_bases base);
extern bool payload_dependency_exists(const struct payload_dep_ctx *ctx,
enum proto_bases base);
-extern void payload_dependency_release(struct payload_dep_ctx *ctx);
+extern struct expr *payload_dependency_get(struct payload_dep_ctx *ctx,
+ enum proto_bases base);
+extern void payload_dependency_release(struct payload_dep_ctx *ctx,
+ enum proto_bases base);
extern void payload_dependency_kill(struct payload_dep_ctx *ctx,
struct expr *expr, unsigned int family);
extern void exthdr_dependency_kill(struct payload_dep_ctx *ctx,
@@ -61,4 +69,6 @@ extern void payload_expr_complete(struct expr *expr,
bool payload_expr_cmp(const struct expr *e1, const struct expr *e2);
+const struct proto_desc *find_proto_desc(const struct nftnl_udata *ud);
+
#endif /* NFTABLES_PAYLOAD_H */
diff --git a/include/proto.h b/include/proto.h
index fab48c1b..9c98a0b7 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -18,6 +18,7 @@ enum proto_bases {
PROTO_BASE_LL_HDR,
PROTO_BASE_NETWORK_HDR,
PROTO_BASE_TRANSPORT_HDR,
+ PROTO_BASE_INNER_HDR,
__PROTO_BASE_MAX
};
#define PROTO_BASE_MAX (__PROTO_BASE_MAX - 1)
@@ -25,6 +26,19 @@ enum proto_bases {
extern const char *proto_base_names[];
extern const char *proto_base_tokens[];
+enum icmp_hdr_field_type {
+ PROTO_ICMP_ANY = 0,
+ PROTO_ICMP_ECHO, /* echo and reply */
+ PROTO_ICMP_MTU, /* destination unreachable */
+ PROTO_ICMP_ADDRESS, /* redirect */
+ PROTO_ICMP6_MTU,
+ PROTO_ICMP6_PPTR,
+ PROTO_ICMP6_ECHO,
+ PROTO_ICMP6_MGMQ,
+ PROTO_ICMP6_ADDRESS, /* neighbor solicit/advert, redirect and MLD */
+ PROTO_ICMP6_REDIRECT,
+};
+
/**
* struct proto_hdr_template - protocol header field description
*
@@ -33,14 +47,16 @@ extern const char *proto_base_tokens[];
* @offset: offset of the header field from base
* @len: length of header field
* @meta_key: special case: meta expression key
+ * @icmp_dep: special case: icmp header dependency
*/
struct proto_hdr_template {
const char *token;
const struct datatype *dtype;
uint16_t offset;
uint16_t len;
- enum byteorder byteorder;
- enum nft_meta_keys meta_key;
+ enum byteorder byteorder:8;
+ enum nft_meta_keys meta_key:8;
+ enum icmp_hdr_field_type icmp_dep:8;
};
#define PROTO_HDR_TEMPLATE(__token, __dtype, __byteorder, __offset, __len)\
@@ -63,10 +79,38 @@ struct proto_hdr_template {
#define PROTO_UPPER_MAX 16
#define PROTO_HDRS_MAX 20
+enum proto_desc_id {
+ PROTO_DESC_UNKNOWN = 0,
+ PROTO_DESC_AH,
+ PROTO_DESC_ESP,
+ PROTO_DESC_COMP,
+ PROTO_DESC_ICMP,
+ PROTO_DESC_IGMP,
+ PROTO_DESC_UDP,
+ PROTO_DESC_UDPLITE,
+ PROTO_DESC_TCP,
+ PROTO_DESC_DCCP,
+ PROTO_DESC_SCTP,
+ PROTO_DESC_TH,
+ PROTO_DESC_IP,
+ PROTO_DESC_IP6,
+ PROTO_DESC_ICMPV6,
+ PROTO_DESC_ARP,
+ PROTO_DESC_VLAN,
+ PROTO_DESC_ETHER,
+ PROTO_DESC_VXLAN,
+ PROTO_DESC_GENEVE,
+ PROTO_DESC_GRE,
+ PROTO_DESC_GRETAP,
+ __PROTO_DESC_MAX
+};
+#define PROTO_DESC_MAX (__PROTO_DESC_MAX - 1)
+
/**
* struct proto_desc - protocol header description
*
* @name: protocol name
+ * @id: protocol identifier
* @base: header base
* @checksum_key: key of template containing checksum
* @protocol_key: key of template containing upper layer protocol description
@@ -77,9 +121,11 @@ struct proto_hdr_template {
*/
struct proto_desc {
const char *name;
- enum proto_bases base;
- unsigned int checksum_key;
- unsigned int protocol_key;
+ enum proto_desc_id id:8;
+ enum proto_bases base:8;
+ enum nft_payload_csum_types checksum_type:8;
+ uint16_t checksum_key;
+ uint16_t protocol_key;
unsigned int length;
struct {
unsigned int num;
@@ -91,7 +137,11 @@ struct proto_desc {
uint32_t filter;
} format;
unsigned int pseudohdr[PROTO_HDRS_MAX];
-
+ struct {
+ uint32_t hdrsize;
+ uint32_t flags;
+ enum nft_inner_type type;
+ } inner;
};
#define PROTO_LINK(__num, __desc) { .num = (__num), .desc = (__desc), }
@@ -127,6 +177,8 @@ struct dev_proto_desc {
extern int proto_dev_type(const struct proto_desc *desc, uint16_t *res);
extern const struct proto_desc *proto_dev_desc(uint16_t type);
+#define PROTO_CTX_NUM_PROTOS 16
+
/**
* struct proto_ctx - protocol context
*
@@ -142,23 +194,43 @@ extern const struct proto_desc *proto_dev_desc(uint16_t type);
*/
struct proto_ctx {
unsigned int debug_mask;
- unsigned int family;
+ uint8_t family;
+ bool inner;
+ union {
+ struct {
+ uint8_t type;
+ } icmp;
+ } th_dep;
struct {
struct location location;
const struct proto_desc *desc;
- unsigned int offset;
+ struct {
+ struct location location;
+ const struct proto_desc *desc;
+ } protos[PROTO_CTX_NUM_PROTOS];
+ unsigned int num_protos;
} protocol[PROTO_BASE_MAX + 1];
+ const struct proto_desc *stacked_ll[PROTO_CTX_NUM_PROTOS];
+ uint8_t stacked_ll_count;
};
extern void proto_ctx_init(struct proto_ctx *ctx, unsigned int family,
- unsigned int debug_mask);
+ unsigned int debug_mask, bool inner);
extern void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base,
const struct location *loc,
const struct proto_desc *desc);
+bool proto_ctx_is_ambiguous(struct proto_ctx *ctx, enum proto_bases bases);
+const struct proto_desc *proto_ctx_find_conflict(struct proto_ctx *ctx,
+ enum proto_bases base,
+ const struct proto_desc *desc);
extern const struct proto_desc *proto_find_upper(const struct proto_desc *base,
unsigned int num);
extern int proto_find_num(const struct proto_desc *base,
const struct proto_desc *desc);
+const struct proto_desc *proto_find_inner(uint32_t type, uint32_t hdrsize,
+ uint32_t flags);
+
+extern const struct proto_desc *proto_find_desc(enum proto_desc_id desc_id);
enum eth_hdr_fields {
ETHHDR_INVALID,
@@ -170,6 +242,7 @@ enum eth_hdr_fields {
enum vlan_hdr_fields {
VLANHDR_INVALID,
VLANHDR_PCP,
+ VLANHDR_DEI,
VLANHDR_CFI,
VLANHDR_VID,
VLANHDR_TYPE,
@@ -183,8 +256,8 @@ enum arp_hdr_fields {
ARPHDR_PLN,
ARPHDR_OP,
ARPHDR_SADDR_ETHER,
- ARPHDR_DADDR_ETHER,
ARPHDR_SADDR_IP,
+ ARPHDR_DADDR_ETHER,
ARPHDR_DADDR_IP,
};
@@ -203,6 +276,7 @@ enum ip_hdr_fields {
IPHDR_SADDR,
IPHDR_DADDR,
};
+#define IPHDR_MAX IPHDR_DADDR
enum icmp_hdr_fields {
ICMPHDR_INVALID,
@@ -233,6 +307,8 @@ enum icmp6_hdr_fields {
ICMP6HDR_ID,
ICMP6HDR_SEQ,
ICMP6HDR_MAXDELAY,
+ ICMP6HDR_TADDR,
+ ICMP6HDR_DADDR,
};
enum ip6_hdr_fields {
@@ -316,6 +392,45 @@ enum th_hdr_fields {
THDR_DPORT,
};
+struct vxlanhdr {
+ uint32_t vx_flags;
+ uint32_t vx_vni;
+};
+
+enum vxlan_hdr_fields {
+ VXLANHDR_INVALID,
+ VXLANHDR_VNI,
+ VXLANHDR_FLAGS,
+};
+
+struct gnvhdr {
+ uint16_t flags;
+ uint16_t type;
+ uint32_t vni;
+};
+enum geneve_hdr_fields {
+ GNVHDR_INVALID,
+ GNVHDR_VNI,
+ GNVHDR_TYPE,
+};
+
+struct grehdr {
+ uint16_t flags;
+ uint16_t protocol;
+};
+
+enum gre_hdr_fields {
+ GREHDR_INVALID,
+ GREHDR_VERSION,
+ GREHDR_FLAGS,
+ GREHDR_PROTOCOL,
+};
+
+extern const struct proto_desc proto_vxlan;
+extern const struct proto_desc proto_geneve;
+extern const struct proto_desc proto_gre;
+extern const struct proto_desc proto_gretap;
+
extern const struct proto_desc proto_icmp;
extern const struct proto_desc proto_igmp;
extern const struct proto_desc proto_ah;
@@ -353,4 +468,7 @@ extern const struct datatype icmp6_type_type;
extern const struct datatype dscp_type;
extern const struct datatype ecn_type;
+struct eval_ctx;
+struct proto_ctx *eval_proto_ctx(struct eval_ctx *ctx);
+
#endif /* NFTABLES_PROTO_H */
diff --git a/include/rbtree.h b/include/rbtree.h
deleted file mode 100644
index ac65283f..00000000
--- a/include/rbtree.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Red Black Trees
- * (C) 1999 Andrea Arcangeli <andrea@suse.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#ifndef NFTABLES_RBTREE_H
-#define NFTABLES_RBTREE_H
-
-#include <stddef.h>
-
-struct rb_node
-{
- unsigned long rb_parent_color;
-#define RB_RED 0
-#define RB_BLACK 1
- struct rb_node *rb_right;
- struct rb_node *rb_left;
-};
-
-struct rb_root
-{
- struct rb_node *rb_node;
-};
-
-#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
-#define rb_color(r) ((r)->rb_parent_color & 1)
-#define rb_is_red(r) (!rb_color(r))
-#define rb_is_black(r) rb_color(r)
-#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
-#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
-
-static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
-{
- rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
-}
-static inline void rb_set_color(struct rb_node *rb, int color)
-{
- rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
-}
-
-#define RB_ROOT (struct rb_root) { NULL, }
-#define rb_entry(ptr, type, member) container_of(ptr, type, member)
-
-#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
-#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
-#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
-
-extern void rb_insert_color(struct rb_node *, struct rb_root *);
-extern void rb_erase(struct rb_node *, struct rb_root *);
-
-/* Find logical next and previous nodes in a tree */
-extern struct rb_node *rb_next(struct rb_node *);
-extern struct rb_node *rb_prev(struct rb_node *);
-extern struct rb_node *rb_first(struct rb_root *);
-extern struct rb_node *rb_last(struct rb_root *);
-
-/* Fast replacement of a single node without remove/rebalance/add/rebalance */
-extern void rb_replace_node(struct rb_node *victim, struct rb_node *new,
- struct rb_root *root);
-
-static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
- struct rb_node ** rb_link)
-{
- node->rb_parent_color = (unsigned long )parent;
- node->rb_left = node->rb_right = NULL;
-
- *rb_link = node;
-}
-
-#define rb_for_each_entry(pos, root, member) \
- for ((pos) = (root)->rb_node ? \
- rb_entry(rb_first(root), typeof(*pos), member) : NULL; \
- (pos) != NULL; \
- (pos) = rb_entry(rb_next(&(pos)->member), typeof(*pos), member))
-
-#define rb_for_each_entry_safe(pos, node, next, root, member) \
- for ((node) = rb_first(root); \
- (pos) = (node) ? rb_entry((node), typeof(*pos), member) : NULL, \
- (next) = (node) ? rb_next(node) : NULL, \
- (pos) != NULL; \
- (node) = (next))
-
-#endif /* NFTABLES_RBTREE_H */
diff --git a/include/rule.h b/include/rule.h
index 2708cbeb..3a833cf3 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -1,12 +1,12 @@
#ifndef NFTABLES_RULE_H
#define NFTABLES_RULE_H
-#include <stdint.h>
#include <nftables.h>
#include <list.h>
#include <netinet/in.h>
#include <libnftnl/object.h> /* For NFTNL_CTTIMEOUT_ARRAY_MAX. */
#include <linux/netfilter/nf_tables.h>
+#include <cache.h>
/**
* struct handle_spec - handle ID
@@ -45,6 +45,11 @@ struct set_spec {
const char *name;
};
+struct flowtable_spec {
+ struct location location;
+ const char *name;
+};
+
struct obj_spec {
struct location location;
const char *name;
@@ -69,11 +74,12 @@ struct handle {
struct chain_spec chain;
struct set_spec set;
struct obj_spec obj;
- const char *flowtable;
+ struct flowtable_spec flowtable;
struct handle_spec handle;
struct position_spec position;
struct position_spec index;
uint32_t set_id;
+ uint32_t chain_id;
uint32_t rule_id;
uint32_t position_id;
};
@@ -92,8 +98,10 @@ struct scope {
struct list_head symbols;
};
+extern struct scope *scope_alloc(void);
extern struct scope *scope_init(struct scope *scope, const struct scope *parent);
extern void scope_release(const struct scope *scope);
+extern void scope_free(struct scope *scope);
/**
* struct symbol
@@ -121,10 +129,11 @@ struct symbol *symbol_get(const struct scope *scope, const char *identifier);
enum table_flags {
TABLE_F_DORMANT = (1 << 0),
+ TABLE_F_OWNER = (1 << 1),
};
-#define TABLE_FLAGS_MAX 1
+#define TABLE_FLAGS_MAX 2
-extern const char *table_flags_name[TABLE_FLAGS_MAX];
+const char *table_flag_name(uint32_t flag);
/**
* struct table - nftables table
@@ -141,23 +150,29 @@ extern const char *table_flags_name[TABLE_FLAGS_MAX];
*/
struct table {
struct list_head list;
+ struct cache_item cache;
struct handle handle;
struct location location;
struct scope scope;
+ struct cache chain_cache;
+ struct cache set_cache;
+ struct cache obj_cache;
+ struct cache ft_cache;
struct list_head chains;
struct list_head sets;
struct list_head objs;
struct list_head flowtables;
+ struct list_head chain_bindings;
enum table_flags flags;
unsigned int refcnt;
+ uint32_t owner;
+ const char *comment;
+ bool has_xt_stmts;
};
extern struct table *table_alloc(void);
extern struct table *table_get(struct table *table);
extern void table_free(struct table *table);
-extern void table_add_hash(struct table *table, struct nft_cache *cache);
-extern struct table *table_lookup(const struct handle *h,
- const struct nft_cache *cache);
extern struct table *table_lookup_fuzzy(const struct handle *h,
const struct nft_cache *cache);
@@ -168,6 +183,16 @@ extern struct table *table_lookup_fuzzy(const struct handle *h,
*/
enum chain_flags {
CHAIN_F_BASECHAIN = 0x1,
+ CHAIN_F_HW_OFFLOAD = 0x2,
+ CHAIN_F_BINDING = 0x4,
+};
+
+/**
+ * enum flowtable_flags - flowtable flags
+ *
+ */
+enum flowtable_flags {
+ FLOWTABLE_F_HW_OFFLOAD = 0x1, /* NF_FLOWTABLE_HW_OFFLOAD in linux nf_flow_table.h */
};
/**
@@ -181,6 +206,17 @@ struct prio_spec {
struct expr *expr;
};
+struct hook_spec {
+ struct location loc;
+ const char *name;
+ unsigned int num;
+};
+
+struct chain_type_spec {
+ struct location loc;
+ const char *str;
+};
+
/**
* struct chain - nftables chain
*
@@ -199,16 +235,22 @@ struct prio_spec {
*/
struct chain {
struct list_head list;
+ struct cache_item cache;
struct handle handle;
struct location location;
unsigned int refcnt;
uint32_t flags;
- const char *hookstr;
- unsigned int hooknum;
- struct prio_spec priority;
- struct expr *policy;
- const char *type;
- const char *dev;
+ const char *comment;
+ struct {
+ struct location loc;
+ struct prio_spec priority;
+ struct hook_spec hook;
+ struct expr *policy;
+ struct chain_type_spec type;
+ const char **dev_array;
+ struct expr *dev_expr;
+ int dev_array_len;
+ };
struct scope scope;
struct list_head rules;
};
@@ -217,21 +259,23 @@ struct chain {
extern int std_prio_lookup(const char *std_prio_name, int family, int hook);
extern const char *chain_type_name_lookup(const char *name);
extern const char *chain_hookname_lookup(const char *name);
-extern struct chain *chain_alloc(const char *name);
+extern struct chain *chain_alloc(void);
extern struct chain *chain_get(struct chain *chain);
extern void chain_free(struct chain *chain);
-extern void chain_add_hash(struct chain *chain, struct table *table);
-extern struct chain *chain_lookup(const struct table *table,
- const struct handle *h);
extern struct chain *chain_lookup_fuzzy(const struct handle *h,
const struct nft_cache *cache,
const struct table **table);
+extern struct chain *chain_binding_lookup(const struct table *table,
+ const char *chain_name);
extern const char *family2str(unsigned int family);
+#define __NF_ARP_INGRESS 255
extern const char *hooknum2str(unsigned int family, unsigned int hooknum);
extern const char *chain_policy2str(uint32_t policy);
extern void chain_print_plain(const struct chain *chain,
struct output_ctx *octx);
+extern void chain_rules_print(const struct chain *chain,
+ struct output_ctx *octx, const char *indent);
/**
* struct rule - nftables rule
@@ -262,6 +306,9 @@ extern void rule_print(const struct rule *rule, struct output_ctx *octx);
extern struct rule *rule_lookup(const struct chain *chain, uint64_t handle);
extern struct rule *rule_lookup_by_index(const struct chain *chain,
uint64_t index);
+void rule_stmt_append(struct rule *rule, struct stmt *stmt);
+void rule_stmt_insert_at(struct rule *rule, struct stmt *nstmt,
+ struct stmt *stmt);
/**
* struct set - nftables set
@@ -274,17 +321,22 @@ extern struct rule *rule_lookup_by_index(const struct chain *chain,
* @gc_int: garbage collection interval
* @timeout: default timeout value
* @key: key expression (data type, length))
- * @datatype: mapping data type
- * @datalen: mapping data len
+ * @data: mapping data expression
* @objtype: mapping object type
+ * @existing_set: reference to existing set in the kernel
* @init: initializer
* @rg_cache: cached range element (left)
* @policy: set mechanism policy
* @automerge: merge adjacents and overlapping elements, if possible
- * @desc: set mechanism desc
+ * @comment: comment
+ * @errors: expr evaluation errors seen
+ * @desc.size: count of set elements
+ * @desc.field_len: length of single concatenated fields, bytes
+ * @desc.field_count: count of concatenated fields
*/
struct set {
struct list_head list;
+ struct cache_item cache;
struct handle handle;
struct location location;
unsigned int refcnt;
@@ -292,15 +344,22 @@ struct set {
uint32_t gc_int;
uint64_t timeout;
struct expr *key;
- const struct datatype *datatype;
- unsigned int datalen;
+ struct expr *data;
uint32_t objtype;
+ struct set *existing_set;
struct expr *init;
struct expr *rg_cache;
uint32_t policy;
+ struct list_head stmt_list;
+ bool root;
bool automerge;
+ bool key_typeof_valid;
+ bool errors;
+ const char *comment;
struct {
uint32_t size;
+ uint8_t field_len[NFT_REG32_COUNT];
+ uint8_t field_count;
} desc;
};
@@ -308,8 +367,6 @@ extern struct set *set_alloc(const struct location *loc);
extern struct set *set_get(struct set *set);
extern void set_free(struct set *set);
extern struct set *set_clone(const struct set *set);
-extern void set_add_hash(struct set *set, struct table *table);
-extern struct set *set_lookup(const struct table *table, const char *name);
extern struct set *set_lookup_global(uint32_t family, const char *table,
const char *name, struct nft_cache *cache);
extern struct set *set_lookup_fuzzy(const char *set_name,
@@ -349,6 +406,26 @@ static inline bool map_is_literal(uint32_t set_flags)
return !(set_is_anonymous(set_flags) || !set_is_map(set_flags));
}
+static inline bool set_is_meter(uint32_t set_flags)
+{
+ return set_is_anonymous(set_flags) && (set_flags & NFT_SET_EVAL);
+}
+
+static inline bool set_is_meter_compat(uint32_t set_flags)
+{
+ return set_flags & NFT_SET_EVAL;
+}
+
+static inline bool set_is_interval(uint32_t set_flags)
+{
+ return set_flags & NFT_SET_INTERVAL;
+}
+
+static inline bool set_is_non_concat_range(struct set *s)
+{
+ return (s->flags & NFT_SET_INTERVAL) && s->desc.field_count <= 1;
+}
+
#include <statement.h>
struct counter {
@@ -420,10 +497,12 @@ struct secmark {
*/
struct obj {
struct list_head list;
+ struct cache_item cache;
struct location location;
struct handle handle;
uint32_t type;
unsigned int refcnt;
+ const char *comment;
union {
struct counter counter;
struct quota quota;
@@ -439,35 +518,35 @@ struct obj {
struct obj *obj_alloc(const struct location *loc);
extern struct obj *obj_get(struct obj *obj);
void obj_free(struct obj *obj);
-void obj_add_hash(struct obj *obj, struct table *table);
-struct obj *obj_lookup(const struct table *table, const char *name,
- uint32_t type);
struct obj *obj_lookup_fuzzy(const char *obj_name,
const struct nft_cache *cache,
const struct table **t);
void obj_print(const struct obj *n, struct output_ctx *octx);
void obj_print_plain(const struct obj *obj, struct output_ctx *octx);
const char *obj_type_name(uint32_t type);
-uint32_t obj_type_to_cmd(uint32_t type);
+enum cmd_obj obj_type_to_cmd(uint32_t type);
struct flowtable {
struct list_head list;
+ struct cache_item cache;
struct handle handle;
struct scope scope;
struct location location;
- const char * hookstr;
- unsigned int hooknum;
+ struct hook_spec hook;
struct prio_spec priority;
const char **dev_array;
struct expr *dev_expr;
int dev_array_len;
+ uint32_t flags;
unsigned int refcnt;
};
extern struct flowtable *flowtable_alloc(const struct location *loc);
extern struct flowtable *flowtable_get(struct flowtable *flowtable);
extern void flowtable_free(struct flowtable *flowtable);
-extern void flowtable_add_hash(struct flowtable *flowtable, struct table *table);
+extern struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
+ const struct nft_cache *cache,
+ const struct table **table);
void flowtable_print(const struct flowtable *n, struct output_ctx *octx);
@@ -489,6 +568,7 @@ void flowtable_print(const struct flowtable *n, struct output_ctx *octx);
* @CMD_EXPORT: export the ruleset in a given format
* @CMD_MONITOR: event listener
* @CMD_DESCRIBE: describe an expression
+ * @CMD_DESTROY: destroy object
*/
enum cmd_ops {
CMD_INVALID,
@@ -506,15 +586,17 @@ enum cmd_ops {
CMD_EXPORT,
CMD_MONITOR,
CMD_DESCRIBE,
+ CMD_DESTROY,
};
/**
* enum cmd_obj - command objects
*
* @CMD_OBJ_INVALID: invalid
- * @CMD_OBJ_SETELEM: set element(s)
+ * @CMD_OBJ_ELEMENTS: set element(s)
* @CMD_OBJ_SET: set
* @CMD_OBJ_SETS: multiple sets
+ * @CMD_OBJ_SETELEMS: set elements
* @CMD_OBJ_RULE: rule
* @CMD_OBJ_CHAIN: chain
* @CMD_OBJ_CHAINS: multiple chains
@@ -533,7 +615,6 @@ enum cmd_ops {
* @CMD_OBJ_QUOTAS: multiple quotas
* @CMD_OBJ_LIMIT: limit
* @CMD_OBJ_LIMITS: multiple limits
- * @CMD_OBJ_FLOWTABLES: flow tables
* @CMD_OBJ_SECMARK: secmark
* @CMD_OBJ_SECMARKS: multiple secmarks
* @CMD_OBJ_SYNPROXY: synproxy
@@ -541,10 +622,12 @@ enum cmd_ops {
*/
enum cmd_obj {
CMD_OBJ_INVALID,
- CMD_OBJ_SETELEM,
+ CMD_OBJ_ELEMENTS,
CMD_OBJ_SET,
+ CMD_OBJ_SETELEMS,
CMD_OBJ_SETS,
CMD_OBJ_RULE,
+ CMD_OBJ_RULES,
CMD_OBJ_CHAIN,
CMD_OBJ_CHAINS,
CMD_OBJ_TABLE,
@@ -567,11 +650,14 @@ enum cmd_obj {
CMD_OBJ_FLOWTABLE,
CMD_OBJ_FLOWTABLES,
CMD_OBJ_CT_TIMEOUT,
+ CMD_OBJ_CT_TIMEOUTS,
CMD_OBJ_SECMARK,
CMD_OBJ_SECMARKS,
CMD_OBJ_CT_EXPECT,
+ CMD_OBJ_CT_EXPECTATIONS,
CMD_OBJ_SYNPROXY,
CMD_OBJ_SYNPROXYS,
+ CMD_OBJ_HOOKS,
};
struct markup {
@@ -604,6 +690,13 @@ struct monitor {
struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event);
void monitor_free(struct monitor *m);
+#define NFT_NLATTR_LOC_MAX 32
+
+struct nlerr_loc {
+ uint16_t offset;
+ const struct location *location;
+};
+
/**
* struct cmd - command statement
*
@@ -623,10 +716,15 @@ struct cmd {
enum cmd_obj obj;
struct handle handle;
uint32_t seqnum;
+ struct list_head collapse_list;
union {
void *data;
struct expr *expr;
struct set *set;
+ struct {
+ struct expr *expr; /* same offset as cmd->expr */
+ struct set *set;
+ } elem;
struct rule *rule;
struct chain *chain;
struct table *table;
@@ -635,13 +733,15 @@ struct cmd {
struct markup *markup;
struct obj *object;
};
+ struct nlerr_loc *attr;
+ uint32_t attr_array_len;
+ uint32_t num_attrs;
const void *arg;
};
extern struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
const struct handle *h, const struct location *loc,
void *data);
-extern void nft_cmd_expand(struct cmd *cmd);
extern struct cmd *cmd_alloc_obj_ct(enum cmd_ops op, int type,
const struct handle *h,
const struct location *loc, struct obj *obj);
@@ -660,10 +760,13 @@ extern void cmd_free(struct cmd *cmd);
* @rule: current rule
* @set: current set
* @stmt: current statement
+ * @stmt_len: current statement template length
+ * @recursion: expr evaluation recursion counter
* @cache: cache context
* @debug_mask: debugging bitmask
* @ectx: expression context
- * @pctx: payload context
+ * @_pctx: payload contexts
+ * @inner_desc: inner header description
*/
struct eval_ctx {
struct nft_ctx *nft;
@@ -673,8 +776,11 @@ struct eval_ctx {
struct rule *rule;
struct set *set;
struct stmt *stmt;
+ uint32_t stmt_len;
+ uint32_t recursion;
struct expr_ctx ectx;
- struct proto_ctx pctx;
+ struct proto_ctx _pctx[2];
+ const struct proto_desc *inner_desc;
};
extern int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd);
@@ -684,19 +790,13 @@ extern struct error_record *rule_postprocess(struct rule *rule);
struct netlink_ctx;
extern int do_command(struct netlink_ctx *ctx, struct cmd *cmd);
-extern unsigned int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds);
-extern int cache_update(struct nft_ctx *ctx, enum cmd_ops cmd,
- struct list_head *msgs);
-extern bool cache_needs_update(struct nft_cache *cache);
-extern void cache_release(struct nft_cache *cache);
-
struct timeout_protocol {
uint32_t array_size;
const char *const *state_to_name;
uint32_t *dflt_timeout;
};
-extern struct timeout_protocol timeout_protocol[IPPROTO_MAX];
+extern struct timeout_protocol timeout_protocol[UINT8_MAX + 1];
extern int timeout_str2num(uint16_t l4proto, struct timeout_state *ts);
#endif /* NFTABLES_RULE_H */
diff --git a/include/sctp_chunk.h b/include/sctp_chunk.h
new file mode 100644
index 00000000..3819200f
--- /dev/null
+++ b/include/sctp_chunk.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright Red Hat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#ifndef NFTABLES_SCTP_CHUNK_H
+#define NFTABLES_SCTP_CHUNK_H
+
+/* SCTP chunk types used on wire */
+enum sctp_hdr_chunk_types {
+ SCTP_CHUNK_TYPE_DATA = 0,
+ SCTP_CHUNK_TYPE_INIT = 1,
+ SCTP_CHUNK_TYPE_INIT_ACK = 2,
+ SCTP_CHUNK_TYPE_SACK = 3,
+ SCTP_CHUNK_TYPE_HEARTBEAT = 4,
+ SCTP_CHUNK_TYPE_HEARTBEAT_ACK = 5,
+ SCTP_CHUNK_TYPE_ABORT = 6,
+ SCTP_CHUNK_TYPE_SHUTDOWN = 7,
+ SCTP_CHUNK_TYPE_SHUTDOWN_ACK = 8,
+ SCTP_CHUNK_TYPE_ERROR = 9,
+ SCTP_CHUNK_TYPE_COOKIE_ECHO = 10,
+ SCTP_CHUNK_TYPE_COOKIE_ACK = 11,
+ SCTP_CHUNK_TYPE_ECNE = 12,
+ SCTP_CHUNK_TYPE_CWR = 13,
+ SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE = 14,
+ SCTP_CHUNK_TYPE_ASCONF_ACK = 128,
+ SCTP_CHUNK_TYPE_FORWARD_TSN = 192,
+ SCTP_CHUNK_TYPE_ASCONF = 193,
+};
+
+enum sctp_hdr_chunk_common_fields {
+ SCTP_CHUNK_COMMON_TYPE,
+ SCTP_CHUNK_COMMON_FLAGS,
+ SCTP_CHUNK_COMMON_LENGTH,
+ __SCTP_CHUNK_COMMON_MAX,
+};
+
+#define SCTP_CHUNK_START_INDEX __SCTP_CHUNK_COMMON_MAX
+
+enum sctp_hdr_chunk_data_fields {
+ SCTP_CHUNK_DATA_TSN = SCTP_CHUNK_START_INDEX,
+ SCTP_CHUNK_DATA_STREAM,
+ SCTP_CHUNK_DATA_SSN,
+ SCTP_CHUNK_DATA_PPID,
+};
+
+enum sctp_hdr_chunk_init_fields {
+ SCTP_CHUNK_INIT_TAG = SCTP_CHUNK_START_INDEX,
+ SCTP_CHUNK_INIT_RWND,
+ SCTP_CHUNK_INIT_OSTREAMS,
+ SCTP_CHUNK_INIT_ISTREAMS,
+ SCTP_CHUNK_INIT_TSN,
+};
+
+enum sctp_hdr_chunk_sack_fields {
+ SCTP_CHUNK_SACK_CTSN_ACK = SCTP_CHUNK_START_INDEX,
+ SCTP_CHUNK_SACK_RWND,
+ SCTP_CHUNK_SACK_GACK_BLOCKS,
+ SCTP_CHUNK_SACK_DUP_TSNS,
+};
+
+enum sctp_hdr_chunk_shutdown_fields {
+ SCTP_CHUNK_SHUTDOWN_CTSN_ACK = SCTP_CHUNK_START_INDEX,
+};
+
+enum sctp_hdr_chunk_ecne_cwr_fields {
+ SCTP_CHUNK_ECNE_CWR_MIN_TSN = SCTP_CHUNK_START_INDEX,
+};
+
+enum sctp_hdr_chunk_asconf_fields {
+ SCTP_CHUNK_ASCONF_SEQNO = SCTP_CHUNK_START_INDEX,
+};
+
+enum sctp_hdr_chunk_fwd_tsn_fields {
+ SCTP_CHUNK_FORWARD_TSN_NCTSN = SCTP_CHUNK_START_INDEX,
+};
+
+struct expr *sctp_chunk_expr_alloc(const struct location *loc,
+ unsigned int type, unsigned int field);
+void sctp_chunk_init_raw(struct expr *expr, uint8_t type, unsigned int off,
+ unsigned int len, uint32_t flags);
+const struct exthdr_desc *sctp_chunk_protocol_find(const char *name);
+
+#endif /* NFTABLES_SCTP_CHUNK_H */
diff --git a/include/socket.h b/include/socket.h
index fbfddd11..79938ccf 100644
--- a/include/socket.h
+++ b/include/socket.h
@@ -19,6 +19,6 @@ struct socket_template {
extern const struct socket_template socket_templates[];
extern struct expr *socket_expr_alloc(const struct location *loc,
- enum nft_socket_keys key);
+ enum nft_socket_keys key, uint32_t level);
#endif /* NFTABLES_SOCKET_H */
diff --git a/include/statement.h b/include/statement.h
index 585908de..662f99dd 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -11,6 +11,14 @@ extern struct stmt *expr_stmt_alloc(const struct location *loc,
extern struct stmt *verdict_stmt_alloc(const struct location *loc,
struct expr *expr);
+struct chain_stmt {
+ struct chain *chain;
+ struct expr *expr;
+};
+
+struct stmt *chain_stmt_alloc(const struct location *loc, struct chain *chain,
+ enum nft_verdicts verdict);
+
struct flow_stmt {
const char *table_name;
};
@@ -39,6 +47,13 @@ struct counter_stmt {
extern struct stmt *counter_stmt_alloc(const struct location *loc);
+struct last_stmt {
+ uint64_t used;
+ uint32_t set;
+};
+
+extern struct stmt *last_stmt_alloc(const struct location *loc);
+
struct exthdr_stmt {
struct expr *expr;
struct expr *val;
@@ -75,7 +90,7 @@ enum {
};
struct log_stmt {
- const char *prefix;
+ struct expr *prefix;
unsigned int snaplen;
uint16_t group;
uint16_t qthreshold;
@@ -119,17 +134,30 @@ enum nft_nat_etypes {
extern const char *nat_etype2str(enum nft_nat_etypes type);
+enum {
+ STMT_NAT_F_INTERVAL = (1 << 0),
+ STMT_NAT_F_PREFIX = (1 << 1),
+ STMT_NAT_F_CONCAT = (1 << 2),
+};
+
struct nat_stmt {
enum nft_nat_etypes type;
struct expr *addr;
struct expr *proto;
uint32_t flags;
uint8_t family;
+ uint32_t type_flags;
};
extern struct stmt *nat_stmt_alloc(const struct location *loc,
enum nft_nat_etypes type);
+struct optstrip_stmt {
+ struct expr *expr;
+};
+
+extern struct stmt *optstrip_stmt_alloc(const struct location *loc, struct expr *e);
+
struct tproxy_stmt {
struct expr *addr;
struct expr *port;
@@ -144,7 +172,8 @@ struct queue_stmt {
uint16_t flags;
};
-extern struct stmt *queue_stmt_alloc(const struct location *loc);
+extern struct stmt *queue_stmt_alloc(const struct location *loc,
+ struct expr *e, uint16_t flags);
struct quota_stmt {
uint64_t bytes;
@@ -186,7 +215,7 @@ uint32_t fwd_stmt_type(const char *type);
struct set_stmt {
struct expr *set;
struct expr *key;
- struct stmt *stmt;
+ struct list_head stmt_list;
enum nft_dynset_ops op;
};
@@ -198,7 +227,7 @@ struct map_stmt {
struct expr *set;
struct expr *key;
struct expr *data;
- struct stmt *stmt;
+ struct list_head stmt_list;
enum nft_dynset_ops op;
};
@@ -233,8 +262,8 @@ enum nft_xt_type {
NFT_XT_MATCH = 0,
NFT_XT_TARGET,
NFT_XT_WATCHER,
- NFT_XT_MAX
};
+#define NFT_XT_MAX (NFT_XT_WATCHER + 1)
struct xtables_match;
struct xtables_target;
@@ -242,12 +271,11 @@ struct xtables_target;
struct xt_stmt {
const char *name;
enum nft_xt_type type;
+ uint32_t rev;
+ uint32_t family;
+ size_t infolen;
+ void *info;
uint32_t proto;
- union {
- struct xtables_match *match;
- struct xtables_target *target;
- };
- void *entry;
};
extern struct stmt *xt_stmt_alloc(const struct location *loc);
@@ -280,6 +308,9 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc);
* @STMT_CONNLIMIT: connection limit statement
* @STMT_MAP: map statement
* @STMT_SYNPROXY: synproxy statement
+ * @STMT_CHAIN: chain statement
+ * @STMT_OPTSTRIP: optstrip statement
+ * @STMT_LAST: last statement
*/
enum stmt_types {
STMT_INVALID,
@@ -308,6 +339,9 @@ enum stmt_types {
STMT_CONNLIMIT,
STMT_MAP,
STMT_SYNPROXY,
+ STMT_CHAIN,
+ STMT_OPTSTRIP,
+ STMT_LAST,
};
/**
@@ -357,11 +391,13 @@ struct stmt {
struct counter_stmt counter;
struct payload_stmt payload;
struct meta_stmt meta;
+ struct last_stmt last;
struct log_stmt log;
struct limit_stmt limit;
struct reject_stmt reject;
struct nat_stmt nat;
struct tproxy_stmt tproxy;
+ struct optstrip_stmt optstrip;
struct queue_stmt queue;
struct quota_stmt quota;
struct ct_stmt ct;
@@ -373,12 +409,14 @@ struct stmt {
struct flow_stmt flow;
struct map_stmt map;
struct synproxy_stmt synproxy;
+ struct chain_stmt chain;
};
};
extern struct stmt *stmt_alloc(const struct location *loc,
const struct stmt_ops *ops);
int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt);
+int stmt_dependency_evaluate(struct eval_ctx *ctx, struct stmt *stmt);
extern void stmt_free(struct stmt *stmt);
extern void stmt_list_free(struct list_head *list);
extern void stmt_print(const struct stmt *stmt, struct output_ctx *octx);
diff --git a/include/tcpopt.h b/include/tcpopt.h
index ffdbcb02..3a0b8424 100644
--- a/include/tcpopt.h
+++ b/include/tcpopt.h
@@ -6,44 +6,80 @@
#include <statement.h>
extern struct expr *tcpopt_expr_alloc(const struct location *loc,
- uint8_t type, uint8_t field);
+ unsigned int kind, unsigned int field);
extern void tcpopt_init_raw(struct expr *expr, uint8_t type,
unsigned int offset, unsigned int len,
uint32_t flags);
-extern bool tcpopt_find_template(struct expr *expr, const struct expr *mask,
- unsigned int *shift);
-
-enum tcpopt_hdr_types {
- TCPOPTHDR_INVALID,
- TCPOPTHDR_EOL,
- TCPOPTHDR_NOOP,
- TCPOPTHDR_MAXSEG,
- TCPOPTHDR_WINDOW,
- TCPOPTHDR_SACK_PERMITTED,
- TCPOPTHDR_SACK0,
- TCPOPTHDR_SACK1,
- TCPOPTHDR_SACK2,
- TCPOPTHDR_SACK3,
- TCPOPTHDR_TIMESTAMP,
- TCPOPTHDR_ECHO,
- TCPOPTHDR_ECHO_REPLY,
- __TCPOPTHDR_MAX
+extern bool tcpopt_find_template(struct expr *expr, unsigned int offset,
+ unsigned int len);
+
+/* TCP option numbers used on wire */
+enum tcpopt_kind {
+ TCPOPT_KIND_EOL = 0,
+ TCPOPT_KIND_NOP = 1,
+ TCPOPT_KIND_MAXSEG = 2,
+ TCPOPT_KIND_WINDOW = 3,
+ TCPOPT_KIND_SACK_PERMITTED = 4,
+ TCPOPT_KIND_SACK = 5,
+ TCPOPT_KIND_TIMESTAMP = 8,
+ TCPOPT_KIND_ECHO = 8,
+ TCPOPT_KIND_MD5SIG = 19,
+ TCPOPT_KIND_MPTCP = 30,
+ TCPOPT_KIND_FASTOPEN = 34,
+ __TCPOPT_KIND_MAX,
+
+ /* extra oob info, internal to nft */
+ TCPOPT_KIND_SACK1 = 256,
+ TCPOPT_KIND_SACK2 = 257,
+ TCPOPT_KIND_SACK3 = 258,
+};
+
+/* Internal identifiers */
+enum tcpopt_common {
+ TCPOPT_COMMON_KIND,
+ TCPOPT_COMMON_LENGTH,
+};
+
+enum tcpopt_maxseg {
+ TCPOPT_MAXSEG_KIND,
+ TCPOPT_MAXSEG_LENGTH,
+ TCPOPT_MAXSEG_SIZE,
+};
+
+enum tcpopt_timestamp {
+ TCPOPT_TS_KIND,
+ TCPOPT_TS_LENGTH,
+ TCPOPT_TS_TSVAL,
+ TCPOPT_TS_TSECR,
+};
+
+enum tcpopt_windowscale {
+ TCPOPT_WINDOW_KIND,
+ TCPOPT_WINDOW_LENGTH,
+ TCPOPT_WINDOW_COUNT,
+};
+
+enum tcpopt_hdr_field_sack {
+ TCPOPT_SACK_KIND,
+ TCPOPT_SACK_LENGTH,
+ TCPOPT_SACK_LEFT,
+ TCPOPT_SACK_RIGHT,
+ TCPOPT_SACK_LEFT1,
+ TCPOPT_SACK_RIGHT1,
+ TCPOPT_SACK_LEFT2,
+ TCPOPT_SACK_RIGHT2,
+ TCPOPT_SACK_LEFT3,
+ TCPOPT_SACK_RIGHT3,
};
-enum tcpopt_hdr_fields {
- TCPOPTHDR_FIELD_INVALID,
- TCPOPTHDR_FIELD_KIND,
- TCPOPTHDR_FIELD_LENGTH,
- TCPOPTHDR_FIELD_SIZE,
- TCPOPTHDR_FIELD_COUNT,
- TCPOPTHDR_FIELD_LEFT,
- TCPOPTHDR_FIELD_RIGHT,
- TCPOPTHDR_FIELD_TSVAL,
- TCPOPTHDR_FIELD_TSECR,
+enum tcpopt_hdr_mptcp_common {
+ TCPOPT_MPTCP_KIND,
+ TCPOPT_MPTCP_LENGTH,
+ TCPOPT_MPTCP_SUBTYPE,
};
-extern const struct exthdr_desc *tcpopthdr_protocols[__TCPOPTHDR_MAX];
+extern const struct exthdr_desc *tcpopt_protocols[__TCPOPT_KIND_MAX];
#endif /* NFTABLES_TCPOPT_H */
diff --git a/include/utils.h b/include/utils.h
index 647e8bbe..e18fabec 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -2,8 +2,6 @@
#define NFTABLES_UTILS_H
#include <asm/byteorder.h>
-#include <stdint.h>
-#include <stdbool.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
@@ -11,7 +9,6 @@
#include <list.h>
#include <gmputil.h>
-#include "config.h"
#ifdef HAVE_VISIBILITY_HIDDEN
# define __visible __attribute__((visibility("default")))
# define EXPORT_SYMBOL(x) typeof(x) (x) __visible;
@@ -39,7 +36,7 @@
#define __must_check __attribute__((warn_unused_result))
#define __noreturn __attribute__((__noreturn__))
-#define BUG(fmt, arg...) ({ fprintf(stderr, "BUG: " fmt, ##arg); assert(0); })
+#define BUG(fmt, arg...) ({ fprintf(stderr, "BUG: " fmt, ##arg); assert(0); abort(); })
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))
#define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1)
@@ -75,15 +72,32 @@
#define max(_x, _y) ({ \
_x > _y ? _x : _y; })
-#define SNPRINTF_BUFFER_SIZE(ret, size, len, offset) \
- if (ret < 0) \
- abort(); \
- offset += ret; \
- assert(ret < len); \
- if (ret > len) \
- ret = len; \
- size += ret; \
- len -= ret;
+#define SNPRINTF_BUFFER_SIZE(ret, len, offset) \
+ ({ \
+ const int _ret = (ret); \
+ size_t *const _len = (len); \
+ size_t *const _offset = (offset); \
+ bool _not_truncated = true; \
+ size_t _ret2; \
+ \
+ assert(_ret >= 0); \
+ \
+ if ((size_t) _ret >= *_len) { \
+ /* Truncated.
+ *
+ * We will leave "len" at zero and increment
+ * "offset" to point one byte after the buffer
+ * (after the terminating NUL byte). */ \
+ _ret2 = *_len; \
+ _not_truncated = false; \
+ } else \
+ _ret2 = (size_t) _ret; \
+ \
+ *_offset += _ret2; \
+ *_len -= _ret2; \
+ \
+ _not_truncated; \
+ })
#define MSEC_PER_SEC 1000L
@@ -94,7 +108,7 @@
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
-static inline int fls(int x)
+static inline int fls(uint32_t x)
{
int r = 32;
@@ -128,12 +142,13 @@ extern void __memory_allocation_error(const char *filename, uint32_t line) __nor
#define memory_allocation_error() \
__memory_allocation_error(__FILE__, __LINE__);
-extern void xfree(const void *ptr);
extern void *xmalloc(size_t size);
extern void *xmalloc_array(size_t nmemb, size_t size);
extern void *xrealloc(void *ptr, size_t size);
extern void *xzalloc(size_t size);
+extern void *xzalloc_array(size_t nmemb, size_t size);
extern char *xstrdup(const char *s);
extern void xstrunescape(const char *in, char *out);
+extern int round_pow_2(unsigned int value);
#endif /* NFTABLES_UTILS_H */
diff --git a/py/Makefile.am b/py/Makefile.am
deleted file mode 100644
index 215ecd9e..00000000
--- a/py/Makefile.am
+++ /dev/null
@@ -1,28 +0,0 @@
-EXTRA_DIST = setup.py __init__.py nftables.py schema.json
-
-all-local:
- cd $(srcdir) && \
- $(PYTHON_BIN) setup.py build --build-base $(abs_builddir)
-
-install-exec-local:
- cd $(srcdir) && \
- $(PYTHON_BIN) setup.py build --build-base $(abs_builddir) \
- install --prefix $(DESTDIR)$(prefix)
-
-uninstall-local:
- rm -rf $(DESTDIR)$(prefix)/lib*/python*/site-packages/nftables
- rm -rf $(DESTDIR)$(prefix)/lib*/python*/dist-packages/nftables
- rm -rf $(DESTDIR)$(prefix)/lib*/python*/site-packages/nftables-[0-9]*.egg-info
- rm -rf $(DESTDIR)$(prefix)/lib*/python*/dist-packages/nftables-[0-9]*.egg-info
- rm -rf $(DESTDIR)$(prefix)/lib*/python*/site-packages/nftables-[0-9]*.egg
- rm -rf $(DESTDIR)$(prefix)/lib*/python*/dist-packages/nftables-[0-9]*.egg
-
-clean-local:
- cd $(srcdir) && \
- $(PYTHON_BIN) setup.py clean \
- --build-base $(abs_builddir)
- rm -rf scripts-* lib* build dist bdist.* nftables.egg-info
- find . -name \*.pyc -delete
-
-distclean-local:
- rm -f version
diff --git a/py/pyproject.toml b/py/pyproject.toml
new file mode 100644
index 00000000..fed528d4
--- /dev/null
+++ b/py/pyproject.toml
@@ -0,0 +1,3 @@
+[build-system]
+requires = ["setuptools"]
+build-backend = "setuptools.build_meta"
diff --git a/py/setup.cfg b/py/setup.cfg
new file mode 100644
index 00000000..953b7f41
--- /dev/null
+++ b/py/setup.cfg
@@ -0,0 +1,24 @@
+[metadata]
+name = nftables
+version = attr: nftables.NFTABLES_VERSION
+description = Libnftables binding
+author = Netfilter project
+author_email = coreteam@netfilter.org
+url = https://netfilter.org/projects/nftables/index.html
+provides = nftables
+classifiers =
+ Development Status :: 4 - Beta
+ Environment :: Console
+ Intended Audience :: Developers
+ License :: OSI Approved :: GNU General Public License v2 (GPLv2)
+ Operating System :: POSIX :: Linux
+ Programming Language :: Python
+ Topic :: System :: Networking :: Firewalls
+
+[options]
+packages = nftables
+package_dir =
+ nftables = src
+
+[options.package_data]
+nftables = schema.json
diff --git a/py/setup.py b/py/setup.py
index 72fc8fd9..beda28e8 100755
--- a/py/setup.py
+++ b/py/setup.py
@@ -1,24 +1,5 @@
#!/usr/bin/env python
-from distutils.core import setup
-from nftables import NFTABLES_VERSION
-setup(name='nftables',
- version=NFTABLES_VERSION,
- description='Libnftables binding',
- author='Netfilter project',
- author_email='coreteam@netfilter.org',
- url='https://netfilter.org/projects/nftables/index.html',
- packages=['nftables'],
- provides=['nftables'],
- package_dir={'nftables':'.'},
- package_data={'nftables':['schema.json']},
- classifiers=[
- 'Development Status :: 4 - Beta',
- 'Environment :: Console',
- 'Intended Audience :: Developers',
- 'License :: OSI Approved :: GNU General Public License v2 (GPLv2)',
- 'Operating System :: POSIX :: Linux',
- 'Programming Language :: Python',
- 'Topic :: System :: Networking :: Firewalls',
- ],
- )
+from setuptools import setup
+
+setup()
diff --git a/py/__init__.py b/py/src/__init__.py
index 7567f095..7567f095 100644
--- a/py/__init__.py
+++ b/py/src/__init__.py
diff --git a/py/nftables.py b/py/src/nftables.py
index 81e57567..f1e43ade 100644
--- a/py/nftables.py
+++ b/py/src/nftables.py
@@ -37,6 +37,11 @@ class SchemaValidator:
class Nftables:
"""A class representing libnftables interface"""
+ input_flags = {
+ "no-dns": 0x1,
+ "json": 0x2,
+ }
+
debug_flags = {
"scanner": 0x1,
"parser": 0x2,
@@ -58,11 +63,13 @@ class Nftables:
"numeric_proto": (1 << 7),
"numeric_prio": (1 << 8),
"numeric_symbol": (1 << 9),
+ "numeric_time": (1 << 10),
+ "terse": (1 << 11),
}
validator = None
- def __init__(self, sofile="libnftables.so"):
+ def __init__(self, sofile="libnftables.so.1"):
"""Instantiate a new Nftables class object.
Accepts a shared object file to open, by default standard search path
@@ -72,6 +79,8 @@ class Nftables:
is requested from the library and buffering of output and error streams
is turned on.
"""
+ self.__ctx = None
+
lib = cdll.LoadLibrary(sofile)
### API function definitions
@@ -80,6 +89,14 @@ class Nftables:
self.nft_ctx_new.restype = c_void_p
self.nft_ctx_new.argtypes = [c_int]
+ self.nft_ctx_input_get_flags = lib.nft_ctx_input_get_flags
+ self.nft_ctx_input_get_flags.restype = c_uint
+ self.nft_ctx_input_get_flags.argtypes = [c_void_p]
+
+ self.nft_ctx_input_set_flags = lib.nft_ctx_input_set_flags
+ self.nft_ctx_input_set_flags.restype = c_uint
+ self.nft_ctx_input_set_flags.argtypes = [c_void_p, c_uint]
+
self.nft_ctx_output_get_flags = lib.nft_ctx_output_get_flags
self.nft_ctx_output_get_flags.restype = c_uint
self.nft_ctx_output_get_flags.argtypes = [c_void_p]
@@ -114,6 +131,31 @@ class Nftables:
self.nft_run_cmd_from_buffer.restype = c_int
self.nft_run_cmd_from_buffer.argtypes = [c_void_p, c_char_p]
+ self.nft_run_cmd_from_filename = lib.nft_run_cmd_from_filename
+ self.nft_run_cmd_from_filename.restype = c_int
+ self.nft_run_cmd_from_filename.argtypes = [c_void_p, c_char_p]
+
+ self.nft_ctx_add_include_path = lib.nft_ctx_add_include_path
+ self.nft_ctx_add_include_path.restype = c_int
+ self.nft_ctx_add_include_path.argtypes = [c_void_p, c_char_p]
+
+ self.nft_ctx_clear_include_paths = lib.nft_ctx_clear_include_paths
+ self.nft_ctx_clear_include_paths.argtypes = [c_void_p]
+
+ self.nft_ctx_get_dry_run = lib.nft_ctx_get_dry_run
+ self.nft_ctx_get_dry_run.restype = c_bool
+ self.nft_ctx_get_dry_run.argtypes = [c_void_p]
+
+ self.nft_ctx_set_dry_run = lib.nft_ctx_set_dry_run
+ self.nft_ctx_set_dry_run.argtypes = [c_void_p, c_bool]
+
+ self.nft_ctx_add_var = lib.nft_ctx_add_var
+ self.nft_ctx_add_var.restype = c_int
+ self.nft_ctx_add_var.argtypes = [c_void_p, c_char_p]
+
+ self.nft_ctx_clear_vars = lib.nft_ctx_clear_vars
+ self.nft_ctx_clear_vars.argtypes = [c_void_p]
+
self.nft_ctx_free = lib.nft_ctx_free
lib.nft_ctx_free.argtypes = [c_void_p]
@@ -123,11 +165,72 @@ class Nftables:
self.nft_ctx_buffer_error(self.__ctx)
def __del__(self):
- self.nft_ctx_free(self.__ctx)
+ if self.__ctx is not None:
+ self.nft_ctx_free(self.__ctx)
+ self.__ctx = None
+
+ def _flags_from_numeric(self, flags_dict, val):
+ names = []
+ for n, v in flags_dict.items():
+ if val & v:
+ names.append(n)
+ val &= ~v
+ if val:
+ names.append(val)
+ return names
+
+ def _flags_to_numeric(self, flags_dict, values):
+ if isinstance(values, (str, int)):
+ values = (values,)
+
+ val = 0
+ for v in values:
+ if isinstance(v, str):
+ v = flags_dict.get(v)
+ if v is None:
+ raise ValueError("Invalid argument")
+ elif isinstance(v, int):
+ if v < 0 or v > 0xFFFFFFFF:
+ raise ValueError("Invalid argument")
+ else:
+ raise TypeError("Not a valid flag")
+ val |= v
+
+ return val
+
+ def get_input_flags(self):
+ """Get currently active input flags.
+
+ Returns a set of flag names. See set_input_flags() for details.
+ """
+ val = self.nft_ctx_input_get_flags(self.__ctx)
+ return self._flags_from_numeric(self.input_flags, val)
+
+ def set_input_flags(self, values):
+ """Set input flags.
+
+ Resets all input flags to values. Accepts either a single flag or a list
+ of flags. Each flag might be given either as string or integer value as
+ shown in the following table:
+
+ Name | Value (hex)
+ -----------------------
+ "no-dns" | 0x1
+ "json" | 0x2
+
+ "no-dns" disables blocking address lookup.
+ "json" enables JSON mode for input.
+
+ Returns a set of previously active input flags, as returned by
+ get_input_flags() method.
+ """
+ val = self._flags_to_numeric(self.input_flags, values)
+ old = self.nft_ctx_input_set_flags(self.__ctx, val)
+ return self._flags_from_numeric(self.input_flags, old)
def __get_output_flag(self, name):
flag = self.output_flags[name]
- return self.nft_ctx_output_get_flags(self.__ctx) & flag
+ return (self.nft_ctx_output_get_flags(self.__ctx) & flag) != 0
def __set_output_flag(self, name, val):
flag = self.output_flags[name]
@@ -137,7 +240,7 @@ class Nftables:
else:
new_flags = flags & ~flag
self.nft_ctx_output_set_flags(self.__ctx, new_flags)
- return flags & flag
+ return (flags & flag) != 0
def get_reversedns_output(self):
"""Get the current state of reverse DNS output.
@@ -305,22 +408,46 @@ class Nftables:
"""
return self.__set_output_flag("numeric_symbol", val)
+ def get_numeric_time_output(self):
+ """Get current status of numeric times output flag.
+
+ Returns a boolean value indicating the status.
+ """
+ return self.__get_output_flag("numeric_time")
+
+ def set_numeric_time_output(self, val):
+ """Set numeric times output flag.
+
+ Accepts a boolean turning numeric representation of time values
+ in output either on or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("numeric_time", val)
+
+ def get_terse_output(self):
+ """Get the current state of terse output.
+
+ Returns a boolean indicating whether terse output is active or not.
+ """
+ return self.__get_output_flag("terse")
+
+ def set_terse_output(self, val):
+ """Enable or disable terse output.
+
+ Accepts a boolean turning terse output either on or off.
+
+ Returns the previous value.
+ """
+ return self.__set_output_flag("terse", val)
+
def get_debug(self):
"""Get currently active debug flags.
Returns a set of flag names. See set_debug() for details.
"""
val = self.nft_ctx_output_get_debug(self.__ctx)
-
- names = []
- for n,v in self.debug_flags.items():
- if val & v:
- names.append(n)
- val &= ~v
- if val:
- names.append(val)
-
- return names
+ return self._flags_from_numeric(self.debug_flags, val)
def set_debug(self, values):
"""Set debug output flags.
@@ -342,19 +469,9 @@ class Nftables:
Returns a set of previously active debug flags, as returned by
get_debug() method.
"""
+ val = self._flags_to_numeric(self.debug_flags, values)
old = self.get_debug()
-
- if type(values) in [str, int]:
- values = [values]
-
- val = 0
- for v in values:
- if type(v) is str:
- v = self.debug_flags[v]
- val |= v
-
self.nft_ctx_output_set_debug(self.__ctx, val)
-
return old
def cmd(self, cmdline):
@@ -411,3 +528,77 @@ class Nftables:
self.validator.validate(json_root)
return True
+
+ def cmd_from_file(self, filename):
+ """Run a nftables command set from a file
+
+ filename can be a str or a Path
+
+ Returns a tuple (rc, output, error):
+ rc -- return code as returned by nft_run_cmd_from_filename() function
+ output -- a string containing output written to stdout
+ error -- a string containing output written to stderr
+ """
+ filename_is_unicode = False
+ if not isinstance(filename, bytes):
+ filename_is_unicode = True
+ filename = str(filename)
+ filename= filename.encode("utf-8")
+ rc = self.nft_run_cmd_from_filename(self.__ctx, filename)
+ output = self.nft_ctx_get_output_buffer(self.__ctx)
+ error = self.nft_ctx_get_error_buffer(self.__ctx)
+ if filename_is_unicode:
+ output = output.decode("utf-8")
+ error = error.decode("utf-8")
+ return (rc, output, error)
+
+ def add_include_path(self, filename):
+ """Add a path to the include file list
+ The default list includes the built-in default one
+
+ Returns True on success, False if memory allocation fails
+ """
+ if not isinstance(filename, bytes):
+ filename = str(filename)
+ filename= filename.encode("utf-8")
+ rc = self.nft_ctx_add_include_path(self.__ctx, filename)
+ return rc == 0
+
+ def clear_include_paths(self):
+ """Clear include path list
+
+ Will also remove the built-in default one
+ """
+ self.nft_ctx_clear_include_paths(self.__ctx)
+
+ def get_dry_run(self):
+ """Get dry run state
+
+ Returns True if set, False otherwise
+ """
+ return self.nft_ctx_get_dry_run(self.__ctx)
+
+ def set_dry_run(self, onoff):
+ """ Set dry run state
+
+ Returns the previous dry run state
+ """
+ old = self.get_dry_run()
+ self.nft_ctx_set_dry_run(self.__ctx, onoff)
+
+ return old
+
+ def add_var(self, var):
+ """Add a variable to the variable list
+
+ Returns True if added, False otherwise
+ """
+ if not isinstance(var, bytes):
+ var = var.encode("utf-8")
+ rc = self.nft_ctx_add_var(self.__ctx, var)
+ return rc == 0
+
+ def clear_vars(self):
+ """Clear variable list
+ """
+ self.nft_ctx_clear_vars(self.__ctx)
diff --git a/py/schema.json b/py/src/schema.json
index 460e2156..460e2156 100644
--- a/py/schema.json
+++ b/py/src/schema.json
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644
index 740c21f2..00000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,108 +0,0 @@
-include $(top_srcdir)/Make_global.am
-
-sbin_PROGRAMS = nft
-
-CLEANFILES = scanner.c parser_bison.c
-
-AM_CPPFLAGS = -I$(top_srcdir)/include
-AM_CPPFLAGS += -DDEFAULT_INCLUDE_PATH="\"${sysconfdir}\"" \
- ${LIBMNL_CFLAGS} ${LIBNFTNL_CFLAGS}
-if BUILD_DEBUG
-AM_CPPFLAGS += -g -DDEBUG
-endif
-if BUILD_XTABLES
-AM_CPPFLAGS += ${XTABLES_CFLAGS}
-endif
-
-AM_CFLAGS = -Wall \
- -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations \
- -Wdeclaration-after-statement -Wsign-compare -Winit-self \
- -Wformat-nonliteral -Wformat-security -Wmissing-format-attribute \
- -Wcast-align -Wundef -Wbad-function-cast \
- -Waggregate-return -Wunused -Wwrite-strings ${GCC_FVISIBILITY_HIDDEN}
-
-
-AM_YFLAGS = -d -Wno-yacc
-
-BUILT_SOURCES = parser_bison.h
-
-lib_LTLIBRARIES = libnftables.la
-
-libnftables_la_SOURCES = \
- rule.c \
- statement.c \
- cache.c \
- datatype.c \
- expression.c \
- evaluate.c \
- proto.c \
- payload.c \
- exthdr.c \
- fib.c \
- hash.c \
- ipopt.c \
- meta.c \
- rt.c \
- numgen.c \
- ct.c \
- xfrm.c \
- netlink.c \
- netlink_linearize.c \
- netlink_delinearize.c \
- misspell.c \
- monitor.c \
- segtree.c \
- rbtree.c \
- gmputil.c \
- utils.c \
- erec.c \
- mnl.c \
- iface.c \
- mergesort.c \
- osf.c \
- nfnl_osf.c \
- tcpopt.c \
- socket.c \
- print.c \
- libnftables.c \
- libnftables.map
-
-# yacc and lex generate dirty code
-noinst_LTLIBRARIES = libparser.la
-libparser_la_SOURCES = parser_bison.y scanner.l
-libparser_la_CFLAGS = ${AM_CFLAGS} \
- -Wno-missing-prototypes \
- -Wno-missing-declarations \
- -Wno-implicit-function-declaration \
- -Wno-nested-externs \
- -Wno-undef \
- -Wno-redundant-decls
-
-libnftables_la_LIBADD = ${LIBMNL_LIBS} ${LIBNFTNL_LIBS} libparser.la
-libnftables_la_LDFLAGS = -version-info ${libnftables_LIBVERSION} \
- --version-script=$(srcdir)/libnftables.map
-
-if BUILD_MINIGMP
-noinst_LTLIBRARIES += libminigmp.la
-libminigmp_la_SOURCES = mini-gmp.c
-libminigmp_la_CFLAGS = ${AM_CFLAGS} -Wno-sign-compare
-libnftables_la_LIBADD += libminigmp.la
-endif
-
-libnftables_la_SOURCES += xt.c
-if BUILD_XTABLES
-libnftables_la_LIBADD += ${XTABLES_LIBS}
-endif
-
-nft_SOURCES = main.c
-
-if BUILD_CLI
-nft_SOURCES += cli.c
-endif
-
-if BUILD_JSON
-libnftables_la_SOURCES += json.c parser_json.c
-libnftables_la_LIBADD += ${JANSSON_LIBS}
-endif
-
-nft_LDADD = libnftables.la
diff --git a/src/cache.c b/src/cache.c
index a778650a..c000e32c 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -6,31 +6,58 @@
* later) as published by the Free Software Foundation.
*/
+#include <nft.h>
+
#include <expression.h>
#include <statement.h>
#include <rule.h>
#include <erec.h>
#include <utils.h>
#include <cache.h>
+#include <netlink.h>
+#include <mnl.h>
+#include <libnftnl/chain.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter/nf_tables.h>
static unsigned int evaluate_cache_add(struct cmd *cmd, unsigned int flags)
{
+ struct set *set;
+
switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ if (!cmd->table)
+ break;
+
+ flags |= NFT_CACHE_TABLE |
+ NFT_CACHE_CHAIN |
+ NFT_CACHE_SET |
+ NFT_CACHE_OBJECT |
+ NFT_CACHE_FLOWTABLE;
+ list_for_each_entry(set, &cmd->table->sets, list) {
+ if (set->automerge)
+ flags |= NFT_CACHE_SETELEM_MAYBE;
+ }
+ break;
case CMD_OBJ_CHAIN:
case CMD_OBJ_SET:
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_LIMIT:
case CMD_OBJ_SECMARK:
+ case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_SYNPROXY:
case CMD_OBJ_FLOWTABLE:
flags |= NFT_CACHE_TABLE;
break;
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_ELEMENTS:
flags |= NFT_CACHE_TABLE |
NFT_CACHE_CHAIN |
NFT_CACHE_SET |
NFT_CACHE_OBJECT |
- NFT_CACHE_SETELEM;
+ NFT_CACHE_SETELEM_MAYBE;
break;
case CMD_OBJ_RULE:
flags |= NFT_CACHE_TABLE |
@@ -53,8 +80,8 @@ static unsigned int evaluate_cache_add(struct cmd *cmd, unsigned int flags)
static unsigned int evaluate_cache_del(struct cmd *cmd, unsigned int flags)
{
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
- flags |= NFT_CACHE_SETELEM;
+ case CMD_OBJ_ELEMENTS:
+ flags |= NFT_CACHE_SETELEM_MAYBE;
break;
default:
break;
@@ -63,13 +90,89 @@ static unsigned int evaluate_cache_del(struct cmd *cmd, unsigned int flags)
return flags;
}
-static unsigned int evaluate_cache_flush(struct cmd *cmd, unsigned int flags)
+static unsigned int evaluate_cache_get(struct cmd *cmd, unsigned int flags)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_ELEMENTS:
+ flags |= NFT_CACHE_TABLE |
+ NFT_CACHE_SET |
+ NFT_CACHE_SETELEM;
+ break;
+ default:
+ break;
+ }
+
+ return flags;
+}
+
+struct nft_cache_filter *nft_cache_filter_init(void)
+{
+ struct nft_cache_filter *filter;
+ int i;
+
+ filter = xzalloc(sizeof(struct nft_cache_filter));
+ memset(&filter->list, 0, sizeof(filter->list));
+ for (i = 0; i < NFT_CACHE_HSIZE; i++)
+ init_list_head(&filter->obj[i].head);
+
+ return filter;
+}
+
+void nft_cache_filter_fini(struct nft_cache_filter *filter)
+{
+ int i;
+
+ for (i = 0; i < NFT_CACHE_HSIZE; i++) {
+ struct nft_filter_obj *obj, *next;
+
+ list_for_each_entry_safe(obj, next, &filter->obj[i].head, list)
+ free(obj);
+ }
+ free(filter);
+}
+
+static void cache_filter_add(struct nft_cache_filter *filter,
+ const struct cmd *cmd)
+{
+ struct nft_filter_obj *obj;
+ uint32_t hash;
+
+ obj = xmalloc(sizeof(struct nft_filter_obj));
+ obj->family = cmd->handle.family;
+ obj->table = cmd->handle.table.name;
+ obj->set = cmd->handle.set.name;
+
+ hash = djb_hash(cmd->handle.set.name) % NFT_CACHE_HSIZE;
+ list_add_tail(&obj->list, &filter->obj[hash].head);
+}
+
+static bool cache_filter_find(const struct nft_cache_filter *filter,
+ const struct handle *handle)
+{
+ struct nft_filter_obj *obj;
+ uint32_t hash;
+
+ hash = djb_hash(handle->set.name) % NFT_CACHE_HSIZE;
+
+ list_for_each_entry(obj, &filter->obj[hash].head, list) {
+ if (obj->family == handle->family &&
+ !strcmp(obj->table, handle->table.name) &&
+ !strcmp(obj->set, handle->set.name))
+ return true;
+ }
+
+ return false;
+}
+
+static unsigned int evaluate_cache_flush(struct cmd *cmd, unsigned int flags,
+ struct nft_cache_filter *filter)
{
switch (cmd->obj) {
case CMD_OBJ_SET:
case CMD_OBJ_MAP:
case CMD_OBJ_METER:
flags |= NFT_CACHE_SET;
+ cache_filter_add(filter, cmd);
break;
case CMD_OBJ_RULESET:
flags |= NFT_CACHE_FLUSHED;
@@ -94,12 +197,229 @@ static unsigned int evaluate_cache_rename(struct cmd *cmd, unsigned int flags)
return flags;
}
-unsigned int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
+static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd,
+ unsigned int flags,
+ struct nft_cache_filter *filter)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ if (filter)
+ filter->list.family = cmd->handle.family;
+ if (!cmd->handle.table.name) {
+ flags |= NFT_CACHE_TABLE;
+ break;
+ } else if (filter) {
+ filter->list.table = cmd->handle.table.name;
+ }
+ flags |= NFT_CACHE_FULL;
+ break;
+ case CMD_OBJ_CHAIN:
+ if (filter && cmd->handle.chain.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ filter->list.chain = cmd->handle.chain.name;
+ /* implicit terse listing to fetch content of anonymous
+ * sets only when chain name is specified.
+ */
+ flags |= NFT_CACHE_TERSE;
+ }
+ flags |= NFT_CACHE_FULL;
+ break;
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ if (filter && cmd->handle.table.name && cmd->handle.set.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ filter->list.set = cmd->handle.set.name;
+ }
+ if (filter->list.table && filter->list.set)
+ flags |= NFT_CACHE_TABLE | NFT_CACHE_SET | NFT_CACHE_SETELEM;
+ else
+ flags |= NFT_CACHE_FULL;
+ break;
+ case CMD_OBJ_CHAINS:
+ flags |= NFT_CACHE_TABLE | NFT_CACHE_CHAIN;
+ break;
+ case CMD_OBJ_SETS:
+ case CMD_OBJ_MAPS:
+ flags |= NFT_CACHE_TABLE | NFT_CACHE_SET;
+ if (!nft_output_terse(&nft->output))
+ flags |= NFT_CACHE_SETELEM;
+ break;
+ case CMD_OBJ_FLOWTABLE:
+ if (filter &&
+ cmd->handle.table.name &&
+ cmd->handle.flowtable.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ filter->list.ft = cmd->handle.flowtable.name;
+ }
+ /* fall through */
+ case CMD_OBJ_FLOWTABLES:
+ flags |= NFT_CACHE_TABLE | NFT_CACHE_FLOWTABLE;
+ break;
+ case CMD_OBJ_RULESET:
+ default:
+ flags |= NFT_CACHE_FULL;
+ break;
+ }
+ flags |= NFT_CACHE_REFRESH;
+
+ if (nft_output_terse(&nft->output))
+ flags |= NFT_CACHE_TERSE;
+
+ return flags;
+}
+
+static unsigned int evaluate_cache_reset(struct cmd *cmd, unsigned int flags,
+ struct nft_cache_filter *filter)
+{
+ switch (cmd->obj) {
+ case CMD_OBJ_RULES:
+ case CMD_OBJ_RULE:
+ if (filter) {
+ if (cmd->handle.table.name) {
+ filter->list.family = cmd->handle.family;
+ filter->list.table = cmd->handle.table.name;
+ }
+ if (cmd->handle.chain.name)
+ filter->list.chain = cmd->handle.chain.name;
+ }
+ flags |= NFT_CACHE_SET | NFT_CACHE_FLOWTABLE |
+ NFT_CACHE_OBJECT | NFT_CACHE_CHAIN;
+ break;
+ case CMD_OBJ_ELEMENTS:
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ flags |= NFT_CACHE_SET;
+ break;
+ default:
+ flags |= NFT_CACHE_TABLE;
+ break;
+ }
+
+ return flags;
+}
+
+static int nft_handle_validate(const struct cmd *cmd, struct list_head *msgs)
+{
+ const struct handle *h = &cmd->handle;
+ const struct location *loc;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ break;
+ case CMD_OBJ_RULE:
+ case CMD_OBJ_RULES:
+ case CMD_OBJ_CHAIN:
+ case CMD_OBJ_CHAINS:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ if (h->chain.name &&
+ strlen(h->chain.name) > NFT_NAME_MAXLEN) {
+ loc = &h->chain.location;
+ goto err_name_too_long;
+ }
+ break;
+ case CMD_OBJ_ELEMENTS:
+ case CMD_OBJ_SET:
+ case CMD_OBJ_SETS:
+ case CMD_OBJ_MAP:
+ case CMD_OBJ_MAPS:
+ case CMD_OBJ_METER:
+ case CMD_OBJ_METERS:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ if (h->set.name &&
+ strlen(h->set.name) > NFT_NAME_MAXLEN) {
+ loc = &h->set.location;
+ goto err_name_too_long;
+ }
+ break;
+ case CMD_OBJ_FLOWTABLE:
+ case CMD_OBJ_FLOWTABLES:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ if (h->flowtable.name &&
+ strlen(h->flowtable.name) > NFT_NAME_MAXLEN) {
+ loc = &h->flowtable.location;
+ goto err_name_too_long;
+ }
+ break;
+ case CMD_OBJ_INVALID:
+ case CMD_OBJ_EXPR:
+ case CMD_OBJ_RULESET:
+ case CMD_OBJ_MARKUP:
+ case CMD_OBJ_MONITOR:
+ case CMD_OBJ_SETELEMS:
+ case CMD_OBJ_HOOKS:
+ break;
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_COUNTERS:
+ case CMD_OBJ_QUOTA:
+ case CMD_OBJ_QUOTAS:
+ case CMD_OBJ_LIMIT:
+ case CMD_OBJ_LIMITS:
+ case CMD_OBJ_SECMARK:
+ case CMD_OBJ_SECMARKS:
+ case CMD_OBJ_SYNPROXY:
+ case CMD_OBJ_SYNPROXYS:
+ case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_HELPERS:
+ case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_CT_TIMEOUTS:
+ case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_CT_EXPECTATIONS:
+ if (h->table.name &&
+ strlen(h->table.name) > NFT_NAME_MAXLEN) {
+ loc = &h->table.location;
+ goto err_name_too_long;
+ }
+ if (h->obj.name &&
+ strlen(h->obj.name) > NFT_NAME_MAXLEN) {
+ loc = &h->obj.location;
+ goto err_name_too_long;
+ }
+ break;
+ }
+
+ return 0;
+
+err_name_too_long:
+ erec_queue(error(loc, "name too long, %d characters maximum allowed",
+ NFT_NAME_MAXLEN),
+ msgs);
+ return -1;
+}
+
+int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
+ struct list_head *msgs, struct nft_cache_filter *filter,
+ unsigned int *pflags)
{
unsigned int flags = NFT_CACHE_EMPTY;
struct cmd *cmd;
list_for_each_entry(cmd, cmds, list) {
+ if (nft_handle_validate(cmd, msgs) < 0)
+ return -1;
+
+ if (filter->list.table && cmd->op != CMD_LIST)
+ memset(&filter->list, 0, sizeof(filter->list));
+
switch (cmd->op) {
case CMD_ADD:
case CMD_INSERT:
@@ -112,6 +432,7 @@ unsigned int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
flags = NFT_CACHE_FULL;
break;
case CMD_DELETE:
+ case CMD_DESTROY:
flags |= NFT_CACHE_TABLE |
NFT_CACHE_CHAIN |
NFT_CACHE_SET |
@@ -121,25 +442,854 @@ unsigned int cache_evaluate(struct nft_ctx *nft, struct list_head *cmds)
flags = evaluate_cache_del(cmd, flags);
break;
case CMD_GET:
- case CMD_LIST:
+ flags = evaluate_cache_get(cmd, flags);
+ break;
case CMD_RESET:
- case CMD_EXPORT:
+ flags |= evaluate_cache_reset(cmd, flags, filter);
+ break;
+ case CMD_LIST:
+ flags |= evaluate_cache_list(nft, cmd, flags, filter);
+ break;
case CMD_MONITOR:
flags |= NFT_CACHE_FULL;
break;
case CMD_FLUSH:
- flags = evaluate_cache_flush(cmd, flags);
+ flags = evaluate_cache_flush(cmd, flags, filter);
break;
case CMD_RENAME:
flags = evaluate_cache_rename(cmd, flags);
break;
case CMD_DESCRIBE:
case CMD_IMPORT:
+ case CMD_EXPORT:
break;
default:
break;
}
}
+ *pflags = flags;
- return flags;
+ return 0;
+}
+
+void table_cache_add(struct table *table, struct nft_cache *cache)
+{
+ uint32_t hash;
+
+ hash = djb_hash(table->handle.table.name) % NFT_CACHE_HSIZE;
+ cache_add(&table->cache, &cache->table_cache, hash);
+}
+
+void table_cache_del(struct table *table)
+{
+ cache_del(&table->cache);
+}
+
+struct table *table_cache_find(const struct cache *cache,
+ const char *name, uint32_t family)
+{
+ struct table *table;
+ uint32_t hash;
+
+ if (!name)
+ return NULL;
+
+ hash = djb_hash(name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(table, &cache->ht[hash], cache.hlist) {
+ if (table->handle.family == family &&
+ !strcmp(table->handle.table.name, name))
+ return table;
+ }
+
+ return NULL;
+}
+
+struct chain_cache_dump_ctx {
+ struct netlink_ctx *nlctx;
+ struct table *table;
+};
+
+static int chain_cache_cb(struct nftnl_chain *nlc, void *arg)
+{
+ struct chain_cache_dump_ctx *ctx = arg;
+ const char *chain_name, *table_name;
+ uint32_t hash, family;
+ struct chain *chain;
+
+ table_name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE);
+ family = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY);
+
+ if (family != ctx->table->handle.family ||
+ strcmp(table_name, ctx->table->handle.table.name))
+ return 0;
+
+ chain_name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME);
+ hash = djb_hash(chain_name) % NFT_CACHE_HSIZE;
+ chain = netlink_delinearize_chain(ctx->nlctx, nlc);
+
+ if (chain->flags & CHAIN_F_BINDING) {
+ list_add_tail(&chain->cache.list, &ctx->table->chain_bindings);
+ } else {
+ cache_add(&chain->cache, &ctx->table->chain_cache, hash);
+ }
+
+ nftnl_chain_list_del(nlc);
+ nftnl_chain_free(nlc);
+
+ return 0;
+}
+
+static int chain_cache_init(struct netlink_ctx *ctx, struct table *table,
+ struct nftnl_chain_list *chain_list)
+{
+ struct chain_cache_dump_ctx dump_ctx = {
+ .nlctx = ctx,
+ .table = table,
+ };
+ nftnl_chain_list_foreach(chain_list, chain_cache_cb, &dump_ctx);
+
+ return 0;
+}
+
+static struct nftnl_chain_list *
+chain_cache_dump(struct netlink_ctx *ctx,
+ const struct nft_cache_filter *filter, int *err)
+{
+ struct nftnl_chain_list *chain_list;
+ const char *table = NULL;
+ const char *chain = NULL;
+ int family = NFPROTO_UNSPEC;
+
+ if (filter && filter->list.table && filter->list.chain) {
+ family = filter->list.family;
+ table = filter->list.table;
+ chain = filter->list.chain;
+ }
+
+ chain_list = mnl_nft_chain_dump(ctx, family, table, chain);
+ if (chain_list == NULL) {
+ if (errno == EINTR) {
+ *err = -1;
+ return NULL;
+ }
+ *err = 0;
+ return NULL;
+ }
+
+ return chain_list;
+}
+
+void nft_chain_cache_update(struct netlink_ctx *ctx, struct table *table,
+ const char *chain)
+{
+ struct nftnl_chain_list *chain_list;
+
+ chain_list = mnl_nft_chain_dump(ctx, table->handle.family,
+ table->handle.table.name, chain);
+ if (!chain_list)
+ return;
+
+ chain_cache_init(ctx, table, chain_list);
+
+ nftnl_chain_list_free(chain_list);
+}
+
+void chain_cache_add(struct chain *chain, struct table *table)
+{
+ uint32_t hash;
+
+ hash = djb_hash(chain->handle.chain.name) % NFT_CACHE_HSIZE;
+ cache_add(&chain->cache, &table->chain_cache, hash);
+}
+
+void chain_cache_del(struct chain *chain)
+{
+ cache_del(&chain->cache);
+}
+
+struct chain *chain_cache_find(const struct table *table, const char *name)
+{
+ struct chain *chain;
+ uint32_t hash;
+
+ hash = djb_hash(name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(chain, &table->chain_cache.ht[hash], cache.hlist) {
+ if (!strcmp(chain->handle.chain.name, name))
+ return chain;
+ }
+
+ return NULL;
+}
+
+static int list_rule_cb(struct nftnl_rule *nlr, void *data)
+{
+ struct netlink_ctx *ctx = data;
+ const struct handle *h = ctx->data;
+ const char *table, *chain;
+ struct rule *rule;
+ uint32_t family;
+
+ family = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
+ table = nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE);
+ chain = nftnl_rule_get_str(nlr, NFTNL_RULE_CHAIN);
+
+ if ((h->family != NFPROTO_UNSPEC && h->family != family) ||
+ (h->table.name && strcmp(table, h->table.name) != 0) ||
+ (h->chain.name && strcmp(chain, h->chain.name) != 0))
+ return 0;
+
+ netlink_dump_rule(nlr, ctx);
+ rule = netlink_delinearize_rule(ctx, nlr);
+ assert(rule);
+ list_add_tail(&rule->list, &ctx->list);
+
+ return 0;
+}
+
+int rule_cache_dump(struct netlink_ctx *ctx, const struct handle *h,
+ const struct nft_cache_filter *filter,
+ bool dump, bool reset)
+{
+ struct nftnl_rule_list *rule_cache;
+ const char *table = NULL;
+ const char *chain = NULL;
+ uint64_t rule_handle = 0;
+
+ if (filter) {
+ table = filter->list.table;
+ chain = filter->list.chain;
+ rule_handle = filter->list.rule_handle;
+ }
+
+ rule_cache = mnl_nft_rule_dump(ctx, h->family,
+ table, chain, rule_handle, dump, reset);
+ if (rule_cache == NULL) {
+ if (errno == EINTR)
+ return -1;
+
+ return 0;
+ }
+
+ ctx->data = h;
+ nftnl_rule_list_foreach(rule_cache, list_rule_cb, ctx);
+ nftnl_rule_list_free(rule_cache);
+ return 0;
+}
+
+struct set_cache_dump_ctx {
+ struct netlink_ctx *nlctx;
+ struct table *table;
+};
+
+static int set_cache_cb(struct nftnl_set *nls, void *arg)
+{
+ struct set_cache_dump_ctx *ctx = arg;
+ const char *set_table;
+ const char *set_name;
+ uint32_t set_family;
+ struct set *set;
+ uint32_t hash;
+
+ set_table = nftnl_set_get_str(nls, NFTNL_SET_TABLE);
+ set_family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
+
+ if (set_family != ctx->table->handle.family ||
+ strcmp(set_table, ctx->table->handle.table.name))
+ return 0;
+
+ set = netlink_delinearize_set(ctx->nlctx, nls);
+ if (!set)
+ return -1;
+
+ set_name = nftnl_set_get_str(nls, NFTNL_SET_NAME);
+ hash = djb_hash(set_name) % NFT_CACHE_HSIZE;
+ cache_add(&set->cache, &ctx->table->set_cache, hash);
+
+ nftnl_set_list_del(nls);
+ nftnl_set_free(nls);
+ return 0;
+}
+
+static int set_cache_init(struct netlink_ctx *ctx, struct table *table,
+ struct nftnl_set_list *set_list)
+{
+ struct set_cache_dump_ctx dump_ctx = {
+ .nlctx = ctx,
+ .table = table,
+ };
+
+ nftnl_set_list_foreach(set_list, set_cache_cb, &dump_ctx);
+
+ return 0;
+}
+
+static struct nftnl_set_list *
+set_cache_dump(struct netlink_ctx *ctx,
+ const struct nft_cache_filter *filter, int *err)
+{
+ struct nftnl_set_list *set_list;
+ int family = NFPROTO_UNSPEC;
+ const char *table = NULL;
+ const char *set = NULL;
+
+ if (filter) {
+ family = filter->list.family;
+ table = filter->list.table;
+ set = filter->list.set;
+ }
+
+ set_list = mnl_nft_set_dump(ctx, family, table, set);
+ if (!set_list) {
+ if (errno == EINTR) {
+ *err = -1;
+ return NULL;
+ }
+ *err = 0;
+ return NULL;
+ }
+
+ return set_list;
+}
+
+void set_cache_add(struct set *set, struct table *table)
+{
+ uint32_t hash;
+
+ hash = djb_hash(set->handle.set.name) % NFT_CACHE_HSIZE;
+ cache_add(&set->cache, &table->set_cache, hash);
+}
+
+void set_cache_del(struct set *set)
+{
+ cache_del(&set->cache);
+}
+
+struct set *set_cache_find(const struct table *table, const char *name)
+{
+ struct set *set;
+ uint32_t hash;
+
+ hash = djb_hash(name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(set, &table->set_cache.ht[hash], cache.hlist) {
+ if (!strcmp(set->handle.set.name, name))
+ return set;
+ }
+
+ return NULL;
+}
+
+struct obj_cache_dump_ctx {
+ struct netlink_ctx *nlctx;
+ struct table *table;
+};
+
+static int obj_cache_cb(struct nftnl_obj *nlo, void *arg)
+{
+ struct obj_cache_dump_ctx *ctx = arg;
+ const char *obj_name;
+ struct obj *obj;
+ uint32_t hash;
+
+ obj = netlink_delinearize_obj(ctx->nlctx, nlo);
+ if (!obj)
+ return -1;
+
+ obj_name = nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME);
+ hash = djb_hash(obj_name) % NFT_CACHE_HSIZE;
+ cache_add(&obj->cache, &ctx->table->obj_cache, hash);
+
+ return 0;
+}
+
+static int obj_cache_init(struct netlink_ctx *ctx, struct table *table,
+ struct nftnl_obj_list *obj_list)
+{
+ struct obj_cache_dump_ctx dump_ctx = {
+ .nlctx = ctx,
+ .table = table,
+ };
+ nftnl_obj_list_foreach(obj_list, obj_cache_cb, &dump_ctx);
+
+ return 0;
+}
+
+static struct nftnl_obj_list *obj_cache_dump(struct netlink_ctx *ctx,
+ const struct table *table)
+{
+ struct nftnl_obj_list *obj_list;
+
+ obj_list = mnl_nft_obj_dump(ctx, table->handle.family,
+ table->handle.table.name, NULL,
+ 0, true, false);
+ if (!obj_list) {
+ if (errno == EINTR)
+ return NULL;
+
+ /* old kernels do not support this, provide an empty list. */
+ obj_list = nftnl_obj_list_alloc();
+ if (!obj_list)
+ memory_allocation_error();
+
+ return obj_list;
+ }
+
+ return obj_list;
+}
+
+void obj_cache_add(struct obj *obj, struct table *table)
+{
+ uint32_t hash;
+
+ hash = djb_hash(obj->handle.obj.name) % NFT_CACHE_HSIZE;
+ cache_add(&obj->cache, &table->obj_cache, hash);
+}
+
+void obj_cache_del(struct obj *obj)
+{
+ cache_del(&obj->cache);
+}
+
+struct obj *obj_cache_find(const struct table *table, const char *name,
+ uint32_t obj_type)
+{
+ struct obj *obj;
+ uint32_t hash;
+
+ hash = djb_hash(name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(obj, &table->obj_cache.ht[hash], cache.hlist) {
+ if (!strcmp(obj->handle.obj.name, name) &&
+ obj->type == obj_type)
+ return obj;
+ }
+
+ return NULL;
+}
+
+struct ft_cache_dump_ctx {
+ struct netlink_ctx *nlctx;
+ struct table *table;
+};
+
+static int ft_cache_cb(struct nftnl_flowtable *nlf, void *arg)
+{
+ struct ft_cache_dump_ctx *ctx = arg;
+ struct flowtable *ft;
+ const char *ft_table;
+ const char *ft_name;
+ uint32_t ft_family;
+ uint32_t hash;
+
+ ft_family = nftnl_flowtable_get_u32(nlf, NFTNL_FLOWTABLE_FAMILY);
+ ft_table = nftnl_flowtable_get_str(nlf, NFTNL_FLOWTABLE_TABLE);
+
+ if (ft_family != ctx->table->handle.family ||
+ strcmp(ft_table, ctx->table->handle.table.name))
+ return 0;
+
+ ft = netlink_delinearize_flowtable(ctx->nlctx, nlf);
+ if (!ft)
+ return -1;
+
+ ft_name = nftnl_flowtable_get_str(nlf, NFTNL_FLOWTABLE_NAME);
+ hash = djb_hash(ft_name) % NFT_CACHE_HSIZE;
+ cache_add(&ft->cache, &ctx->table->ft_cache, hash);
+
+ nftnl_flowtable_list_del(nlf);
+ nftnl_flowtable_free(nlf);
+ return 0;
+}
+
+static int ft_cache_init(struct netlink_ctx *ctx, struct table *table,
+ struct nftnl_flowtable_list *ft_list)
+{
+ struct ft_cache_dump_ctx dump_ctx = {
+ .nlctx = ctx,
+ .table = table,
+ };
+ nftnl_flowtable_list_foreach(ft_list, ft_cache_cb, &dump_ctx);
+
+ return 0;
+}
+
+static struct nftnl_flowtable_list *
+ft_cache_dump(struct netlink_ctx *ctx, const struct nft_cache_filter *filter)
+{
+ struct nftnl_flowtable_list *ft_list;
+ int family = NFPROTO_UNSPEC;
+ const char *table = NULL;
+ const char *ft = NULL;
+
+ if (filter) {
+ family = filter->list.family;
+ table = filter->list.table;
+ ft = filter->list.ft;
+ }
+
+ ft_list = mnl_nft_flowtable_dump(ctx, family, table, ft);
+ if (!ft_list) {
+ if (errno == EINTR)
+ return NULL;
+
+ /* old kernels do not support this, provide an empty list. */
+ ft_list = nftnl_flowtable_list_alloc();
+ if (!ft_list)
+ memory_allocation_error();
+
+ return ft_list;
+ }
+
+ return ft_list;
+}
+
+void ft_cache_add(struct flowtable *ft, struct table *table)
+{
+ uint32_t hash;
+
+ hash = djb_hash(ft->handle.flowtable.name) % NFT_CACHE_HSIZE;
+ cache_add(&ft->cache, &table->ft_cache, hash);
+}
+
+void ft_cache_del(struct flowtable *ft)
+{
+ cache_del(&ft->cache);
+}
+
+struct flowtable *ft_cache_find(const struct table *table, const char *name)
+{
+ struct flowtable *ft;
+ uint32_t hash;
+
+ hash = djb_hash(name) % NFT_CACHE_HSIZE;
+ list_for_each_entry(ft, &table->ft_cache.ht[hash], cache.hlist) {
+ if (!strcmp(ft->handle.flowtable.name, name))
+ return ft;
+ }
+
+ return NULL;
+}
+
+static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
+ struct nft_cache *cache,
+ const struct nft_cache_filter *filter)
+{
+ struct table *table, *next;
+ int ret;
+
+ ret = netlink_list_tables(ctx, h, filter);
+ if (ret < 0)
+ return -1;
+
+ list_for_each_entry_safe(table, next, &ctx->list, list) {
+ list_del(&table->list);
+ table_cache_add(table, cache);
+ }
+
+ return 0;
+}
+
+static int rule_init_cache(struct netlink_ctx *ctx, struct table *table,
+ const struct nft_cache_filter *filter)
+{
+ struct rule *rule, *nrule;
+ struct chain *chain;
+ int ret;
+
+ ret = rule_cache_dump(ctx, &table->handle, filter, true, false);
+
+ list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
+ chain = chain_cache_find(table, rule->handle.chain.name);
+ if (!chain)
+ chain = chain_binding_lookup(table,
+ rule->handle.chain.name);
+ if (!chain)
+ goto err_ctx_list;
+
+ list_move_tail(&rule->list, &chain->rules);
+ }
+
+ return ret;
+
+err_ctx_list:
+ list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
+ list_del(&rule->list);
+ rule_free(rule);
+ }
+ errno = EINTR;
+
+ return -1;
+}
+
+static int implicit_chain_cache(struct netlink_ctx *ctx, struct table *table,
+ const char *chain_name)
+{
+ struct nft_cache_filter filter;
+ struct chain *chain;
+ int ret = 0;
+
+ list_for_each_entry(chain, &table->chain_bindings, cache.list) {
+ filter.list = (typeof(filter.list)) {
+ .table = table->handle.table.name,
+ .chain = chain->handle.chain.name,
+ };
+ ret = rule_init_cache(ctx, table, &filter);
+ }
+
+ return ret;
+}
+
+static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
+ const struct nft_cache_filter *filter)
+{
+ struct nftnl_flowtable_list *ft_list = NULL;
+ struct nftnl_chain_list *chain_list = NULL;
+ struct nftnl_set_list *set_list = NULL;
+ struct nftnl_obj_list *obj_list;
+ struct table *table;
+ struct set *set;
+ int ret = 0;
+
+ if (flags & NFT_CACHE_CHAIN_BIT) {
+ chain_list = chain_cache_dump(ctx, filter, &ret);
+ if (!chain_list)
+ return -1;
+ }
+ if (flags & NFT_CACHE_SET_BIT) {
+ set_list = set_cache_dump(ctx, filter, &ret);
+ if (!set_list) {
+ ret = -1;
+ goto cache_fails;
+ }
+ }
+ if (flags & NFT_CACHE_FLOWTABLE_BIT) {
+ ft_list = ft_cache_dump(ctx, filter);
+ if (!ft_list) {
+ ret = -1;
+ goto cache_fails;
+ }
+ }
+
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
+ if (flags & NFT_CACHE_SET_BIT) {
+ ret = set_cache_init(ctx, table, set_list);
+ if (ret < 0)
+ goto cache_fails;
+ }
+ if (flags & NFT_CACHE_SETELEM_BIT) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (cache_filter_find(filter, &set->handle))
+ continue;
+ if (!set_is_anonymous(set->flags) &&
+ flags & NFT_CACHE_TERSE)
+ continue;
+
+ ret = netlink_list_setelems(ctx, &set->handle,
+ set, false);
+ if (ret < 0)
+ goto cache_fails;
+ }
+ } else if (flags & NFT_CACHE_SETELEM_MAYBE) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
+ if (cache_filter_find(filter, &set->handle))
+ continue;
+
+ if (!set_is_non_concat_range(set))
+ continue;
+
+ ret = netlink_list_setelems(ctx, &set->handle,
+ set, false);
+ if (ret < 0)
+ goto cache_fails;
+ }
+ }
+ if (flags & NFT_CACHE_CHAIN_BIT) {
+ ret = chain_cache_init(ctx, table, chain_list);
+ if (ret < 0)
+ goto cache_fails;
+ }
+ if (flags & NFT_CACHE_FLOWTABLE_BIT) {
+ ret = ft_cache_init(ctx, table, ft_list);
+ if (ret < 0)
+ goto cache_fails;
+ }
+ if (flags & NFT_CACHE_OBJECT_BIT) {
+ obj_list = obj_cache_dump(ctx, table);
+ if (!obj_list) {
+ ret = -1;
+ goto cache_fails;
+ }
+ ret = obj_cache_init(ctx, table, obj_list);
+
+ nftnl_obj_list_free(obj_list);
+
+ if (ret < 0)
+ goto cache_fails;
+ }
+
+ if (flags & NFT_CACHE_RULE_BIT) {
+ ret = rule_init_cache(ctx, table, filter);
+ if (ret < 0)
+ goto cache_fails;
+
+ if (filter && filter->list.table && filter->list.chain) {
+ ret = implicit_chain_cache(ctx, table, filter->list.chain);
+ if (ret < 0)
+ goto cache_fails;
+ }
+ }
+ }
+
+cache_fails:
+ if (set_list)
+ nftnl_set_list_free(set_list);
+ if (ft_list)
+ nftnl_flowtable_list_free(ft_list);
+
+ if (flags & NFT_CACHE_CHAIN_BIT)
+ nftnl_chain_list_free(chain_list);
+
+ return ret;
+}
+
+static int nft_cache_init(struct netlink_ctx *ctx, unsigned int flags,
+ const struct nft_cache_filter *filter)
+{
+ struct handle handle = {
+ .family = NFPROTO_UNSPEC,
+ };
+ int ret;
+
+ if (flags == NFT_CACHE_EMPTY)
+ return 0;
+
+ /* assume NFT_CACHE_TABLE is always set. */
+ ret = cache_init_tables(ctx, &handle, &ctx->nft->cache, filter);
+ if (ret < 0)
+ return ret;
+ ret = cache_init_objects(ctx, flags, filter);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static bool nft_cache_is_complete(struct nft_cache *cache, unsigned int flags)
+{
+ return (cache->flags & flags) == flags;
+}
+
+static bool nft_cache_needs_refresh(struct nft_cache *cache)
+{
+ return cache->flags & NFT_CACHE_REFRESH;
+}
+
+static bool nft_cache_is_updated(struct nft_cache *cache, uint16_t genid)
+{
+ return genid && genid == cache->genid;
+}
+
+bool nft_cache_needs_update(struct nft_cache *cache)
+{
+ return cache->flags & NFT_CACHE_UPDATE;
+}
+
+int nft_cache_update(struct nft_ctx *nft, unsigned int flags,
+ struct list_head *msgs,
+ const struct nft_cache_filter *filter)
+{
+ struct netlink_ctx ctx = {
+ .list = LIST_HEAD_INIT(ctx.list),
+ .nft = nft,
+ .msgs = msgs,
+ };
+ struct nft_cache *cache = &nft->cache;
+ uint32_t genid, genid_stop, oldflags;
+ int ret;
+replay:
+ ctx.seqnum = cache->seqnum++;
+ genid = mnl_genid_get(&ctx);
+ if (!nft_cache_needs_refresh(cache) &&
+ nft_cache_is_complete(cache, flags) &&
+ nft_cache_is_updated(cache, genid))
+ return 0;
+
+ if (cache->genid)
+ nft_cache_release(cache);
+
+ if (flags & NFT_CACHE_FLUSHED) {
+ oldflags = flags;
+ flags = NFT_CACHE_EMPTY;
+ if (oldflags & NFT_CACHE_UPDATE)
+ flags |= NFT_CACHE_UPDATE;
+ goto skip;
+ }
+
+ ret = nft_cache_init(&ctx, flags, filter);
+ if (ret < 0) {
+ if (errno == EINTR) {
+ nft_cache_release(cache);
+ goto replay;
+ }
+
+ erec_queue(error(&netlink_location, "cache initialization failed: %s",
+ strerror(errno)),
+ msgs);
+ nft_cache_release(cache);
+
+ return -1;
+ }
+
+ genid_stop = mnl_genid_get(&ctx);
+ if (genid != genid_stop) {
+ nft_cache_release(cache);
+ goto replay;
+ }
+skip:
+ cache->genid = genid;
+ cache->flags = flags;
+ return 0;
+}
+
+static void nft_cache_flush(struct cache *table_cache)
+{
+ struct table *table, *next;
+
+ list_for_each_entry_safe(table, next, &table_cache->list, cache.list) {
+ table_cache_del(table);
+ table_free(table);
+ }
+}
+
+void nft_cache_release(struct nft_cache *cache)
+{
+ nft_cache_flush(&cache->table_cache);
+ cache->genid = 0;
+ cache->flags = NFT_CACHE_EMPTY;
+}
+
+void cache_init(struct cache *cache)
+{
+ int i;
+
+ cache->ht = xmalloc(sizeof(struct list_head) * NFT_CACHE_HSIZE);
+ for (i = 0; i < NFT_CACHE_HSIZE; i++)
+ init_list_head(&cache->ht[i]);
+
+ init_list_head(&cache->list);
+}
+
+void cache_free(struct cache *cache)
+{
+ free(cache->ht);
+}
+
+void cache_add(struct cache_item *item, struct cache *cache, uint32_t hash)
+{
+ list_add_tail(&item->hlist, &cache->ht[hash]);
+ list_add_tail(&item->list, &cache->list);
+}
+
+void cache_del(struct cache_item *item)
+{
+ list_del(&item->hlist);
+ list_del(&item->list);
}
diff --git a/src/cli.c b/src/cli.c
index 4c0c3e9d..448c25c2 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -12,18 +12,19 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
-#include <config.h>
-#include <stdlib.h>
+#include <nft.h>
+
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <errno.h>
-#include <string.h>
#include <ctype.h>
#include <limits.h>
#ifdef HAVE_LIBREADLINE
#include <readline/readline.h>
#include <readline/history.h>
+#elif defined(HAVE_LIBEDIT)
+#include <editline/readline.h>
#else
#include <linenoise.h>
#endif
@@ -35,6 +36,15 @@
#define CMDLINE_PROMPT "nft> "
#define CMDLINE_QUIT "quit"
+static bool cli_quit;
+static int cli_rc;
+
+static void __cli_exit(int rc)
+{
+ cli_quit = true;
+ cli_rc = rc;
+}
+
static char histfile[PATH_MAX];
static void
@@ -48,7 +58,26 @@ init_histfile(void)
snprintf(histfile, sizeof(histfile), "%s/%s", home, CMDLINE_HISTFILE);
}
-#ifdef HAVE_LIBREADLINE
+#if defined(HAVE_LIBREADLINE)
+static void nft_rl_prompt_save(void)
+{
+ rl_save_prompt();
+ rl_clear_message();
+ rl_set_prompt(".... ");
+}
+#define nft_rl_prompt_restore rl_restore_prompt
+#elif defined(HAVE_LIBEDIT)
+static void nft_rl_prompt_save(void)
+{
+ rl_set_prompt(".... ");
+}
+static void nft_rl_prompt_restore(void)
+{
+ rl_set_prompt("nft> ");
+}
+#endif
+
+#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT)
static struct nft_ctx *cli_nft;
static char *multiline;
@@ -72,17 +101,15 @@ static char *cli_append_multiline(char *line)
if (multiline == NULL) {
multiline = line;
- rl_save_prompt();
- rl_clear_message();
- rl_set_prompt(".... ");
+ nft_rl_prompt_save();
} else {
len += strlen(multiline);
s = malloc(len + 1);
if (!s) {
fprintf(stderr, "%s:%u: Memory allocation failure\n",
__FILE__, __LINE__);
- cli_exit();
- exit(EXIT_FAILURE);
+ cli_exit(EXIT_FAILURE);
+ return NULL;
}
snprintf(s, len + 1, "%s%s", multiline, line);
free(multiline);
@@ -93,7 +120,7 @@ static char *cli_append_multiline(char *line)
if (complete) {
line = multiline;
multiline = NULL;
- rl_restore_prompt();
+ nft_rl_prompt_restore();
}
return line;
}
@@ -106,8 +133,7 @@ static void cli_complete(char *line)
if (line == NULL) {
printf("\n");
- cli_exit();
- exit(0);
+ return cli_exit(0);
}
line = cli_append_multiline(line);
@@ -120,10 +146,8 @@ static void cli_complete(char *line)
if (*c == '\0')
return;
- if (!strcmp(line, CMDLINE_QUIT)) {
- cli_exit();
- exit(0);
- }
+ if (!strcmp(line, CMDLINE_QUIT))
+ return cli_exit(0);
/* avoid duplicate history entries */
hist = history_get(history_length);
@@ -133,6 +157,9 @@ static void cli_complete(char *line)
nft_run_cmd_from_buffer(cli_nft, line);
free(line);
}
+#endif
+
+#if defined(HAVE_LIBREADLINE)
static char **cli_completion(const char *text, int start, int end)
{
@@ -142,7 +169,7 @@ static char **cli_completion(const char *text, int start, int end)
int cli_init(struct nft_ctx *nft)
{
cli_nft = nft;
- rl_readline_name = "nft";
+ rl_readline_name = (char *)"nft";
rl_instream = stdin;
rl_outstream = stdout;
@@ -154,45 +181,95 @@ int cli_init(struct nft_ctx *nft)
read_history(histfile);
history_set_pos(history_length);
- while (true)
+ while (!cli_quit)
rl_callback_read_char();
- return 0;
+
+ return cli_rc;
}
-void cli_exit(void)
+void cli_exit(int rc)
{
rl_callback_handler_remove();
rl_deprep_terminal();
write_history(histfile);
+
+ __cli_exit(rc);
+}
+
+#elif defined(HAVE_LIBEDIT)
+
+int cli_init(struct nft_ctx *nft)
+{
+ char *line;
+
+ cli_nft = nft;
+ rl_readline_name = (char *)"nft";
+ rl_instream = stdin;
+ rl_outstream = stdout;
+
+ init_histfile();
+
+ read_history(histfile);
+ history_set_pos(history_length);
+
+ rl_set_prompt(CMDLINE_PROMPT);
+ while (!cli_quit) {
+ line = readline(rl_prompt);
+ if (!line) {
+ cli_exit(0);
+ break;
+ }
+ line = cli_append_multiline(line);
+ if (!line)
+ continue;
+
+ cli_complete(line);
+ }
+
+ return cli_rc;
+}
+
+void cli_exit(int rc)
+{
+ rl_deprep_terminal();
+ write_history(histfile);
+
+ __cli_exit(rc);
}
-#else /* !HAVE_LIBREADLINE */
+#else /* HAVE_LINENOISE */
int cli_init(struct nft_ctx *nft)
{
- int quit = 0;
char *line;
init_histfile();
linenoiseHistoryLoad(histfile);
linenoiseSetMultiLine(1);
- while (!quit && (line = linenoise(CMDLINE_PROMPT)) != NULL) {
+ while (!cli_quit) {
+ line = linenoise(CMDLINE_PROMPT);
+ if (!line) {
+ cli_exit(0);
+ break;
+ }
if (strcmp(line, CMDLINE_QUIT) == 0) {
- quit = 1;
+ cli_exit(0);
} else if (line[0] != '\0') {
linenoiseHistoryAdd(line);
nft_run_cmd_from_buffer(nft, line);
}
linenoiseFree(line);
}
- cli_exit();
- exit(0);
+
+ return cli_rc;
}
-void cli_exit(void)
+void cli_exit(int rc)
{
linenoiseHistorySave(histfile);
+
+ __cli_exit(rc);
}
-#endif /* HAVE_LIBREADLINE */
+#endif /* HAVE_LINENOISE */
diff --git a/src/cmd.c b/src/cmd.c
new file mode 100644
index 00000000..14cb1b51
--- /dev/null
+++ b/src/cmd.c
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 2020 Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <erec.h>
+#include <mnl.h>
+#include <cmd.h>
+#include <parser.h>
+#include <utils.h>
+#include <iface.h>
+#include <errno.h>
+#include <cache.h>
+
+void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc)
+{
+ if (cmd->num_attrs >= cmd->attr_array_len) {
+ cmd->attr_array_len *= 2;
+ cmd->attr = xrealloc(cmd->attr, sizeof(struct nlerr_loc) * cmd->attr_array_len);
+ }
+
+ cmd->attr[cmd->num_attrs].offset = offset;
+ cmd->attr[cmd->num_attrs].location = loc;
+ cmd->num_attrs++;
+}
+
+static int nft_cmd_enoent_table(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct location *loc)
+{
+ struct table *table;
+
+ if (!cmd->handle.table.name)
+ return 0;
+
+ table = table_lookup_fuzzy(&cmd->handle, &ctx->nft->cache);
+ if (!table)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean table '%s' in family %s?",
+ strerror(ENOENT), table->handle.table.name,
+ family2str(table->handle.family));
+ return 1;
+}
+
+static int table_fuzzy_check(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct table *table)
+{
+ if (table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name, cmd->handle.family))
+ return 0;
+
+ if (strcmp(cmd->handle.table.name, table->handle.table.name) ||
+ cmd->handle.family != table->handle.family) {
+ netlink_io_error(ctx, &cmd->handle.table.location,
+ "%s; did you mean table '%s' in family %s?",
+ strerror(ENOENT), table->handle.table.name,
+ family2str(table->handle.family));
+ return 1;
+ }
+
+ return 0;
+}
+
+static int nft_cmd_enoent_chain(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct location *loc)
+{
+ const struct table *table = NULL;
+ struct chain *chain;
+
+ if (!cmd->handle.chain.name)
+ return 0;
+
+ chain = chain_lookup_fuzzy(&cmd->handle, &ctx->nft->cache, &table);
+ /* check table first. */
+ if (!table)
+ return 0;
+
+ if (table_fuzzy_check(ctx, cmd, table))
+ return 1;
+
+ if (!chain)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean chain '%s' in table %s '%s'?",
+ strerror(ENOENT), chain->handle.chain.name,
+ family2str(table->handle.family),
+ table->handle.table.name);
+ return 1;
+}
+
+static int nft_cmd_enoent_rule(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct location *loc)
+{
+ unsigned int flags = NFT_CACHE_TABLE |
+ NFT_CACHE_CHAIN;
+ const struct table *table = NULL;
+ struct chain *chain;
+
+ if (nft_cache_update(ctx->nft, flags, ctx->msgs, NULL) < 0)
+ return 0;
+
+ chain = chain_lookup_fuzzy(&cmd->handle, &ctx->nft->cache, &table);
+ /* check table first. */
+ if (!table)
+ return 0;
+
+ if (table_fuzzy_check(ctx, cmd, table))
+ return 1;
+
+ if (!chain)
+ return 0;
+
+ if (strcmp(cmd->handle.chain.name, chain->handle.chain.name)) {
+ netlink_io_error(ctx, loc, "%s; did you mean chain '%s' in table %s '%s'?",
+ strerror(ENOENT),
+ chain->handle.chain.name,
+ family2str(table->handle.family),
+ table->handle.table.name);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int nft_cmd_enoent_set(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct location *loc)
+{
+ const struct table *table = NULL;
+ struct set *set;
+
+ if (!cmd->handle.set.name)
+ return 0;
+
+ set = set_lookup_fuzzy(cmd->handle.set.name, &ctx->nft->cache, &table);
+ /* check table first. */
+ if (!table)
+ return 0;
+
+ if (table_fuzzy_check(ctx, cmd, table))
+ return 1;
+
+ if (!set)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean %s '%s' in table %s '%s'?",
+ strerror(ENOENT),
+ set_is_map(set->flags) ? "map" : "set",
+ set->handle.set.name,
+ family2str(set->handle.family),
+ table->handle.table.name);
+ return 1;
+}
+
+static int nft_cmd_enoent_obj(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct location *loc)
+{
+ const struct table *table = NULL;
+ struct obj *obj;
+
+ if (!cmd->handle.obj.name)
+ return 0;
+
+ obj = obj_lookup_fuzzy(cmd->handle.obj.name, &ctx->nft->cache, &table);
+ /* check table first. */
+ if (!table)
+ return 0;
+
+ if (table_fuzzy_check(ctx, cmd, table))
+ return 1;
+
+ if (!obj)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean obj '%s' in table %s '%s'?",
+ strerror(ENOENT), obj->handle.obj.name,
+ family2str(obj->handle.family),
+ table->handle.table.name);
+ return 1;
+}
+
+static int nft_cmd_enoent_flowtable(struct netlink_ctx *ctx,
+ const struct cmd *cmd,
+ const struct location *loc)
+{
+ const struct table *table = NULL;
+ struct flowtable *ft;
+
+ if (!cmd->handle.flowtable.name)
+ return 0;
+
+ ft = flowtable_lookup_fuzzy(cmd->handle.flowtable.name,
+ &ctx->nft->cache, &table);
+ /* check table first. */
+ if (!table)
+ return 0;
+
+ if (table_fuzzy_check(ctx, cmd, table))
+ return 1;
+
+ if (!ft)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean flowtable '%s' in table %s '%s'?",
+ strerror(ENOENT), ft->handle.flowtable.name,
+ family2str(ft->handle.family),
+ table->handle.table.name);
+ return 1;
+}
+
+static void nft_cmd_enoent(struct netlink_ctx *ctx, const struct cmd *cmd,
+ const struct location *loc, int err)
+{
+ int ret = 0;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ ret = nft_cmd_enoent_table(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_CHAIN:
+ ret = nft_cmd_enoent_chain(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_SET:
+ ret = nft_cmd_enoent_set(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_RULE:
+ ret = nft_cmd_enoent_rule(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_LIMIT:
+ case CMD_OBJ_SECMARK:
+ case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_SYNPROXY:
+ ret = nft_cmd_enoent_obj(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_FLOWTABLE:
+ ret = nft_cmd_enoent_flowtable(ctx, cmd, loc);
+ break;
+ default:
+ break;
+ }
+
+ if (ret)
+ return;
+
+ netlink_io_error(ctx, loc, "Could not process rule: %s", strerror(err));
+}
+
+static int nft_cmd_chain_error(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct mnl_err *err)
+{
+ struct chain *chain = cmd->chain;
+ int priority;
+
+ switch (err->err) {
+ case EOPNOTSUPP:
+ if (!(chain->flags & CHAIN_F_BASECHAIN))
+ break;
+
+ mpz_export_data(&priority, chain->priority.expr->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ if (priority <= -200 && !strcmp(chain->type.str, "nat"))
+ return netlink_io_error(ctx, &chain->priority.loc,
+ "Chains of type \"nat\" must have a priority value above -200");
+
+ return netlink_io_error(ctx, &chain->loc,
+ "Chain of type \"%s\" is not supported, perhaps kernel support is missing?",
+ chain->type.str);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+void nft_cmd_error(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct mnl_err *err)
+{
+ const struct location *loc = NULL;
+ uint32_t i;
+
+ for (i = 0; i < cmd->num_attrs; i++) {
+ if (!cmd->attr[i].offset)
+ break;
+ if (cmd->attr[i].offset == err->offset)
+ loc = cmd->attr[i].location;
+ }
+
+ if (loc) {
+ if (err->err == ENOENT) {
+ nft_cmd_enoent(ctx, cmd, loc, err->err);
+ return;
+ }
+ } else {
+ loc = &cmd->location;
+ }
+
+ switch (cmd->obj) {
+ case CMD_OBJ_CHAIN:
+ if (nft_cmd_chain_error(ctx, cmd, err) < 0)
+ return;
+ break;
+ default:
+ break;
+ }
+
+ if (cmd->op == CMD_DESTROY && err->err == EINVAL) {
+ netlink_io_error(ctx, loc,
+ "\"destroy\" command is not supported, perhaps kernel support is missing?");
+ return;
+ }
+
+ netlink_io_error(ctx, loc, "Could not process rule: %s",
+ strerror(err->err));
+}
+
+static void nft_cmd_expand_chain(struct chain *chain, struct list_head *new_cmds)
+{
+ struct rule *rule, *next;
+ struct handle h;
+ struct cmd *new;
+
+ list_for_each_entry_safe(rule, next, &chain->rules, list) {
+ list_del(&rule->list);
+ handle_merge(&rule->handle, &chain->handle);
+ memset(&h, 0, sizeof(h));
+ handle_merge(&h, &chain->handle);
+ if (chain->flags & CHAIN_F_BINDING) {
+ rule->handle.chain_id = chain->handle.chain_id;
+ rule->handle.chain.location = chain->location;
+ }
+ new = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &h,
+ &rule->location, rule);
+ list_add_tail(&new->list, new_cmds);
+ }
+}
+
+void nft_cmd_expand(struct cmd *cmd)
+{
+ struct list_head new_cmds;
+ struct flowtable *ft;
+ struct table *table;
+ struct chain *chain;
+ struct set *set;
+ struct obj *obj;
+ struct cmd *new;
+ struct handle h;
+
+ init_list_head(&new_cmds);
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ table = cmd->table;
+ if (!table)
+ return;
+
+ list_for_each_entry(chain, &table->chains, list) {
+ handle_merge(&chain->handle, &table->handle);
+ memset(&h, 0, sizeof(h));
+ handle_merge(&h, &chain->handle);
+ h.chain_id = chain->handle.chain_id;
+ new = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &h,
+ &chain->location, chain_get(chain));
+ list_add_tail(&new->list, &new_cmds);
+ }
+ list_for_each_entry(obj, &table->objs, list) {
+ handle_merge(&obj->handle, &table->handle);
+ memset(&h, 0, sizeof(h));
+ handle_merge(&h, &obj->handle);
+ new = cmd_alloc(CMD_ADD, obj_type_to_cmd(obj->type), &h,
+ &obj->location, obj_get(obj));
+ list_add_tail(&new->list, &new_cmds);
+ }
+ list_for_each_entry(set, &table->sets, list) {
+ handle_merge(&set->handle, &table->handle);
+ memset(&h, 0, sizeof(h));
+ handle_merge(&h, &set->handle);
+ new = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &h,
+ &set->location, set_get(set));
+ list_add_tail(&new->list, &new_cmds);
+ }
+ list_for_each_entry(ft, &table->flowtables, list) {
+ handle_merge(&ft->handle, &table->handle);
+ memset(&h, 0, sizeof(h));
+ handle_merge(&h, &ft->handle);
+ new = cmd_alloc(CMD_ADD, CMD_OBJ_FLOWTABLE, &h,
+ &ft->location, flowtable_get(ft));
+ list_add_tail(&new->list, &new_cmds);
+ }
+ list_for_each_entry(chain, &table->chains, list)
+ nft_cmd_expand_chain(chain, &new_cmds);
+
+ list_splice(&new_cmds, &cmd->list);
+ break;
+ case CMD_OBJ_CHAIN:
+ chain = cmd->chain;
+ if (!chain || list_empty(&chain->rules))
+ break;
+
+ nft_cmd_expand_chain(chain, &new_cmds);
+ list_splice(&new_cmds, &cmd->list);
+ break;
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ set = cmd->set;
+ if (!set->init)
+ break;
+
+ memset(&h, 0, sizeof(h));
+ handle_merge(&h, &set->handle);
+ new = cmd_alloc(CMD_ADD, CMD_OBJ_SETELEMS, &h,
+ &set->location, set_get(set));
+ list_add(&new->list, &cmd->list);
+ break;
+ default:
+ break;
+ }
+}
+
+bool nft_cmd_collapse(struct list_head *cmds)
+{
+ struct cmd *cmd, *next, *elems = NULL;
+ struct expr *expr, *enext;
+ bool collapse = false;
+
+ list_for_each_entry_safe(cmd, next, cmds, list) {
+ if (cmd->op != CMD_ADD &&
+ cmd->op != CMD_CREATE) {
+ elems = NULL;
+ continue;
+ }
+
+ if (cmd->obj != CMD_OBJ_ELEMENTS) {
+ elems = NULL;
+ continue;
+ }
+
+ if (!elems) {
+ elems = cmd;
+ continue;
+ }
+
+ if (cmd->op != elems->op) {
+ elems = cmd;
+ continue;
+ }
+
+ if (elems->handle.family != cmd->handle.family ||
+ strcmp(elems->handle.table.name, cmd->handle.table.name) ||
+ strcmp(elems->handle.set.name, cmd->handle.set.name)) {
+ elems = cmd;
+ continue;
+ }
+
+ collapse = true;
+ list_for_each_entry_safe(expr, enext, &cmd->expr->expressions, list) {
+ expr->cmd = cmd;
+ list_move_tail(&expr->list, &elems->expr->expressions);
+ }
+ elems->expr->size += cmd->expr->size;
+ list_move_tail(&cmd->list, &elems->collapse_list);
+ }
+
+ return collapse;
+}
+
+void nft_cmd_uncollapse(struct list_head *cmds)
+{
+ struct cmd *cmd, *cmd_next, *collapse_cmd, *collapse_cmd_next;
+ struct expr *expr, *next;
+
+ list_for_each_entry_safe(cmd, cmd_next, cmds, list) {
+ if (list_empty(&cmd->collapse_list))
+ continue;
+
+ assert(cmd->obj == CMD_OBJ_ELEMENTS);
+
+ list_for_each_entry_safe(expr, next, &cmd->expr->expressions, list) {
+ if (!expr->cmd)
+ continue;
+
+ list_move_tail(&expr->list, &expr->cmd->expr->expressions);
+ cmd->expr->size--;
+ expr->cmd = NULL;
+ }
+
+ list_for_each_entry_safe(collapse_cmd, collapse_cmd_next, &cmd->collapse_list, list) {
+ if (cmd->elem.set)
+ collapse_cmd->elem.set = set_get(cmd->elem.set);
+
+ list_add(&collapse_cmd->list, &cmd->list);
+ }
+ }
+}
diff --git a/src/ct.c b/src/ct.c
index ed458e6b..67934648 100644
--- a/src/ct.c
+++ b/src/ct.c
@@ -10,11 +10,11 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <stddef.h>
-#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
-#include <string.h>
#include <netinet/ip.h>
#include <linux/netfilter.h>
@@ -131,7 +131,7 @@ static const struct symbol_table ct_events_tbl = {
},
};
-static const struct datatype ct_event_type = {
+const struct datatype ct_event_type = {
.type = TYPE_CT_EVENTBIT,
.name = "ct_event",
.desc = "conntrack event bits",
@@ -176,7 +176,7 @@ static struct error_record *ct_label_type_parse(struct parse_ctx *ctx,
{
const struct symbolic_constant *s;
const struct datatype *dtype;
- uint8_t data[CT_LABEL_BIT_SIZE];
+ uint8_t data[CT_LABEL_BIT_SIZE / BITS_PER_BYTE];
uint64_t bit;
mpz_t value;
@@ -211,16 +211,22 @@ static struct error_record *ct_label_type_parse(struct parse_ctx *ctx,
mpz_export_data(data, value, BYTEORDER_HOST_ENDIAN, sizeof(data));
*res = constant_expr_alloc(&sym->location, dtype,
- dtype->byteorder, sizeof(data),
- data);
+ dtype->byteorder, CT_LABEL_BIT_SIZE, data);
mpz_clear(value);
return NULL;
}
-static const struct datatype ct_label_type = {
+static void ct_label_type_describe(struct output_ctx *octx)
+{
+ rt_symbol_table_describe(octx, CONNLABEL_CONF,
+ octx->tbl.ct_label, &ct_label_type);
+}
+
+const struct datatype ct_label_type = {
.type = TYPE_CT_LABEL,
.name = "ct_label",
.desc = "conntrack label",
+ .describe = ct_label_type_describe,
.byteorder = BYTEORDER_HOST_ENDIAN,
.size = CT_LABEL_BIT_SIZE,
.basetype = &bitmask_type,
@@ -272,10 +278,10 @@ const struct ct_template ct_templates[__NFT_CT_MAX] = {
[NFT_CT_PROTOCOL] = CT_TEMPLATE("protocol", &inet_protocol_type,
BYTEORDER_BIG_ENDIAN,
BITS_PER_BYTE),
- [NFT_CT_PROTO_SRC] = CT_TEMPLATE("proto-src", &invalid_type,
+ [NFT_CT_PROTO_SRC] = CT_TEMPLATE("proto-src", &inet_service_type,
BYTEORDER_BIG_ENDIAN,
2 * BITS_PER_BYTE),
- [NFT_CT_PROTO_DST] = CT_TEMPLATE("proto-dst", &invalid_type,
+ [NFT_CT_PROTO_DST] = CT_TEMPLATE("proto-dst", &inet_service_type,
BYTEORDER_BIG_ENDIAN,
2 * BITS_PER_BYTE),
[NFT_CT_LABELS] = CT_TEMPLATE("label", &ct_label_type,
@@ -299,6 +305,10 @@ const struct ct_template ct_templates[__NFT_CT_MAX] = {
BYTEORDER_BIG_ENDIAN, 128),
[NFT_CT_DST_IP6] = CT_TEMPLATE("ip6 daddr", &ip6addr_type,
BYTEORDER_BIG_ENDIAN, 128),
+ [NFT_CT_SECMARK] = CT_TEMPLATE("secmark", &integer_type,
+ BYTEORDER_HOST_ENDIAN, 32),
+ [NFT_CT_ID] = CT_TEMPLATE("id", &integer_type,
+ BYTEORDER_BIG_ENDIAN, 32),
};
static void ct_print(enum nft_ct_keys key, int8_t dir, uint8_t nfproto,
@@ -347,9 +357,11 @@ static void ct_expr_clone(struct expr *new, const struct expr *expr)
new->ct = expr->ct;
}
-static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr)
+static void ct_expr_pctx_update(struct proto_ctx *ctx,
+ const struct location *loc,
+ const struct expr *left,
+ const struct expr *right)
{
- const struct expr *left = expr->left, *right = expr->right;
const struct proto_desc *base = NULL, *desc;
uint32_t nhproto;
@@ -362,7 +374,61 @@ static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr)
if (!desc)
return;
- proto_ctx_update(ctx, left->ct.base + 1, &expr->location, desc);
+ proto_ctx_update(ctx, left->ct.base + 1, loc, desc);
+}
+
+#define NFTNL_UDATA_CT_KEY 0
+#define NFTNL_UDATA_CT_DIR 1
+#define NFTNL_UDATA_CT_MAX 2
+
+static int ct_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_CT_KEY, expr->ct.key);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_CT_DIR, expr->ct.direction);
+
+ return 0;
+}
+
+static int ct_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_CT_KEY:
+ case NFTNL_UDATA_CT_DIR:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *ct_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_CT_MAX + 1] = {};
+ uint32_t key, dir;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ ct_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_CT_KEY] ||
+ !ud[NFTNL_UDATA_CT_DIR])
+ return NULL;
+
+ key = nftnl_udata_get_u32(ud[NFTNL_UDATA_CT_KEY]);
+ dir = nftnl_udata_get_u32(ud[NFTNL_UDATA_CT_DIR]);
+
+ return ct_expr_alloc(&internal_location, key, dir);
}
const struct expr_ops ct_expr_ops = {
@@ -373,6 +439,8 @@ const struct expr_ops ct_expr_ops = {
.cmp = ct_expr_cmp,
.clone = ct_expr_clone,
.pctx_update = ct_expr_pctx_update,
+ .parse_udata = ct_expr_parse_udata,
+ .build_udata = ct_expr_build_udata,
};
struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key,
@@ -509,7 +577,7 @@ static void flow_offload_stmt_print(const struct stmt *stmt,
static void flow_offload_stmt_destroy(struct stmt *stmt)
{
- xfree(stmt->flow.table_name);
+ free_const(stmt->flow.table_name);
}
static const struct stmt_ops flow_offload_stmt_ops = {
@@ -517,6 +585,7 @@ static const struct stmt_ops flow_offload_stmt_ops = {
.name = "flow_offload",
.print = flow_offload_stmt_print,
.destroy = flow_offload_stmt_destroy,
+ .json = flow_offload_stmt_json,
};
struct stmt *flow_offload_stmt_alloc(const struct location *loc,
diff --git a/src/datatype.c b/src/datatype.c
index b9e167e0..d398a9c8 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -8,8 +8,8 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
-#include <stdlib.h>
-#include <string.h>
+#include <nft.h>
+
#include <inttypes.h>
#include <ctype.h> /* isdigit */
#include <errno.h>
@@ -18,6 +18,8 @@
#include <linux/types.h>
#include <linux/netfilter.h>
#include <linux/icmpv6.h>
+#include <dirent.h>
+#include <sys/stat.h>
#include <nftables.h>
#include <datatype.h>
@@ -26,6 +28,8 @@
#include <erec.h>
#include <netlink.h>
#include <json.h>
+#include <misspell.h>
+#include "nftutils.h"
#include <netinet/ip_icmp.h>
@@ -60,6 +64,7 @@ static const struct datatype *datatypes[TYPE_MAX + 1] = {
[TYPE_CT_DIR] = &ct_dir_type,
[TYPE_CT_STATUS] = &ct_status_type,
[TYPE_ICMP6_TYPE] = &icmp6_type_type,
+ [TYPE_CT_LABEL] = &ct_label_type,
[TYPE_PKTTYPE] = &pkttype_type,
[TYPE_ICMP_CODE] = &icmp_code_type,
[TYPE_ICMPV6_CODE] = &icmpv6_code_type,
@@ -69,11 +74,13 @@ static const struct datatype *datatypes[TYPE_MAX + 1] = {
[TYPE_ECN] = &ecn_type,
[TYPE_FIB_ADDR] = &fib_addr_type,
[TYPE_BOOLEAN] = &boolean_type,
+ [TYPE_CT_EVENTBIT] = &ct_event_type,
[TYPE_IFNAME] = &ifname_type,
[TYPE_IGMP_TYPE] = &igmp_type_type,
[TYPE_TIME_DATE] = &date_type,
[TYPE_TIME_HOUR] = &hour_type,
[TYPE_TIME_DAY] = &day_type,
+ [TYPE_CGROUPV2] = &cgroupv2_type,
};
const struct datatype *datatype_lookup(enum datatypes type)
@@ -120,6 +127,7 @@ struct error_record *symbol_parse(struct parse_ctx *ctx, const struct expr *sym,
struct expr **res)
{
const struct datatype *dtype = sym->dtype;
+ struct error_record *erec;
assert(sym->etype == EXPR_SYMBOL);
@@ -133,11 +141,54 @@ struct error_record *symbol_parse(struct parse_ctx *ctx, const struct expr *sym,
res);
} while ((dtype = dtype->basetype));
- return error(&sym->location,
- "Can't parse symbolic %s expressions",
+ dtype = sym->dtype;
+ if (dtype->err) {
+ erec = dtype->err(sym);
+ if (erec)
+ return erec;
+ }
+
+ return error(&sym->location, "Could not parse symbolic %s expression",
sym->dtype->desc);
}
+static struct error_record *__symbol_parse_fuzzy(const struct expr *sym,
+ const struct symbol_table *tbl)
+{
+ const struct symbolic_constant *s;
+ struct string_misspell_state st;
+
+ string_misspell_init(&st);
+
+ for (s = tbl->symbols; s->identifier != NULL; s++) {
+ string_misspell_update(sym->identifier, s->identifier,
+ (void *)s->identifier, &st);
+ }
+
+ if (st.obj) {
+ return error(&sym->location,
+ "Could not parse %s expression; did you you mean `%s`?",
+ sym->dtype->desc, st.obj);
+ }
+
+ return NULL;
+}
+
+static struct error_record *symbol_parse_fuzzy(const struct expr *sym,
+ const struct symbol_table *tbl)
+{
+ struct error_record *erec;
+
+ if (!tbl)
+ return NULL;
+
+ erec = __symbol_parse_fuzzy(sym, tbl);
+ if (erec)
+ return erec;
+
+ return NULL;
+}
+
struct error_record *symbolic_constant_parse(struct parse_ctx *ctx,
const struct expr *sym,
const struct symbol_table *tbl,
@@ -160,8 +211,16 @@ struct error_record *symbolic_constant_parse(struct parse_ctx *ctx,
do {
if (dtype->basetype->parse) {
erec = dtype->basetype->parse(ctx, sym, res);
- if (erec != NULL)
- return erec;
+ if (erec != NULL) {
+ struct error_record *fuzzy_erec;
+
+ fuzzy_erec = symbol_parse_fuzzy(sym, tbl);
+ if (!fuzzy_erec)
+ return erec;
+
+ erec_destroy(erec);
+ return fuzzy_erec;
+ }
if (*res)
return NULL;
goto out;
@@ -247,20 +306,25 @@ const struct datatype invalid_type = {
.print = invalid_type_print,
};
+void expr_chain_export(const struct expr *e, char *chain_name)
+{
+ unsigned int len;
+
+ len = e->len / BITS_PER_BYTE;
+ if (len >= NFT_CHAIN_MAXNAMELEN)
+ BUG("verdict expression length %u is too large (%u bits max)",
+ e->len, NFT_CHAIN_MAXNAMELEN * BITS_PER_BYTE);
+
+ mpz_export_data(chain_name, e->value, BYTEORDER_HOST_ENDIAN, len);
+}
+
static void verdict_jump_chain_print(const char *what, const struct expr *e,
struct output_ctx *octx)
{
char chain[NFT_CHAIN_MAXNAMELEN];
- unsigned int len;
memset(chain, 0, sizeof(chain));
-
- len = e->len / BITS_PER_BYTE;
- if (len >= sizeof(chain))
- BUG("verdict expression length %u is too large (%lu bits max)",
- e->len, (unsigned long)sizeof(chain) * BITS_PER_BYTE);
-
- mpz_export_data(chain, e->value, BYTEORDER_HOST_ENDIAN, len);
+ expr_chain_export(e, chain);
nft_print(octx, "%s %s", what, chain);
}
@@ -313,15 +377,33 @@ static void verdict_type_print(const struct expr *expr, struct output_ctx *octx)
}
}
-static struct error_record *verdict_type_parse(struct parse_ctx *ctx,
- const struct expr *sym,
- struct expr **res)
+static struct error_record *verdict_type_error(const struct expr *sym)
{
- *res = constant_expr_alloc(&sym->location, &string_type,
- BYTEORDER_HOST_ENDIAN,
- (strlen(sym->identifier) + 1) * BITS_PER_BYTE,
- sym->identifier);
- return NULL;
+ /* Skip jump and goto from fuzzy match to provide better error
+ * reporting, fall back to `jump chain' if no clue.
+ */
+ static const char *verdict_array[] = {
+ "continue", "break", "return", "accept", "drop", "queue",
+ "stolen", NULL,
+ };
+ struct string_misspell_state st;
+ int i;
+
+ string_misspell_init(&st);
+
+ for (i = 0; verdict_array[i] != NULL; i++) {
+ string_misspell_update(sym->identifier, verdict_array[i],
+ (void *)verdict_array[i], &st);
+ }
+
+ if (st.obj) {
+ return error(&sym->location, "Could not parse %s; did you mean `%s'?",
+ sym->dtype->desc, st.obj);
+ }
+
+ /* assume user would like to jump to chain as a hint. */
+ return error(&sym->location, "Could not parse %s; did you mean `jump %s'?",
+ sym->dtype->desc, sym->identifier);
}
const struct datatype verdict_type = {
@@ -329,7 +411,7 @@ const struct datatype verdict_type = {
.name = "verdict",
.desc = "netfilter verdict",
.print = verdict_type_print,
- .parse = verdict_type_parse,
+ .err = verdict_type_error,
};
static const struct symbol_table nfproto_tbl = {
@@ -402,6 +484,22 @@ const struct datatype integer_type = {
.parse = integer_type_parse,
};
+static void xinteger_type_print(const struct expr *expr, struct output_ctx *octx)
+{
+ nft_gmp_print(octx, "0x%Zx", expr->value);
+}
+
+/* Alias of integer_type to print raw payload expressions in hexadecimal. */
+const struct datatype xinteger_type = {
+ .type = TYPE_INTEGER,
+ .name = "integer",
+ .desc = "integer",
+ .basetype = &integer_type,
+ .print = xinteger_type_print,
+ .json = integer_type_json,
+ .parse = integer_type_parse,
+};
+
static void string_type_print(const struct expr *expr, struct output_ctx *octx)
{
unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
@@ -504,27 +602,34 @@ static struct error_record *ipaddr_type_parse(struct parse_ctx *ctx,
const struct expr *sym,
struct expr **res)
{
- struct addrinfo *ai, hints = { .ai_family = AF_INET,
- .ai_socktype = SOCK_DGRAM};
- struct in_addr *addr;
- int err;
+ struct in_addr addr;
- err = getaddrinfo(sym->identifier, NULL, &hints, &ai);
- if (err != 0)
- return error(&sym->location, "Could not resolve hostname: %s",
- gai_strerror(err));
+ if (nft_input_no_dns(ctx->input)) {
+ if (inet_pton(AF_INET, sym->identifier, &addr) != 1)
+ return error(&sym->location, "Invalid IPv4 address");
+ } else {
+ struct addrinfo *ai, hints = { .ai_family = AF_INET,
+ .ai_socktype = SOCK_DGRAM};
+ int err;
- if (ai->ai_next != NULL) {
+ err = getaddrinfo(sym->identifier, NULL, &hints, &ai);
+ if (err != 0)
+ return error(&sym->location, "Could not resolve hostname: %s",
+ gai_strerror(err));
+
+ if (ai->ai_next != NULL) {
+ freeaddrinfo(ai);
+ return error(&sym->location,
+ "Hostname resolves to multiple addresses");
+ }
+ assert(ai->ai_addr->sa_family == AF_INET);
+ addr = ((struct sockaddr_in *) (void *) ai->ai_addr)->sin_addr;
freeaddrinfo(ai);
- return error(&sym->location,
- "Hostname resolves to multiple addresses");
}
- addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr;
*res = constant_expr_alloc(&sym->location, &ipaddr_type,
BYTEORDER_BIG_ENDIAN,
- sizeof(*addr) * BITS_PER_BYTE, addr);
- freeaddrinfo(ai);
+ sizeof(addr) * BITS_PER_BYTE, &addr);
return NULL;
}
@@ -563,27 +668,35 @@ static struct error_record *ip6addr_type_parse(struct parse_ctx *ctx,
const struct expr *sym,
struct expr **res)
{
- struct addrinfo *ai, hints = { .ai_family = AF_INET6,
- .ai_socktype = SOCK_DGRAM};
- struct in6_addr *addr;
- int err;
+ struct in6_addr addr;
- err = getaddrinfo(sym->identifier, NULL, &hints, &ai);
- if (err != 0)
- return error(&sym->location, "Could not resolve hostname: %s",
- gai_strerror(err));
+ if (nft_input_no_dns(ctx->input)) {
+ if (inet_pton(AF_INET6, sym->identifier, &addr) != 1)
+ return error(&sym->location, "Invalid IPv6 address");
+ } else {
+ struct addrinfo *ai, hints = { .ai_family = AF_INET6,
+ .ai_socktype = SOCK_DGRAM};
+ int err;
- if (ai->ai_next != NULL) {
+ err = getaddrinfo(sym->identifier, NULL, &hints, &ai);
+ if (err != 0)
+ return error(&sym->location, "Could not resolve hostname: %s",
+ gai_strerror(err));
+
+ if (ai->ai_next != NULL) {
+ freeaddrinfo(ai);
+ return error(&sym->location,
+ "Hostname resolves to multiple addresses");
+ }
+
+ assert(ai->ai_addr->sa_family == AF_INET6);
+ addr = ((struct sockaddr_in6 *)(void *)ai->ai_addr)->sin6_addr;
freeaddrinfo(ai);
- return error(&sym->location,
- "Hostname resolves to multiple addresses");
}
- addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
*res = constant_expr_alloc(&sym->location, &ip6addr_type,
BYTEORDER_BIG_ENDIAN,
- sizeof(*addr) * BITS_PER_BYTE, addr);
- freeaddrinfo(ai);
+ sizeof(addr) * BITS_PER_BYTE, &addr);
return NULL;
}
@@ -602,23 +715,36 @@ const struct datatype ip6addr_type = {
static void inet_protocol_type_print(const struct expr *expr,
struct output_ctx *octx)
{
- struct protoent *p;
+ if (!nft_output_numeric_proto(octx) &&
+ mpz_cmp_ui(expr->value, UINT8_MAX) <= 0) {
+ char name[NFT_PROTONAME_MAXSIZE];
- if (!nft_output_numeric_proto(octx)) {
- p = getprotobynumber(mpz_get_uint8(expr->value));
- if (p != NULL) {
- nft_print(octx, "%s", p->p_name);
+ if (nft_getprotobynumber(mpz_get_uint8(expr->value), name, sizeof(name))) {
+ nft_print(octx, "%s", name);
return;
}
}
integer_type_print(expr, octx);
}
+static void inet_protocol_type_describe(struct output_ctx *octx)
+{
+ uint8_t protonum;
+
+ for (protonum = 0; protonum < UINT8_MAX; protonum++) {
+ char name[NFT_PROTONAME_MAXSIZE];
+
+ if (!nft_getprotobynumber(protonum, name, sizeof(name)))
+ continue;
+
+ nft_print(octx, "\t%-30s\t%u\n", name, protonum);
+ }
+}
+
static struct error_record *inet_protocol_type_parse(struct parse_ctx *ctx,
const struct expr *sym,
struct expr **res)
{
- struct protoent *p;
uint8_t proto;
uintmax_t i;
char *end;
@@ -631,11 +757,13 @@ static struct error_record *inet_protocol_type_parse(struct parse_ctx *ctx,
proto = i;
} else {
- p = getprotobyname(sym->identifier);
- if (p == NULL)
+ int r;
+
+ r = nft_getprotobyname(sym->identifier);
+ if (r < 0)
return error(&sym->location, "Could not resolve protocol name");
- proto = p->p_proto;
+ proto = r;
}
*res = constant_expr_alloc(&sym->location, &inet_protocol_type,
@@ -653,43 +781,24 @@ const struct datatype inet_protocol_type = {
.print = inet_protocol_type_print,
.json = inet_protocol_type_json,
.parse = inet_protocol_type_parse,
+ .describe = inet_protocol_type_describe,
};
static void inet_service_print(const struct expr *expr, struct output_ctx *octx)
{
- struct sockaddr_in sin = { .sin_family = AF_INET };
- char buf[NI_MAXSERV];
- uint16_t port;
- int err;
+ uint16_t port = mpz_get_be16(expr->value);
+ char name[NFT_SERVNAME_MAXSIZE];
- sin.sin_port = mpz_get_be16(expr->value);
- err = getnameinfo((struct sockaddr *)&sin, sizeof(sin), NULL, 0,
- buf, sizeof(buf), 0);
- if (err != 0) {
- nft_print(octx, "%u", ntohs(sin.sin_port));
- return;
- }
- port = atoi(buf);
- /* We got a TCP service name string, display it... */
- if (htons(port) != sin.sin_port) {
- nft_print(octx, "\"%s\"", buf);
- return;
- }
-
- /* ...otherwise, this might be a UDP service name. */
- err = getnameinfo((struct sockaddr *)&sin, sizeof(sin), NULL, 0,
- buf, sizeof(buf), NI_DGRAM);
- if (err != 0) {
- /* No service name, display numeric value. */
- nft_print(octx, "%u", ntohs(sin.sin_port));
- return;
- }
- nft_print(octx, "\"%s\"", buf);
+ if (!nft_getservbyport(port, NULL, name, sizeof(name)))
+ nft_print(octx, "%hu", ntohs(port));
+ else
+ nft_print(octx, "\"%s\"", name);
}
void inet_service_type_print(const struct expr *expr, struct output_ctx *octx)
{
- if (nft_output_service(octx)) {
+ if (nft_output_service(octx) &&
+ mpz_cmp_ui(expr->value, UINT16_MAX) <= 0) {
inet_service_print(expr, octx);
return;
}
@@ -719,7 +828,12 @@ static struct error_record *inet_service_type_parse(struct parse_ctx *ctx,
return error(&sym->location, "Could not resolve service: %s",
gai_strerror(err));
- port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
+ if (ai->ai_addr->sa_family == AF_INET) {
+ port = ((struct sockaddr_in *)(void *)ai->ai_addr)->sin_port;
+ } else {
+ assert(ai->ai_addr->sa_family == AF_INET6);
+ port = ((struct sockaddr_in6 *)(void *)ai->ai_addr)->sin6_port;
+ }
freeaddrinfo(ai);
}
@@ -743,19 +857,48 @@ const struct datatype inet_service_type = {
#define RT_SYM_TAB_INITIAL_SIZE 16
+static FILE *open_iproute2_db(const char *filename, char **path)
+{
+ FILE *ret;
+
+ if (filename[0] == '/')
+ return fopen(filename, "r");
+
+ if (asprintf(path, "/etc/iproute2/%s", filename) == -1)
+ goto fail;
+
+ ret = fopen(*path, "r");
+ if (ret)
+ return ret;
+
+ free(*path);
+ if (asprintf(path, "/usr/share/iproute2/%s", filename) == -1)
+ goto fail;
+
+ ret = fopen(*path, "r");
+ if (ret)
+ return ret;
+
+ free(*path);
+fail:
+ *path = NULL;
+ return NULL;
+}
+
struct symbol_table *rt_symbol_table_init(const char *filename)
{
+ char buf[512], namebuf[512], *p, *path = NULL;
struct symbolic_constant s;
struct symbol_table *tbl;
unsigned int size, nelems, val;
- char buf[512], namebuf[512], *p;
FILE *f;
size = RT_SYM_TAB_INITIAL_SIZE;
tbl = xmalloc(sizeof(*tbl) + size * sizeof(s));
+ tbl->base = BASE_DECIMAL;
nelems = 0;
- f = fopen(filename, "r");
+ f = open_iproute2_db(filename, &path);
if (f == NULL)
goto out;
@@ -765,12 +908,15 @@ struct symbol_table *rt_symbol_table_init(const char *filename)
p++;
if (*p == '#' || *p == '\n' || *p == '\0')
continue;
- if (sscanf(p, "0x%x %511s\n", &val, namebuf) != 2 &&
- sscanf(p, "0x%x %511s #", &val, namebuf) != 2 &&
- sscanf(p, "%u %511s\n", &val, namebuf) != 2 &&
- sscanf(p, "%u %511s #", &val, namebuf) != 2) {
+ if (sscanf(p, "0x%x %511s\n", &val, namebuf) == 2 ||
+ sscanf(p, "0x%x %511s #", &val, namebuf) == 2) {
+ tbl->base = BASE_HEXADECIMAL;
+ } else if (sscanf(p, "%u %511s\n", &val, namebuf) == 2 ||
+ sscanf(p, "%u %511s #", &val, namebuf) == 2) {
+ tbl->base = BASE_DECIMAL;
+ } else {
fprintf(stderr, "iproute database '%s' corrupted\n",
- filename);
+ path ?: filename);
break;
}
@@ -787,6 +933,8 @@ struct symbol_table *rt_symbol_table_init(const char *filename)
fclose(f);
out:
+ if (path)
+ free(path);
tbl->symbols[nelems] = SYMBOL_LIST_END;
return tbl;
}
@@ -796,13 +944,40 @@ void rt_symbol_table_free(const struct symbol_table *tbl)
const struct symbolic_constant *s;
for (s = tbl->symbols; s->identifier != NULL; s++)
- xfree(s->identifier);
- xfree(tbl);
+ free_const(s->identifier);
+ free_const(tbl);
+}
+
+void rt_symbol_table_describe(struct output_ctx *octx, const char *name,
+ const struct symbol_table *tbl,
+ const struct datatype *type)
+{
+ char *path = NULL;
+ FILE *f;
+
+ if (!tbl || !tbl->symbols[0].identifier)
+ return;
+
+ f = open_iproute2_db(name, &path);
+ if (f)
+ fclose(f);
+ if (!path && asprintf(&path, "%s%s",
+ name[0] == '/' ? "" : "unknown location of ",
+ name) < 0)
+ return;
+
+ nft_print(octx, "\npre-defined symbolic constants from %s ", path);
+ if (tbl->base == BASE_DECIMAL)
+ nft_print(octx, "(in decimal):\n");
+ else
+ nft_print(octx, "(in hexadecimal):\n");
+ symbol_table_print(tbl, type, type->byteorder, octx);
+ free(path);
}
void mark_table_init(struct nft_ctx *ctx)
{
- ctx->output.tbl.mark = rt_symbol_table_init("/etc/iproute2/rt_marks");
+ ctx->output.tbl.mark = rt_symbol_table_init("rt_marks");
}
void mark_table_exit(struct nft_ctx *ctx)
@@ -822,10 +997,17 @@ static struct error_record *mark_type_parse(struct parse_ctx *ctx,
return symbolic_constant_parse(ctx, sym, ctx->tbl->mark, res);
}
+static void mark_type_describe(struct output_ctx *octx)
+{
+ rt_symbol_table_describe(octx, "rt_marks",
+ octx->tbl.mark, &mark_type);
+}
+
const struct datatype mark_type = {
.type = TYPE_MARK,
.name = "mark",
.desc = "packet mark",
+ .describe = mark_type_describe,
.size = 4 * BITS_PER_BYTE,
.byteorder = BYTEORDER_HOST_ENDIAN,
.basetype = &integer_type,
@@ -833,9 +1015,9 @@ const struct datatype mark_type = {
.print = mark_type_print,
.json = mark_type_json,
.parse = mark_type_parse,
- .flags = DTYPE_F_PREFIX,
};
+/* symbol table for private datatypes for reject statement. */
static const struct symbol_table icmp_code_tbl = {
.base = BASE_DECIMAL,
.symbols = {
@@ -846,20 +1028,22 @@ static const struct symbol_table icmp_code_tbl = {
SYMBOL("net-prohibited", ICMP_NET_ANO),
SYMBOL("host-prohibited", ICMP_HOST_ANO),
SYMBOL("admin-prohibited", ICMP_PKT_FILTERED),
+ SYMBOL("frag-needed", ICMP_FRAG_NEEDED),
SYMBOL_LIST_END
},
};
-const struct datatype icmp_code_type = {
- .type = TYPE_ICMP_CODE,
+/* private datatype for reject statement. */
+const struct datatype reject_icmp_code_type = {
.name = "icmp_code",
- .desc = "icmp code",
+ .desc = "reject icmp code",
.size = BITS_PER_BYTE,
.byteorder = BYTEORDER_BIG_ENDIAN,
.basetype = &integer_type,
.sym_tbl = &icmp_code_tbl,
};
+/* symbol table for private datatypes for reject statement. */
static const struct symbol_table icmpv6_code_tbl = {
.base = BASE_DECIMAL,
.symbols = {
@@ -873,16 +1057,17 @@ static const struct symbol_table icmpv6_code_tbl = {
},
};
-const struct datatype icmpv6_code_type = {
- .type = TYPE_ICMPV6_CODE,
+/* private datatype for reject statement. */
+const struct datatype reject_icmpv6_code_type = {
.name = "icmpv6_code",
- .desc = "icmpv6 code",
+ .desc = "reject icmpv6 code",
.size = BITS_PER_BYTE,
.byteorder = BYTEORDER_BIG_ENDIAN,
.basetype = &integer_type,
.sym_tbl = &icmpv6_code_tbl,
};
+/* symbol table for private datatypes for reject statement. */
static const struct symbol_table icmpx_code_tbl = {
.base = BASE_DECIMAL,
.symbols = {
@@ -894,6 +1079,60 @@ static const struct symbol_table icmpx_code_tbl = {
},
};
+/* private datatype for reject statement. */
+const struct datatype reject_icmpx_code_type = {
+ .name = "icmpx_code",
+ .desc = "reject icmpx code",
+ .size = BITS_PER_BYTE,
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .basetype = &integer_type,
+ .sym_tbl = &icmpx_code_tbl,
+};
+
+/* Backward compatible parser for the reject statement. */
+static struct error_record *icmp_code_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ return symbolic_constant_parse(ctx, sym, &icmp_code_tbl, res);
+}
+
+const struct datatype icmp_code_type = {
+ .type = TYPE_ICMP_CODE,
+ .name = "icmp_code",
+ .desc = "icmp code",
+ .size = BITS_PER_BYTE,
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .basetype = &integer_type,
+ .parse = icmp_code_parse,
+};
+
+/* Backward compatible parser for the reject statement. */
+static struct error_record *icmpv6_code_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ return symbolic_constant_parse(ctx, sym, &icmpv6_code_tbl, res);
+}
+
+const struct datatype icmpv6_code_type = {
+ .type = TYPE_ICMPV6_CODE,
+ .name = "icmpv6_code",
+ .desc = "icmpv6 code",
+ .size = BITS_PER_BYTE,
+ .byteorder = BYTEORDER_BIG_ENDIAN,
+ .basetype = &integer_type,
+ .parse = icmpv6_code_parse,
+};
+
+/* Backward compatible parser for the reject statement. */
+static struct error_record *icmpx_code_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ return symbolic_constant_parse(ctx, sym, &icmpx_code_tbl, res);
+}
+
const struct datatype icmpx_code_type = {
.type = TYPE_ICMPX_CODE,
.name = "icmpx_code",
@@ -901,12 +1140,18 @@ const struct datatype icmpx_code_type = {
.size = BITS_PER_BYTE,
.byteorder = BYTEORDER_BIG_ENDIAN,
.basetype = &integer_type,
- .sym_tbl = &icmpx_code_tbl,
+ .parse = icmpx_code_parse,
};
void time_print(uint64_t ms, struct output_ctx *octx)
{
uint64_t days, hours, minutes, seconds;
+ bool printed = false;
+
+ if (nft_output_seconds(octx)) {
+ nft_print(octx, "%" PRIu64 "s", ms / 1000);
+ return;
+ }
days = ms / 86400000;
ms %= 86400000;
@@ -920,16 +1165,29 @@ void time_print(uint64_t ms, struct output_ctx *octx)
seconds = ms / 1000;
ms %= 1000;
- if (days > 0)
+ if (days > 0) {
nft_print(octx, "%" PRIu64 "d", days);
- if (hours > 0)
+ printed = true;
+ }
+ if (hours > 0) {
nft_print(octx, "%" PRIu64 "h", hours);
- if (minutes > 0)
+ printed = true;
+ }
+ if (minutes > 0) {
nft_print(octx, "%" PRIu64 "m", minutes);
- if (seconds > 0)
+ printed = true;
+ }
+ if (seconds > 0) {
nft_print(octx, "%" PRIu64 "s", seconds);
- if (ms > 0)
+ printed = true;
+ }
+ if (ms > 0) {
nft_print(octx, "%" PRIu64 "ms", ms);
+ printed = true;
+ }
+
+ if (!printed)
+ nft_print(octx, "0s");
}
enum {
@@ -1044,6 +1302,7 @@ static struct error_record *time_type_parse(struct parse_ctx *ctx,
struct expr **res)
{
struct error_record *erec;
+ uint32_t s32;
uint64_t s;
erec = time_parse(&sym->location, sym->identifier, &s);
@@ -1053,9 +1312,10 @@ static struct error_record *time_type_parse(struct parse_ctx *ctx,
if (s > UINT32_MAX)
return error(&sym->location, "value too large");
+ s32 = s;
*res = constant_expr_alloc(&sym->location, &time_type,
BYTEORDER_HOST_ENDIAN,
- sizeof(uint32_t) * BITS_PER_BYTE, &s);
+ sizeof(uint32_t) * BITS_PER_BYTE, &s32);
return NULL;
}
@@ -1064,7 +1324,7 @@ const struct datatype time_type = {
.name = "time",
.desc = "relative time",
.byteorder = BYTEORDER_HOST_ENDIAN,
- .size = 8 * BITS_PER_BYTE,
+ .size = 4 * BITS_PER_BYTE,
.basetype = &integer_type,
.print = time_type_print,
.json = time_type_json,
@@ -1079,17 +1339,18 @@ static struct error_record *concat_type_parse(struct parse_ctx *ctx,
sym->dtype->desc);
}
-static struct datatype *dtype_alloc(void)
+static struct datatype *datatype_alloc(void)
{
struct datatype *dtype;
dtype = xzalloc(sizeof(*dtype));
dtype->flags = DTYPE_F_ALLOC;
+ dtype->refcnt = 1;
return dtype;
}
-struct datatype *datatype_get(const struct datatype *ptr)
+const struct datatype *datatype_get(const struct datatype *ptr)
{
struct datatype *dtype = (struct datatype *)ptr;
@@ -1102,22 +1363,31 @@ struct datatype *datatype_get(const struct datatype *ptr)
return dtype;
}
+void __datatype_set(struct expr *expr, const struct datatype *dtype)
+{
+ const struct datatype *dtype_free;
+
+ dtype_free = expr->dtype;
+ expr->dtype = dtype;
+ datatype_free(dtype_free);
+}
+
void datatype_set(struct expr *expr, const struct datatype *dtype)
{
- datatype_free(expr->dtype);
- expr->dtype = datatype_get(dtype);
+ if (dtype != expr->dtype)
+ __datatype_set(expr, datatype_get(dtype));
}
-static struct datatype *dtype_clone(const struct datatype *orig_dtype)
+struct datatype *datatype_clone(const struct datatype *orig_dtype)
{
struct datatype *dtype;
- dtype = xzalloc(sizeof(*dtype));
+ dtype = xmalloc(sizeof(*dtype));
*dtype = *orig_dtype;
dtype->name = xstrdup(orig_dtype->name);
dtype->desc = xstrdup(orig_dtype->desc);
dtype->flags = DTYPE_F_ALLOC | orig_dtype->flags;
- dtype->refcnt = 0;
+ dtype->refcnt = 1;
return dtype;
}
@@ -1130,12 +1400,15 @@ void datatype_free(const struct datatype *ptr)
return;
if (!(dtype->flags & DTYPE_F_ALLOC))
return;
+
+ assert(dtype->refcnt != 0);
+
if (--dtype->refcnt > 0)
return;
- xfree(dtype->name);
- xfree(dtype->desc);
- xfree(dtype);
+ free_const(dtype->name);
+ free_const(dtype->desc);
+ free(dtype);
}
const struct datatype *concat_type_alloc(uint32_t type)
@@ -1164,7 +1437,7 @@ const struct datatype *concat_type_alloc(uint32_t type)
}
strncat(desc, ")", sizeof(desc) - strlen(desc) - 1);
- dtype = dtype_alloc();
+ dtype = datatype_alloc();
dtype->type = type;
dtype->size = size;
dtype->subtypes = subtypes;
@@ -1176,25 +1449,20 @@ const struct datatype *concat_type_alloc(uint32_t type)
}
const struct datatype *set_datatype_alloc(const struct datatype *orig_dtype,
- unsigned int byteorder)
+ enum byteorder byteorder)
{
struct datatype *dtype;
/* Restrict dynamic datatype allocation to generic integer datatype. */
if (orig_dtype != &integer_type)
- return orig_dtype;
+ return datatype_get(orig_dtype);
- dtype = dtype_clone(orig_dtype);
+ dtype = datatype_clone(orig_dtype);
dtype->byteorder = byteorder;
return dtype;
}
-void set_datatype_destroy(const struct datatype *dtype)
-{
- datatype_free(dtype);
-}
-
static struct error_record *time_unit_parse(const struct location *loc,
const char *str, uint64_t *unit)
{
@@ -1334,3 +1602,92 @@ const struct datatype policy_type = {
.desc = "policy type",
.parse = policy_type_parse,
};
+
+#define SYSFS_CGROUPSV2_PATH "/sys/fs/cgroup"
+
+static char *cgroupv2_get_path(const char *path, uint64_t id)
+{
+ char dent_name[PATH_MAX + 1];
+ char *cgroup_path = NULL;
+ struct dirent *dent;
+ struct stat st;
+ DIR *d;
+
+ d = opendir(path);
+ if (!d)
+ return NULL;
+
+ while ((dent = readdir(d)) != NULL) {
+ if (!strcmp(dent->d_name, ".") ||
+ !strcmp(dent->d_name, ".."))
+ continue;
+
+ snprintf(dent_name, sizeof(dent_name), "%s/%s",
+ path, dent->d_name);
+ dent_name[sizeof(dent_name) - 1] = '\0';
+
+ if (dent->d_ino == id) {
+ cgroup_path = xstrdup(dent_name);
+ break;
+ }
+
+ if (stat(dent_name, &st) >= 0 && S_ISDIR(st.st_mode)) {
+ cgroup_path = cgroupv2_get_path(dent_name, id);
+ if (cgroup_path)
+ break;
+ }
+ }
+ closedir(d);
+
+ return cgroup_path;
+}
+
+static void cgroupv2_type_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ uint64_t id = mpz_get_uint64(expr->value);
+ char *cgroup_path;
+
+ cgroup_path = cgroupv2_get_path(SYSFS_CGROUPSV2_PATH, id);
+ if (cgroup_path)
+ nft_print(octx, "\"%s\"",
+ &cgroup_path[strlen(SYSFS_CGROUPSV2_PATH) + 1]);
+ else
+ nft_print(octx, "%" PRIu64, id);
+
+ free(cgroup_path);
+}
+
+static struct error_record *cgroupv2_type_parse(struct parse_ctx *ctx,
+ const struct expr *sym,
+ struct expr **res)
+{
+ char cgroupv2_path[PATH_MAX + 1];
+ struct stat st;
+ uint64_t ino;
+
+ snprintf(cgroupv2_path, sizeof(cgroupv2_path), "%s/%s",
+ SYSFS_CGROUPSV2_PATH, sym->identifier);
+ cgroupv2_path[sizeof(cgroupv2_path) - 1] = '\0';
+
+ if (stat(cgroupv2_path, &st) < 0)
+ return error(&sym->location, "cgroupv2 path fails: %s",
+ strerror(errno));
+
+ ino = st.st_ino;
+ *res = constant_expr_alloc(&sym->location, &cgroupv2_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(ino) * BITS_PER_BYTE, &ino);
+ return NULL;
+}
+
+const struct datatype cgroupv2_type = {
+ .type = TYPE_CGROUPV2,
+ .name = "cgroupsv2",
+ .desc = "cgroupsv2 path",
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ .size = 8 * BITS_PER_BYTE,
+ .basetype = &integer_type,
+ .print = cgroupv2_type_print,
+ .parse = cgroupv2_type_parse,
+};
diff --git a/src/dccpopt.c b/src/dccpopt.c
new file mode 100644
index 00000000..ebb645a9
--- /dev/null
+++ b/src/dccpopt.c
@@ -0,0 +1,277 @@
+#include <nft.h>
+
+#include <stddef.h>
+
+#include <datatype.h>
+#include <dccpopt.h>
+#include <expression.h>
+#include <nftables.h>
+#include <utils.h>
+
+#define PHT(__token, __offset, __len) \
+ PROTO_HDR_TEMPLATE(__token, &integer_type, BYTEORDER_BIG_ENDIAN, \
+ __offset, __len)
+
+static const struct proto_hdr_template dccpopt_unknown_template =
+ PROTO_HDR_TEMPLATE("unknown", &invalid_type, BYTEORDER_INVALID, 0, 0);
+
+/*
+ * Option DCCP- Section
+ * Type Length Meaning Data? Reference
+ * ---- ------ ------- ----- ---------
+ * 0 1 Padding Y 5.8.1
+ * 1 1 Mandatory N 5.8.2
+ * 2 1 Slow Receiver Y 11.6
+ * 3-31 1 Reserved
+ * 32 variable Change L N 6.1
+ * 33 variable Confirm L N 6.2
+ * 34 variable Change R N 6.1
+ * 35 variable Confirm R N 6.2
+ * 36 variable Init Cookie N 8.1.4
+ * 37 3-8 NDP Count Y 7.7
+ * 38 variable Ack Vector [Nonce 0] N 11.4
+ * 39 variable Ack Vector [Nonce 1] N 11.4
+ * 40 variable Data Dropped N 11.7
+ * 41 6 Timestamp Y 13.1
+ * 42 6/8/10 Timestamp Echo Y 13.3
+ * 43 4/6 Elapsed Time N 13.2
+ * 44 6 Data Checksum Y 9.3
+ * 45-127 variable Reserved
+ * 128-255 variable CCID-specific options - 10.3
+ */
+
+static const struct exthdr_desc dccpopt_padding = {
+ .name = "padding",
+ .type = DCCPOPT_PADDING,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_mandatory = {
+ .name = "mandatory",
+ .type = DCCPOPT_MANDATORY,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_slow_receiver = {
+ .name = "slow_receiver",
+ .type = DCCPOPT_SLOW_RECEIVER,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_reserved_short = {
+ .name = "reserved_short",
+ .type = DCCPOPT_RESERVED_SHORT,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_change_l = {
+ .name = "change_l",
+ .type = DCCPOPT_CHANGE_L,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8)
+ },
+};
+
+static const struct exthdr_desc dccpopt_confirm_l = {
+ .name = "confirm_l",
+ .type = DCCPOPT_CONFIRM_L,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_change_r = {
+ .name = "change_r",
+ .type = DCCPOPT_CHANGE_R,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_confirm_r = {
+ .name = "confirm_r",
+ .type = DCCPOPT_CONFIRM_R,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_init_cookie = {
+ .name = "init_cookie",
+ .type = DCCPOPT_INIT_COOKIE,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_ndp_count = {
+ .name = "ndp_count",
+ .type = DCCPOPT_NDP_COUNT,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_ack_vector_nonce_0 = {
+ .name = "ack_vector_nonce_0",
+ .type = DCCPOPT_ACK_VECTOR_NONCE_0,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_ack_vector_nonce_1 = {
+ .name = "ack_vector_nonce_1",
+ .type = DCCPOPT_ACK_VECTOR_NONCE_1,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_data_dropped = {
+ .name = "data_dropped",
+ .type = DCCPOPT_DATA_DROPPED,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_timestamp = {
+ .name = "timestamp",
+ .type = DCCPOPT_TIMESTAMP,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_timestamp_echo = {
+ .name = "timestamp_echo",
+ .type = DCCPOPT_TIMESTAMP_ECHO,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_elapsed_time = {
+ .name = "elapsed_time",
+ .type = DCCPOPT_ELAPSED_TIME,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_data_checksum = {
+ .name = "data_checksum",
+ .type = DCCPOPT_DATA_CHECKSUM,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_reserved_long = {
+ .name = "reserved_long",
+ .type = DCCPOPT_RESERVED_LONG,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+static const struct exthdr_desc dccpopt_ccid_specific = {
+ .name = "ccid_specific",
+ .type = DCCPOPT_CCID_SPECIFIC,
+ .templates = {
+ [DCCPOPT_FIELD_TYPE] = PHT("type", 0, 8),
+ },
+};
+
+const struct exthdr_desc *dccpopt_protocols[1 + UINT8_MAX] = {
+ [DCCPOPT_PADDING] = &dccpopt_padding,
+ [DCCPOPT_MANDATORY] = &dccpopt_mandatory,
+ [DCCPOPT_SLOW_RECEIVER] = &dccpopt_slow_receiver,
+ [DCCPOPT_RESERVED_SHORT] = &dccpopt_reserved_short,
+ [DCCPOPT_CHANGE_L] = &dccpopt_change_l,
+ [DCCPOPT_CONFIRM_L] = &dccpopt_confirm_l,
+ [DCCPOPT_CHANGE_R] = &dccpopt_change_r,
+ [DCCPOPT_CONFIRM_R] = &dccpopt_confirm_r,
+ [DCCPOPT_INIT_COOKIE] = &dccpopt_init_cookie,
+ [DCCPOPT_NDP_COUNT] = &dccpopt_ndp_count,
+ [DCCPOPT_ACK_VECTOR_NONCE_0] = &dccpopt_ack_vector_nonce_0,
+ [DCCPOPT_ACK_VECTOR_NONCE_1] = &dccpopt_ack_vector_nonce_1,
+ [DCCPOPT_DATA_DROPPED] = &dccpopt_data_dropped,
+ [DCCPOPT_TIMESTAMP] = &dccpopt_timestamp,
+ [DCCPOPT_TIMESTAMP_ECHO] = &dccpopt_timestamp_echo,
+ [DCCPOPT_ELAPSED_TIME] = &dccpopt_elapsed_time,
+ [DCCPOPT_DATA_CHECKSUM] = &dccpopt_data_checksum,
+ [DCCPOPT_RESERVED_LONG] = &dccpopt_reserved_long,
+ [DCCPOPT_CCID_SPECIFIC] = &dccpopt_ccid_specific,
+};
+
+const struct exthdr_desc *
+dccpopt_find_desc(uint8_t type)
+{
+ enum dccpopt_types proto_idx =
+ 3 <= type && type <= 31 ? DCCPOPT_RESERVED_SHORT :
+ 45 <= type && type <= 127 ? DCCPOPT_RESERVED_LONG :
+ 128 <= type ? DCCPOPT_CCID_SPECIFIC : type;
+
+ return dccpopt_protocols[proto_idx];
+}
+
+struct expr *
+dccpopt_expr_alloc(const struct location *loc, uint8_t type)
+{
+ const struct proto_hdr_template *tmpl;
+ const struct exthdr_desc *desc;
+ struct expr *expr;
+
+ desc = dccpopt_find_desc(type);
+ tmpl = &desc->templates[DCCPOPT_FIELD_TYPE];
+
+ expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
+ BYTEORDER_BIG_ENDIAN, BITS_PER_BYTE);
+ expr->exthdr.desc = desc;
+ expr->exthdr.tmpl = tmpl;
+ expr->exthdr.offset = tmpl->offset;
+ expr->exthdr.raw_type = type;
+ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ expr->exthdr.op = NFT_EXTHDR_OP_DCCP;
+
+ return expr;
+}
+
+void
+dccpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
+ unsigned int len)
+{
+ const struct proto_hdr_template *tmpl;
+ const struct exthdr_desc *desc;
+
+ assert(expr->etype == EXPR_EXTHDR);
+
+ desc = dccpopt_find_desc(type);
+ tmpl = &desc->templates[DCCPOPT_FIELD_TYPE];
+
+ expr->len = len;
+ datatype_set(expr, &boolean_type);
+
+ expr->exthdr.offset = offset;
+ expr->exthdr.desc = desc;
+ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ expr->exthdr.op = NFT_EXTHDR_OP_DCCP;
+
+ /* Make sure that it's the right template based on offset and
+ * len
+ */
+ if (tmpl->offset != offset || tmpl->len != len)
+ expr->exthdr.tmpl = &dccpopt_unknown_template;
+ else
+ expr->exthdr.tmpl = tmpl;
+}
diff --git a/src/erec.c b/src/erec.c
index c550a596..fe66abbe 100644
--- a/src/erec.c
+++ b/src/erec.c
@@ -8,12 +8,10 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
-#define _GNU_SOURCE
-#include <config.h>
+#include <nft.h>
+
#include <stdio.h>
-#include <string.h>
#include <stdarg.h>
-#include <stdlib.h>
#include <netlink.h>
#include <gmputil.h>
@@ -38,14 +36,15 @@ void erec_add_location(struct error_record *erec, const struct location *loc)
{
assert(erec->num_locations < EREC_LOCATIONS_MAX);
erec->locations[erec->num_locations] = *loc;
- erec->locations[erec->num_locations].indesc = loc->indesc;
+ erec->locations[erec->num_locations].indesc = loc->indesc ?
+ : &internal_indesc;
erec->num_locations++;
}
void erec_destroy(struct error_record *erec)
{
- xfree(erec->msg);
- xfree(erec);
+ free(erec->msg);
+ free(erec);
}
__attribute__((format(printf, 3, 0)))
@@ -80,11 +79,58 @@ struct error_record *erec_create(enum error_record_types type,
return erec;
}
+void print_location(FILE *f, const struct input_descriptor *indesc,
+ const struct location *loc)
+{
+ const struct input_descriptor *tmp;
+ const struct location *iloc;
+
+ if (indesc->location.indesc != NULL) {
+ const char *prefix = "In file included from";
+ iloc = &indesc->location;
+ for (tmp = iloc->indesc;
+ tmp != NULL && tmp->type != INDESC_INTERNAL;
+ tmp = iloc->indesc) {
+ fprintf(f, "%s %s:%u:%u-%u:\n", prefix,
+ tmp->name,
+ iloc->first_line, iloc->first_column,
+ iloc->last_column);
+ prefix = " from";
+ iloc = &tmp->location;
+ }
+ }
+ if (indesc->type != INDESC_BUFFER && indesc->name) {
+ fprintf(f, "%s:%u:%u-%u: ", indesc->name,
+ loc->first_line, loc->first_column,
+ loc->last_column);
+ }
+}
+
+const char *line_location(const struct input_descriptor *indesc,
+ const struct location *loc, char *buf, size_t bufsiz)
+{
+ const char *line = NULL;
+ FILE *f;
+
+ f = fopen(indesc->name, "r");
+ if (!f)
+ return NULL;
+
+ if (!fseek(f, loc->line_offset, SEEK_SET) &&
+ fread(buf, 1, bufsiz - 1, f) > 0) {
+ *strchrnul(buf, '\n') = '\0';
+ line = buf;
+ }
+ fclose(f);
+
+ return line;
+}
+
void erec_print(struct output_ctx *octx, const struct error_record *erec,
unsigned int debug_mask)
{
- const struct location *loc = erec->locations, *iloc;
- const struct input_descriptor *indesc = loc->indesc, *tmp;
+ const struct location *loc = erec->locations;
+ const struct input_descriptor *indesc = loc->indesc;
const char *line = NULL;
char buf[1024] = {};
char *pbuf = NULL;
@@ -98,17 +144,13 @@ void erec_print(struct output_ctx *octx, const struct error_record *erec,
line = indesc->data;
*strchrnul(line, '\n') = '\0';
break;
+ case INDESC_STDIN:
+ line = indesc->data;
+ line += loc->line_offset;
+ *strchrnul(line, '\n') = '\0';
+ break;
case INDESC_FILE:
- f = fopen(indesc->name, "r");
- if (!f)
- break;
-
- if (!fseek(f, loc->line_offset, SEEK_SET) &&
- fread(buf, 1, sizeof(buf) - 1, f) > 0) {
- *strchrnul(buf, '\n') = '\0';
- line = buf;
- }
- fclose(f);
+ line = line_location(indesc, loc, buf, sizeof(buf));
break;
case INDESC_INTERNAL:
case INDESC_NETLINK:
@@ -126,29 +168,15 @@ void erec_print(struct output_ctx *octx, const struct error_record *erec,
fprintf(f, "%s\n", erec->msg);
for (l = 0; l < (int)erec->num_locations; l++) {
loc = &erec->locations[l];
+ if (!loc->nle)
+ continue;
netlink_dump_expr(loc->nle, f, debug_mask);
}
return;
}
- if (indesc->location.indesc != NULL) {
- const char *prefix = "In file included from";
- iloc = &indesc->location;
- for (tmp = iloc->indesc;
- tmp != NULL && tmp->type != INDESC_INTERNAL;
- tmp = iloc->indesc) {
- fprintf(f, "%s %s:%u:%u-%u:\n", prefix,
- tmp->name,
- iloc->first_line, iloc->first_column,
- iloc->last_column);
- prefix = " from";
- iloc = &tmp->location;
- }
- }
- if (indesc->name != NULL)
- fprintf(f, "%s:%u:%u-%u: ", indesc->name,
- loc->first_line, loc->first_column,
- loc->last_column);
+ print_location(f, indesc, loc);
+
if (error_record_names[erec->type])
fprintf(f, "%s: ", error_record_names[erec->type]);
fprintf(f, "%s\n", erec->msg);
@@ -175,7 +203,7 @@ void erec_print(struct output_ctx *octx, const struct error_record *erec,
}
pbuf[end] = '\0';
fprintf(f, "%s", pbuf);
- xfree(pbuf);
+ free(pbuf);
}
fprintf(f, "\n");
}
diff --git a/src/evaluate.c b/src/evaluate.c
index a56cd2a5..1682ba58 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -8,16 +8,17 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <stddef.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
#include <arpa/inet.h>
#include <linux/netfilter.h>
#include <linux/netfilter_arp.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nf_synproxy.h>
+#include <linux/netfilter/nf_nat.h>
+#include <linux/netfilter/nf_log.h>
#include <linux/netfilter_ipv4.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
@@ -27,6 +28,7 @@
#include <expression.h>
#include <statement.h>
+#include <intervals.h>
#include <netlink.h>
#include <time.h>
#include <rule.h>
@@ -36,6 +38,13 @@
#include <utils.h>
#include <xt.h>
+struct proto_ctx *eval_proto_ctx(struct eval_ctx *ctx)
+{
+ uint8_t idx = ctx->inner_desc ? 1 : 0;
+
+ return &ctx->_pctx[idx];
+}
+
static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr);
static const char * const byteorder_names[] = {
@@ -65,6 +74,33 @@ static int __fmtstring(3, 4) set_error(struct eval_ctx *ctx,
return -1;
}
+static const char *stmt_name(const struct stmt *stmt)
+{
+ switch (stmt->ops->type) {
+ case STMT_NAT:
+ switch (stmt->nat.type) {
+ case NFT_NAT_SNAT:
+ return "snat";
+ case NFT_NAT_DNAT:
+ return "dnat";
+ case NFT_NAT_REDIR:
+ return "redirect";
+ case NFT_NAT_MASQ:
+ return "masquerade";
+ }
+ break;
+ default:
+ break;
+ }
+
+ return stmt->ops->name;
+}
+
+static int stmt_error_range(struct eval_ctx *ctx, const struct stmt *stmt, const struct expr *e)
+{
+ return expr_error(ctx->msgs, e, "%s: range argument not supported", stmt_name(stmt));
+}
+
static void key_fix_dtype_byteorder(struct expr *key)
{
const struct datatype *dtype = key->dtype;
@@ -72,13 +108,16 @@ static void key_fix_dtype_byteorder(struct expr *key)
if (dtype->byteorder == key->byteorder)
return;
- datatype_set(key, set_datatype_alloc(dtype, key->byteorder));
+ __datatype_set(key, set_datatype_alloc(dtype, key->byteorder));
}
+static int set_evaluate(struct eval_ctx *ctx, struct set *set);
static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
const char *name,
struct expr *key,
- struct expr *expr)
+ struct expr *data,
+ struct expr *expr,
+ uint32_t flags)
{
struct cmd *cmd;
struct set *set;
@@ -88,18 +127,28 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
key_fix_dtype_byteorder(key);
set = set_alloc(&expr->location);
- set->flags = NFT_SET_ANONYMOUS | expr->set_flags;
+ set->flags = expr->set_flags | flags;
set->handle.set.name = xstrdup(name);
set->key = key;
+ set->data = data;
set->init = expr;
set->automerge = set->flags & NFT_SET_INTERVAL;
+ handle_merge(&set->handle, &ctx->cmd->handle);
+
+ if (set_evaluate(ctx, set) < 0) {
+ if (set->flags & NFT_SET_MAP)
+ set->init = NULL;
+ set_free(set);
+ return NULL;
+ }
+
if (ctx->table != NULL)
list_add_tail(&set->list, &ctx->table->sets);
else {
- handle_merge(&set->handle, &ctx->cmd->handle);
memset(&h, 0, sizeof(h));
handle_merge(&h, &set->handle);
+ h.set.location = expr->location;
cmd = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &h, &expr->location, set);
cmd->location = set->location;
list_add_tail(&cmd->list, &ctx->cmd->list);
@@ -130,19 +179,63 @@ static enum ops byteorder_conversion_op(struct expr *expr,
static int byteorder_conversion(struct eval_ctx *ctx, struct expr **expr,
enum byteorder byteorder)
{
+ enum datatypes basetype;
enum ops op;
assert(!expr_is_constant(*expr) || expr_is_singleton(*expr));
if ((*expr)->byteorder == byteorder)
return 0;
- if (expr_basetype(*expr)->type != TYPE_INTEGER)
+
+ /* Conversion for EXPR_CONCAT is handled for single composing ranges */
+ if ((*expr)->etype == EXPR_CONCAT) {
+ struct expr *i, *next, *unary;
+
+ list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
+ if (i->byteorder == BYTEORDER_BIG_ENDIAN)
+ continue;
+
+ basetype = expr_basetype(i)->type;
+ if (basetype == TYPE_STRING)
+ continue;
+
+ assert(basetype == TYPE_INTEGER);
+
+ switch (i->etype) {
+ case EXPR_VALUE:
+ if (i->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(i->value, div_round_up(i->len, BITS_PER_BYTE));
+ break;
+ default:
+ if (div_round_up(i->len, BITS_PER_BYTE) >= 2) {
+ op = byteorder_conversion_op(i, byteorder);
+ unary = unary_expr_alloc(&i->location, op, i);
+ if (expr_evaluate(ctx, &unary) < 0)
+ return -1;
+
+ list_replace(&i->list, &unary->list);
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ basetype = expr_basetype(*expr)->type;
+ switch (basetype) {
+ case TYPE_INTEGER:
+ break;
+ case TYPE_STRING:
+ return 0;
+ default:
return expr_error(ctx->msgs, *expr,
- "Byteorder mismatch: expected %s, got %s",
+ "Byteorder mismatch: %s expected %s, %s got %s",
byteorder_names[byteorder],
+ expr_name(*expr),
byteorder_names[(*expr)->byteorder]);
+ }
- if (expr_is_constant(*expr))
+ if (expr_is_constant(*expr) || div_round_up((*expr)->len, BITS_PER_BYTE) < 2)
(*expr)->byteorder = byteorder;
else {
op = byteorder_conversion_op(*expr, byteorder);
@@ -153,20 +246,6 @@ static int byteorder_conversion(struct eval_ctx *ctx, struct expr **expr,
return 0;
}
-static struct table *table_lookup_global(struct eval_ctx *ctx)
-{
- struct table *table;
-
- if (ctx->table != NULL)
- return ctx->table;
-
- table = table_lookup(&ctx->cmd->handle, &ctx->nft->cache);
- if (table == NULL)
- return NULL;
-
- return table;
-}
-
static int table_not_found(struct eval_ctx *ctx)
{
struct table *table;
@@ -177,7 +256,7 @@ static int table_not_found(struct eval_ctx *ctx)
"%s", strerror(ENOENT));
return cmd_error(ctx, &ctx->cmd->handle.table.location,
- "%s; did you mean table ‘%s’ in family %s?",
+ "%s; did you mean table '%s' in family %s?",
strerror(ENOENT), table->handle.table.name,
family2str(table->handle.family));
}
@@ -193,7 +272,7 @@ static int chain_not_found(struct eval_ctx *ctx)
"%s", strerror(ENOENT));
return cmd_error(ctx, &ctx->cmd->handle.chain.location,
- "%s; did you mean chain ‘%s’ in table %s ‘%s’?",
+ "%s; did you mean chain '%s' in table %s '%s'?",
strerror(ENOENT), chain->handle.chain.name,
family2str(chain->handle.family),
table->handle.table.name);
@@ -210,7 +289,7 @@ static int set_not_found(struct eval_ctx *ctx, const struct location *loc,
return cmd_error(ctx, loc, "%s", strerror(ENOENT));
return cmd_error(ctx, loc,
- "%s; did you mean %s ‘%s’ in table %s ‘%s’?",
+ "%s; did you mean %s '%s' in table %s '%s'?",
strerror(ENOENT),
set_is_map(set->flags) ? "map" : "set",
set->handle.set.name,
@@ -218,12 +297,32 @@ static int set_not_found(struct eval_ctx *ctx, const struct location *loc,
table->handle.table.name);
}
+static int flowtable_not_found(struct eval_ctx *ctx, const struct location *loc,
+ const char *ft_name)
+{
+ const struct table *table;
+ struct flowtable *ft;
+
+ ft = flowtable_lookup_fuzzy(ft_name, &ctx->nft->cache, &table);
+ if (!ft)
+ return cmd_error(ctx, loc, "%s", strerror(ENOENT));
+
+ return cmd_error(ctx, loc,
+ "%s; did you mean flowtable '%s' in table %s '%s'?",
+ strerror(ENOENT), ft->handle.flowtable.name,
+ family2str(ft->handle.family),
+ table->handle.table.name);
+}
+
/*
* Symbol expression: parse symbol and evaluate resulting expression.
*/
static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
{
- struct parse_ctx parse_ctx = { .tbl = &ctx->nft->output.tbl, };
+ struct parse_ctx parse_ctx = {
+ .tbl = &ctx->nft->output.tbl,
+ .input = &ctx->nft->input,
+ };
struct error_record *erec;
struct table *table;
struct set *set;
@@ -239,12 +338,14 @@ static int expr_evaluate_symbol(struct eval_ctx *ctx, struct expr **expr)
}
break;
case SYMBOL_SET:
- table = table_lookup_global(ctx);
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ ctx->cmd->handle.table.name,
+ ctx->cmd->handle.family);
if (table == NULL)
return table_not_found(ctx);
- set = set_lookup(table, (*expr)->identifier);
- if (set == NULL)
+ set = set_cache_find(table, (*expr)->identifier);
+ if (set == NULL || !set->key)
return set_not_found(ctx, &(*expr)->location,
(*expr)->identifier);
@@ -294,8 +395,11 @@ static int expr_evaluate_string(struct eval_ctx *ctx, struct expr **exprp)
return 0;
}
- if (datalen >= 1 &&
- data[datalen - 1] == '\\') {
+ if (datalen == 0)
+ return expr_error(ctx->msgs, expr,
+ "All-wildcard strings are not supported");
+
+ if (data[datalen - 1] == '\\') {
char unescaped_str[data_len];
memset(unescaped_str, 0, sizeof(unescaped_str));
@@ -308,15 +412,18 @@ static int expr_evaluate_string(struct eval_ctx *ctx, struct expr **exprp)
*exprp = value;
return 0;
}
+
+ data[datalen] = 0;
value = constant_expr_alloc(&expr->location, ctx->ectx.dtype,
BYTEORDER_HOST_ENDIAN,
- datalen * BITS_PER_BYTE, data);
+ expr->len, data);
prefix = prefix_expr_alloc(&expr->location, value,
datalen * BITS_PER_BYTE);
datatype_set(prefix, ctx->ectx.dtype);
prefix->flags |= EXPR_F_CONSTANT;
prefix->byteorder = BYTEORDER_HOST_ENDIAN;
+ prefix->len = expr->len;
expr_free(expr);
*exprp = prefix;
@@ -327,6 +434,7 @@ static int expr_evaluate_integer(struct eval_ctx *ctx, struct expr **exprp)
{
struct expr *expr = *exprp;
char *valstr, *rangestr;
+ uint32_t masklen;
mpz_t mask;
if (ctx->ectx.maxval > 0 &&
@@ -335,24 +443,29 @@ static int expr_evaluate_integer(struct eval_ctx *ctx, struct expr **exprp)
expr_error(ctx->msgs, expr,
"Value %s exceeds valid range 0-%u",
valstr, ctx->ectx.maxval);
- free(valstr);
+ nft_gmp_free(valstr);
return -1;
}
- mpz_init_bitmask(mask, ctx->ectx.len);
+ if (ctx->stmt_len > ctx->ectx.len)
+ masklen = ctx->stmt_len;
+ else
+ masklen = ctx->ectx.len;
+
+ mpz_init_bitmask(mask, masklen);
if (mpz_cmp(expr->value, mask) > 0) {
valstr = mpz_get_str(NULL, 10, expr->value);
rangestr = mpz_get_str(NULL, 10, mask);
expr_error(ctx->msgs, expr,
"Value %s exceeds valid range 0-%s",
valstr, rangestr);
- free(valstr);
- free(rangestr);
+ nft_gmp_free(valstr);
+ nft_gmp_free(rangestr);
mpz_clear(mask);
return -1;
}
expr->byteorder = ctx->ectx.byteorder;
- expr->len = ctx->ectx.len;
+ expr->len = masklen;
mpz_clear(mask);
return 0;
}
@@ -384,20 +497,34 @@ static int expr_evaluate_primary(struct eval_ctx *ctx, struct expr **expr)
return 0;
}
+int stmt_dependency_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ uint32_t stmt_len = ctx->stmt_len;
+
+ if (stmt_evaluate(ctx, stmt) < 0)
+ return stmt_error(ctx, stmt, "dependency statement is invalid");
+
+ ctx->stmt_len = stmt_len;
+
+ return 0;
+}
+
static int
-conflict_resolution_gen_dependency(struct eval_ctx *ctx, int protocol,
- const struct expr *expr,
- struct stmt **res)
+ll_conflict_resolution_gen_dependency(struct eval_ctx *ctx, int protocol,
+ const struct expr *expr,
+ struct stmt **res)
{
enum proto_bases base = expr->payload.base;
const struct proto_hdr_template *tmpl;
const struct proto_desc *desc = NULL;
struct expr *dep, *left, *right;
+ struct proto_ctx *pctx;
struct stmt *stmt;
assert(expr->payload.base == PROTO_BASE_LL_HDR);
- desc = ctx->pctx.protocol[base].desc;
+ pctx = eval_proto_ctx(ctx);
+ desc = pctx->protocol[base].desc;
tmpl = &desc->templates[desc->protocol_key];
left = payload_expr_alloc(&expr->location, desc, desc->protocol_key);
@@ -407,10 +534,13 @@ conflict_resolution_gen_dependency(struct eval_ctx *ctx, int protocol,
dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
stmt = expr_stmt_alloc(&dep->location, dep);
- if (stmt_evaluate(ctx, stmt) < 0)
+ if (stmt_dependency_evaluate(ctx, stmt) < 0)
return expr_error(ctx->msgs, expr,
"dependency statement is invalid");
+ if (ctx->inner_desc)
+ left->payload.inner_desc = ctx->inner_desc;
+
*res = stmt;
return 0;
}
@@ -431,10 +561,11 @@ static uint8_t expr_offset_shift(const struct expr *expr, unsigned int offset,
return shift;
}
-static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
+static int expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
{
- struct expr *expr = *exprp, *and, *mask, *lshift, *off;
+ struct expr *expr = *exprp, *and, *mask, *rshift, *off;
unsigned masklen, len = expr->len, extra_len = 0;
+ enum byteorder byteorder;
uint8_t shift;
mpz_t bitmask;
@@ -444,7 +575,7 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
&extra_len);
break;
case EXPR_EXTHDR:
- shift = expr_offset_shift(expr, expr->exthdr.tmpl->offset,
+ shift = expr_offset_shift(expr, expr->exthdr.offset,
&extra_len);
break;
default:
@@ -452,7 +583,10 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
}
masklen = len + shift;
- assert(masklen <= NFT_REG_SIZE * BITS_PER_BYTE);
+
+ if (masklen > NFT_REG_SIZE * BITS_PER_BYTE)
+ return expr_error(ctx->msgs, expr, "mask length %u exceeds allowed maximum of %u\n",
+ masklen, NFT_REG_SIZE * BITS_PER_BYTE);
mpz_init2(bitmask, masklen);
mpz_bitmask(bitmask, len);
@@ -461,6 +595,7 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
mask = constant_expr_alloc(&expr->location, expr_basetype(expr),
BYTEORDER_HOST_ENDIAN, masklen, NULL);
mpz_set(mask->value, bitmask);
+ mpz_clear(bitmask);
and = binop_expr_alloc(&expr->location, OP_AND, expr, mask);
and->dtype = expr->dtype;
@@ -468,26 +603,39 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
and->len = masklen;
if (shift) {
+ if ((ctx->ectx.key || ctx->stmt_len > 0) &&
+ div_round_up(masklen, BITS_PER_BYTE) > 1) {
+ int op = byteorder_conversion_op(expr, BYTEORDER_HOST_ENDIAN);
+ and = unary_expr_alloc(&expr->location, op, and);
+ and->len = masklen;
+ byteorder = BYTEORDER_HOST_ENDIAN;
+ } else {
+ byteorder = expr->byteorder;
+ }
+
off = constant_expr_alloc(&expr->location,
expr_basetype(expr),
- BYTEORDER_BIG_ENDIAN,
+ BYTEORDER_HOST_ENDIAN,
sizeof(shift), &shift);
- lshift = binop_expr_alloc(&expr->location, OP_RSHIFT, and, off);
- lshift->dtype = expr->dtype;
- lshift->byteorder = expr->byteorder;
- lshift->len = masklen;
+ rshift = binop_expr_alloc(&expr->location, OP_RSHIFT, and, off);
+ rshift->dtype = expr->dtype;
+ rshift->byteorder = byteorder;
+ rshift->len = masklen;
- *exprp = lshift;
+ *exprp = rshift;
} else
*exprp = and;
if (extra_len)
expr->len += extra_len;
+
+ return 0;
}
static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
{
+ const struct expr *key = ctx->ectx.key;
struct expr *expr = *exprp;
if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
@@ -496,18 +644,22 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
if (expr_evaluate_primary(ctx, exprp) < 0)
return -1;
- if (expr->exthdr.tmpl->offset % BITS_PER_BYTE != 0 ||
- expr->len % BITS_PER_BYTE != 0)
- expr_evaluate_bits(ctx, exprp);
+ ctx->ectx.key = key;
+
+ if (expr->exthdr.offset % BITS_PER_BYTE != 0 ||
+ expr->len % BITS_PER_BYTE != 0) {
+ int err = expr_evaluate_bits(ctx, exprp);
+
+ if (err)
+ return err;
+ }
switch (expr->exthdr.op) {
case NFT_EXTHDR_OP_TCPOPT: {
static const unsigned int max_tcpoptlen = (15 * 4 - 20) * BITS_PER_BYTE;
- unsigned int totlen = 0;
+ unsigned int totlen;
- totlen += expr->exthdr.tmpl->offset;
- totlen += expr->exthdr.tmpl->len;
- totlen += expr->exthdr.offset;
+ totlen = expr->exthdr.tmpl->len + expr->exthdr.offset;
if (totlen > max_tcpoptlen)
return expr_error(ctx->msgs, expr,
@@ -517,11 +669,9 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
}
case NFT_EXTHDR_OP_IPV4: {
static const unsigned int max_ipoptlen = 40 * BITS_PER_BYTE;
- unsigned int totlen = 0;
+ unsigned int totlen;
- totlen += expr->exthdr.tmpl->offset;
- totlen += expr->exthdr.tmpl->len;
- totlen += expr->exthdr.offset;
+ totlen = expr->exthdr.offset + expr->exthdr.tmpl->len;
if (totlen > max_ipoptlen)
return expr_error(ctx->msgs, expr,
@@ -546,13 +696,14 @@ static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
const struct proto_desc *base, *dependency = NULL;
enum proto_bases pb = PROTO_BASE_NETWORK_HDR;
struct expr *expr = *exprp;
+ struct proto_ctx *pctx;
struct stmt *nstmt;
switch (expr->exthdr.op) {
case NFT_EXTHDR_OP_TCPOPT:
- dependency = &proto_tcp;
- pb = PROTO_BASE_TRANSPORT_HDR;
- break;
+ case NFT_EXTHDR_OP_SCTP:
+ case NFT_EXTHDR_OP_DCCP:
+ return __expr_evaluate_exthdr(ctx, exprp);
case NFT_EXTHDR_OP_IPV4:
dependency = &proto_ip;
break;
@@ -564,7 +715,8 @@ static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
assert(dependency);
- base = ctx->pctx.protocol[pb].desc;
+ pctx = eval_proto_ctx(ctx);
+ base = pctx->protocol[pb].desc;
if (base == dependency)
return __expr_evaluate_exthdr(ctx, exprp);
@@ -582,7 +734,7 @@ static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
/* dependency supersede.
*
- * 'inet' is a 'phony' l2 dependency used by NFPROTO_INET to fulfill network
+ * 'inet' is a 'phony' l2 dependency used by NFPROTO_INET to fulfil network
* header dependency, i.e. ensure that 'ip saddr 1.2.3.4' only sees ip headers.
*
* If a match expression that depends on a particular L2 header, e.g. ethernet,
@@ -594,7 +746,7 @@ static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
* Example: inet filter in ip saddr 1.2.3.4 ether saddr a:b:c:d:e:f
*
* ip saddr adds meta dependency on ipv4 packets
- * ether saddr adds another dependeny on ethernet frames.
+ * ether saddr adds another dependency on ethernet frames.
*/
static int meta_iiftype_gen_dependency(struct eval_ctx *ctx,
struct expr *payload, struct stmt **res)
@@ -608,9 +760,11 @@ static int meta_iiftype_gen_dependency(struct eval_ctx *ctx,
"for this family");
nstmt = meta_stmt_meta_iiftype(&payload->location, type);
- if (stmt_evaluate(ctx, nstmt) < 0)
- return expr_error(ctx->msgs, payload,
- "dependency statement is invalid");
+ if (stmt_dependency_evaluate(ctx, nstmt) < 0)
+ return -1;
+
+ if (ctx->inner_desc)
+ nstmt->expr->left->meta.inner_desc = ctx->inner_desc;
*res = nstmt;
return 0;
@@ -621,35 +775,54 @@ static bool proto_is_dummy(const struct proto_desc *desc)
return desc == &proto_inet || desc == &proto_netdev;
}
-static int resolve_protocol_conflict(struct eval_ctx *ctx,
- const struct proto_desc *desc,
- struct expr *payload)
+static int resolve_ll_protocol_conflict(struct eval_ctx *ctx,
+ const struct proto_desc *desc,
+ struct expr *payload)
{
enum proto_bases base = payload->payload.base;
struct stmt *nstmt = NULL;
+ struct proto_ctx *pctx;
+ unsigned int i;
int link, err;
- if (payload->payload.base == PROTO_BASE_LL_HDR &&
- proto_is_dummy(desc)) {
- err = meta_iiftype_gen_dependency(ctx, payload, &nstmt);
- if (err < 0)
- return err;
+ assert(base == PROTO_BASE_LL_HDR);
+
+ pctx = eval_proto_ctx(ctx);
+
+ if (proto_is_dummy(desc)) {
+ if (ctx->inner_desc) {
+ proto_ctx_update(pctx, PROTO_BASE_LL_HDR, &payload->location, &proto_eth);
+ } else {
+ err = meta_iiftype_gen_dependency(ctx, payload, &nstmt);
+ if (err < 0)
+ return err;
- list_add_tail(&nstmt->list, &ctx->stmt->list);
+ desc = payload->payload.desc;
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+ }
+ } else {
+ unsigned int i;
+
+ /* payload desc stored in the L2 header stack? No conflict. */
+ for (i = 0; i < pctx->stacked_ll_count; i++) {
+ if (pctx->stacked_ll[i] == payload->payload.desc)
+ return 0;
+ }
}
- assert(base <= PROTO_BASE_MAX);
/* This payload and the existing context don't match, conflict. */
- if (ctx->pctx.protocol[base + 1].desc != NULL)
+ if (pctx->protocol[base + 1].desc != NULL)
return 1;
link = proto_find_num(desc, payload->payload.desc);
if (link < 0 ||
- conflict_resolution_gen_dependency(ctx, link, payload, &nstmt) < 0)
+ ll_conflict_resolution_gen_dependency(ctx, link, payload, &nstmt) < 0)
return 1;
- payload->payload.offset += ctx->pctx.protocol[base].offset;
- list_add_tail(&nstmt->list, &ctx->stmt->list);
+ for (i = 0; i < pctx->stacked_ll_count; i++)
+ payload->payload.offset += pctx->stacked_ll[i]->length;
+
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
return 0;
}
@@ -664,44 +837,102 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr)
struct expr *payload = expr;
enum proto_bases base = payload->payload.base;
const struct proto_desc *desc;
+ struct proto_ctx *pctx;
struct stmt *nstmt;
int err;
if (expr->etype == EXPR_PAYLOAD && expr->payload.is_raw)
return 0;
- desc = ctx->pctx.protocol[base].desc;
+ pctx = eval_proto_ctx(ctx);
+ desc = pctx->protocol[base].desc;
if (desc == NULL) {
if (payload_gen_dependency(ctx, payload, &nstmt) < 0)
return -1;
- list_add_tail(&nstmt->list, &ctx->stmt->list);
- } else {
- /* No conflict: Same payload protocol as context, adjust offset
- * if needed.
- */
- if (desc == payload->payload.desc) {
- payload->payload.offset +=
- ctx->pctx.protocol[base].offset;
- return 0;
- }
- /* If we already have context and this payload is on the same
- * base, try to resolve the protocol conflict.
- */
- if (payload->payload.base == desc->base) {
- err = resolve_protocol_conflict(ctx, desc, payload);
- if (err <= 0)
- return err;
- desc = ctx->pctx.protocol[base].desc;
- if (desc == payload->payload.desc)
- return 0;
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+
+ desc = pctx->protocol[base].desc;
+
+ if (desc == expr->payload.desc)
+ goto check_icmp;
+
+ if (base == PROTO_BASE_LL_HDR) {
+ int link;
+
+ link = proto_find_num(desc, payload->payload.desc);
+ if (link < 0 ||
+ ll_conflict_resolution_gen_dependency(ctx, link, payload, &nstmt) < 0)
+ return expr_error(ctx->msgs, payload,
+ "conflicting protocols specified: %s vs. %s",
+ desc->name,
+ payload->payload.desc->name);
+
+ assert(pctx->stacked_ll_count);
+ payload->payload.offset += pctx->stacked_ll[0]->length;
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+ return 1;
}
+ goto check_icmp;
+ }
+
+ if (payload->payload.base == desc->base &&
+ proto_ctx_is_ambiguous(pctx, base)) {
+ desc = proto_ctx_find_conflict(pctx, base, payload->payload.desc);
+ assert(desc);
+
return expr_error(ctx->msgs, payload,
"conflicting protocols specified: %s vs. %s",
- ctx->pctx.protocol[base].desc->name,
+ desc->name,
payload->payload.desc->name);
}
- return 0;
+
+ /* No conflict: Same payload protocol as context, adjust offset
+ * if needed.
+ */
+ if (desc == payload->payload.desc) {
+ const struct proto_hdr_template *tmpl;
+
+ if (desc->base == PROTO_BASE_LL_HDR) {
+ unsigned int i;
+
+ for (i = 0; i < pctx->stacked_ll_count; i++)
+ payload->payload.offset += pctx->stacked_ll[i]->length;
+ }
+check_icmp:
+ if (desc != &proto_icmp && desc != &proto_icmp6)
+ return 0;
+
+ tmpl = expr->payload.tmpl;
+
+ if (!tmpl || !tmpl->icmp_dep)
+ return 0;
+
+ if (payload_gen_icmp_dependency(ctx, expr, &nstmt) < 0)
+ return -1;
+
+ if (nstmt)
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+
+ return 0;
+ }
+ /* If we already have context and this payload is on the same
+ * base, try to resolve the protocol conflict.
+ */
+ if (base == PROTO_BASE_LL_HDR) {
+ err = resolve_ll_protocol_conflict(ctx, desc, payload);
+ if (err <= 0)
+ return err;
+
+ desc = pctx->protocol[base].desc;
+ if (desc == payload->payload.desc)
+ return 0;
+ }
+ return expr_error(ctx->msgs, payload,
+ "conflicting %s protocols specified: %s vs. %s",
+ proto_base_names[base],
+ pctx->protocol[base].desc->name,
+ payload->payload.desc->name);
}
static bool payload_needs_adjustment(const struct expr *expr)
@@ -712,20 +943,93 @@ static bool payload_needs_adjustment(const struct expr *expr)
static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **exprp)
{
+ const struct expr *key = ctx->ectx.key;
struct expr *expr = *exprp;
+ if (expr->payload.evaluated)
+ return 0;
+
if (__expr_evaluate_payload(ctx, expr) < 0)
return -1;
if (expr_evaluate_primary(ctx, exprp) < 0)
return -1;
- if (payload_needs_adjustment(expr))
- expr_evaluate_bits(ctx, exprp);
+ ctx->ectx.key = key;
+
+ if (payload_needs_adjustment(expr)) {
+ int err = expr_evaluate_bits(ctx, exprp);
+
+ if (err)
+ return err;
+ }
+
+ expr->payload.evaluated = true;
return 0;
}
+static int expr_evaluate_inner(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ const struct proto_desc *desc = NULL;
+ struct expr *expr = *exprp;
+ int ret;
+
+ assert(expr->etype == EXPR_PAYLOAD);
+
+ pctx = eval_proto_ctx(ctx);
+ desc = pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc;
+
+ if (desc == NULL &&
+ expr->payload.inner_desc->base < PROTO_BASE_INNER_HDR) {
+ struct stmt *nstmt;
+
+ if (payload_gen_inner_dependency(ctx, expr, &nstmt) < 0)
+ return -1;
+
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+
+ proto_ctx_update(pctx, PROTO_BASE_TRANSPORT_HDR, &expr->location, expr->payload.inner_desc);
+ }
+
+ if (expr->payload.inner_desc->base == PROTO_BASE_INNER_HDR) {
+ desc = pctx->protocol[expr->payload.inner_desc->base - 1].desc;
+ if (!desc) {
+ return expr_error(ctx->msgs, expr,
+ "no transport protocol specified");
+ }
+
+ if (proto_find_num(desc, expr->payload.inner_desc) < 0) {
+ return expr_error(ctx->msgs, expr,
+ "unexpected transport protocol %s",
+ desc->name);
+ }
+
+ proto_ctx_update(pctx, expr->payload.inner_desc->base, &expr->location,
+ expr->payload.inner_desc);
+ }
+
+ if (expr->payload.base != PROTO_BASE_INNER_HDR)
+ ctx->inner_desc = expr->payload.inner_desc;
+
+ ret = expr_evaluate_payload(ctx, exprp);
+
+ return ret;
+}
+
+static int expr_evaluate_payload_inner(struct eval_ctx *ctx, struct expr **exprp)
+{
+ int ret;
+
+ if ((*exprp)->payload.inner_desc)
+ ret = expr_evaluate_inner(ctx, exprp);
+ else
+ ret = expr_evaluate_payload(ctx, exprp);
+
+ return ret;
+}
+
/*
* RT expression: validate protocol dependencies.
*/
@@ -733,20 +1037,22 @@ static int expr_evaluate_rt(struct eval_ctx *ctx, struct expr **expr)
{
static const char emsg[] = "cannot determine ip protocol version, use \"ip nexthop\" or \"ip6 nexthop\" instead";
struct expr *rt = *expr;
+ struct proto_ctx *pctx;
- rt_expr_update_type(&ctx->pctx, rt);
+ pctx = eval_proto_ctx(ctx);
+ rt_expr_update_type(pctx, rt);
switch (rt->rt.key) {
case NFT_RT_NEXTHOP4:
if (rt->dtype != &ipaddr_type)
return expr_error(ctx->msgs, rt, "%s", emsg);
- if (ctx->pctx.family == NFPROTO_IPV6)
+ if (pctx->family == NFPROTO_IPV6)
return expr_error(ctx->msgs, rt, "%s nexthop will not match", "ip");
break;
case NFT_RT_NEXTHOP6:
if (rt->dtype != &ip6addr_type)
return expr_error(ctx->msgs, rt, "%s", emsg);
- if (ctx->pctx.family == NFPROTO_IPV4)
+ if (pctx->family == NFPROTO_IPV4)
return expr_error(ctx->msgs, rt, "%s nexthop will not match", "ip6");
break;
default:
@@ -761,8 +1067,10 @@ static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct)
const struct proto_desc *base, *base_now;
struct expr *left, *right, *dep;
struct stmt *nstmt = NULL;
+ struct proto_ctx *pctx;
- base_now = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ pctx = eval_proto_ctx(ctx);
+ base_now = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
switch (ct->ct.nfproto) {
case NFPROTO_IPV4:
@@ -772,7 +1080,7 @@ static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct)
base = &proto_ip6;
break;
default:
- base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ base = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
if (base == &proto_ip)
ct->ct.nfproto = NFPROTO_IPV4;
else if (base == &proto_ip)
@@ -794,8 +1102,8 @@ static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct)
return expr_error(ctx->msgs, ct,
"conflicting dependencies: %s vs. %s\n",
base->name,
- ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc->name);
- switch (ctx->pctx.family) {
+ pctx->protocol[PROTO_BASE_NETWORK_HDR].desc->name);
+ switch (pctx->family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6:
return 0;
@@ -808,11 +1116,11 @@ static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct)
constant_data_ptr(ct->ct.nfproto, left->len));
dep = relational_expr_alloc(&ct->location, OP_EQ, left, right);
- relational_expr_pctx_update(&ctx->pctx, dep);
+ relational_expr_pctx_update(pctx, dep);
nstmt = expr_stmt_alloc(&dep->location, dep);
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
- list_add_tail(&nstmt->list, &ctx->stmt->list);
return 0;
}
@@ -824,8 +1132,10 @@ static int expr_evaluate_ct(struct eval_ctx *ctx, struct expr **expr)
{
const struct proto_desc *base, *error;
struct expr *ct = *expr;
+ struct proto_ctx *pctx;
- base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ pctx = eval_proto_ctx(ctx);
+ base = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
switch (ct->ct.key) {
case NFT_CT_SRC:
@@ -850,13 +1160,13 @@ static int expr_evaluate_ct(struct eval_ctx *ctx, struct expr **expr)
break;
}
- ct_expr_update_type(&ctx->pctx, ct);
+ ct_expr_update_type(pctx, ct);
return expr_evaluate_primary(ctx, expr);
err_conflict:
return stmt_binary_error(ctx, ct,
- &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR],
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
"conflicting protocols specified: %s vs. %s",
base->name, error->name);
}
@@ -903,7 +1213,6 @@ static int expr_evaluate_prefix(struct eval_ctx *ctx, struct expr **expr)
mpz_prefixmask(mask->value, base->len, prefix->prefix_len);
break;
case TYPE_STRING:
- mpz_init2(mask->value, base->len);
mpz_bitmask(mask->value, prefix->prefix_len);
break;
}
@@ -914,7 +1223,7 @@ static int expr_evaluate_prefix(struct eval_ctx *ctx, struct expr **expr)
base = prefix->prefix;
assert(expr_is_constant(base));
- prefix->dtype = base->dtype;
+ prefix->dtype = datatype_get(base->dtype);
prefix->byteorder = base->byteorder;
prefix->len = base->len;
prefix->flags |= EXPR_F_CONSTANT;
@@ -965,9 +1274,8 @@ static int expr_evaluate_range(struct eval_ctx *ctx, struct expr **expr)
left = range->left;
right = range->right;
- if (mpz_cmp(left->value, right->value) >= 0)
- return expr_error(ctx->msgs, range,
- "Range has zero or negative size");
+ if (mpz_cmp(left->value, right->value) > 0)
+ return expr_error(ctx->msgs, range, "Range negative size");
datatype_set(range, left->dtype);
range->flags |= EXPR_F_CONSTANT;
@@ -980,12 +1288,10 @@ static int expr_evaluate_range(struct eval_ctx *ctx, struct expr **expr)
*/
static int expr_evaluate_unary(struct eval_ctx *ctx, struct expr **expr)
{
- struct expr *unary = *expr, *arg;
+ struct expr *unary = *expr, *arg = unary->arg;
enum byteorder byteorder;
- if (expr_evaluate(ctx, &unary->arg) < 0)
- return -1;
- arg = unary->arg;
+ /* unary expression arguments has already been evaluated. */
assert(!expr_is_constant(arg));
assert(expr_basetype(arg)->type == TYPE_INTEGER);
@@ -1004,7 +1310,7 @@ static int expr_evaluate_unary(struct eval_ctx *ctx, struct expr **expr)
BUG("invalid unary operation %u\n", unary->op);
}
- unary->dtype = arg->dtype;
+ unary->dtype = datatype_clone(arg->dtype);
unary->byteorder = byteorder;
unary->len = arg->len;
return 0;
@@ -1071,14 +1377,24 @@ static int constant_binop_simplify(struct eval_ctx *ctx, struct expr **expr)
static int expr_evaluate_shift(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *op = *expr, *left = op->left, *right = op->right;
+ unsigned int shift, max_shift_len;
+
+ /* mpz_get_uint32 has assert() for huge values */
+ if (mpz_cmp_ui(right->value, UINT_MAX) > 0)
+ return expr_binary_error(ctx->msgs, right, left,
+ "shifts exceeding %u bits are not supported", UINT_MAX);
+
+ shift = mpz_get_uint32(right->value);
+ if (ctx->stmt_len > left->len)
+ max_shift_len = ctx->stmt_len;
+ else
+ max_shift_len = left->len;
- if (mpz_get_uint32(right->value) >= left->len)
+ if (shift >= max_shift_len)
return expr_binary_error(ctx->msgs, right, left,
- "%s shift of %u bits is undefined "
- "for type of %u bits width",
+ "%s shift of %u bits is undefined for type of %u bits width",
op->op == OP_LSHIFT ? "Left" : "Right",
- mpz_get_uint32(right->value),
- left->len);
+ shift, max_shift_len);
/* Both sides need to be in host byte order */
if (byteorder_conversion(ctx, &op->left, BYTEORDER_HOST_ENDIAN) < 0)
@@ -1087,9 +1403,9 @@ static int expr_evaluate_shift(struct eval_ctx *ctx, struct expr **expr)
if (byteorder_conversion(ctx, &op->right, BYTEORDER_HOST_ENDIAN) < 0)
return -1;
- op->dtype = &integer_type;
+ datatype_set(op, &integer_type);
op->byteorder = BYTEORDER_HOST_ENDIAN;
- op->len = left->len;
+ op->len = max_shift_len;
if (expr_is_constant(left))
return constant_binop_simplify(ctx, expr);
@@ -1099,13 +1415,32 @@ static int expr_evaluate_shift(struct eval_ctx *ctx, struct expr **expr)
static int expr_evaluate_bitwise(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *op = *expr, *left = op->left;
+ const struct datatype *dtype;
+ enum byteorder byteorder;
+ unsigned int max_len;
- if (byteorder_conversion(ctx, &op->right, left->byteorder) < 0)
+ if (ctx->stmt_len > left->len) {
+ max_len = ctx->stmt_len;
+ byteorder = BYTEORDER_HOST_ENDIAN;
+ dtype = &integer_type;
+
+ /* Both sides need to be in host byte order */
+ if (byteorder_conversion(ctx, &op->left, BYTEORDER_HOST_ENDIAN) < 0)
+ return -1;
+
+ left = op->left;
+ } else {
+ max_len = left->len;
+ byteorder = left->byteorder;
+ dtype = left->dtype;
+ }
+
+ if (byteorder_conversion(ctx, &op->right, byteorder) < 0)
return -1;
- op->dtype = left->dtype;
- op->byteorder = left->byteorder;
- op->len = left->len;
+ datatype_set(op, dtype);
+ op->byteorder = byteorder;
+ op->len = max_len;
if (expr_is_constant(left))
return constant_binop_simplify(ctx, expr);
@@ -1122,13 +1457,27 @@ static int expr_evaluate_binop(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *op = *expr, *left, *right;
const char *sym = expr_op_symbols[op->op];
+ unsigned int max_shift_len = ctx->ectx.len;
+ int ret = -1;
+
+ if (ctx->recursion >= USHRT_MAX)
+ return expr_binary_error(ctx->msgs, op, NULL,
+ "Binary operation limit %u reached ",
+ ctx->recursion);
+ ctx->recursion++;
if (expr_evaluate(ctx, &op->left) < 0)
return -1;
left = op->left;
- if (op->op == OP_LSHIFT || op->op == OP_RSHIFT)
- expr_set_context(&ctx->ectx, &integer_type, ctx->ectx.len);
+ if (op->op == OP_LSHIFT || op->op == OP_RSHIFT) {
+ if (left->len > max_shift_len)
+ max_shift_len = left->len;
+
+ __expr_set_context(&ctx->ectx, &integer_type,
+ left->byteorder, max_shift_len, 0);
+ }
+
if (expr_evaluate(ctx, &op->right) < 0)
return -1;
right = op->right;
@@ -1161,20 +1510,51 @@ static int expr_evaluate_binop(struct eval_ctx *ctx, struct expr **expr)
"for %s expressions",
sym, expr_name(right));
- /* The grammar guarantees this */
- assert(expr_basetype(left) == expr_basetype(right));
+ if (!datatype_equal(expr_basetype(left), expr_basetype(right)))
+ return expr_binary_error(ctx->msgs, left, op,
+ "Binary operation (%s) with different base types "
+ "(%s vs %s) is not supported",
+ sym, expr_basetype(left)->name, expr_basetype(right)->name);
switch (op->op) {
case OP_LSHIFT:
case OP_RSHIFT:
- return expr_evaluate_shift(ctx, expr);
+ ret = expr_evaluate_shift(ctx, expr);
+ break;
case OP_AND:
case OP_XOR:
case OP_OR:
- return expr_evaluate_bitwise(ctx, expr);
+ ret = expr_evaluate_bitwise(ctx, expr);
+ break;
default:
BUG("invalid binary operation %u\n", op->op);
}
+
+
+ if (ctx->recursion == 0)
+ BUG("recursion counter underflow");
+
+ /* can't check earlier: evaluate functions might do constant-merging + expr_free.
+ *
+ * So once we've evaluate everything check for remaining length of the
+ * binop chain.
+ */
+ if (--ctx->recursion == 0) {
+ unsigned int to_linearize = 0;
+
+ op = *expr;
+ while (op && op->etype == EXPR_BINOP && op->left != NULL) {
+ to_linearize++;
+ op = op->left;
+
+ if (to_linearize >= NFT_MAX_EXPR_RECURSION)
+ return expr_binary_error(ctx->msgs, op, NULL,
+ "Binary operation limit %u reached ",
+ NFT_MAX_EXPR_RECURSION);
+ }
+ }
+
+ return ret;
}
static int list_member_evaluate(struct eval_ctx *ctx, struct expr **expr)
@@ -1189,45 +1569,117 @@ static int list_member_evaluate(struct eval_ctx *ctx, struct expr **expr)
return err;
}
-static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr,
- bool eval)
+static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
{
const struct datatype *dtype = ctx->ectx.dtype, *tmp;
uint32_t type = dtype ? dtype->type : 0, ntype = 0;
int off = dtype ? dtype->subtypes : 0;
unsigned int flags = EXPR_F_CONSTANT | EXPR_F_SINGLETON;
- struct expr *i, *next;
+ const struct list_head *expressions = NULL;
+ struct expr *i, *next, *key = NULL;
+ const struct expr *key_ctx = NULL;
+ bool runaway = false;
+ uint32_t size = 0;
+
+ if (ctx->ectx.key && ctx->ectx.key->etype == EXPR_CONCAT) {
+ key_ctx = ctx->ectx.key;
+ assert(!list_empty(&ctx->ectx.key->expressions));
+ key = list_first_entry(&ctx->ectx.key->expressions, struct expr, list);
+ expressions = &ctx->ectx.key->expressions;
+ }
list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
+ enum byteorder bo = BYTEORDER_INVALID;
+ unsigned dsize_bytes, dsize = 0;
+
+ if (runaway) {
+ return expr_binary_error(ctx->msgs, *expr, key_ctx,
+ "too many concatenation components");
+ }
+
+ if (i->etype == EXPR_CT &&
+ (i->ct.key == NFT_CT_SRC ||
+ i->ct.key == NFT_CT_DST))
+ return expr_error(ctx->msgs, i,
+ "specify either ip or ip6 for address matching");
+
if (expr_is_constant(*expr) && dtype && off == 0)
return expr_binary_error(ctx->msgs, i, *expr,
"unexpected concat component, "
"expecting %s",
dtype->desc);
- if (dtype == NULL)
+ if (key) {
+ tmp = key->dtype;
+ dsize = key->len;
+ bo = key->byteorder;
+ off--;
+ } else if (dtype == NULL || off == 0) {
tmp = datatype_lookup(TYPE_INVALID);
- else
+ } else {
tmp = concat_subtype_lookup(type, --off);
- expr_set_context(&ctx->ectx, tmp, tmp->size);
+ dsize = tmp->size;
+ bo = tmp->byteorder;
+ }
+
+ __expr_set_context(&ctx->ectx, tmp, bo, dsize, 0);
+ ctx->ectx.key = i;
- if (eval && list_member_evaluate(ctx, &i) < 0)
+ if (list_member_evaluate(ctx, &i) < 0)
return -1;
+
+ if (i->etype == EXPR_SET)
+ return expr_error(ctx->msgs, i,
+ "cannot use %s in concatenation",
+ expr_name(i));
+
+ if (!i->dtype)
+ return expr_error(ctx->msgs, i,
+ "cannot use %s in concatenation, lacks datatype",
+ expr_name(i));
+
flags &= i->flags;
+ if (!key && i->dtype->type == TYPE_INTEGER) {
+ struct datatype *clone;
+
+ clone = datatype_clone(i->dtype);
+ clone->size = i->len;
+ clone->byteorder = i->byteorder;
+ __datatype_set(i, clone);
+ }
+
if (dtype == NULL && i->dtype->size == 0)
return expr_binary_error(ctx->msgs, i, *expr,
"can not use variable sized "
"data types (%s) in concat "
"expressions",
i->dtype->name);
+ if (dsize == 0) /* reload after evaluation or clone above */
+ dsize = i->dtype->size;
ntype = concat_subtype_add(ntype, i->dtype->type);
+
+ dsize_bytes = div_round_up(dsize, BITS_PER_BYTE);
+ (*expr)->field_len[(*expr)->field_count++] = dsize_bytes;
+ size += netlink_padded_len(dsize);
+ if (key && expressions) {
+ if (list_is_last(&key->list, expressions))
+ runaway = true;
+ else
+ key = list_next_entry(key, list);
+ }
+
+ ctx->inner_desc = NULL;
+
+ if (size > NFT_MAX_EXPR_LEN_BITS)
+ return expr_error(ctx->msgs, i, "Concatenation of size %u exceeds maximum size of %u",
+ size, NFT_MAX_EXPR_LEN_BITS);
}
(*expr)->flags |= flags;
- datatype_set(*expr, concat_type_alloc(ntype));
- (*expr)->len = (*expr)->dtype->size;
+ __datatype_set(*expr, concat_type_alloc(ntype));
+ (*expr)->len = size;
if (off > 0)
return expr_error(ctx->msgs, *expr,
@@ -1236,6 +1688,10 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr,
dtype->desc, (*expr)->dtype->desc);
expr_set_context(&ctx->ectx, (*expr)->dtype, (*expr)->len);
+ if (!key_ctx)
+ ctx->ectx.key = *expr;
+ else
+ ctx->ectx.key = key_ctx;
return 0;
}
@@ -1247,16 +1703,22 @@ static int expr_evaluate_list(struct eval_ctx *ctx, struct expr **expr)
mpz_init_set_ui(val, 0);
list_for_each_entry_safe(i, next, &list->expressions, list) {
- if (list_member_evaluate(ctx, &i) < 0)
+ if (list_member_evaluate(ctx, &i) < 0) {
+ mpz_clear(val);
return -1;
- if (i->etype != EXPR_VALUE)
+ }
+ if (i->etype != EXPR_VALUE) {
+ mpz_clear(val);
return expr_error(ctx->msgs, i,
"List member must be a constant "
"value");
- if (i->dtype->basetype->type != TYPE_BITMASK)
+ }
+ if (datatype_basetype(i->dtype)->type != TYPE_BITMASK) {
+ mpz_clear(val);
return expr_error(ctx->msgs, i,
"Basetype of type %s is not bitmask",
i->dtype->desc);
+ }
mpz_ior(val, val, i->value);
}
@@ -1270,9 +1732,67 @@ static int expr_evaluate_list(struct eval_ctx *ctx, struct expr **expr)
return 0;
}
+static int __expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr *elem)
+{
+ int num_elem_exprs = 0, num_set_exprs = 0;
+ struct set *set = ctx->set;
+ struct stmt *stmt;
+
+ list_for_each_entry(stmt, &elem->stmt_list, list)
+ num_elem_exprs++;
+ list_for_each_entry(stmt, &set->stmt_list, list)
+ num_set_exprs++;
+
+ if (num_elem_exprs > 0) {
+ struct stmt *set_stmt, *elem_stmt;
+
+ if (num_set_exprs > 0 && num_elem_exprs != num_set_exprs) {
+ return expr_error(ctx->msgs, elem,
+ "number of statements mismatch, set expects %d "
+ "but element has %d", num_set_exprs,
+ num_elem_exprs);
+ } else if (num_set_exprs == 0) {
+ if (!(set->flags & NFT_SET_ANONYMOUS) &&
+ !(set->flags & NFT_SET_EVAL)) {
+ elem_stmt = list_first_entry(&elem->stmt_list, struct stmt, list);
+ return stmt_error(ctx, elem_stmt,
+ "missing statement in %s declaration",
+ set_is_map(set->flags) ? "map" : "set");
+ }
+ return 0;
+ }
+
+ set_stmt = list_first_entry(&set->stmt_list, struct stmt, list);
+
+ list_for_each_entry(elem_stmt, &elem->stmt_list, list) {
+ if (set_stmt->ops != elem_stmt->ops) {
+ return stmt_error(ctx, elem_stmt,
+ "statement mismatch, element expects %s, "
+ "but %s has type %s",
+ elem_stmt->ops->name,
+ set_is_map(set->flags) ? "map" : "set",
+ set_stmt->ops->name);
+ }
+ set_stmt = list_next_entry(set_stmt, list);
+ }
+ }
+
+ return 0;
+}
+
static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *elem = *expr;
+ const struct expr *key;
+
+ if (ctx->set) {
+ if (__expr_evaluate_set_elem(ctx, elem) < 0)
+ return -1;
+
+ key = ctx->set->key;
+ __expr_set_context(&ctx->ectx, key->dtype, key->byteorder, key->len, 0);
+ ctx->ectx.key = key;
+ }
if (expr_evaluate(ctx, &elem->key) < 0)
return -1;
@@ -1281,13 +1801,20 @@ static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr)
!(ctx->set->flags & (NFT_SET_ANONYMOUS | NFT_SET_INTERVAL))) {
switch (elem->key->etype) {
case EXPR_PREFIX:
- return expr_error(ctx->msgs, elem,
- "Set member cannot be prefix, "
- "missing interval flag on declaration");
case EXPR_RANGE:
- return expr_error(ctx->msgs, elem,
- "Set member cannot be range, "
- "missing interval flag on declaration");
+ key = elem->key;
+ goto err_missing_flag;
+ case EXPR_CONCAT:
+ list_for_each_entry(key, &elem->key->expressions, list) {
+ switch (key->etype) {
+ case EXPR_PREFIX:
+ case EXPR_RANGE:
+ goto err_missing_flag;
+ default:
+ break;
+ }
+ }
+ break;
default:
break;
}
@@ -1296,30 +1823,109 @@ static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr)
datatype_set(elem, elem->key->dtype);
elem->len = elem->key->len;
elem->flags = elem->key->flags;
+
return 0;
+
+err_missing_flag:
+ return expr_error(ctx->msgs, key,
+ "You must add 'flags interval' to your %s declaration if you want to add %s elements",
+ set_is_map(ctx->set->flags) ? "map" : "set", expr_name(key));
+}
+
+static const struct expr *expr_set_elem(const struct expr *expr)
+{
+ if (expr->etype == EXPR_MAPPING)
+ return expr->left;
+
+ return expr;
+}
+
+static int interval_set_eval(struct eval_ctx *ctx, struct set *set,
+ struct expr *init)
+{
+ int ret;
+
+ if (!init)
+ return 0;
+
+ ret = 0;
+ switch (ctx->cmd->op) {
+ case CMD_CREATE:
+ case CMD_ADD:
+ case CMD_REPLACE:
+ case CMD_INSERT:
+ if (set->automerge) {
+ ret = set_automerge(ctx->msgs, ctx->cmd, set, init,
+ ctx->nft->debug_mask);
+ } else {
+ ret = set_overlap(ctx->msgs, set, init);
+ }
+ break;
+ case CMD_DELETE:
+ case CMD_DESTROY:
+ ret = set_delete(ctx->msgs, ctx->cmd, set, init,
+ ctx->nft->debug_mask);
+ break;
+ case CMD_GET:
+ break;
+ default:
+ BUG("unhandled op %d\n", ctx->cmd->op);
+ break;
+ }
+
+ return ret;
+}
+
+static void expr_evaluate_set_ref(struct eval_ctx *ctx, struct expr *expr)
+{
+ struct set *set = expr->set;
+
+ expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
+ ctx->ectx.key = set->key;
}
static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *set = *expr, *i, *next;
+ const struct expr *elem;
list_for_each_entry_safe(i, next, &set->expressions, list) {
if (list_member_evaluate(ctx, &i) < 0)
return -1;
- if (i->etype == EXPR_SET_ELEM &&
- i->key->etype == EXPR_SET_REF)
+ if (i->etype == EXPR_MAPPING &&
+ i->left->etype == EXPR_SET_ELEM &&
+ i->left->key->etype == EXPR_SET) {
+ struct expr *new, *j;
+
+ list_for_each_entry(j, &i->left->key->expressions, list) {
+ new = mapping_expr_alloc(&i->location,
+ expr_get(j),
+ expr_get(i->right));
+ list_add_tail(&new->list, &set->expressions);
+ set->size++;
+ }
+ list_del(&i->list);
+ expr_free(i);
+ continue;
+ }
+
+ elem = expr_set_elem(i);
+
+ if (elem->etype == EXPR_SET_ELEM &&
+ elem->key->etype == EXPR_SET_REF)
return expr_error(ctx->msgs, i,
"Set reference cannot be part of another set");
- if (i->etype == EXPR_SET_ELEM &&
- i->key->etype == EXPR_SET) {
- struct expr *new = expr_clone(i->key);
+ if (elem->etype == EXPR_SET_ELEM &&
+ elem->key->etype == EXPR_SET) {
+ struct expr *new = expr_get(elem->key);
- set->set_flags |= i->key->set_flags;
+ set->set_flags |= elem->key->set_flags;
list_replace(&i->list, &new->list);
expr_free(i);
i = new;
+ elem = expr_set_elem(i);
}
if (!expr_is_constant(i))
@@ -1333,8 +1939,16 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
set->size += i->size - 1;
set->set_flags |= i->set_flags;
expr_free(i);
- } else if (!expr_is_singleton(i))
+ } else if (!expr_is_singleton(i)) {
set->set_flags |= NFT_SET_INTERVAL;
+ if (elem->key->etype == EXPR_CONCAT)
+ set->set_flags |= NFT_SET_CONCAT;
+ }
+ }
+
+ if (ctx->set) {
+ if (ctx->set->flags & NFT_SET_CONCAT)
+ set->set_flags |= NFT_SET_CONCAT;
}
set->set_flags |= NFT_SET_CONSTANT;
@@ -1342,15 +1956,98 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
datatype_set(set, ctx->ectx.dtype);
set->len = ctx->ectx.len;
set->flags |= EXPR_F_CONSTANT;
+
return 0;
}
static int binop_transfer(struct eval_ctx *ctx, struct expr **expr);
+
+static void map_set_concat_info(struct expr *map)
+{
+ map->mappings->set->flags |= map->mappings->set->init->set_flags;
+
+ if (map->mappings->set->flags & NFT_SET_INTERVAL &&
+ map->map->etype == EXPR_CONCAT) {
+ memcpy(&map->mappings->set->desc.field_len, &map->map->field_len,
+ sizeof(map->mappings->set->desc.field_len));
+ map->mappings->set->desc.field_count = map->map->field_count;
+ map->mappings->flags |= NFT_SET_CONCAT;
+ }
+}
+
+static void __mapping_expr_expand(struct expr *i)
+{
+ struct expr *j, *range, *next;
+
+ assert(i->etype == EXPR_MAPPING);
+ switch (i->right->etype) {
+ case EXPR_VALUE:
+ range = range_expr_alloc(&i->location, expr_get(i->right), expr_get(i->right));
+ expr_free(i->right);
+ i->right = range;
+ break;
+ case EXPR_CONCAT:
+ list_for_each_entry_safe(j, next, &i->right->expressions, list) {
+ if (j->etype != EXPR_VALUE)
+ continue;
+
+ range = range_expr_alloc(&j->location, expr_get(j), expr_get(j));
+ list_replace(&j->list, &range->list);
+ expr_free(j);
+ }
+ i->right->flags &= ~EXPR_F_SINGLETON;
+ break;
+ default:
+ break;
+ }
+}
+
+static int mapping_expr_expand(struct eval_ctx *ctx)
+{
+ struct expr *i;
+
+ if (!set_is_anonymous(ctx->set->flags))
+ return 0;
+
+ list_for_each_entry(i, &ctx->set->init->expressions, list) {
+ if (i->etype != EXPR_MAPPING)
+ return expr_error(ctx->msgs, i,
+ "expected mapping, not %s", expr_name(i));
+ __mapping_expr_expand(i);
+ }
+
+ return 0;
+}
+
+static bool datatype_compatible(const struct datatype *a, const struct datatype *b)
+{
+ return (a->type == TYPE_MARK &&
+ datatype_equal(datatype_basetype(a), datatype_basetype(b))) ||
+ datatype_equal(a, b);
+}
+
static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
{
- struct expr_ctx ectx = ctx->ectx;
struct expr *map = *expr, *mappings;
- struct expr *key;
+ struct expr_ctx ectx = ctx->ectx;
+ struct expr *key, *data;
+
+ if (map->map->etype == EXPR_CT &&
+ (map->map->ct.key == NFT_CT_SRC ||
+ map->map->ct.key == NFT_CT_DST))
+ return expr_error(ctx->msgs, map->map,
+ "specify either ip or ip6 for address matching");
+ else if (map->map->etype == EXPR_CONCAT) {
+ struct expr *i;
+
+ list_for_each_entry(i, &map->map->expressions, list) {
+ if (i->etype == EXPR_CT &&
+ (i->ct.key == NFT_CT_SRC ||
+ i->ct.key == NFT_CT_DST))
+ return expr_error(ctx->msgs, i,
+ "specify either ip or ip6 for address matching");
+ }
+ }
expr_set_context(&ctx->ectx, NULL, 0);
if (expr_evaluate(ctx, &map->map) < 0)
@@ -1359,37 +2056,75 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
return expr_error(ctx->msgs, map->map,
"Map expression can not be constant");
+ ctx->stmt_len = 0;
mappings = map->mappings;
mappings->set_flags |= NFT_SET_MAP;
switch (map->mappings->etype) {
case EXPR_SET:
- key = constant_expr_alloc(&map->location,
- ctx->ectx.dtype,
- ctx->ectx.byteorder,
- ctx->ectx.len, NULL);
+ if (ctx->ectx.key && ctx->ectx.key->etype == EXPR_CONCAT) {
+ key = expr_clone(ctx->ectx.key);
+ } else {
+ key = constant_expr_alloc(&map->location,
+ ctx->ectx.dtype,
+ ctx->ectx.byteorder,
+ ctx->ectx.len, NULL);
+ }
+
+ if (!ectx.dtype) {
+ expr_free(key);
+ return expr_error(ctx->msgs, map,
+ "Implicit map expression without known datatype");
+ }
+
+ if (ectx.dtype->type == TYPE_VERDICT) {
+ data = verdict_expr_alloc(&netlink_location, 0, NULL);
+ } else {
+ const struct datatype *dtype;
+
+ dtype = set_datatype_alloc(ectx.dtype, ectx.byteorder);
+ data = constant_expr_alloc(&netlink_location, dtype,
+ dtype->byteorder, ectx.len, NULL);
+ datatype_free(dtype);
+ }
mappings = implicit_set_declaration(ctx, "__map%d",
- key,
- mappings);
- mappings->set->datatype =
- datatype_get(set_datatype_alloc(ectx.dtype,
- ectx.byteorder));
- mappings->set->datalen = ectx.len;
+ key, data,
+ mappings,
+ NFT_SET_ANONYMOUS);
+ if (!mappings)
+ return -1;
+
+ if (ectx.len && mappings->set->data->len != ectx.len)
+ BUG("%d vs %d\n", mappings->set->data->len, ectx.len);
map->mappings = mappings;
ctx->set = mappings->set;
if (expr_evaluate(ctx, &map->mappings->set->init) < 0)
return -1;
+
+ if (set_is_interval(map->mappings->set->init->set_flags) &&
+ !(map->mappings->set->init->set_flags & NFT_SET_CONCAT) &&
+ interval_set_eval(ctx, ctx->set, map->mappings->set->init) < 0)
+ return -1;
+
expr_set_context(&ctx->ectx, ctx->set->key->dtype, ctx->set->key->len);
if (binop_transfer(ctx, expr) < 0)
return -1;
+ if (ctx->set->data->flags & EXPR_F_INTERVAL) {
+ ctx->set->data->len *= 2;
+
+ if (mapping_expr_expand(ctx))
+ return -1;
+ }
+
ctx->set->key->len = ctx->ectx.len;
ctx->set = NULL;
map = *expr;
- map->mappings->set->flags |= map->mappings->set->init->set_flags;
+
+ map_set_concat_info(map);
break;
case EXPR_SYMBOL:
if (expr_evaluate(ctx, &map->mappings) < 0)
@@ -1399,19 +2134,25 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
return expr_error(ctx->msgs, map->mappings,
"Expression is not a map");
break;
+ case EXPR_SET_REF:
+ /* symbol has been already evaluated to set reference */
+ if (!set_is_map(mappings->set->flags))
+ return expr_error(ctx->msgs, map->mappings,
+ "Expression is not a map");
+ break;
default:
- BUG("invalid mapping expression %s\n",
- expr_name(map->mappings));
+ return expr_binary_error(ctx->msgs, map->mappings, map->map,
+ "invalid mapping expression %s", expr_name(map->mappings));
}
- if (!datatype_equal(map->map->dtype, map->mappings->set->key->dtype))
+ if (!datatype_compatible(map->mappings->set->key->dtype, map->map->dtype))
return expr_binary_error(ctx->msgs, map->mappings, map->map,
"datatype mismatch, map expects %s, "
"mapping expression has type %s",
map->mappings->set->key->dtype->desc,
map->map->dtype->desc);
- datatype_set(map, map->mappings->set->datatype);
+ datatype_set(map, map->mappings->set->data->dtype);
map->flags |= EXPR_F_CONSTANT;
/* Data for range lookups needs to be in big endian order */
@@ -1422,10 +2163,31 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
return 0;
}
+static bool data_mapping_has_interval(struct expr *data)
+{
+ struct expr *i;
+
+ if (data->etype == EXPR_RANGE ||
+ data->etype == EXPR_PREFIX)
+ return true;
+
+ if (data->etype != EXPR_CONCAT)
+ return false;
+
+ list_for_each_entry(i, &data->expressions, list) {
+ if (i->etype == EXPR_RANGE ||
+ i->etype == EXPR_PREFIX)
+ return true;
+ }
+
+ return false;
+}
+
static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *mapping = *expr;
struct set *set = ctx->set;
+ uint32_t datalen;
if (set == NULL)
return expr_error(ctx->msgs, mapping,
@@ -1441,16 +2203,39 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
"Key must be a constant");
mapping->flags |= mapping->left->flags & EXPR_F_SINGLETON;
- expr_set_context(&ctx->ectx, set->datatype, set->datalen);
+ assert(set->data != NULL);
+ if (!set_is_anonymous(set->flags) &&
+ set->data->flags & EXPR_F_INTERVAL)
+ datalen = set->data->len / 2;
+ else
+ datalen = set->data->len;
+ __expr_set_context(&ctx->ectx, set->data->dtype,
+ set->data->byteorder, datalen, 0);
+
if (expr_evaluate(ctx, &mapping->right) < 0)
return -1;
if (!expr_is_constant(mapping->right))
return expr_error(ctx->msgs, mapping->right,
"Value must be a constant");
- if (!expr_is_singleton(mapping->right))
+
+ if (set_is_anonymous(set->flags) &&
+ data_mapping_has_interval(mapping->right))
+ set->data->flags |= EXPR_F_INTERVAL;
+
+ if (!set_is_anonymous(set->flags) &&
+ set->data->flags & EXPR_F_INTERVAL)
+ __mapping_expr_expand(mapping);
+
+ if (!(set->data->flags & EXPR_F_INTERVAL) &&
+ !expr_is_singleton(mapping->right))
return expr_error(ctx->msgs, mapping->right,
"Value must be a singleton");
+ if (set_is_objmap(set->flags) && mapping->right->etype != EXPR_VALUE)
+ return expr_error(ctx->msgs, mapping->right,
+ "Object mapping data should be a value, not %s",
+ expr_name(mapping->right));
+
mapping->flags |= EXPR_F_CONSTANT;
return 0;
}
@@ -1476,17 +2261,20 @@ static void expr_dtype_integer_compatible(struct eval_ctx *ctx,
static int expr_evaluate_numgen(struct eval_ctx *ctx, struct expr **exprp)
{
struct expr *expr = *exprp;
+ unsigned int maxval;
expr_dtype_integer_compatible(ctx, expr);
+ maxval = expr->numgen.mod + expr->numgen.offset - 1;
__expr_set_context(&ctx->ectx, expr->dtype, expr->byteorder, expr->len,
- expr->numgen.mod - 1);
+ maxval);
return 0;
}
static int expr_evaluate_hash(struct eval_ctx *ctx, struct expr **exprp)
{
struct expr *expr = *exprp;
+ unsigned int maxval;
expr_dtype_integer_compatible(ctx, expr);
@@ -1499,8 +2287,9 @@ static int expr_evaluate_hash(struct eval_ctx *ctx, struct expr **exprp)
* expression to be hashed. Since this input is transformed to a 4 bytes
* integer, restore context to the datatype that results from hashing.
*/
+ maxval = expr->hash.mod + expr->hash.offset - 1;
__expr_set_context(&ctx->ectx, expr->dtype, expr->byteorder, expr->len,
- expr->hash.mod - 1);
+ maxval);
return 0;
}
@@ -1569,8 +2358,6 @@ static int binop_transfer_one(struct eval_ctx *ctx,
return 0;
}
- expr_get(*right);
-
switch (left->op) {
case OP_LSHIFT:
(*right) = binop_expr_alloc(&(*right)->location, OP_RSHIFT,
@@ -1683,7 +2470,7 @@ static int binop_transfer(struct eval_ctx *ctx, struct expr **expr)
return 0;
}
-static bool lhs_is_meta_hour(const struct expr *meta)
+bool lhs_is_meta_hour(const struct expr *meta)
{
if (meta->etype != EXPR_META)
return false;
@@ -1692,7 +2479,7 @@ static bool lhs_is_meta_hour(const struct expr *meta)
meta->meta.key == NFT_META_TIME_DAY;
}
-static void swap_values(struct expr *range)
+void range_expr_swap_values(struct expr *range)
{
struct expr *left_tmp;
@@ -1709,16 +2496,54 @@ static bool range_needs_swap(const struct expr *range)
return mpz_cmp(left->value, right->value) > 0;
}
+static void optimize_singleton_set(struct expr *rel, struct expr **expr)
+{
+ struct expr *set = rel->right, *i;
+
+ i = list_first_entry(&set->expressions, struct expr, list);
+ if (i->etype == EXPR_SET_ELEM &&
+ list_empty(&i->stmt_list)) {
+
+ switch (i->key->etype) {
+ case EXPR_PREFIX:
+ case EXPR_RANGE:
+ case EXPR_VALUE:
+ rel->right = *expr = i->key;
+ i->key = NULL;
+ expr_free(set);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (rel->op == OP_IMPLICIT &&
+ rel->right->dtype->basetype &&
+ rel->right->dtype->basetype->type == TYPE_BITMASK &&
+ rel->right->dtype->type != TYPE_CT_STATE) {
+ rel->op = OP_EQ;
+ }
+}
+
static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *rel = *expr, *left, *right;
+ struct proto_ctx *pctx;
struct expr *range;
int ret;
+ right = rel->right;
+ if (right->etype == EXPR_SYMBOL &&
+ right->symtype == SYMBOL_SET &&
+ expr_evaluate(ctx, &rel->right) < 0)
+ return -1;
+
if (expr_evaluate(ctx, &rel->left) < 0)
return -1;
left = rel->left;
+ pctx = eval_proto_ctx(ctx);
+
if (rel->right->etype == EXPR_RANGE && lhs_is_meta_hour(rel->left)) {
ret = __expr_evaluate_range(ctx, &rel->right);
if (ret)
@@ -1736,10 +2561,10 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
"Inverting range values for cross-day hour matching\n\n");
if (rel->op == OP_EQ || rel->op == OP_IMPLICIT) {
- swap_values(range);
+ range_expr_swap_values(range);
rel->op = OP_NEQ;
} else if (rel->op == OP_NEQ) {
- swap_values(range);
+ range_expr_swap_values(range);
rel->op = OP_EQ;
}
}
@@ -1767,6 +2592,31 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
left->dtype->desc,
right->dtype->desc);
+ /*
+ * Statements like 'ct secmark 12' are parsed as relational,
+ * disallow constant value on the right hand side.
+ */
+ if (((left->etype == EXPR_META &&
+ left->meta.key == NFT_META_SECMARK) ||
+ (left->etype == EXPR_CT &&
+ left->ct.key == NFT_CT_SECMARK)) &&
+ right->flags & EXPR_F_CONSTANT)
+ return expr_binary_error(ctx->msgs, right, left,
+ "Cannot be used with right hand side constant value");
+
+ if (left->etype != EXPR_CONCAT) {
+ switch (rel->op) {
+ case OP_EQ:
+ case OP_IMPLICIT:
+ case OP_NEQ:
+ if (right->etype == EXPR_SET && right->size == 1)
+ optimize_singleton_set(rel, &right);
+ break;
+ default:
+ break;
+ }
+ }
+
switch (rel->op) {
case OP_EQ:
case OP_IMPLICIT:
@@ -1774,11 +2624,22 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
* Update protocol context for payload and meta iiftype
* equality expressions.
*/
- if (expr_is_singleton(right))
- relational_expr_pctx_update(&ctx->pctx, rel);
+ relational_expr_pctx_update(pctx, rel);
/* fall through */
case OP_NEQ:
+ case OP_NEG:
+ if (rel->op == OP_NEG) {
+ if (left->etype == EXPR_BINOP)
+ return expr_binary_error(ctx->msgs, left, right,
+ "cannot combine negation with binary expression");
+ if (right->etype != EXPR_VALUE ||
+ right->dtype->basetype == NULL ||
+ right->dtype->basetype->type != TYPE_BITMASK)
+ return expr_binary_error(ctx->msgs, left, right,
+ "negation can only be used with singleton bitmask values. Did you mean \"!=\"?");
+ }
+
switch (right->etype) {
case EXPR_RANGE:
if (byteorder_conversion(ctx, &rel->left, BYTEORDER_BIG_ENDIAN) < 0)
@@ -1797,16 +2658,34 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
return -1;
break;
case EXPR_SET:
+ if (right->size == 0)
+ return expr_error(ctx->msgs, right, "Set is empty");
+
right = rel->right =
implicit_set_declaration(ctx, "__set%d",
- expr_get(left), right);
+ expr_get(left), NULL,
+ right,
+ NFT_SET_ANONYMOUS);
+ if (!right)
+ return -1;
+
/* fall through */
case EXPR_SET_REF:
+ if (rel->left->etype == EXPR_CT &&
+ (rel->left->ct.key == NFT_CT_SRC ||
+ rel->left->ct.key == NFT_CT_DST))
+ return expr_error(ctx->msgs, left,
+ "specify either ip or ip6 for address matching");
+
/* Data for range lookups needs to be in big endian order */
if (right->set->flags & NFT_SET_INTERVAL &&
byteorder_conversion(ctx, &rel->left, BYTEORDER_BIG_ENDIAN) < 0)
return -1;
break;
+ case EXPR_CONCAT:
+ return expr_binary_error(ctx->msgs, left, right,
+ "Use concatenations with sets and maps, not singleton values");
+ break;
default:
BUG("invalid expression type %s\n", expr_name(right));
}
@@ -1861,11 +2740,12 @@ static int expr_evaluate_fib(struct eval_ctx *ctx, struct expr **exprp)
static int expr_evaluate_meta(struct eval_ctx *ctx, struct expr **exprp)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
struct expr *meta = *exprp;
switch (meta->meta.key) {
case NFT_META_NFPROTO:
- if (ctx->pctx.family != NFPROTO_INET &&
+ if (pctx->family != NFPROTO_INET &&
meta->flags & EXPR_F_PROTOCOL)
return expr_error(ctx->msgs, meta,
"meta nfproto is only useful in the inet family");
@@ -1883,9 +2763,11 @@ static int expr_evaluate_meta(struct eval_ctx *ctx, struct expr **exprp)
static int expr_evaluate_socket(struct eval_ctx *ctx, struct expr **expr)
{
+ enum nft_socket_keys key = (*expr)->socket.key;
int maxval = 0;
- if((*expr)->socket.key == NFT_SOCKET_TRANSPARENT)
+ if (key == NFT_SOCKET_TRANSPARENT ||
+ key == NFT_SOCKET_WILDCARD)
maxval = 1;
__expr_set_context(&ctx->ectx, (*expr)->dtype, (*expr)->byteorder,
(*expr)->len, maxval);
@@ -1906,19 +2788,34 @@ static int expr_evaluate_osf(struct eval_ctx *ctx, struct expr **expr)
static int expr_evaluate_variable(struct eval_ctx *ctx, struct expr **exprp)
{
- struct expr *new = expr_clone((*exprp)->sym->expr);
+ struct symbol *sym = (*exprp)->sym;
+ struct expr *new;
+
+ /* If variable is reused from different locations in the ruleset, then
+ * clone expression.
+ */
+ if (sym->refcnt > 2)
+ new = expr_clone(sym->expr);
+ else
+ new = expr_get(sym->expr);
+
+ if (expr_evaluate(ctx, &new) < 0) {
+ expr_free(new);
+ return -1;
+ }
expr_free(*exprp);
*exprp = new;
- return expr_evaluate(ctx, exprp);
+ return 0;
}
static int expr_evaluate_xfrm(struct eval_ctx *ctx, struct expr **exprp)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
struct expr *expr = *exprp;
- switch (ctx->pctx.family) {
+ switch (pctx->family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6:
case NFPROTO_INET:
@@ -1931,6 +2828,54 @@ static int expr_evaluate_xfrm(struct eval_ctx *ctx, struct expr **exprp)
return expr_evaluate_primary(ctx, exprp);
}
+static int expr_evaluate_flagcmp(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *expr = *exprp, *binop, *rel;
+
+ if (expr->op != OP_EQ &&
+ expr->op != OP_NEQ)
+ return expr_error(ctx->msgs, expr, "either == or != is allowed");
+
+ binop = binop_expr_alloc(&expr->location, OP_AND,
+ expr_get(expr->flagcmp.expr),
+ expr_get(expr->flagcmp.mask));
+ rel = relational_expr_alloc(&expr->location, expr->op, binop,
+ expr_get(expr->flagcmp.value));
+ expr_free(expr);
+ *exprp = rel;
+
+ return expr_evaluate(ctx, exprp);
+}
+
+static int verdict_validate_chainlen(struct eval_ctx *ctx,
+ struct expr *chain)
+{
+ if (chain->len > NFT_CHAIN_MAXNAMELEN * BITS_PER_BYTE)
+ return expr_error(ctx->msgs, chain,
+ "chain name too long (%u, max %u)",
+ chain->len / BITS_PER_BYTE,
+ NFT_CHAIN_MAXNAMELEN);
+
+ return 0;
+}
+
+static int expr_evaluate_verdict(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *expr = *exprp;
+
+ switch (expr->verdict) {
+ case NFT_GOTO:
+ case NFT_JUMP:
+ if (expr->chain->etype == EXPR_VALUE &&
+ verdict_validate_chainlen(ctx, expr->chain))
+ return -1;
+
+ break;
+ }
+
+ return expr_evaluate_primary(ctx, exprp);
+}
+
static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
{
if (ctx->nft->debug_mask & NFT_DEBUG_EVALUATION) {
@@ -1949,13 +2894,14 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
case EXPR_VARIABLE:
return expr_evaluate_variable(ctx, expr);
case EXPR_SET_REF:
+ expr_evaluate_set_ref(ctx, *expr);
return 0;
case EXPR_VALUE:
return expr_evaluate_value(ctx, expr);
case EXPR_EXTHDR:
return expr_evaluate_exthdr(ctx, expr);
case EXPR_VERDICT:
- return expr_evaluate_primary(ctx, expr);
+ return expr_evaluate_verdict(ctx, expr);
case EXPR_META:
return expr_evaluate_meta(ctx, expr);
case EXPR_SOCKET:
@@ -1965,7 +2911,7 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
case EXPR_FIB:
return expr_evaluate_fib(ctx, expr);
case EXPR_PAYLOAD:
- return expr_evaluate_payload(ctx, expr);
+ return expr_evaluate_payload_inner(ctx, expr);
case EXPR_RT:
return expr_evaluate_rt(ctx, expr);
case EXPR_CT:
@@ -1979,7 +2925,7 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
case EXPR_BINOP:
return expr_evaluate_binop(ctx, expr);
case EXPR_CONCAT:
- return expr_evaluate_concat(ctx, expr, true);
+ return expr_evaluate_concat(ctx, expr);
case EXPR_LIST:
return expr_evaluate_list(ctx, expr);
case EXPR_SET:
@@ -1998,6 +2944,10 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr)
return expr_evaluate_hash(ctx, expr);
case EXPR_XFRM:
return expr_evaluate_xfrm(ctx, expr);
+ case EXPR_SET_ELEM_CATCHALL:
+ return 0;
+ case EXPR_FLAGCMP:
+ return expr_evaluate_flagcmp(ctx, expr);
default:
BUG("unknown expression type %s\n", expr_name(*expr));
}
@@ -2055,14 +3005,10 @@ static int stmt_prefix_conversion(struct eval_ctx *ctx, struct expr **expr,
return 0;
}
-static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
- const struct datatype *dtype, unsigned int len,
- enum byteorder byteorder, struct expr **expr)
+static int __stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
+ const struct datatype *dtype, unsigned int len,
+ enum byteorder byteorder, struct expr **expr)
{
- __expr_set_context(&ctx->ectx, dtype, byteorder, len, 0);
- if (expr_evaluate(ctx, expr) < 0)
- return -1;
-
if ((*expr)->etype == EXPR_PAYLOAD &&
(*expr)->dtype->type == TYPE_INTEGER &&
((*expr)->dtype->type != datatype_basetype(dtype)->type ||
@@ -2072,13 +3018,18 @@ static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
"expression has type %s with length %d",
dtype->desc, (*expr)->dtype->desc,
(*expr)->len);
- else if ((*expr)->dtype->type != TYPE_INTEGER &&
- !datatype_equal((*expr)->dtype, dtype))
- return stmt_binary_error(ctx, *expr, stmt,
+
+ if (!datatype_compatible(dtype, (*expr)->dtype))
+ return stmt_binary_error(ctx, *expr, stmt, /* verdict vs invalid? */
"datatype mismatch: expected %s, "
"expression has type %s",
dtype->desc, (*expr)->dtype->desc);
+ if (dtype->type == TYPE_MARK &&
+ datatype_equal(datatype_basetype(dtype), datatype_basetype((*expr)->dtype)) &&
+ !expr_is_constant(*expr))
+ return byteorder_conversion(ctx, expr, byteorder);
+
/* we are setting a value, we can't use a set */
switch ((*expr)->etype) {
case EXPR_SET:
@@ -2093,6 +3044,10 @@ static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
return byteorder_conversion(ctx, expr, byteorder);
case EXPR_PREFIX:
return stmt_prefix_conversion(ctx, expr, byteorder);
+ case EXPR_NUMGEN:
+ if (dtype->type == TYPE_IPADDR)
+ return byteorder_conversion(ctx, expr, byteorder);
+ break;
default:
break;
}
@@ -2100,6 +3055,36 @@ static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
return 0;
}
+static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
+ const struct datatype *dtype, unsigned int len,
+ enum byteorder byteorder, struct expr **expr)
+{
+ __expr_set_context(&ctx->ectx, dtype, byteorder, len, 0);
+ if (expr_evaluate(ctx, expr) < 0)
+ return -1;
+
+ return __stmt_evaluate_arg(ctx, stmt, dtype, len, byteorder, expr);
+}
+
+/* like stmt_evaluate_arg, but keep existing context created
+ * by previous expr_evaluate().
+ *
+ * This is needed for add/update statements:
+ * ctx->ectx.key has the set key, which may be needed for 'typeof'
+ * sets: the 'add/update' expression might contain integer data types.
+ *
+ * Without the key we cannot derive the element size.
+ */
+static int stmt_evaluate_key(struct eval_ctx *ctx, struct stmt *stmt,
+ const struct datatype *dtype, unsigned int len,
+ enum byteorder byteorder, struct expr **expr)
+{
+ if (expr_evaluate(ctx, expr) < 0)
+ return -1;
+
+ return __stmt_evaluate_arg(ctx, stmt, dtype, len, byteorder, expr);
+}
+
static int stmt_evaluate_verdict(struct eval_ctx *ctx, struct stmt *stmt)
{
if (stmt_evaluate_arg(ctx, stmt, &verdict_type, 0, 0, &stmt->expr) < 0)
@@ -2110,12 +3095,16 @@ static int stmt_evaluate_verdict(struct eval_ctx *ctx, struct stmt *stmt)
if (stmt->expr->verdict != NFT_CONTINUE)
stmt->flags |= STMT_F_TERMINAL;
if (stmt->expr->chain != NULL) {
- if (expr_evaluate(ctx, &stmt->expr->chain) < 0)
+ if (stmt_evaluate_arg(ctx, stmt, &string_type, 0, 0,
+ &stmt->expr->chain) < 0)
return -1;
if (stmt->expr->chain->etype != EXPR_VALUE) {
return expr_error(ctx->msgs, stmt->expr->chain,
"not a value expression");
}
+
+ if (verdict_validate_chainlen(ctx, stmt->expr->chain))
+ return -1;
}
break;
case EXPR_MAP:
@@ -2130,6 +3119,9 @@ static bool stmt_evaluate_payload_need_csum(const struct expr *payload)
{
const struct proto_desc *desc;
+ if (payload->payload.base == PROTO_BASE_INNER_HDR)
+ return true;
+
desc = payload->payload.desc;
return desc && desc->checksum_key;
@@ -2138,19 +3130,27 @@ static bool stmt_evaluate_payload_need_csum(const struct expr *payload)
static int stmt_evaluate_exthdr(struct eval_ctx *ctx, struct stmt *stmt)
{
struct expr *exthdr;
+ int ret;
if (__expr_evaluate_exthdr(ctx, &stmt->exthdr.expr) < 0)
return -1;
exthdr = stmt->exthdr.expr;
- return stmt_evaluate_arg(ctx, stmt, exthdr->dtype, exthdr->len,
- BYTEORDER_BIG_ENDIAN,
- &stmt->exthdr.val);
+ ret = stmt_evaluate_arg(ctx, stmt, exthdr->dtype, exthdr->len,
+ BYTEORDER_BIG_ENDIAN,
+ &stmt->exthdr.val);
+ if (ret < 0)
+ return ret;
+
+ if (stmt->exthdr.val->etype == EXPR_RANGE)
+ return stmt_error_range(ctx, stmt, stmt->exthdr.val);
+
+ return 0;
}
static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
{
- struct expr *binop, *mask, *and, *payload_bytes;
+ struct expr *mask, *and, *xor, *payload_bytes;
unsigned int masklen, extra_len = 0;
unsigned int payload_byte_size, payload_byte_offset;
uint8_t shift_imm, data[NFT_REG_SIZE];
@@ -2158,6 +3158,11 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
mpz_t bitmask, ff;
bool need_csum;
+ if (stmt->payload.expr->payload.inner_desc) {
+ return expr_error(ctx->msgs, stmt->payload.expr,
+ "payload statement for this expression is not supported");
+ }
+
if (__expr_evaluate_payload(ctx, stmt->payload.expr) < 0)
return -1;
@@ -2166,6 +3171,14 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
payload->byteorder, &stmt->payload.val) < 0)
return -1;
+ if (!expr_is_constant(stmt->payload.val) &&
+ byteorder_conversion(ctx, &stmt->payload.val,
+ payload->byteorder) < 0)
+ return -1;
+
+ if (stmt->payload.val->etype == EXPR_RANGE)
+ return stmt_error_range(ctx, stmt, stmt->payload.val);
+
need_csum = stmt_evaluate_payload_need_csum(payload);
if (!payload_needs_adjustment(payload)) {
@@ -2182,8 +3195,13 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
shift_imm = expr_offset_shift(payload, payload->payload.offset,
&extra_len);
- payload_byte_size = round_up(payload->len, BITS_PER_BYTE) / BITS_PER_BYTE;
- payload_byte_size += (extra_len / BITS_PER_BYTE);
+ payload_byte_size = div_round_up(payload->len + extra_len,
+ BITS_PER_BYTE);
+
+ if (payload_byte_size > sizeof(data))
+ return expr_error(ctx->msgs, stmt->payload.expr,
+ "uneven load cannot span more than %u bytes, got %u",
+ sizeof(data), payload_byte_size);
if (need_csum && payload_byte_size & 1) {
payload_byte_size++;
@@ -2197,22 +3215,21 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
}
if (shift_imm) {
- struct expr *off;
+ struct expr *off, *lshift;
off = constant_expr_alloc(&payload->location,
expr_basetype(payload),
BYTEORDER_HOST_ENDIAN,
sizeof(shift_imm), &shift_imm);
- binop = binop_expr_alloc(&payload->location, OP_LSHIFT,
- stmt->payload.val, off);
- binop->dtype = payload->dtype;
- binop->byteorder = payload->byteorder;
+ lshift = binop_expr_alloc(&payload->location, OP_LSHIFT,
+ stmt->payload.val, off);
+ lshift->dtype = payload->dtype;
+ lshift->byteorder = payload->byteorder;
- stmt->payload.val = binop;
+ stmt->payload.val = lshift;
}
-
masklen = payload_byte_size * BITS_PER_BYTE;
mpz_init_bitmask(ff, masklen);
@@ -2224,15 +3241,17 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
mpz_clear(ff);
assert(sizeof(data) * BITS_PER_BYTE >= masklen);
- mpz_export_data(data, bitmask, BYTEORDER_HOST_ENDIAN, sizeof(data));
+ mpz_export_data(data, bitmask, payload->byteorder, payload_byte_size);
mask = constant_expr_alloc(&payload->location, expr_basetype(payload),
- BYTEORDER_HOST_ENDIAN, masklen, data);
+ payload->byteorder, masklen, data);
+ mpz_clear(bitmask);
payload_bytes = payload_expr_alloc(&payload->location, NULL, 0);
payload_init_raw(payload_bytes, payload->payload.base,
payload_byte_offset * BITS_PER_BYTE,
payload_byte_size * BITS_PER_BYTE);
+ payload_bytes->payload.is_raw = 1;
payload_bytes->payload.desc = payload->payload.desc;
payload_bytes->byteorder = payload->byteorder;
@@ -2241,16 +3260,17 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
and = binop_expr_alloc(&payload->location, OP_AND, payload_bytes, mask);
- and->dtype = payload_bytes->dtype;
- and->byteorder = payload_bytes->byteorder;
- and->len = payload_bytes->len;
+ and->dtype = payload_bytes->dtype;
+ and->byteorder = payload_bytes->byteorder;
+ and->len = payload_bytes->len;
- binop = binop_expr_alloc(&payload->location, OP_XOR, and,
- stmt->payload.val);
- binop->dtype = payload->dtype;
- binop->byteorder = payload->byteorder;
- binop->len = mask->len;
- stmt->payload.val = binop;
+ xor = binop_expr_alloc(&payload->location, OP_XOR, and,
+ stmt->payload.val);
+ xor->dtype = payload->dtype;
+ xor->byteorder = payload->byteorder;
+ xor->len = mask->len;
+
+ stmt->payload.val = xor;
return expr_evaluate(ctx, &stmt->payload.val);
}
@@ -2258,6 +3278,24 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
static int stmt_evaluate_meter(struct eval_ctx *ctx, struct stmt *stmt)
{
struct expr *key, *set, *setref;
+ struct set *existing_set;
+ struct table *table;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ ctx->cmd->handle.table.name,
+ ctx->cmd->handle.family);
+ if (table == NULL)
+ return table_not_found(ctx);
+
+ existing_set = set_cache_find(table, stmt->meter.name);
+ if (existing_set)
+ return cmd_error(ctx, &stmt->location,
+ "%s; meter '%s' overlaps an existing %s '%s' in family %s",
+ strerror(EEXIST),
+ stmt->meter.name,
+ set_is_map(existing_set->flags) ? "map" : "set",
+ existing_set->handle.set.name,
+ family2str(existing_set->handle.family));
expr_set_context(&ctx->ectx, NULL, 0);
if (expr_evaluate(ctx, &stmt->meter.key) < 0)
@@ -2277,7 +3315,9 @@ static int stmt_evaluate_meter(struct eval_ctx *ctx, struct stmt *stmt)
set->set_flags |= NFT_SET_TIMEOUT;
setref = implicit_set_declaration(ctx, stmt->meter.name,
- expr_get(key), set);
+ expr_get(key), NULL, set, 0);
+ if (!setref)
+ return -1;
setref->set->desc.size = stmt->meter.size;
stmt->meter.set = setref;
@@ -2293,29 +3333,56 @@ static int stmt_evaluate_meter(struct eval_ctx *ctx, struct stmt *stmt)
static int stmt_evaluate_meta(struct eval_ctx *ctx, struct stmt *stmt)
{
- return stmt_evaluate_arg(ctx, stmt,
- stmt->meta.tmpl->dtype,
- stmt->meta.tmpl->len,
- stmt->meta.tmpl->byteorder,
- &stmt->meta.expr);
+ int ret;
+
+ ctx->stmt_len = stmt->meta.tmpl->len;
+
+ ret = stmt_evaluate_arg(ctx, stmt,
+ stmt->meta.tmpl->dtype,
+ stmt->meta.tmpl->len,
+ stmt->meta.tmpl->byteorder,
+ &stmt->meta.expr);
+ if (ret < 0)
+ return ret;
+
+ if (stmt->meta.expr->etype == EXPR_RANGE)
+ return stmt_error_range(ctx, stmt, stmt->meta.expr);
+
+ return ret;
}
static int stmt_evaluate_ct(struct eval_ctx *ctx, struct stmt *stmt)
{
- return stmt_evaluate_arg(ctx, stmt,
- stmt->ct.tmpl->dtype,
- stmt->ct.tmpl->len,
- stmt->ct.tmpl->byteorder,
- &stmt->ct.expr);
+ int ret;
+
+ ctx->stmt_len = stmt->ct.tmpl->len;
+
+ ret = stmt_evaluate_arg(ctx, stmt,
+ stmt->ct.tmpl->dtype,
+ stmt->ct.tmpl->len,
+ stmt->ct.tmpl->byteorder,
+ &stmt->ct.expr);
+ if (ret < 0)
+ return -1;
+
+ if (stmt->ct.key == NFT_CT_SECMARK && expr_is_constant(stmt->ct.expr))
+ return stmt_error(ctx, stmt,
+ "ct secmark must not be set to constant value");
+
+ if (stmt->ct.expr->etype == EXPR_RANGE)
+ return stmt_error_range(ctx, stmt, stmt->ct.expr);
+
+ return 0;
}
static int reject_payload_gen_dependency_tcp(struct eval_ctx *ctx,
struct stmt *stmt,
struct expr **payload)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct proto_desc *desc;
- desc = ctx->pctx.protocol[PROTO_BASE_TRANSPORT_HDR].desc;
+ desc = pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc;
if (desc != NULL)
return 0;
*payload = payload_expr_alloc(&stmt->location, &proto_tcp,
@@ -2327,9 +3394,10 @@ static int reject_payload_gen_dependency_family(struct eval_ctx *ctx,
struct stmt *stmt,
struct expr **payload)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct proto_desc *base;
- base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ base = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
if (base != NULL)
return 0;
@@ -2388,7 +3456,7 @@ static int stmt_reject_gen_dependency(struct eval_ctx *ctx, struct stmt *stmt,
*/
list_add(&nstmt->list, &ctx->rule->stmts);
out:
- xfree(payload);
+ free(payload);
return ret;
}
@@ -2396,6 +3464,7 @@ static int stmt_evaluate_reject_inet_family(struct eval_ctx *ctx,
struct stmt *stmt,
const struct proto_desc *desc)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct proto_desc *base;
int protocol;
@@ -2405,23 +3474,26 @@ static int stmt_evaluate_reject_inet_family(struct eval_ctx *ctx,
case NFT_REJECT_ICMPX_UNREACH:
break;
case NFT_REJECT_ICMP_UNREACH:
- base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
+ base = pctx->protocol[PROTO_BASE_LL_HDR].desc;
protocol = proto_find_num(base, desc);
switch (protocol) {
case NFPROTO_IPV4:
+ case __constant_htons(ETH_P_IP):
if (stmt->reject.family == NFPROTO_IPV4)
break;
return stmt_binary_error(ctx, stmt->reject.expr,
- &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR],
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
"conflicting protocols specified: ip vs ip6");
case NFPROTO_IPV6:
+ case __constant_htons(ETH_P_IPV6):
if (stmt->reject.family == NFPROTO_IPV6)
break;
return stmt_binary_error(ctx, stmt->reject.expr,
- &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR],
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
"conflicting protocols specified: ip vs ip6");
default:
- BUG("unsupported family");
+ return stmt_error(ctx, stmt,
+ "cannot infer ICMP reject variant to use: explicit value required.\n");
}
break;
}
@@ -2432,9 +3504,10 @@ static int stmt_evaluate_reject_inet_family(struct eval_ctx *ctx,
static int stmt_evaluate_reject_inet(struct eval_ctx *ctx, struct stmt *stmt,
struct expr *expr)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct proto_desc *desc;
- desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ desc = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
if (desc != NULL &&
stmt_evaluate_reject_inet_family(ctx, stmt, desc) < 0)
return -1;
@@ -2449,13 +3522,14 @@ static int stmt_evaluate_reject_bridge_family(struct eval_ctx *ctx,
struct stmt *stmt,
const struct proto_desc *desc)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct proto_desc *base;
int protocol;
switch (stmt->reject.type) {
case NFT_REJECT_ICMPX_UNREACH:
case NFT_REJECT_TCP_RST:
- base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
+ base = pctx->protocol[PROTO_BASE_LL_HDR].desc;
protocol = proto_find_num(base, desc);
switch (protocol) {
case __constant_htons(ETH_P_IP):
@@ -2463,29 +3537,29 @@ static int stmt_evaluate_reject_bridge_family(struct eval_ctx *ctx,
break;
default:
return stmt_binary_error(ctx, stmt,
- &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR],
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
"cannot reject this network family");
}
break;
case NFT_REJECT_ICMP_UNREACH:
- base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
+ base = pctx->protocol[PROTO_BASE_LL_HDR].desc;
protocol = proto_find_num(base, desc);
switch (protocol) {
case __constant_htons(ETH_P_IP):
if (NFPROTO_IPV4 == stmt->reject.family)
break;
return stmt_binary_error(ctx, stmt->reject.expr,
- &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR],
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
"conflicting protocols specified: ip vs ip6");
case __constant_htons(ETH_P_IPV6):
if (NFPROTO_IPV6 == stmt->reject.family)
break;
return stmt_binary_error(ctx, stmt->reject.expr,
- &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR],
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
"conflicting protocols specified: ip vs ip6");
default:
return stmt_binary_error(ctx, stmt,
- &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR],
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
"cannot reject this network family");
}
break;
@@ -2497,15 +3571,15 @@ static int stmt_evaluate_reject_bridge_family(struct eval_ctx *ctx,
static int stmt_evaluate_reject_bridge(struct eval_ctx *ctx, struct stmt *stmt,
struct expr *expr)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct proto_desc *desc;
- desc = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
- if (desc != &proto_eth)
- return stmt_binary_error(ctx,
- &ctx->pctx.protocol[PROTO_BASE_LL_HDR],
- stmt, "unsupported link layer protocol");
+ desc = pctx->protocol[PROTO_BASE_LL_HDR].desc;
+ if (desc != &proto_eth && desc != &proto_vlan && desc != &proto_netdev)
+ return __stmt_binary_error(ctx, &stmt->location, NULL,
+ "cannot reject from this link layer protocol");
- desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ desc = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
if (desc != NULL &&
stmt_evaluate_reject_bridge_family(ctx, stmt, desc) < 0)
return -1;
@@ -2519,7 +3593,9 @@ static int stmt_evaluate_reject_bridge(struct eval_ctx *ctx, struct stmt *stmt,
static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt,
struct expr *expr)
{
- switch (ctx->pctx.family) {
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+
+ switch (pctx->family) {
case NFPROTO_ARP:
return stmt_error(ctx, stmt, "cannot use reject with arp");
case NFPROTO_IPV4:
@@ -2533,13 +3609,14 @@ static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt,
return stmt_binary_error(ctx, stmt->reject.expr, stmt,
"abstracted ICMP unreachable not supported");
case NFT_REJECT_ICMP_UNREACH:
- if (stmt->reject.family == ctx->pctx.family)
+ if (stmt->reject.family == pctx->family)
break;
return stmt_binary_error(ctx, stmt->reject.expr, stmt,
"conflicting protocols specified: ip vs ip6");
}
break;
case NFPROTO_BRIDGE:
+ case NFPROTO_NETDEV:
if (stmt_evaluate_reject_bridge(ctx, stmt, expr) < 0)
return -1;
break;
@@ -2556,49 +3633,53 @@ static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt,
static int stmt_evaluate_reject_default(struct eval_ctx *ctx,
struct stmt *stmt)
{
- int protocol;
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct proto_desc *desc, *base;
+ int protocol;
- switch (ctx->pctx.family) {
+ switch (pctx->family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6:
stmt->reject.type = NFT_REJECT_ICMP_UNREACH;
- stmt->reject.family = ctx->pctx.family;
- if (ctx->pctx.family == NFPROTO_IPV4)
+ stmt->reject.family = pctx->family;
+ if (pctx->family == NFPROTO_IPV4)
stmt->reject.icmp_code = ICMP_PORT_UNREACH;
else
stmt->reject.icmp_code = ICMP6_DST_UNREACH_NOPORT;
break;
case NFPROTO_INET:
- desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ desc = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
if (desc == NULL) {
stmt->reject.type = NFT_REJECT_ICMPX_UNREACH;
stmt->reject.icmp_code = NFT_REJECT_ICMPX_PORT_UNREACH;
break;
}
stmt->reject.type = NFT_REJECT_ICMP_UNREACH;
- base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
+ base = pctx->protocol[PROTO_BASE_LL_HDR].desc;
protocol = proto_find_num(base, desc);
switch (protocol) {
case NFPROTO_IPV4:
+ case __constant_htons(ETH_P_IP):
stmt->reject.family = NFPROTO_IPV4;
stmt->reject.icmp_code = ICMP_PORT_UNREACH;
break;
case NFPROTO_IPV6:
+ case __constant_htons(ETH_P_IPV6):
stmt->reject.family = NFPROTO_IPV6;
stmt->reject.icmp_code = ICMP6_DST_UNREACH_NOPORT;
break;
}
break;
case NFPROTO_BRIDGE:
- desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ case NFPROTO_NETDEV:
+ desc = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
if (desc == NULL) {
stmt->reject.type = NFT_REJECT_ICMPX_UNREACH;
stmt->reject.icmp_code = NFT_REJECT_ICMPX_PORT_UNREACH;
break;
}
stmt->reject.type = NFT_REJECT_ICMP_UNREACH;
- base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
+ base = pctx->protocol[PROTO_BASE_LL_HDR].desc;
protocol = proto_find_num(base, desc);
switch (protocol) {
case __constant_htons(ETH_P_IP):
@@ -2617,7 +3698,10 @@ static int stmt_evaluate_reject_default(struct eval_ctx *ctx,
static int stmt_evaluate_reject_icmp(struct eval_ctx *ctx, struct stmt *stmt)
{
- struct parse_ctx parse_ctx = { .tbl = &ctx->nft->output.tbl, };
+ struct parse_ctx parse_ctx = {
+ .tbl = &ctx->nft->output.tbl,
+ .input = &ctx->nft->input,
+ };
struct error_record *erec;
struct expr *code;
@@ -2626,15 +3710,24 @@ static int stmt_evaluate_reject_icmp(struct eval_ctx *ctx, struct stmt *stmt)
erec_queue(erec, ctx->msgs);
return -1;
}
+
+ if (mpz_cmp_ui(code->value, UINT8_MAX) > 0) {
+ expr_free(code);
+ return expr_error(ctx->msgs, stmt->reject.expr,
+ "reject code must be integer in range 0-255");
+ }
+
stmt->reject.icmp_code = mpz_get_uint8(code->value);
+ expr_free(code);
+
return 0;
}
static int stmt_evaluate_reset(struct eval_ctx *ctx, struct stmt *stmt)
{
- int protonum;
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct proto_desc *desc, *base;
- struct proto_ctx *pctx = &ctx->pctx;
+ int protonum;
desc = pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc;
if (desc == NULL)
@@ -2651,7 +3744,7 @@ static int stmt_evaluate_reset(struct eval_ctx *ctx, struct stmt *stmt)
default:
if (stmt->reject.type == NFT_REJECT_TCP_RST) {
return stmt_binary_error(ctx, stmt,
- &ctx->pctx.protocol[PROTO_BASE_TRANSPORT_HDR],
+ &pctx->protocol[PROTO_BASE_TRANSPORT_HDR],
"you cannot use tcp reset with this protocol");
}
break;
@@ -2679,22 +3772,24 @@ static int stmt_evaluate_reject(struct eval_ctx *ctx, struct stmt *stmt)
static int nat_evaluate_family(struct eval_ctx *ctx, struct stmt *stmt)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct proto_desc *nproto;
- switch (ctx->pctx.family) {
+ switch (pctx->family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6:
if (stmt->nat.family == NFPROTO_UNSPEC)
- stmt->nat.family = ctx->pctx.family;
+ stmt->nat.family = pctx->family;
return 0;
case NFPROTO_INET:
- if (!stmt->nat.addr)
+ if (!stmt->nat.addr) {
+ stmt->nat.family = NFPROTO_INET;
return 0;
-
+ }
if (stmt->nat.family != NFPROTO_UNSPEC)
return 0;
- nproto = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ nproto = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
if (nproto == &proto_ip)
stmt->nat.family = NFPROTO_IPV4;
@@ -2708,81 +3803,160 @@ static int nat_evaluate_family(struct eval_ctx *ctx, struct stmt *stmt)
}
}
+static const struct datatype *get_addr_dtype(uint8_t family)
+{
+ switch (family) {
+ case NFPROTO_IPV4:
+ return &ipaddr_type;
+ case NFPROTO_IPV6:
+ return &ip6addr_type;
+ }
+
+ return &invalid_type;
+}
+
static int evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
struct expr **expr)
{
- struct proto_ctx *pctx = &ctx->pctx;
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct datatype *dtype;
- unsigned int len;
- if (pctx->family == NFPROTO_IPV4) {
- dtype = &ipaddr_type;
- len = 4 * BITS_PER_BYTE;
- } else {
- dtype = &ip6addr_type;
- len = 16 * BITS_PER_BYTE;
- }
+ dtype = get_addr_dtype(pctx->family);
- return stmt_evaluate_arg(ctx, stmt, dtype, len, BYTEORDER_BIG_ENDIAN,
+ return stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ BYTEORDER_BIG_ENDIAN,
expr);
}
+static bool nat_evaluate_addr_has_th_expr(const struct expr *map)
+{
+ const struct expr *i, *concat;
+
+ if (!map || map->etype != EXPR_MAP)
+ return false;
+
+ concat = map->map;
+ if (concat ->etype != EXPR_CONCAT)
+ return false;
+
+ list_for_each_entry(i, &concat->expressions, list) {
+ enum proto_bases base;
+
+ if (i->etype == EXPR_PAYLOAD &&
+ i->payload.base == PROTO_BASE_TRANSPORT_HDR &&
+ i->payload.desc != &proto_th)
+ return true;
+
+ if ((i->flags & EXPR_F_PROTOCOL) == 0)
+ continue;
+
+ switch (i->etype) {
+ case EXPR_META:
+ base = i->meta.base;
+ break;
+ case EXPR_PAYLOAD:
+ base = i->payload.base;
+ break;
+ default:
+ return false;
+ }
+
+ if (base == PROTO_BASE_NETWORK_HDR)
+ return true;
+ }
+
+ return false;
+}
+
static int nat_evaluate_transport(struct eval_ctx *ctx, struct stmt *stmt,
struct expr **expr)
{
- struct proto_ctx *pctx = &ctx->pctx;
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ int err;
- if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL)
+ err = stmt_evaluate_arg(ctx, stmt,
+ &inet_service_type, 2 * BITS_PER_BYTE,
+ BYTEORDER_BIG_ENDIAN, expr);
+ if (err < 0)
+ return err;
+
+ if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL &&
+ !nat_evaluate_addr_has_th_expr(stmt->nat.addr))
return stmt_binary_error(ctx, *expr, stmt,
"transport protocol mapping is only "
"valid after transport protocol match");
- return stmt_evaluate_arg(ctx, stmt,
- &inet_service_type, 2 * BITS_PER_BYTE,
- BYTEORDER_BIG_ENDIAN, expr);
+ return 0;
}
static int stmt_evaluate_l3proto(struct eval_ctx *ctx,
struct stmt *stmt, uint8_t family)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct proto_desc *nproto;
- nproto = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ nproto = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
if ((nproto == &proto_ip && family != NFPROTO_IPV4) ||
(nproto == &proto_ip6 && family != NFPROTO_IPV6))
return stmt_binary_error(ctx, stmt,
- &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR],
- "conflicting protocols specified: %s vs. %s. You must specify ip or ip6 family in tproxy statement",
- ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc->name,
- family2str(stmt->tproxy.family));
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
+ "conflicting protocols specified: %s vs. %s. You must specify ip or ip6 family in %s statement",
+ pctx->protocol[PROTO_BASE_NETWORK_HDR].desc->name,
+ family2str(family),
+ stmt->ops->name);
return 0;
}
-static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
- uint8_t family,
- struct expr **addr)
+static void expr_family_infer(struct proto_ctx *pctx, const struct expr *expr,
+ uint8_t *family)
{
- const struct datatype *dtype;
- unsigned int len;
- int err;
+ struct expr *i;
- if (ctx->pctx.family == NFPROTO_INET) {
- switch (family) {
- case NFPROTO_IPV4:
- dtype = &ipaddr_type;
- len = 4 * BITS_PER_BYTE;
+ if (expr->etype == EXPR_MAP) {
+ switch (expr->map->etype) {
+ case EXPR_CONCAT:
+ list_for_each_entry(i, &expr->map->expressions, list) {
+ if (i->etype == EXPR_PAYLOAD) {
+ if (i->payload.desc == &proto_ip)
+ *family = NFPROTO_IPV4;
+ else if (i->payload.desc == &proto_ip6)
+ *family = NFPROTO_IPV6;
+ }
+ }
break;
- case NFPROTO_IPV6:
- dtype = &ip6addr_type;
- len = 16 * BITS_PER_BYTE;
+ case EXPR_PAYLOAD:
+ if (expr->map->payload.desc == &proto_ip)
+ *family = NFPROTO_IPV4;
+ else if (expr->map->payload.desc == &proto_ip6)
+ *family = NFPROTO_IPV6;
break;
default:
+ break;
+ }
+ }
+}
+
+static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
+ uint8_t *family, struct expr **addr)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ const struct datatype *dtype;
+ int err;
+
+ if (pctx->family == NFPROTO_INET) {
+ if (*family == NFPROTO_INET ||
+ *family == NFPROTO_UNSPEC)
+ expr_family_infer(pctx, *addr, family);
+
+ dtype = get_addr_dtype(*family);
+ if (dtype->size == 0) {
return stmt_error(ctx, stmt,
- "ip or ip6 must be specified with address for inet tables.");
+ "specify `%s ip' or '%s ip6' in %s table to disambiguate",
+ stmt_name(stmt), stmt_name(stmt), family2str(pctx->family));
}
- err = stmt_evaluate_arg(ctx, stmt, dtype, len,
+ err = stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
BYTEORDER_BIG_ENDIAN, addr);
} else {
err = evaluate_addr(ctx, stmt, addr);
@@ -2791,6 +3965,137 @@ static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
return err;
}
+static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ struct expr *one, *two, *data, *tmp;
+ const struct datatype *dtype = NULL;
+ const struct datatype *dtype2;
+ int addr_type;
+ int err;
+
+ if (stmt->nat.family == NFPROTO_INET)
+ expr_family_infer(pctx, stmt->nat.addr, &stmt->nat.family);
+
+ switch (stmt->nat.family) {
+ case NFPROTO_IPV4:
+ addr_type = TYPE_IPADDR;
+ break;
+ case NFPROTO_IPV6:
+ addr_type = TYPE_IP6ADDR;
+ break;
+ default:
+ return stmt_error(ctx, stmt,
+ "specify `%s ip' or '%s ip6' in %s table to disambiguate",
+ stmt_name(stmt), stmt_name(stmt), family2str(pctx->family));
+ }
+ dtype = concat_type_alloc((addr_type << TYPE_BITS) | TYPE_INET_SERVICE);
+
+ expr_set_context(&ctx->ectx, dtype, dtype->size);
+ if (expr_evaluate(ctx, &stmt->nat.addr)) {
+ err = -1;
+ goto out;
+ }
+
+ if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL &&
+ !nat_evaluate_addr_has_th_expr(stmt->nat.addr)) {
+ err = stmt_binary_error(ctx, stmt->nat.addr, stmt,
+ "transport protocol mapping is only "
+ "valid after transport protocol match");
+ goto out;
+ }
+
+ if (stmt->nat.addr->etype != EXPR_MAP) {
+ err = 0;
+ goto out;
+ }
+
+ data = stmt->nat.addr->mappings->set->data;
+ if (data->flags & EXPR_F_INTERVAL)
+ stmt->nat.type_flags |= STMT_NAT_F_INTERVAL;
+
+ datatype_set(data, dtype);
+
+ if (expr_ops(data)->type != EXPR_CONCAT) {
+ err = __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ BYTEORDER_BIG_ENDIAN,
+ &stmt->nat.addr);
+ goto out;
+ }
+
+ one = list_first_entry(&data->expressions, struct expr, list);
+ two = list_entry(one->list.next, struct expr, list);
+
+ if (one == two || !list_is_last(&two->list, &data->expressions)) {
+ err = __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ BYTEORDER_BIG_ENDIAN,
+ &stmt->nat.addr);
+ goto out;
+ }
+
+ dtype2 = get_addr_dtype(stmt->nat.family);
+ tmp = one;
+ err = __stmt_evaluate_arg(ctx, stmt, dtype2, dtype2->size,
+ BYTEORDER_BIG_ENDIAN,
+ &tmp);
+ if (err < 0)
+ goto out;
+ if (tmp != one)
+ BUG("Internal error: Unexpected alteration of l3 expression");
+
+ tmp = two;
+ err = nat_evaluate_transport(ctx, stmt, &tmp);
+ if (err < 0)
+ goto out;
+ if (tmp != two)
+ BUG("Internal error: Unexpected alteration of l4 expression");
+
+out:
+ datatype_free(dtype);
+ return err;
+}
+
+static bool nat_concat_map(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct expr *i;
+
+ if (stmt->nat.addr->etype != EXPR_MAP)
+ return false;
+
+ switch (stmt->nat.addr->mappings->etype) {
+ case EXPR_SET:
+ list_for_each_entry(i, &stmt->nat.addr->mappings->expressions, list) {
+ if (i->etype == EXPR_MAPPING &&
+ i->right->etype == EXPR_CONCAT) {
+ stmt->nat.type_flags |= STMT_NAT_F_CONCAT;
+ return true;
+ }
+ }
+ break;
+ case EXPR_SYMBOL:
+ /* expr_evaluate_map() see EXPR_SET_REF after this evaluation. */
+ if (expr_evaluate(ctx, &stmt->nat.addr->mappings))
+ return false;
+
+ if (!set_is_datamap(stmt->nat.addr->mappings->set->flags)) {
+ expr_error(ctx->msgs, stmt->nat.addr->mappings,
+ "Expression is not a map");
+ return false;
+ }
+
+ if (stmt->nat.addr->mappings->set->data->etype == EXPR_CONCAT ||
+ stmt->nat.addr->mappings->set->data->dtype->subtypes) {
+ stmt->nat.type_flags |= STMT_NAT_F_CONCAT;
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt)
{
int err;
@@ -2804,15 +4109,29 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt)
if (err < 0)
return err;
- err = stmt_evaluate_addr(ctx, stmt, stmt->nat.family,
+ if (nat_concat_map(ctx, stmt) ||
+ stmt->nat.type_flags & STMT_NAT_F_CONCAT) {
+
+ err = stmt_evaluate_nat_map(ctx, stmt);
+ if (err < 0)
+ return err;
+
+ stmt->flags |= STMT_F_TERMINAL;
+ return 0;
+ }
+
+ err = stmt_evaluate_addr(ctx, stmt, &stmt->nat.family,
&stmt->nat.addr);
if (err < 0)
return err;
}
+
if (stmt->nat.proto != NULL) {
err = nat_evaluate_transport(ctx, stmt, &stmt->nat.proto);
if (err < 0)
return err;
+
+ stmt->nat.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
}
stmt->flags |= STMT_F_TERMINAL;
@@ -2821,13 +4140,14 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt)
static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
int err;
- switch (ctx->pctx.family) {
+ switch (pctx->family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6: /* fallthrough */
if (stmt->tproxy.family == NFPROTO_UNSPEC)
- stmt->tproxy.family = ctx->pctx.family;
+ stmt->tproxy.family = pctx->family;
break;
case NFPROTO_INET:
break;
@@ -2836,7 +4156,7 @@ static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt)
"tproxy is only supported for IPv4/IPv6/INET");
}
- if (ctx->pctx.protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL)
+ if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL)
return stmt_error(ctx, stmt, "Transparent proxy support requires"
" transport protocol match");
@@ -2848,22 +4168,22 @@ static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt)
return err;
if (stmt->tproxy.addr != NULL) {
- if (stmt->tproxy.addr->etype == EXPR_RANGE)
- return stmt_error(ctx, stmt, "Address ranges are not supported for tproxy.");
-
- err = stmt_evaluate_addr(ctx, stmt, stmt->tproxy.family,
+ err = stmt_evaluate_addr(ctx, stmt, &stmt->tproxy.family,
&stmt->tproxy.addr);
-
if (err < 0)
return err;
+
+ if (stmt->tproxy.addr->etype == EXPR_RANGE)
+ return stmt_error(ctx, stmt, "Address ranges are not supported for tproxy.");
}
if (stmt->tproxy.port != NULL) {
- if (stmt->tproxy.port->etype == EXPR_RANGE)
- return stmt_error(ctx, stmt, "Port ranges are not supported for tproxy.");
err = nat_evaluate_transport(ctx, stmt, &stmt->tproxy.port);
if (err < 0)
return err;
+
+ if (stmt->tproxy.port->etype == EXPR_RANGE)
+ return stmt_error(ctx, stmt, "Port ranges are not supported for tproxy.");
}
return 0;
@@ -2881,11 +4201,75 @@ static int stmt_evaluate_synproxy(struct eval_ctx *ctx, struct stmt *stmt)
return 0;
}
+static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule,
+ enum cmd_ops op);
+
+static int stmt_evaluate_chain(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct chain *chain = stmt->chain.chain;
+ struct cmd *cmd;
+
+ chain->flags |= CHAIN_F_BINDING;
+
+ if (ctx->table != NULL) {
+ list_add_tail(&chain->list, &ctx->table->chains);
+ } else {
+ struct rule *rule, *next;
+ struct handle h;
+
+ memset(&h, 0, sizeof(h));
+ handle_merge(&h, &chain->handle);
+ h.family = ctx->rule->handle.family;
+ free_const(h.table.name);
+ h.table.name = xstrdup(ctx->rule->handle.table.name);
+ h.chain.location = stmt->location;
+ h.chain_id = chain->handle.chain_id;
+
+ cmd = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &h, &stmt->location,
+ chain);
+ cmd->location = stmt->location;
+ list_add_tail(&cmd->list, &ctx->cmd->list);
+ h.chain_id = chain->handle.chain_id;
+
+ list_for_each_entry_safe(rule, next, &chain->rules, list) {
+ struct eval_ctx rule_ctx = {
+ .nft = ctx->nft,
+ .msgs = ctx->msgs,
+ .cmd = ctx->cmd,
+ };
+ struct handle h2 = {};
+
+ handle_merge(&rule->handle, &ctx->rule->handle);
+ free_const(rule->handle.table.name);
+ rule->handle.table.name = xstrdup(ctx->rule->handle.table.name);
+ free_const(rule->handle.chain.name);
+ rule->handle.chain.name = NULL;
+ rule->handle.chain_id = chain->handle.chain_id;
+ if (rule_evaluate(&rule_ctx, rule, CMD_INVALID) < 0)
+ return -1;
+
+ handle_merge(&h2, &rule->handle);
+ cmd = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &h2,
+ &rule->location, rule);
+ list_add_tail(&cmd->list, &ctx->cmd->list);
+ list_del(&rule->list);
+ }
+ }
+
+ return 0;
+}
+
+static int stmt_evaluate_optstrip(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ return expr_evaluate(ctx, &stmt->optstrip.expr);
+}
+
static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
int err;
- switch (ctx->pctx.family) {
+ switch (pctx->family) {
case NFPROTO_IPV4:
case NFPROTO_IPV6:
if (stmt->dup.to == NULL)
@@ -2902,6 +4286,9 @@ static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt)
&stmt->dup.dev);
if (err < 0)
return err;
+
+ if (stmt->dup.dev->etype == EXPR_RANGE)
+ return stmt_error_range(ctx, stmt, stmt->dup.dev);
}
break;
case NFPROTO_NETDEV:
@@ -2920,15 +4307,20 @@ static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt)
default:
return stmt_error(ctx, stmt, "unsupported family");
}
+
+ if (stmt->dup.to->etype == EXPR_RANGE)
+ return stmt_error_range(ctx, stmt, stmt->dup.to);
+
return 0;
}
static int stmt_evaluate_fwd(struct eval_ctx *ctx, struct stmt *stmt)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct datatype *dtype;
int err, len;
- switch (ctx->pctx.family) {
+ switch (pctx->family) {
case NFPROTO_NETDEV:
if (stmt->fwd.dev == NULL)
return stmt_error(ctx, stmt,
@@ -2940,6 +4332,9 @@ static int stmt_evaluate_fwd(struct eval_ctx *ctx, struct stmt *stmt)
if (err < 0)
return err;
+ if (stmt->fwd.dev->etype == EXPR_RANGE)
+ return stmt_error_range(ctx, stmt, stmt->fwd.dev);
+
if (stmt->fwd.addr != NULL) {
switch (stmt->fwd.family) {
case NFPROTO_IPV4:
@@ -2958,6 +4353,9 @@ static int stmt_evaluate_fwd(struct eval_ctx *ctx, struct stmt *stmt)
&stmt->fwd.addr);
if (err < 0)
return err;
+
+ if (stmt->fwd.addr->etype == EXPR_RANGE)
+ return stmt_error_range(ctx, stmt, stmt->fwd.addr);
}
break;
default:
@@ -2974,21 +4372,74 @@ static int stmt_evaluate_queue(struct eval_ctx *ctx, struct stmt *stmt)
BYTEORDER_HOST_ENDIAN,
&stmt->queue.queue) < 0)
return -1;
- if (!expr_is_constant(stmt->queue.queue))
- return expr_error(ctx->msgs, stmt->queue.queue,
- "queue number is not constant");
- if (stmt->queue.queue->etype != EXPR_RANGE &&
- (stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT))
+
+ if ((stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT) &&
+ stmt->queue.queue->etype != EXPR_RANGE)
return expr_error(ctx->msgs, stmt->queue.queue,
"fanout requires a range to be "
"specified");
+
+ if (ctx->ectx.maxval > USHRT_MAX)
+ return expr_error(ctx->msgs, stmt->queue.queue,
+ "queue expression max value exceeds %u", USHRT_MAX);
}
stmt->flags |= STMT_F_TERMINAL;
return 0;
}
+static int stmt_evaluate_log_prefix(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ char tmp[NF_LOG_PREFIXLEN] = {};
+ char prefix[NF_LOG_PREFIXLEN];
+ size_t len = sizeof(prefix);
+ size_t offset = 0;
+ struct expr *expr;
+
+ if (stmt->log.prefix->etype != EXPR_LIST) {
+ if (stmt->log.prefix &&
+ div_round_up(stmt->log.prefix->len, BITS_PER_BYTE) >= NF_LOG_PREFIXLEN)
+ return expr_error(ctx->msgs, stmt->log.prefix, "log prefix is too long");
+
+ return 0;
+ }
+
+ prefix[0] = '\0';
+
+ list_for_each_entry(expr, &stmt->log.prefix->expressions, list) {
+ int ret;
+
+ switch (expr->etype) {
+ case EXPR_VALUE:
+ expr_to_string(expr, tmp);
+ ret = snprintf(prefix + offset, len, "%s", tmp);
+ break;
+ case EXPR_VARIABLE:
+ ret = snprintf(prefix + offset, len, "%s",
+ expr->sym->expr->identifier);
+ break;
+ default:
+ BUG("unknown expression type %s\n", expr_name(expr));
+ break;
+ }
+ SNPRINTF_BUFFER_SIZE(ret, &len, &offset);
+ }
+
+ if (len == 0)
+ return stmt_error(ctx, stmt, "log prefix is too long");
+
+ expr = constant_expr_alloc(&stmt->log.prefix->location, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen(prefix) * BITS_PER_BYTE, prefix);
+ expr_free(stmt->log.prefix);
+ stmt->log.prefix = expr;
+
+ return 0;
+}
+
static int stmt_evaluate_log(struct eval_ctx *ctx, struct stmt *stmt)
{
+ int ret = 0;
+
if (stmt->log.flags & (STMT_LOG_GROUP | STMT_LOG_SNAPLEN |
STMT_LOG_QTHRESHOLD)) {
if (stmt->log.flags & STMT_LOG_LEVEL)
@@ -3002,11 +4453,18 @@ static int stmt_evaluate_log(struct eval_ctx *ctx, struct stmt *stmt)
(stmt->log.flags & ~STMT_LOG_LEVEL || stmt->log.logflags))
return stmt_error(ctx, stmt,
"log level audit doesn't support any further options");
- return 0;
+
+ if (stmt->log.prefix)
+ ret = stmt_evaluate_log_prefix(ctx, stmt);
+
+ return ret;
}
static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
{
+ struct set *this_set;
+ struct stmt *this;
+
expr_set_context(&ctx->ectx, NULL, 0);
if (expr_evaluate(ctx, &stmt->set.set) < 0)
return -1;
@@ -3014,7 +4472,7 @@ static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
return expr_error(ctx->msgs, stmt->set.set,
"Expression does not refer to a set");
- if (stmt_evaluate_arg(ctx, stmt,
+ if (stmt_evaluate_key(ctx, stmt,
stmt->set.set->set->key->dtype,
stmt->set.set->set->key->len,
stmt->set.set->set->key->byteorder,
@@ -3026,19 +4484,30 @@ static int stmt_evaluate_set(struct eval_ctx *ctx, struct stmt *stmt)
if (stmt->set.key->comment != NULL)
return expr_error(ctx->msgs, stmt->set.key,
"Key expression comments are not supported");
- if (stmt->set.stmt) {
- if (stmt_evaluate(ctx, stmt->set.stmt) < 0)
+ list_for_each_entry(this, &stmt->set.stmt_list, list) {
+ if (stmt_evaluate(ctx, this) < 0)
return -1;
- if (!(stmt->set.stmt->flags & STMT_F_STATEFUL))
- return stmt_binary_error(ctx, stmt->set.stmt, stmt,
- "meter statement must be stateful");
+ if (!(this->flags & STMT_F_STATEFUL))
+ return stmt_error(ctx, this,
+ "statement must be stateful");
}
+ this_set = stmt->set.set->set;
+
+ /* Make sure EVAL flag is set on set definition so that kernel
+ * picks a set that allows updates from the packet path.
+ *
+ * Alternatively we could error out in case 'flags dynamic' was
+ * not given, but we can repair this here.
+ */
+ this_set->flags |= NFT_SET_EVAL;
return 0;
}
static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
{
+ struct stmt *this;
+
expr_set_context(&ctx->ectx, NULL, 0);
if (expr_evaluate(ctx, &stmt->map.set) < 0)
return -1;
@@ -3046,7 +4515,11 @@ static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
return expr_error(ctx->msgs, stmt->map.set,
"Expression does not refer to a set");
- if (stmt_evaluate_arg(ctx, stmt,
+ if (!set_is_map(stmt->map.set->set->flags))
+ return expr_error(ctx->msgs, stmt->map.set,
+ "%s is not a map", stmt->map.set->set->handle.set.name);
+
+ if (stmt_evaluate_key(ctx, stmt,
stmt->map.set->set->key->dtype,
stmt->map.set->set->key->len,
stmt->map.set->set->key->byteorder,
@@ -3060,9 +4533,9 @@ static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
"Key expression comments are not supported");
if (stmt_evaluate_arg(ctx, stmt,
- stmt->map.set->set->datatype,
- stmt->map.set->set->datalen,
- stmt->map.set->set->datatype->byteorder,
+ stmt->map.set->set->data->dtype,
+ stmt->map.set->set->data->len,
+ stmt->map.set->set->data->byteorder,
&stmt->map.data->key) < 0)
return -1;
if (expr_is_constant(stmt->map.data))
@@ -3071,13 +4544,16 @@ static int stmt_evaluate_map(struct eval_ctx *ctx, struct stmt *stmt)
if (stmt->map.data->comment != NULL)
return expr_error(ctx->msgs, stmt->map.data,
"Data expression comments are not supported");
+ if (stmt->map.data->timeout > 0)
+ return expr_error(ctx->msgs, stmt->map.data,
+ "Data expression timeouts are not supported");
- if (stmt->map.stmt) {
- if (stmt_evaluate(ctx, stmt->map.stmt) < 0)
+ list_for_each_entry(this, &stmt->map.stmt_list, list) {
+ if (stmt_evaluate(ctx, this) < 0)
return -1;
- if (!(stmt->map.stmt->flags & STMT_F_STATEFUL))
- return stmt_binary_error(ctx, stmt->map.stmt, stmt,
- "meter statement must be stateful");
+ if (!(this->flags & STMT_F_STATEFUL))
+ return stmt_error(ctx, this,
+ "statement must be stateful");
}
return 0;
@@ -3107,9 +4583,10 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
ctx->ectx.len, NULL);
mappings = implicit_set_declaration(ctx, "__objmap%d",
- key, mappings);
- mappings->set->datatype = &string_type;
- mappings->set->datalen = NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE;
+ key, NULL, mappings,
+ NFT_SET_ANONYMOUS);
+ if (!mappings)
+ return -1;
mappings->set->objtype = stmt->objref.type;
map->mappings = mappings;
@@ -3117,10 +4594,15 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
ctx->set = mappings->set;
if (expr_evaluate(ctx, &map->mappings->set->init) < 0)
return -1;
+
+ if (set_is_interval(map->mappings->set->init->set_flags) &&
+ !(map->mappings->set->init->set_flags & NFT_SET_CONCAT) &&
+ interval_set_eval(ctx, ctx->set, map->mappings->set->init) < 0)
+ return -1;
+
ctx->set = NULL;
- map->mappings->set->flags |=
- map->mappings->set->init->set_flags;
+ map_set_concat_info(map);
/* fall through */
case EXPR_SYMBOL:
if (expr_evaluate(ctx, &map->mappings) < 0)
@@ -3137,14 +4619,14 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
expr_name(map->mappings));
}
- if (!datatype_equal(map->map->dtype, map->mappings->set->key->dtype))
+ if (!datatype_compatible(map->mappings->set->key->dtype, map->map->dtype))
return expr_binary_error(ctx->msgs, map->mappings, map->map,
"datatype mismatch, map expects %s, "
"mapping expression has type %s",
map->mappings->set->key->dtype->desc,
map->map->dtype->desc);
- datatype_set(map, map->mappings->set->datatype);
+ datatype_set(map, map->mappings->set->data->dtype);
map->flags |= EXPR_F_CONSTANT;
/* Data for range lookups needs to be in big endian order */
@@ -3185,9 +4667,12 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
erec_destroy(erec);
}
+ ctx->stmt_len = 0;
+
switch (stmt->ops->type) {
case STMT_CONNLIMIT:
case STMT_COUNTER:
+ case STMT_LAST:
case STMT_LIMIT:
case STMT_QUOTA:
case STMT_NOTRACK:
@@ -3229,94 +4714,274 @@ int stmt_evaluate(struct eval_ctx *ctx, struct stmt *stmt)
return stmt_evaluate_map(ctx, stmt);
case STMT_SYNPROXY:
return stmt_evaluate_synproxy(ctx, stmt);
+ case STMT_CHAIN:
+ return stmt_evaluate_chain(ctx, stmt);
+ case STMT_OPTSTRIP:
+ return stmt_evaluate_optstrip(ctx, stmt);
default:
BUG("unknown statement type %s\n", stmt->ops->name);
}
}
-static int setelem_evaluate(struct eval_ctx *ctx, struct expr **expr)
+static int setelem_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
{
struct table *table;
struct set *set;
- table = table_lookup_global(ctx);
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ ctx->cmd->handle.table.name,
+ ctx->cmd->handle.family);
if (table == NULL)
return table_not_found(ctx);
- set = set_lookup(table, ctx->cmd->handle.set.name);
+ set = set_cache_find(table, ctx->cmd->handle.set.name);
if (set == NULL)
return set_not_found(ctx, &ctx->cmd->handle.set.location,
ctx->cmd->handle.set.name);
+ if (set->key == NULL)
+ return -1;
+
+ set->existing_set = set;
ctx->set = set;
expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
- if (expr_evaluate(ctx, expr) < 0)
+ if (expr_evaluate(ctx, &cmd->expr) < 0)
+ return -1;
+
+ cmd->elem.set = set_get(set);
+ if (set_is_interval(ctx->set->flags)) {
+ if (!(set->flags & NFT_SET_CONCAT) &&
+ interval_set_eval(ctx, ctx->set, cmd->expr) < 0)
+ return -1;
+
+ assert(cmd->expr->etype == EXPR_SET);
+ cmd->expr->set_flags |= NFT_SET_INTERVAL;
+ }
+
+ ctx->set = NULL;
+
+ return 0;
+}
+
+static int set_key_data_error(struct eval_ctx *ctx, const struct set *set,
+ const struct datatype *dtype,
+ const char *name)
+{
+ const char *hint = "";
+
+ if (dtype->size == 0)
+ hint = ". Try \"typeof expression\" instead of \"type datatype\".";
+
+ return set_error(ctx, set, "unqualified type %s "
+ "specified in %s definition%s",
+ dtype->name, name, hint);
+}
+
+static int set_expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
+{
+ unsigned int flags = EXPR_F_CONSTANT | EXPR_F_SINGLETON;
+ uint32_t ntype = 0, size = 0;
+ struct expr *i, *next;
+
+ list_for_each_entry_safe(i, next, &(*expr)->expressions, list) {
+ unsigned dsize_bytes;
+
+ if (i->etype == EXPR_CT &&
+ (i->ct.key == NFT_CT_SRC ||
+ i->ct.key == NFT_CT_DST))
+ return expr_error(ctx->msgs, i,
+ "specify either ip or ip6 for address matching");
+
+ if (i->etype == EXPR_PAYLOAD &&
+ i->dtype->type == TYPE_INTEGER) {
+ struct datatype *dtype;
+
+ dtype = datatype_clone(i->dtype);
+ dtype->size = i->len;
+ dtype->byteorder = i->byteorder;
+ __datatype_set(i, dtype);
+ }
+
+ if (i->dtype->size == 0 && i->len == 0)
+ return expr_binary_error(ctx->msgs, i, *expr,
+ "can not use variable sized "
+ "data types (%s) in concat "
+ "expressions",
+ i->dtype->name);
+
+ flags &= i->flags;
+
+ ntype = concat_subtype_add(ntype, i->dtype->type);
+
+ dsize_bytes = div_round_up(i->len, BITS_PER_BYTE);
+
+ if (i->dtype->size)
+ assert(dsize_bytes == div_round_up(i->dtype->size, BITS_PER_BYTE));
+
+ (*expr)->field_len[(*expr)->field_count++] = dsize_bytes;
+ size += netlink_padded_len(i->len);
+
+ if (size > NFT_MAX_EXPR_LEN_BITS)
+ return expr_error(ctx->msgs, i, "Concatenation of size %u exceeds maximum size of %u",
+ size, NFT_MAX_EXPR_LEN_BITS);
+ }
+
+ (*expr)->flags |= flags;
+ __datatype_set(*expr, concat_type_alloc(ntype));
+ (*expr)->len = size;
+
+ expr_set_context(&ctx->ectx, (*expr)->dtype, (*expr)->len);
+ ctx->ectx.key = *expr;
+
+ return 0;
+}
+
+static int elems_evaluate(struct eval_ctx *ctx, struct set *set)
+{
+ ctx->set = set;
+ if (set->init != NULL) {
+ if (set->key == NULL)
+ return set_error(ctx, set, "set definition does not specify key");
+
+ __expr_set_context(&ctx->ectx, set->key->dtype,
+ set->key->byteorder, set->key->len, 0);
+ if (expr_evaluate(ctx, &set->init) < 0) {
+ set->errors = true;
+ return -1;
+ }
+ if (set->init->etype != EXPR_SET)
+ return expr_error(ctx->msgs, set->init, "Set %s: Unexpected initial type %s, missing { }?",
+ set->handle.set.name, expr_name(set->init));
+ }
+
+ if (set_is_interval(ctx->set->flags) &&
+ !(ctx->set->flags & NFT_SET_CONCAT) &&
+ interval_set_eval(ctx, ctx->set, set->init) < 0)
return -1;
+
ctx->set = NULL;
+
return 0;
}
static int set_evaluate(struct eval_ctx *ctx, struct set *set)
{
+ struct set *existing_set = NULL;
+ unsigned int num_stmts = 0;
struct table *table;
+ struct stmt *stmt;
const char *type;
- table = table_lookup_global(ctx);
- if (table == NULL)
- return table_not_found(ctx);
+ type = set_is_map(set->flags) ? "map" : "set";
+
+ if (set->key == NULL)
+ return set_error(ctx, set, "%s definition does not specify key",
+ type);
+
+ if (!set_is_anonymous(set->flags)) {
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ set->handle.table.name,
+ set->handle.family);
+ if (table == NULL)
+ return table_not_found(ctx);
+
+ existing_set = set_cache_find(table, set->handle.set.name);
+ if (!existing_set)
+ set_cache_add(set_get(set), table);
+
+ if (existing_set && existing_set->flags & NFT_SET_EVAL) {
+ uint32_t existing_flags = existing_set->flags & ~NFT_SET_EVAL;
+ uint32_t new_flags = set->flags & ~NFT_SET_EVAL;
+
+ if (existing_flags == new_flags)
+ set->flags |= NFT_SET_EVAL;
+ }
+ }
if (!(set->flags & NFT_SET_INTERVAL) && set->automerge)
return set_error(ctx, set, "auto-merge only works with interval sets");
- type = set_is_map(set->flags) ? "map" : "set";
-
if (set->key == NULL)
return set_error(ctx, set, "%s definition does not specify key",
type);
if (set->key->len == 0) {
if (set->key->etype == EXPR_CONCAT &&
- expr_evaluate_concat(ctx, &set->key, false) < 0)
+ set_expr_evaluate_concat(ctx, &set->key) < 0)
return -1;
if (set->key->len == 0)
- return set_error(ctx, set, "unqualified key type %s "
- "specified in %s definition",
- set->key->dtype->name, type);
+ return set_key_data_error(ctx, set,
+ set->key->dtype, type);
+ }
+
+ if (set->flags & NFT_SET_INTERVAL && set->key->etype == EXPR_CONCAT) {
+ memcpy(&set->desc.field_len, &set->key->field_len,
+ sizeof(set->desc.field_len));
+ set->desc.field_count = set->key->field_count;
+ set->flags |= NFT_SET_CONCAT;
+ }
+
+ if (set_is_anonymous(set->flags) && set->key->etype == EXPR_CONCAT) {
+ struct expr *i;
+
+ list_for_each_entry(i, &set->init->expressions, list) {
+ if ((i->etype == EXPR_SET_ELEM &&
+ i->key->etype != EXPR_CONCAT &&
+ i->key->etype != EXPR_SET_ELEM_CATCHALL) ||
+ (i->etype == EXPR_MAPPING &&
+ i->left->etype == EXPR_SET_ELEM &&
+ i->left->key->etype != EXPR_CONCAT &&
+ i->left->key->etype != EXPR_SET_ELEM_CATCHALL))
+ return expr_error(ctx->msgs, i, "expression is not a concatenation");
+ }
}
- if (set->flags & NFT_SET_INTERVAL &&
- set->key->etype == EXPR_CONCAT)
- return set_error(ctx, set, "concatenated types not supported in interval sets");
if (set_is_datamap(set->flags)) {
- if (set->datatype == NULL)
+ if (set->data == NULL)
return set_error(ctx, set, "map definition does not "
"specify mapping data type");
- set->datalen = set->datatype->size;
- if (set->datalen == 0 && set->datatype->type != TYPE_VERDICT)
- return set_error(ctx, set, "unqualified mapping data "
- "type specified in map definition");
+ if (set->data->etype == EXPR_CONCAT &&
+ set_expr_evaluate_concat(ctx, &set->data) < 0)
+ return -1;
+
+ if (set->data->flags & EXPR_F_INTERVAL)
+ set->data->len *= 2;
+
+ if (set->data->len == 0 && set->data->dtype->type != TYPE_VERDICT)
+ return set_key_data_error(ctx, set,
+ set->data->dtype, type);
} else if (set_is_objmap(set->flags)) {
- set->datatype = &string_type;
- set->datalen = NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE;
- }
+ assert(set->data == NULL);
+ set->data = constant_expr_alloc(&netlink_location, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE,
+ NULL);
- ctx->set = set;
- if (set->init != NULL) {
- expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
- if (expr_evaluate(ctx, &set->init) < 0)
- return -1;
}
- ctx->set = NULL;
-
- if (set_lookup(table, set->handle.set.name) == NULL)
- set_add_hash(set_get(set), table);
/* Default timeout value implies timeout support */
if (set->timeout)
set->flags |= NFT_SET_TIMEOUT;
+ list_for_each_entry(stmt, &set->stmt_list, list)
+ num_stmts++;
+
+ if (num_stmts > 1)
+ set->flags |= NFT_SET_EXPR;
+
+ if (set_is_anonymous(set->flags)) {
+ if (set_is_interval(set->init->set_flags) &&
+ !(set->init->set_flags & NFT_SET_CONCAT) &&
+ interval_set_eval(ctx, set, set->init) < 0)
+ return -1;
+
+ return 0;
+ }
+
+ set->existing_set = existing_set;
+
return 0;
}
@@ -3330,8 +4995,8 @@ static bool evaluate_priority(struct eval_ctx *ctx, struct prio_spec *prio,
int prio_snd;
char op;
- ctx->ectx.dtype = &priority_type;
- ctx->ectx.len = NFT_NAME_MAXLEN * BITS_PER_BYTE;
+ expr_set_context(&ctx->ectx, &priority_type, NFT_NAME_MAXLEN * BITS_PER_BYTE);
+
if (expr_evaluate(ctx, &prio->expr) < 0)
return false;
if (prio->expr->etype != EXPR_VALUE) {
@@ -3345,9 +5010,8 @@ static bool evaluate_priority(struct eval_ctx *ctx, struct prio_spec *prio,
mpz_export_data(prio_str, prio->expr->value, BYTEORDER_HOST_ENDIAN,
NFT_NAME_MAXLEN);
loc = prio->expr->location;
- expr_free(prio->expr);
- if (sscanf(prio_str, "%s %c %d", prio_fst, &op, &prio_snd) < 3) {
+ if (sscanf(prio_str, "%255s %c %d", prio_fst, &op, &prio_snd) < 3) {
priority = std_prio_lookup(prio_str, family, hook);
if (priority == NF_IP_PRI_LAST)
return false;
@@ -3362,6 +5026,7 @@ static bool evaluate_priority(struct eval_ctx *ctx, struct prio_spec *prio,
else
return false;
}
+ expr_free(prio->expr);
prio->expr = constant_expr_alloc(&loc, &integer_type,
BYTEORDER_HOST_ENDIAN,
sizeof(int) * BITS_PER_BYTE,
@@ -3369,27 +5034,101 @@ static bool evaluate_priority(struct eval_ctx *ctx, struct prio_spec *prio,
return true;
}
+static bool evaluate_expr_variable(struct eval_ctx *ctx, struct expr **exprp)
+{
+ struct expr *expr;
+
+ if (expr_evaluate(ctx, exprp) < 0)
+ return false;
+
+ expr = *exprp;
+ if (expr->etype != EXPR_VALUE &&
+ expr->etype != EXPR_SET) {
+ expr_error(ctx->msgs, expr, "%s is not a valid "
+ "variable expression", expr_name(expr));
+ return false;
+ }
+
+ return true;
+}
+
+static bool evaluate_device_expr(struct eval_ctx *ctx, struct expr **dev_expr)
+{
+ struct expr *expr, *next, *key;
+ LIST_HEAD(tmp);
+
+ if ((*dev_expr)->etype == EXPR_VARIABLE) {
+ expr_set_context(&ctx->ectx, &ifname_type,
+ IFNAMSIZ * BITS_PER_BYTE);
+ if (!evaluate_expr_variable(ctx, dev_expr))
+ return false;
+ }
+
+ if ((*dev_expr)->etype != EXPR_SET &&
+ (*dev_expr)->etype != EXPR_LIST)
+ return true;
+
+ list_for_each_entry_safe(expr, next, &(*dev_expr)->expressions, list) {
+ list_del(&expr->list);
+
+ switch (expr->etype) {
+ case EXPR_VARIABLE:
+ expr_set_context(&ctx->ectx, &ifname_type,
+ IFNAMSIZ * BITS_PER_BYTE);
+ if (!evaluate_expr_variable(ctx, &expr))
+ return false;
+ break;
+ case EXPR_SET_ELEM:
+ key = expr_clone(expr->key);
+ expr_free(expr);
+ expr = key;
+ break;
+ case EXPR_VALUE:
+ break;
+ default:
+ BUG("invalid expression type %s\n", expr_name(expr));
+ break;
+ }
+
+ list_add(&expr->list, &tmp);
+ }
+ list_splice_init(&tmp, &(*dev_expr)->expressions);
+
+ return true;
+}
+
static uint32_t str2hooknum(uint32_t family, const char *hook);
static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft)
{
struct table *table;
- table = table_lookup_global(ctx);
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ ctx->cmd->handle.table.name,
+ ctx->cmd->handle.family);
if (table == NULL)
return table_not_found(ctx);
- ft->hooknum = str2hooknum(NFPROTO_NETDEV, ft->hookstr);
- if (ft->hooknum == NF_INET_NUMHOOKS)
- return chain_error(ctx, ft, "invalid hook %s", ft->hookstr);
+ if (!ft_cache_find(table, ft->handle.flowtable.name)) {
+ if (!ft->hook.name && !ft->dev_expr)
+ return chain_error(ctx, ft, "missing hook and priority in flowtable declaration");
- if (!evaluate_priority(ctx, &ft->priority, NFPROTO_NETDEV, ft->hooknum))
- return __stmt_binary_error(ctx, &ft->priority.loc, NULL,
- "invalid priority expression %s.",
- expr_name(ft->priority.expr));
+ ft_cache_add(flowtable_get(ft), table);
+ }
- if (!ft->dev_expr)
- return chain_error(ctx, ft, "Unbound flowtable not allowed (must specify devices)");
+ if (ft->hook.name) {
+ ft->hook.num = str2hooknum(NFPROTO_NETDEV, ft->hook.name);
+ if (ft->hook.num == NF_INET_NUMHOOKS)
+ return chain_error(ctx, ft, "invalid hook %s",
+ ft->hook.name);
+ if (!evaluate_priority(ctx, &ft->priority, NFPROTO_NETDEV, ft->hook.num))
+ return __stmt_binary_error(ctx, &ft->priority.loc, NULL,
+ "invalid priority expression %s.",
+ expr_name(ft->priority.expr));
+ }
+
+ if (ft->dev_expr && !evaluate_device_expr(ctx, &ft->dev_expr))
+ return -1;
return 0;
}
@@ -3418,11 +5157,13 @@ static int rule_cache_update(struct eval_ctx *ctx, enum cmd_ops op)
struct table *table;
struct chain *chain;
- table = table_lookup(&rule->handle, &ctx->nft->cache);
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ rule->handle.table.name,
+ rule->handle.family);
if (!table)
return table_not_found(ctx);
- chain = chain_lookup(table, &rule->handle);
+ chain = chain_cache_find(table, rule->handle.chain.name);
if (!chain)
return chain_not_found(ctx);
@@ -3483,7 +5224,9 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule,
struct stmt *stmt, *tstmt = NULL;
struct error_record *erec;
- proto_ctx_init(&ctx->pctx, rule->handle.family, ctx->nft->debug_mask);
+ proto_ctx_init(&ctx->_pctx[0], rule->handle.family, ctx->nft->debug_mask, false);
+ /* use NFPROTO_BRIDGE to set up proto_eth as base protocol. */
+ proto_ctx_init(&ctx->_pctx[1], NFPROTO_BRIDGE, ctx->nft->debug_mask, true);
memset(&ctx->ectx, 0, sizeof(ctx->ectx));
ctx->rule = rule;
@@ -3498,6 +5241,8 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule,
return -1;
if (stmt->flags & STMT_F_TERMINAL)
tstmt = stmt;
+
+ ctx->inner_desc = NULL;
}
erec = rule_postprocess(rule);
@@ -3506,7 +5251,7 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule,
return -1;
}
- if (cache_needs_update(&ctx->nft->cache))
+ if (nft_cache_needs_update(&ctx->nft->cache))
return rule_cache_update(ctx, op);
return 0;
@@ -3518,10 +5263,13 @@ static uint32_t str2hooknum(uint32_t family, const char *hook)
return NF_INET_NUMHOOKS;
switch (family) {
+ case NFPROTO_INET:
+ if (!strcmp(hook, "ingress"))
+ return NF_INET_INGRESS;
+ /* fall through */
case NFPROTO_IPV4:
case NFPROTO_BRIDGE:
case NFPROTO_IPV6:
- case NFPROTO_INET:
/* These families have overlapping values for each hook */
if (!strcmp(hook, "prerouting"))
return NF_INET_PRE_ROUTING;
@@ -3545,6 +5293,8 @@ static uint32_t str2hooknum(uint32_t family, const char *hook)
case NFPROTO_NETDEV:
if (!strcmp(hook, "ingress"))
return NF_NETDEV_INGRESS;
+ else if (!strcmp(hook, "egress"))
+ return NF_NETDEV_EGRESS;
break;
default:
break;
@@ -3553,70 +5303,66 @@ static uint32_t str2hooknum(uint32_t family, const char *hook)
return NF_INET_NUMHOOKS;
}
-static bool evaluate_policy(struct eval_ctx *ctx, struct expr **exprp)
-{
- struct expr *expr;
-
- ctx->ectx.dtype = &policy_type;
- ctx->ectx.len = NFT_NAME_MAXLEN * BITS_PER_BYTE;
- if (expr_evaluate(ctx, exprp) < 0)
- return false;
-
- expr = *exprp;
- if (expr->etype != EXPR_VALUE) {
- expr_error(ctx->msgs, expr, "%s is not a valid "
- "policy expression", expr_name(expr));
- return false;
- }
-
- return true;
-}
-
static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
{
struct table *table;
- struct rule *rule;
- table = table_lookup_global(ctx);
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ ctx->cmd->handle.table.name,
+ ctx->cmd->handle.family);
if (table == NULL)
return table_not_found(ctx);
if (chain == NULL) {
- if (chain_lookup(table, &ctx->cmd->handle) == NULL) {
- chain = chain_alloc(NULL);
+ if (!chain_cache_find(table, ctx->cmd->handle.chain.name)) {
+ chain = chain_alloc();
handle_merge(&chain->handle, &ctx->cmd->handle);
- chain_add_hash(chain, table);
+ chain_cache_add(chain, table);
}
return 0;
- } else {
- if (chain_lookup(table, &chain->handle) == NULL)
- chain_add_hash(chain_get(chain), table);
+ } else if (!(chain->flags & CHAIN_F_BINDING)) {
+ if (!chain_cache_find(table, chain->handle.chain.name))
+ chain_cache_add(chain_get(chain), table);
}
if (chain->flags & CHAIN_F_BASECHAIN) {
- chain->hooknum = str2hooknum(chain->handle.family,
- chain->hookstr);
- if (chain->hooknum == NF_INET_NUMHOOKS)
- return chain_error(ctx, chain, "invalid hook %s",
- chain->hookstr);
+ chain->hook.num = str2hooknum(chain->handle.family,
+ chain->hook.name);
+ if (chain->hook.num == NF_INET_NUMHOOKS)
+ return __stmt_binary_error(ctx, &chain->hook.loc, NULL,
+ "The %s family does not support this hook",
+ family2str(chain->handle.family));
if (!evaluate_priority(ctx, &chain->priority,
- chain->handle.family, chain->hooknum))
+ chain->handle.family, chain->hook.num))
return __stmt_binary_error(ctx, &chain->priority.loc, NULL,
"invalid priority expression %s in this context.",
expr_name(chain->priority.expr));
if (chain->policy) {
- if (!evaluate_policy(ctx, &chain->policy))
+ expr_set_context(&ctx->ectx, &policy_type,
+ NFT_NAME_MAXLEN * BITS_PER_BYTE);
+ if (!evaluate_expr_variable(ctx, &chain->policy))
return chain_error(ctx, chain, "invalid policy expression %s",
expr_name(chain->policy));
}
}
- list_for_each_entry(rule, &chain->rules, list) {
- handle_merge(&rule->handle, &chain->handle);
- if (rule_evaluate(ctx, rule, CMD_INVALID) < 0)
- return -1;
+ if (chain->dev_expr) {
+ if (!(chain->flags & CHAIN_F_BASECHAIN))
+ chain->flags |= CHAIN_F_BASECHAIN;
+
+ if (chain->handle.family == NFPROTO_NETDEV ||
+ (chain->handle.family == NFPROTO_INET &&
+ chain->hook.num == NF_INET_INGRESS)) {
+ if (chain->dev_expr &&
+ !evaluate_device_expr(ctx, &chain->dev_expr))
+ return -1;
+ } else if (chain->dev_expr) {
+ return __stmt_binary_error(ctx, &chain->dev_expr->location, NULL,
+ "This chain type cannot be bound to device");
+ }
}
+
return 0;
}
@@ -3650,7 +5396,8 @@ static int ct_timeout_evaluate(struct eval_ctx *ctx, struct obj *obj)
ct->timeout[ts->timeout_index] = ts->timeout_value;
list_del(&ts->head);
- xfree(ts);
+ free_const(ts->timeout_str);
+ free(ts);
}
return 0;
@@ -3658,6 +5405,17 @@ static int ct_timeout_evaluate(struct eval_ctx *ctx, struct obj *obj)
static int obj_evaluate(struct eval_ctx *ctx, struct obj *obj)
{
+ struct table *table;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ ctx->cmd->handle.table.name,
+ ctx->cmd->handle.family);
+ if (!table)
+ return table_not_found(ctx);
+
+ if (!obj_cache_find(table, obj->handle.obj.name, obj->type))
+ obj_cache_add(obj_get(obj), table);
+
switch (obj->type) {
case NFT_OBJECT_CT_TIMEOUT:
return ct_timeout_evaluate(ctx, obj);
@@ -3672,60 +5430,31 @@ static int obj_evaluate(struct eval_ctx *ctx, struct obj *obj)
static int table_evaluate(struct eval_ctx *ctx, struct table *table)
{
- struct flowtable *ft;
- struct chain *chain;
- struct set *set;
- struct obj *obj;
-
- if (table_lookup(&ctx->cmd->handle, &ctx->nft->cache) == NULL) {
- if (table == NULL) {
+ if (!table_cache_find(&ctx->nft->cache.table_cache,
+ ctx->cmd->handle.table.name,
+ ctx->cmd->handle.family)) {
+ if (!table) {
table = table_alloc();
handle_merge(&table->handle, &ctx->cmd->handle);
- table_add_hash(table, &ctx->nft->cache);
+ table_cache_add(table, &ctx->nft->cache);
} else {
- table_add_hash(table_get(table), &ctx->nft->cache);
+ table_cache_add(table_get(table), &ctx->nft->cache);
}
}
- if (ctx->cmd->table == NULL)
- return 0;
-
- ctx->table = table;
- list_for_each_entry(set, &table->sets, list) {
- expr_set_context(&ctx->ectx, NULL, 0);
- handle_merge(&set->handle, &table->handle);
- if (set_evaluate(ctx, set) < 0)
- return -1;
- }
- list_for_each_entry(chain, &table->chains, list) {
- handle_merge(&chain->handle, &table->handle);
- ctx->cmd->handle.chain.location = chain->location;
- if (chain_evaluate(ctx, chain) < 0)
- return -1;
- }
- list_for_each_entry(ft, &table->flowtables, list) {
- handle_merge(&ft->handle, &table->handle);
- if (flowtable_evaluate(ctx, ft) < 0)
- return -1;
- }
- list_for_each_entry(obj, &table->objs, list) {
- handle_merge(&obj->handle, &table->handle);
- if (obj_evaluate(ctx, obj) < 0)
- return -1;
- }
-
- ctx->table = NULL;
return 0;
}
static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
{
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
- return setelem_evaluate(ctx, &cmd->expr);
+ case CMD_OBJ_ELEMENTS:
+ return setelem_evaluate(ctx, cmd);
case CMD_OBJ_SET:
handle_merge(&cmd->set->handle, &cmd->handle);
return set_evaluate(ctx, cmd->set);
+ case CMD_OBJ_SETELEMS:
+ return elems_evaluate(ctx, cmd->set);
case CMD_OBJ_RULE:
handle_merge(&cmd->rule->handle, &cmd->handle);
return rule_evaluate(ctx, cmd->rule, cmd->op);
@@ -3744,30 +5473,160 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_SECMARK:
case CMD_OBJ_CT_EXPECT:
case CMD_OBJ_SYNPROXY:
+ handle_merge(&cmd->object->handle, &cmd->handle);
return obj_evaluate(ctx, cmd->object);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
}
+static void table_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table;
+
+ if (!cmd->handle.table.name)
+ return;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return;
+
+ table_cache_del(table);
+ table_free(table);
+}
+
+static void chain_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table;
+ struct chain *chain;
+
+ if (!cmd->handle.chain.name)
+ return;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return;
+
+ chain = chain_cache_find(table, cmd->handle.chain.name);
+ if (!chain)
+ return;
+
+ chain_cache_del(chain);
+ chain_free(chain);
+}
+
+static void set_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ struct table *table;
+ struct set *set;
+
+ if (!cmd->handle.set.name)
+ return;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return;
+
+ set = set_cache_find(table, cmd->handle.set.name);
+ if (!set)
+ return;
+
+ set_cache_del(set);
+ set_free(set);
+}
+
+static void ft_del_cache(struct eval_ctx *ctx, struct cmd *cmd)
+{
+ struct flowtable *ft;
+ struct table *table;
+
+ if (!cmd->handle.flowtable.name)
+ return;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return;
+
+ ft = ft_cache_find(table, cmd->handle.flowtable.name);
+ if (!ft)
+ return;
+
+ ft_cache_del(ft);
+ flowtable_free(ft);
+}
+
+static void obj_del_cache(struct eval_ctx *ctx, struct cmd *cmd, int type)
+{
+ struct table *table;
+ struct obj *obj;
+
+ if (!cmd->handle.obj.name)
+ return;
+
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
+ return;
+
+ obj = obj_cache_find(table, cmd->handle.obj.name, type);
+ if (!obj)
+ return;
+
+ obj_cache_del(obj);
+ obj_free(obj);
+}
+
static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
{
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
- return setelem_evaluate(ctx, &cmd->expr);
+ case CMD_OBJ_ELEMENTS:
+ return setelem_evaluate(ctx, cmd);
case CMD_OBJ_SET:
+ set_del_cache(ctx, cmd);
+ return 0;
case CMD_OBJ_RULE:
+ return 0;
case CMD_OBJ_CHAIN:
+ chain_del_cache(ctx, cmd);
+ return 0;
case CMD_OBJ_TABLE:
+ table_del_cache(ctx, cmd);
+ return 0;
case CMD_OBJ_FLOWTABLE:
+ ft_del_cache(ctx, cmd);
+ return 0;
case CMD_OBJ_COUNTER:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_COUNTER);
+ return 0;
case CMD_OBJ_QUOTA:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_QUOTA);
+ return 0;
case CMD_OBJ_CT_HELPER:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_CT_HELPER);
+ return 0;
case CMD_OBJ_CT_TIMEOUT:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
+ return 0;
case CMD_OBJ_LIMIT:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_LIMIT);
+ return 0;
case CMD_OBJ_SECMARK:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_SECMARK);
+ return 0;
case CMD_OBJ_CT_EXPECT:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_CT_EXPECT);
+ return 0;
case CMD_OBJ_SYNPROXY:
+ obj_del_cache(ctx, cmd, NFT_OBJECT_SYNPROXY);
return 0;
default:
BUG("invalid command object type %u\n", cmd->obj);
@@ -3776,21 +5635,9 @@ static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
static int cmd_evaluate_get(struct eval_ctx *ctx, struct cmd *cmd)
{
- struct table *table;
- struct set *set;
-
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
- if (table == NULL)
- return table_not_found(ctx);
-
- set = set_lookup(table, cmd->handle.set.name);
- if (set == NULL || set_is_map(set->flags))
- return set_not_found(ctx, &ctx->cmd->handle.set.location,
- ctx->cmd->handle.set.name);
-
- return setelem_evaluate(ctx, &cmd->expr);
+ case CMD_OBJ_ELEMENTS:
+ return setelem_evaluate(ctx, cmd);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -3807,7 +5654,7 @@ static int obj_not_found(struct eval_ctx *ctx, const struct location *loc,
return cmd_error(ctx, loc, "%s", strerror(ENOENT));
return cmd_error(ctx, loc,
- "%s; did you mean obj ‘%s’ in table %s ‘%s’?",
+ "%s; did you mean obj '%s' in table %s '%s'?",
strerror(ENOENT), obj->handle.obj.name,
family2str(obj->handle.family),
table->handle.table.name);
@@ -3821,11 +5668,13 @@ static int cmd_evaluate_list_obj(struct eval_ctx *ctx, const struct cmd *cmd,
if (obj_type == NFT_OBJECT_UNSPEC)
obj_type = NFT_OBJECT_COUNTER;
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
if (table == NULL)
return table_not_found(ctx);
- if (obj_lookup(table, cmd->handle.obj.name, obj_type) == NULL)
+ if (!obj_cache_find(table, cmd->handle.obj.name, obj_type))
return obj_not_found(ctx, &cmd->handle.obj.location,
cmd->handle.obj.name);
@@ -3834,6 +5683,7 @@ static int cmd_evaluate_list_obj(struct eval_ctx *ctx, const struct cmd *cmd,
static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
{
+ struct flowtable *ft;
struct table *table;
struct set *set;
@@ -3842,61 +5692,56 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
if (cmd->handle.table.name == NULL)
return 0;
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
- if (table == NULL)
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
return table_not_found(ctx);
return 0;
case CMD_OBJ_SET:
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
- if (table == NULL)
- return table_not_found(ctx);
-
- set = set_lookup(table, cmd->handle.set.name);
- if (set == NULL)
- return set_not_found(ctx, &ctx->cmd->handle.set.location,
- ctx->cmd->handle.set.name);
- else if (!set_is_literal(set->flags))
- return cmd_error(ctx, &ctx->cmd->handle.set.location,
- "%s", strerror(ENOENT));
-
- return 0;
+ case CMD_OBJ_MAP:
case CMD_OBJ_METER:
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
- if (table == NULL)
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
return table_not_found(ctx);
- set = set_lookup(table, cmd->handle.set.name);
+ set = set_cache_find(table, cmd->handle.set.name);
if (set == NULL)
return set_not_found(ctx, &ctx->cmd->handle.set.location,
ctx->cmd->handle.set.name);
- else if (!(set->flags & NFT_SET_EVAL) ||
- !(set->flags & NFT_SET_ANONYMOUS))
+ if ((cmd->obj == CMD_OBJ_SET && !set_is_literal(set->flags)) ||
+ (cmd->obj == CMD_OBJ_MAP && !map_is_literal(set->flags)) ||
+ (cmd->obj == CMD_OBJ_METER && !set_is_meter_compat(set->flags)))
return cmd_error(ctx, &ctx->cmd->handle.set.location,
"%s", strerror(ENOENT));
+ cmd->set = set_get(set);
return 0;
- case CMD_OBJ_MAP:
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
- if (table == NULL)
+ case CMD_OBJ_CHAIN:
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
return table_not_found(ctx);
- set = set_lookup(table, cmd->handle.set.name);
- if (set == NULL)
- return set_not_found(ctx, &ctx->cmd->handle.set.location,
- ctx->cmd->handle.set.name);
- else if (!map_is_literal(set->flags))
- return cmd_error(ctx, &ctx->cmd->handle.set.location,
- "%s", strerror(ENOENT));
+ if (!chain_cache_find(table, cmd->handle.chain.name))
+ return chain_not_found(ctx);
return 0;
- case CMD_OBJ_CHAIN:
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
- if (table == NULL)
+ case CMD_OBJ_FLOWTABLE:
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
return table_not_found(ctx);
- if (chain_lookup(table, &cmd->handle) == NULL)
- return chain_not_found(ctx);
+ ft = ft_cache_find(table, cmd->handle.flowtable.name);
+ if (!ft)
+ return flowtable_not_found(ctx, &ctx->cmd->handle.flowtable.location,
+ ctx->cmd->handle.flowtable.name);
return 0;
case CMD_OBJ_QUOTA:
@@ -3923,9 +5768,13 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_FLOWTABLES:
case CMD_OBJ_SECMARKS:
case CMD_OBJ_SYNPROXYS:
+ case CMD_OBJ_CT_TIMEOUTS:
+ case CMD_OBJ_CT_EXPECTATIONS:
if (cmd->handle.table.name == NULL)
return 0;
- if (table_lookup(&cmd->handle, &ctx->nft->cache) == NULL)
+ if (!table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family))
return table_not_found(ctx);
return 0;
@@ -3934,6 +5783,16 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_METERS:
case CMD_OBJ_MAPS:
return 0;
+ case CMD_OBJ_HOOKS:
+ if (cmd->handle.chain.name) {
+ int hooknum = str2hooknum(cmd->handle.family, cmd->handle.chain.name);
+
+ if (hooknum == NF_INET_NUMHOOKS)
+ return chain_not_found(ctx);
+
+ cmd->handle.chain_id = hooknum;
+ }
+ return 0;
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -3946,19 +5805,37 @@ static int cmd_evaluate_reset(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_QUOTA:
case CMD_OBJ_COUNTERS:
case CMD_OBJ_QUOTAS:
+ case CMD_OBJ_RULES:
+ case CMD_OBJ_RULE:
if (cmd->handle.table.name == NULL)
return 0;
- if (table_lookup(&cmd->handle, &ctx->nft->cache) == NULL)
+ if (!table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family))
return table_not_found(ctx);
return 0;
+ case CMD_OBJ_ELEMENTS:
+ return setelem_evaluate(ctx, cmd);
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ return cmd_evaluate_list(ctx, cmd);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
}
+static void __flush_set_cache(struct set *set)
+{
+ if (set->init != NULL) {
+ expr_free(set->init);
+ set->init = NULL;
+ }
+}
+
static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
{
+ struct cache *table_cache = &ctx->nft->cache.table_cache;
struct table *table;
struct set *set;
@@ -3973,24 +5850,29 @@ static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
/* Chains don't hold sets */
break;
case CMD_OBJ_SET:
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
- if (table == NULL)
+ table = table_cache_find(table_cache, cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
return table_not_found(ctx);
- set = set_lookup(table, cmd->handle.set.name);
+ set = set_cache_find(table, cmd->handle.set.name);
if (set == NULL)
return set_not_found(ctx, &ctx->cmd->handle.set.location,
ctx->cmd->handle.set.name);
else if (!set_is_literal(set->flags))
return cmd_error(ctx, &ctx->cmd->handle.set.location,
"%s", strerror(ENOENT));
+
+ __flush_set_cache(set);
+
return 0;
case CMD_OBJ_MAP:
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
- if (table == NULL)
+ table = table_cache_find(table_cache, cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
return table_not_found(ctx);
- set = set_lookup(table, cmd->handle.set.name);
+ set = set_cache_find(table, cmd->handle.set.name);
if (set == NULL)
return set_not_found(ctx, &ctx->cmd->handle.set.location,
ctx->cmd->handle.set.name);
@@ -3998,21 +5880,25 @@ static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
return cmd_error(ctx, &ctx->cmd->handle.set.location,
"%s", strerror(ENOENT));
+ __flush_set_cache(set);
+
return 0;
case CMD_OBJ_METER:
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
- if (table == NULL)
+ table = table_cache_find(table_cache, cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
return table_not_found(ctx);
- set = set_lookup(table, cmd->handle.set.name);
+ set = set_cache_find(table, cmd->handle.set.name);
if (set == NULL)
return set_not_found(ctx, &ctx->cmd->handle.set.location,
ctx->cmd->handle.set.name);
- else if (!(set->flags & NFT_SET_EVAL) ||
- !(set->flags & NFT_SET_ANONYMOUS))
+ else if (!set_is_meter_compat(set->flags))
return cmd_error(ctx, &ctx->cmd->handle.set.location,
"%s", strerror(ENOENT));
+ __flush_set_cache(set);
+
return 0;
default:
BUG("invalid command object type %u\n", cmd->obj);
@@ -4026,11 +5912,13 @@ static int cmd_evaluate_rename(struct eval_ctx *ctx, struct cmd *cmd)
switch (cmd->obj) {
case CMD_OBJ_CHAIN:
- table = table_lookup(&ctx->cmd->handle, &ctx->nft->cache);
- if (table == NULL)
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
+ if (!table)
return table_not_found(ctx);
- if (chain_lookup(table, &ctx->cmd->handle) == NULL)
+ if (!chain_cache_find(table, ctx->cmd->handle.chain.name))
return chain_not_found(ctx);
break;
@@ -4168,11 +6056,12 @@ static const char * const cmd_op_name[] = {
[CMD_EXPORT] = "export",
[CMD_MONITOR] = "monitor",
[CMD_DESCRIBE] = "describe",
+ [CMD_DESTROY] = "destroy",
};
static const char *cmd_op_to_name(enum cmd_ops op)
{
- if (op > CMD_DESCRIBE)
+ if (op >= array_size(cmd_op_name))
return "unknown";
return cmd_op_name[op];
@@ -4200,6 +6089,7 @@ int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
case CMD_INSERT:
return cmd_evaluate_add(ctx, cmd);
case CMD_DELETE:
+ case CMD_DESTROY:
return cmd_evaluate_delete(ctx, cmd);
case CMD_GET:
return cmd_evaluate_get(ctx, cmd);
diff --git a/src/expression.c b/src/expression.c
index e456010f..cb2573fe 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -8,16 +8,16 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <stddef.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
#include <limits.h>
#include <expression.h>
#include <statement.h>
#include <datatype.h>
+#include <netlink.h>
#include <rule.h>
#include <gmputil.h>
#include <utils.h>
@@ -28,6 +28,7 @@
extern const struct expr_ops ct_expr_ops;
extern const struct expr_ops fib_expr_ops;
extern const struct expr_ops hash_expr_ops;
+extern const struct expr_ops inner_expr_ops;
extern const struct expr_ops meta_expr_ops;
extern const struct expr_ops numgen_expr_ops;
extern const struct expr_ops osf_expr_ops;
@@ -93,7 +94,7 @@ void expr_free(struct expr *expr)
*/
if (expr->etype != EXPR_INVALID)
expr_destroy(expr);
- xfree(expr);
+ free(expr);
}
void expr_print(const struct expr *expr, struct output_ctx *octx)
@@ -138,6 +139,11 @@ void expr_describe(const struct expr *expr, struct output_ctx *octx)
} else {
nft_print(octx, "%s expression, datatype %s (%s)",
expr_name(expr), dtype->name, dtype->desc);
+
+ if (dtype == &invalid_type) {
+ nft_print(octx, "\n");
+ return;
+ }
}
if (dtype->basetype != NULL) {
@@ -172,9 +178,20 @@ void expr_describe(const struct expr *expr, struct output_ctx *octx)
nft_print(octx, "(in hexadecimal):\n");
symbol_table_print(edtype->sym_tbl, edtype,
expr->byteorder, octx);
+ } else if (edtype->describe) {
+ edtype->describe(octx);
}
}
+void expr_to_string(const struct expr *expr, char *string)
+{
+ int len = expr->len / BITS_PER_BYTE;
+
+ assert(expr->dtype == &string_type);
+
+ mpz_export_data(string, expr->value, BYTEORDER_HOST_ENDIAN, len);
+}
+
void expr_set_type(struct expr *expr, const struct datatype *dtype,
enum byteorder byteorder)
{
@@ -243,6 +260,22 @@ static void verdict_expr_destroy(struct expr *expr)
expr_free(expr->chain);
}
+static int verdict_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ return 0;
+}
+
+static struct expr *verdict_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ struct expr *e;
+
+ e = symbol_expr_alloc(&internal_location, SYMBOL_VALUE, NULL, "verdict");
+ e->dtype = &verdict_type;
+ e->len = NFT_REG_SIZE * BITS_PER_BYTE;
+ return e;
+}
+
static const struct expr_ops verdict_expr_ops = {
.type = EXPR_VERDICT,
.name = "verdict",
@@ -251,6 +284,8 @@ static const struct expr_ops verdict_expr_ops = {
.cmp = verdict_expr_cmp,
.clone = verdict_expr_clone,
.destroy = verdict_expr_destroy,
+ .build_udata = verdict_expr_build_udata,
+ .parse_udata = verdict_expr_parse_udata,
};
struct expr *verdict_expr_alloc(const struct location *loc,
@@ -269,8 +304,7 @@ struct expr *verdict_expr_alloc(const struct location *loc,
static void symbol_expr_print(const struct expr *expr, struct output_ctx *octx)
{
- nft_print(octx, "%s%s", expr->scope != NULL ? "$" : "",
- expr->identifier);
+ nft_print(octx, "%s", expr->identifier);
}
static void symbol_expr_clone(struct expr *new, const struct expr *expr)
@@ -282,7 +316,7 @@ static void symbol_expr_clone(struct expr *new, const struct expr *expr)
static void symbol_expr_destroy(struct expr *expr)
{
- xfree(expr->identifier);
+ free_const(expr->identifier);
}
static const struct expr_ops symbol_expr_ops = {
@@ -551,6 +585,7 @@ const char *expr_op_symbols[] = {
[OP_GT] = ">",
[OP_LTE] = "<=",
[OP_GTE] = ">=",
+ [OP_NEG] = "!",
};
static void unary_expr_print(const struct expr *expr, struct output_ctx *octx)
@@ -699,16 +734,26 @@ struct expr *relational_expr_alloc(const struct location *loc, enum ops op,
void relational_expr_pctx_update(struct proto_ctx *ctx,
const struct expr *expr)
{
- const struct expr *left = expr->left;
+ const struct expr *left = expr->left, *right = expr->right;
const struct expr_ops *ops;
+ const struct expr *i;
assert(expr->etype == EXPR_RELATIONAL);
assert(expr->op == OP_EQ || expr->op == OP_IMPLICIT);
ops = expr_ops(left);
if (ops->pctx_update &&
- (left->flags & EXPR_F_PROTOCOL))
- ops->pctx_update(ctx, expr);
+ (left->flags & EXPR_F_PROTOCOL)) {
+ if (expr_is_singleton(right))
+ ops->pctx_update(ctx, &expr->location, left, right);
+ else if (right->etype == EXPR_SET) {
+ list_for_each_entry(i, &right->expressions, list) {
+ if (i->etype == EXPR_SET_ELEM &&
+ i->key->etype == EXPR_VALUE)
+ ops->pctx_update(ctx, &expr->location, left, i->key);
+ }
+ }
+ }
}
static void range_expr_print(const struct expr *expr, struct output_ctx *octx)
@@ -829,6 +874,156 @@ static void concat_expr_print(const struct expr *expr, struct output_ctx *octx)
compound_expr_print(expr, " . ", octx);
}
+#define NFTNL_UDATA_SET_KEY_CONCAT_NEST 0
+#define NFTNL_UDATA_SET_KEY_CONCAT_NEST_MAX NFT_REG32_SIZE
+
+#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE 0
+#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA 1
+#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_MAX 2
+
+static struct expr *expr_build_udata_recurse(struct expr *e)
+{
+ switch (e->etype) {
+ case EXPR_BINOP:
+ return e->left;
+ default:
+ break;
+ }
+
+ return e;
+}
+
+static int concat_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *concat_expr)
+{
+ struct nftnl_udata *nest;
+ struct expr *expr, *tmp;
+ unsigned int i = 0;
+
+ list_for_each_entry_safe(expr, tmp, &concat_expr->expressions, list) {
+ struct nftnl_udata *nest_expr;
+ int err;
+
+ expr = expr_build_udata_recurse(expr);
+ if (!expr_ops(expr)->build_udata || i >= NFT_REG32_SIZE)
+ return -1;
+
+ nest = nftnl_udata_nest_start(udbuf, NFTNL_UDATA_SET_KEY_CONCAT_NEST + i);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE, expr->etype);
+ nest_expr = nftnl_udata_nest_start(udbuf, NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA);
+ err = expr_ops(expr)->build_udata(udbuf, expr);
+ if (err < 0)
+ return err;
+ nftnl_udata_nest_end(udbuf, nest_expr);
+ nftnl_udata_nest_end(udbuf, nest);
+ i++;
+ }
+
+ return 0;
+}
+
+static int concat_parse_udata_nest(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ if (type >= NFTNL_UDATA_SET_KEY_CONCAT_NEST_MAX)
+ return -1;
+
+ if (len <= sizeof(uint32_t))
+ return -1;
+
+ ud[type] = attr;
+ return 0;
+}
+
+static int concat_parse_udata_nested(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ case NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA:
+ if (len <= sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *concat_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_SET_KEY_CONCAT_NEST_MAX] = {};
+ const struct datatype *dtype;
+ struct expr *concat_expr;
+ uint32_t dt = 0, len = 0;
+ unsigned int i;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ concat_parse_udata_nest, ud);
+ if (err < 0)
+ return NULL;
+
+ concat_expr = concat_expr_alloc(&internal_location);
+ if (!concat_expr)
+ return NULL;
+
+ for (i = 0; i < array_size(ud); i++) {
+ const struct nftnl_udata *nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_MAX];
+ const struct nftnl_udata *nested, *subdata;
+ const struct expr_ops *ops;
+ struct expr *expr;
+ uint32_t etype;
+
+ if (ud[NFTNL_UDATA_SET_KEY_CONCAT_NEST + i] == NULL)
+ break;
+
+ nested = ud[NFTNL_UDATA_SET_KEY_CONCAT_NEST + i];
+ err = nftnl_udata_parse(nftnl_udata_get(nested), nftnl_udata_len(nested),
+ concat_parse_udata_nested, nest_ud);
+ if (err < 0)
+ goto err_free;
+
+ etype = nftnl_udata_get_u32(nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE]);
+ ops = expr_ops_by_type_u32(etype);
+ if (!ops || !ops->parse_udata)
+ goto err_free;
+
+ subdata = nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA];
+ expr = ops->parse_udata(subdata);
+ if (!expr)
+ goto err_free;
+
+ dt = concat_subtype_add(dt, expr->dtype->type);
+ compound_expr_add(concat_expr, expr);
+ len += netlink_padded_len(expr->len);
+ }
+
+ dtype = concat_type_alloc(dt);
+ if (!dtype)
+ goto err_free;
+
+ __datatype_set(concat_expr, dtype);
+ concat_expr->len = len;
+
+ return concat_expr;
+
+err_free:
+ expr_free(concat_expr);
+ return NULL;
+}
+
static const struct expr_ops concat_expr_ops = {
.type = EXPR_CONCAT,
.name = "concat",
@@ -836,6 +1031,8 @@ static const struct expr_ops concat_expr_ops = {
.json = concat_expr_json,
.clone = compound_expr_clone,
.destroy = concat_expr_destroy,
+ .build_udata = concat_expr_build_udata,
+ .parse_udata = concat_expr_parse_udata,
};
struct expr *concat_expr_alloc(const struct location *loc)
@@ -1006,14 +1203,40 @@ struct expr *mapping_expr_alloc(const struct location *loc,
return expr;
}
+static bool __set_expr_is_vmap(const struct expr *mappings)
+{
+ const struct expr *mapping;
+
+ if (list_empty(&mappings->expressions))
+ return false;
+
+ mapping = list_first_entry(&mappings->expressions, struct expr, list);
+ if (mapping->etype == EXPR_MAPPING &&
+ mapping->right->etype == EXPR_VERDICT)
+ return true;
+
+ return false;
+}
+
+static bool set_expr_is_vmap(const struct expr *expr)
+{
+
+ if (expr->mappings->etype == EXPR_SET)
+ return __set_expr_is_vmap(expr->mappings);
+
+ return false;
+}
+
static void map_expr_print(const struct expr *expr, struct output_ctx *octx)
{
expr_print(expr->map, octx);
- if (expr->mappings->etype == EXPR_SET_REF &&
- expr->mappings->set->datatype->type == TYPE_VERDICT)
+ if ((expr->mappings->etype == EXPR_SET_REF &&
+ expr->mappings->set->data->dtype->type == TYPE_VERDICT) ||
+ set_expr_is_vmap(expr))
nft_print(octx, " vmap ");
else
nft_print(octx, " map ");
+
expr_print(expr->mappings, octx);
}
@@ -1051,14 +1274,12 @@ struct expr *map_expr_alloc(const struct location *loc, struct expr *arg,
static void set_ref_expr_print(const struct expr *expr, struct output_ctx *octx)
{
- if (set_is_anonymous(expr->set->flags)) {
- if (expr->set->flags & NFT_SET_EVAL)
- nft_print(octx, "%s", expr->set->handle.set.name);
- else
- expr_print(expr->set->init, octx);
- } else {
+ if (set_is_meter(expr->set->flags))
+ nft_print(octx, "%s", expr->set->handle.set.name);
+ else if (set_is_anonymous(expr->set->flags))
+ expr_print(expr->set->init, octx);
+ else
nft_print(octx, "@%s", expr->set->handle.set.name);
- }
}
static void set_ref_expr_clone(struct expr *new, const struct expr *expr)
@@ -1093,7 +1314,13 @@ struct expr *set_ref_expr_alloc(const struct location *loc, struct set *set)
static void set_elem_expr_print(const struct expr *expr,
struct output_ctx *octx)
{
+ struct stmt *stmt;
+
expr_print(expr->key, octx);
+ list_for_each_entry(stmt, &expr->stmt_list, list) {
+ nft_print(octx, " ");
+ stmt_print(stmt, octx);
+ }
if (expr->timeout) {
nft_print(octx, " timeout ");
time_print(expr->timeout, octx);
@@ -1102,28 +1329,33 @@ static void set_elem_expr_print(const struct expr *expr,
nft_print(octx, " expires ");
time_print(expr->expiration, octx);
}
- if (expr->stmt) {
- nft_print(octx, " ");
- stmt_print(expr->stmt, octx);
- }
if (expr->comment)
nft_print(octx, " comment \"%s\"", expr->comment);
}
static void set_elem_expr_destroy(struct expr *expr)
{
- xfree(expr->comment);
+ struct stmt *stmt, *next;
+
+ free_const(expr->comment);
expr_free(expr->key);
- stmt_free(expr->stmt);
+ list_for_each_entry_safe(stmt, next, &expr->stmt_list, list)
+ stmt_free(stmt);
}
-static void set_elem_expr_clone(struct expr *new, const struct expr *expr)
+static void __set_elem_expr_clone(struct expr *new, const struct expr *expr)
{
- new->key = expr_clone(expr->key);
new->expiration = expr->expiration;
new->timeout = expr->timeout;
if (expr->comment)
new->comment = xstrdup(expr->comment);
+ init_list_head(&new->stmt_list);
+}
+
+static void set_elem_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->key = expr_clone(expr->key);
+ __set_elem_expr_clone(new, expr);
}
static const struct expr_ops set_elem_expr_ops = {
@@ -1142,6 +1374,93 @@ struct expr *set_elem_expr_alloc(const struct location *loc, struct expr *key)
expr = expr_alloc(loc, EXPR_SET_ELEM, key->dtype,
key->byteorder, key->len);
expr->key = key;
+ init_list_head(&expr->stmt_list);
+
+ return expr;
+}
+
+static void set_elem_catchall_expr_print(const struct expr *expr,
+ struct output_ctx *octx)
+{
+ nft_print(octx, "*");
+}
+
+static void set_elem_catchall_expr_clone(struct expr *new, const struct expr *expr)
+{
+ __set_elem_expr_clone(new, expr);
+}
+
+static const struct expr_ops set_elem_catchall_expr_ops = {
+ .type = EXPR_SET_ELEM_CATCHALL,
+ .name = "catch-all set element",
+ .print = set_elem_catchall_expr_print,
+ .json = set_elem_catchall_expr_json,
+ .clone = set_elem_catchall_expr_clone,
+};
+
+struct expr *set_elem_catchall_expr_alloc(const struct location *loc)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_SET_ELEM_CATCHALL, &invalid_type,
+ BYTEORDER_INVALID, 0);
+ expr->flags = EXPR_F_CONSTANT | EXPR_F_SINGLETON;
+
+ return expr;
+}
+
+static void flagcmp_expr_print(const struct expr *expr, struct output_ctx *octx)
+{
+ expr_print(expr->flagcmp.expr, octx);
+
+ if (expr->op == OP_NEQ)
+ nft_print(octx, " != ");
+ else
+ nft_print(octx, " ");
+
+ expr_print(expr->flagcmp.value, octx);
+ nft_print(octx, " / ");
+ expr_print(expr->flagcmp.mask, octx);
+}
+
+static void flagcmp_expr_clone(struct expr *new, const struct expr *expr)
+{
+ new->flagcmp.expr = expr_clone(expr->flagcmp.expr);
+ new->flagcmp.mask = expr_clone(expr->flagcmp.mask);
+ new->flagcmp.value = expr_clone(expr->flagcmp.value);
+}
+
+static void flagcmp_expr_destroy(struct expr *expr)
+{
+ expr_free(expr->flagcmp.expr);
+ expr_free(expr->flagcmp.mask);
+ expr_free(expr->flagcmp.value);
+}
+
+static const struct expr_ops flagcmp_expr_ops = {
+ .type = EXPR_FLAGCMP,
+ .name = "flags comparison",
+ .print = flagcmp_expr_print,
+ .json = flagcmp_expr_json,
+ .clone = flagcmp_expr_clone,
+ .destroy = flagcmp_expr_destroy,
+};
+
+struct expr *flagcmp_expr_alloc(const struct location *loc, enum ops op,
+ struct expr *match, struct expr *mask,
+ struct expr *value)
+{
+ struct expr *expr;
+
+ expr = expr_alloc(loc, EXPR_FLAGCMP, match->dtype, match->byteorder,
+ match->len);
+ expr->op = op;
+ expr->flagcmp.expr = match;
+ expr->flagcmp.mask = mask;
+ /* json output needs this operation for compatibility */
+ expr->flagcmp.mask->op = OP_OR;
+ expr->flagcmp.value = value;
+
return expr;
}
@@ -1172,6 +1491,7 @@ void range_expr_value_high(mpz_t rop, const struct expr *expr)
return mpz_set(rop, expr->value);
case EXPR_PREFIX:
range_expr_value_low(rop, expr->prefix);
+ assert(expr->len >= expr->prefix_len);
mpz_init_bitmask(tmp, expr->len - expr->prefix_len);
mpz_add(rop, rop, tmp);
mpz_clear(tmp);
@@ -1187,12 +1507,10 @@ void range_expr_value_high(mpz_t rop, const struct expr *expr)
}
}
-const struct expr_ops *expr_ops(const struct expr *e)
+static const struct expr_ops *__expr_ops_by_type(enum expr_types etype)
{
- switch (e->etype) {
- case EXPR_INVALID:
- BUG("Invalid expression ops requested");
- break;
+ switch (etype) {
+ case EXPR_INVALID: break;
case EXPR_VERDICT: return &verdict_expr_ops;
case EXPR_SYMBOL: return &symbol_expr_ops;
case EXPR_VARIABLE: return &variable_expr_ops;
@@ -1220,7 +1538,28 @@ const struct expr_ops *expr_ops(const struct expr *e)
case EXPR_RT: return &rt_expr_ops;
case EXPR_FIB: return &fib_expr_ops;
case EXPR_XFRM: return &xfrm_expr_ops;
+ case EXPR_SET_ELEM_CATCHALL: return &set_elem_catchall_expr_ops;
+ case EXPR_FLAGCMP: return &flagcmp_expr_ops;
}
- BUG("Unknown expression type %d\n", e->etype);
+ return NULL;
+}
+
+const struct expr_ops *expr_ops(const struct expr *e)
+{
+ const struct expr_ops *ops;
+
+ ops = __expr_ops_by_type(e->etype);
+ if (!ops)
+ BUG("Unknown expression type %d\n", e->etype);
+
+ return ops;
+}
+
+const struct expr_ops *expr_ops_by_type_u32(uint32_t value)
+{
+ if (value > EXPR_MAX)
+ return NULL;
+
+ return __expr_ops_by_type(value);
}
diff --git a/src/exthdr.c b/src/exthdr.c
index e1ec6f3d..60c7cd1e 100644
--- a/src/exthdr.c
+++ b/src/exthdr.c
@@ -10,11 +10,10 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <stddef.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
@@ -22,9 +21,33 @@
#include <headers.h>
#include <expression.h>
#include <statement.h>
+#include <sctp_chunk.h>
+
+static const struct exthdr_desc *exthdr_definitions[PROTO_DESC_MAX + 1] = {
+ [EXTHDR_DESC_HBH] = &exthdr_hbh,
+ [EXTHDR_DESC_RT] = &exthdr_rt,
+ [EXTHDR_DESC_RT0] = &exthdr_rt0,
+ [EXTHDR_DESC_RT2] = &exthdr_rt2,
+ [EXTHDR_DESC_SRH] = &exthdr_rt4,
+ [EXTHDR_DESC_FRAG] = &exthdr_frag,
+ [EXTHDR_DESC_DST] = &exthdr_dst,
+ [EXTHDR_DESC_MH] = &exthdr_mh,
+};
+
+static const struct exthdr_desc *exthdr_find_desc(enum exthdr_desc_id desc_id)
+{
+ if (desc_id >= EXTHDR_DESC_UNKNOWN &&
+ desc_id <= EXTHDR_DESC_MAX)
+ return exthdr_definitions[desc_id];
+
+ return NULL;
+}
static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx)
{
+ const char *name = expr->exthdr.desc ?
+ expr->exthdr.desc->name : "unknown-exthdr";
+
if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT) {
/* Offset calculation is a bit hacky at this point.
* There might be a tcp option one day with another
@@ -32,23 +55,42 @@ static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx)
*/
unsigned int offset = expr->exthdr.offset / 64;
- nft_print(octx, "tcp option %s", expr->exthdr.desc->name);
+ if (expr->exthdr.desc == NULL) {
+ if (expr->exthdr.offset == 0 &&
+ expr->exthdr.flags & NFT_EXTHDR_F_PRESENT) {
+ nft_print(octx, "tcp option %d", expr->exthdr.raw_type);
+ return;
+ }
+
+ nft_print(octx, "tcp option @%u,%u,%u", expr->exthdr.raw_type,
+ expr->exthdr.offset, expr->len);
+ return;
+ }
+
+ nft_print(octx, "tcp option %s", name);
if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
return;
if (offset)
nft_print(octx, "%d", offset);
nft_print(octx, " %s", expr->exthdr.tmpl->token);
} else if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) {
- nft_print(octx, "ip option %s", expr->exthdr.desc->name);
+ nft_print(octx, "ip option %s", name);
+ if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
+ return;
+ nft_print(octx, " %s", expr->exthdr.tmpl->token);
+ } else if (expr->exthdr.op == NFT_EXTHDR_OP_SCTP) {
+ nft_print(octx, "sctp chunk %s", expr->exthdr.desc->name);
if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
return;
nft_print(octx, " %s", expr->exthdr.tmpl->token);
+ } else if (expr->exthdr.op == NFT_EXTHDR_OP_DCCP) {
+ nft_print(octx, "dccp option %d", expr->exthdr.raw_type);
+ return;
} else {
if (expr->exthdr.flags & NFT_EXTHDR_F_PRESENT)
- nft_print(octx, "exthdr %s", expr->exthdr.desc->name);
+ nft_print(octx, "exthdr %s", name);
else {
- nft_print(octx, "%s %s",
- expr->exthdr.desc ? expr->exthdr.desc->name : "unknown-exthdr",
+ nft_print(octx, "%s %s", name,
expr->exthdr.tmpl->token);
}
}
@@ -59,6 +101,7 @@ static bool exthdr_expr_cmp(const struct expr *e1, const struct expr *e2)
return e1->exthdr.desc == e2->exthdr.desc &&
e1->exthdr.tmpl == e2->exthdr.tmpl &&
e1->exthdr.op == e2->exthdr.op &&
+ e1->exthdr.raw_type == e2->exthdr.raw_type &&
e1->exthdr.flags == e2->exthdr.flags;
}
@@ -69,6 +112,113 @@ static void exthdr_expr_clone(struct expr *new, const struct expr *expr)
new->exthdr.offset = expr->exthdr.offset;
new->exthdr.op = expr->exthdr.op;
new->exthdr.flags = expr->exthdr.flags;
+ new->exthdr.raw_type = expr->exthdr.raw_type;
+}
+
+#define NFTNL_UDATA_EXTHDR_DESC 0
+#define NFTNL_UDATA_EXTHDR_TYPE 1
+#define NFTNL_UDATA_EXTHDR_OP 2
+#define NFTNL_UDATA_EXTHDR_MAX 3
+
+static int exthdr_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_EXTHDR_DESC:
+ case NFTNL_UDATA_EXTHDR_TYPE:
+ case NFTNL_UDATA_EXTHDR_OP:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *exthdr_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_EXTHDR_MAX + 1] = {};
+ enum nft_exthdr_op op = NFT_EXTHDR_OP_IPV6;
+ const struct exthdr_desc *desc;
+ unsigned int type;
+ uint32_t desc_id;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ exthdr_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_EXTHDR_DESC] ||
+ !ud[NFTNL_UDATA_EXTHDR_TYPE])
+ return NULL;
+
+ if (ud[NFTNL_UDATA_EXTHDR_OP])
+ op = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXTHDR_OP]);
+
+ desc_id = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXTHDR_DESC]);
+ type = nftnl_udata_get_u32(ud[NFTNL_UDATA_EXTHDR_TYPE]);
+
+ switch (op) {
+ case NFT_EXTHDR_OP_IPV6:
+ desc = exthdr_find_desc(desc_id);
+
+ return exthdr_expr_alloc(&internal_location, desc, type);
+ case NFT_EXTHDR_OP_TCPOPT:
+ return tcpopt_expr_alloc(&internal_location,
+ desc_id, type);
+ case NFT_EXTHDR_OP_IPV4:
+ return ipopt_expr_alloc(&internal_location,
+ desc_id, type);
+ case NFT_EXTHDR_OP_SCTP:
+ return sctp_chunk_expr_alloc(&internal_location,
+ desc_id, type);
+ case NFT_EXTHDR_OP_DCCP:
+ return dccpopt_expr_alloc(&internal_location, type);
+ case __NFT_EXTHDR_OP_MAX:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+static unsigned int expr_exthdr_type(const struct exthdr_desc *desc,
+ const struct proto_hdr_template *tmpl)
+{
+ return (unsigned int)(tmpl - &desc->templates[0]);
+}
+
+static int exthdr_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ const struct proto_hdr_template *tmpl = expr->exthdr.tmpl;
+ const struct exthdr_desc *desc = expr->exthdr.desc;
+ unsigned int type = expr_exthdr_type(desc, tmpl);
+ enum nft_exthdr_op op = expr->exthdr.op;
+
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_TYPE, type);
+ switch (op) {
+ case NFT_EXTHDR_OP_IPV6:
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_DESC, desc->id);
+ break;
+ case NFT_EXTHDR_OP_TCPOPT:
+ case NFT_EXTHDR_OP_IPV4:
+ case NFT_EXTHDR_OP_SCTP:
+ case NFT_EXTHDR_OP_DCCP:
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_OP, op);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_EXTHDR_DESC, expr->exthdr.raw_type);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
}
const struct expr_ops exthdr_expr_ops = {
@@ -78,6 +228,8 @@ const struct expr_ops exthdr_expr_ops = {
.json = exthdr_expr_json,
.cmp = exthdr_expr_cmp,
.clone = exthdr_expr_clone,
+ .build_udata = exthdr_expr_build_udata,
+ .parse_udata = exthdr_expr_parse_udata,
};
static const struct proto_hdr_template exthdr_unknown_template =
@@ -98,7 +250,9 @@ struct expr *exthdr_expr_alloc(const struct location *loc,
expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
BYTEORDER_BIG_ENDIAN, tmpl->len);
expr->exthdr.desc = desc;
+ expr->exthdr.raw_type = desc ? desc->type : 0;
expr->exthdr.tmpl = tmpl;
+ expr->exthdr.offset = tmpl->offset;
return expr;
}
@@ -134,7 +288,7 @@ struct stmt *exthdr_stmt_alloc(const struct location *loc,
return stmt;
}
-static const struct exthdr_desc *exthdr_protocols[IPPROTO_MAX] = {
+static const struct exthdr_desc *exthdr_protocols[UINT8_MAX + 1] = {
[IPPROTO_HOPOPTS] = &exthdr_hbh,
[IPPROTO_ROUTING] = &exthdr_rt,
[IPPROTO_FRAGMENT] = &exthdr_frag,
@@ -175,18 +329,23 @@ void exthdr_init_raw(struct expr *expr, uint8_t type,
unsigned int i;
assert(expr->etype == EXPR_EXTHDR);
+ expr->exthdr.raw_type = type;
+
if (op == NFT_EXTHDR_OP_TCPOPT)
return tcpopt_init_raw(expr, type, offset, len, flags);
if (op == NFT_EXTHDR_OP_IPV4)
return ipopt_init_raw(expr, type, offset, len, flags, true);
+ if (op == NFT_EXTHDR_OP_SCTP)
+ return sctp_chunk_init_raw(expr, type, offset, len, flags);
+ if (op == NFT_EXTHDR_OP_DCCP)
+ return dccpopt_init_raw(expr, type, offset, len);
expr->len = len;
expr->exthdr.flags = flags;
expr->exthdr.offset = offset;
expr->exthdr.desc = NULL;
- if (type < array_size(exthdr_protocols))
- expr->exthdr.desc = exthdr_protocols[type];
+ expr->exthdr.desc = exthdr_protocols[type];
if (expr->exthdr.desc == NULL)
goto out;
@@ -228,16 +387,7 @@ static unsigned int mask_length(const struct expr *mask)
bool exthdr_find_template(struct expr *expr, const struct expr *mask, unsigned int *shift)
{
unsigned int off, mask_offset, mask_len;
-
- if (expr->exthdr.op != NFT_EXTHDR_OP_IPV4 &&
- expr->exthdr.tmpl != &exthdr_unknown_template)
- return false;
-
- /* In case we are handling tcp options instead of the default ipv6
- * extension headers.
- */
- if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT)
- return tcpopt_find_template(expr, mask, shift);
+ bool found;
mask_offset = mpz_scan1(mask->value, 0);
mask_len = mask_length(mask);
@@ -246,24 +396,31 @@ bool exthdr_find_template(struct expr *expr, const struct expr *mask, unsigned i
off += round_up(mask->len, BITS_PER_BYTE) - mask_len;
/* Handle ip options after the offset and mask have been calculated. */
- if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) {
- if (ipopt_find_template(expr, off, mask_len - mask_offset)) {
- *shift = mask_offset;
- return true;
- } else {
+ switch (expr->exthdr.op) {
+ case NFT_EXTHDR_OP_IPV4:
+ found = ipopt_find_template(expr, off, mask_len - mask_offset);
+ break;
+ case NFT_EXTHDR_OP_TCPOPT:
+ found = tcpopt_find_template(expr, off, mask_len - mask_offset);
+ break;
+ case NFT_EXTHDR_OP_IPV6:
+ exthdr_init_raw(expr, expr->exthdr.raw_type,
+ off, mask_len - mask_offset, expr->exthdr.op, 0);
+
+ /* still failed to find a template... Bug. */
+ if (expr->exthdr.tmpl == &exthdr_unknown_template)
return false;
- }
+ found = true;
+ break;
+ default:
+ found = false;
+ break;
}
- exthdr_init_raw(expr, expr->exthdr.desc->type,
- off, mask_len - mask_offset, expr->exthdr.op, 0);
-
- /* still failed to find a template... Bug. */
- if (expr->exthdr.tmpl == &exthdr_unknown_template)
- return false;
+ if (found)
+ *shift = mask_offset;
- *shift = mask_offset;
- return true;
+ return found;
}
#define HDR_TEMPLATE(__name, __dtype, __type, __member) \
@@ -281,6 +438,7 @@ bool exthdr_find_template(struct expr *expr, const struct expr *mask, unsigned i
const struct exthdr_desc exthdr_hbh = {
.name = "hbh",
+ .id = EXTHDR_DESC_HBH,
.type = IPPROTO_HOPOPTS,
.templates = {
[HBHHDR_NEXTHDR] = HBH_FIELD("nexthdr", ip6h_nxt, &inet_protocol_type),
@@ -294,8 +452,8 @@ const struct exthdr_desc exthdr_hbh = {
const struct exthdr_desc exthdr_rt2 = {
.name = "rt2",
+ .id = EXTHDR_DESC_RT2,
.type = IPPROTO_ROUTING,
- .proto_key = 2,
.templates = {
[RT2HDR_RESERVED] = {},
[RT2HDR_ADDR] = {},
@@ -307,8 +465,8 @@ const struct exthdr_desc exthdr_rt2 = {
const struct exthdr_desc exthdr_rt0 = {
.name = "rt0",
+ .id = EXTHDR_DESC_RT0,
.type = IPPROTO_ROUTING,
- .proto_key = 0,
.templates = {
[RT0HDR_RESERVED] = RT0_FIELD("reserved", ip6r0_reserved, &integer_type),
[RT0HDR_ADDR_1] = RT0_FIELD("addr[1]", ip6r0_addr[0], &ip6addr_type),
@@ -322,8 +480,8 @@ const struct exthdr_desc exthdr_rt0 = {
const struct exthdr_desc exthdr_rt4 = {
.name = "srh",
+ .id = EXTHDR_DESC_SRH,
.type = IPPROTO_ROUTING,
- .proto_key = 4,
.templates = {
[RT4HDR_LASTENT] = RT4_FIELD("last-entry", ip6r4_last_entry, &integer_type),
[RT4HDR_FLAGS] = RT4_FIELD("flags", ip6r4_flags, &integer_type),
@@ -340,8 +498,8 @@ const struct exthdr_desc exthdr_rt4 = {
const struct exthdr_desc exthdr_rt = {
.name = "rt",
+ .id = EXTHDR_DESC_RT,
.type = IPPROTO_ROUTING,
- .proto_key = -1,
#if 0
.protocol_key = RTHDR_TYPE,
.protocols = {
@@ -366,6 +524,7 @@ const struct exthdr_desc exthdr_rt = {
const struct exthdr_desc exthdr_frag = {
.name = "frag",
+ .id = EXTHDR_DESC_FRAG,
.type = IPPROTO_FRAGMENT,
.templates = {
[FRAGHDR_NEXTHDR] = FRAG_FIELD("nexthdr", ip6f_nxt, &inet_protocol_type),
@@ -392,6 +551,7 @@ const struct exthdr_desc exthdr_frag = {
const struct exthdr_desc exthdr_dst = {
.name = "dst",
+ .id = EXTHDR_DESC_DST,
.type = IPPROTO_DSTOPTS,
.templates = {
[DSTHDR_NEXTHDR] = DST_FIELD("nexthdr", ip6d_nxt, &inet_protocol_type),
@@ -438,6 +598,7 @@ const struct datatype mh_type_type = {
const struct exthdr_desc exthdr_mh = {
.name = "mh",
+ .id = EXTHDR_DESC_MH,
.type = IPPROTO_MH,
.templates = {
[MHHDR_NEXTHDR] = MH_FIELD("nexthdr", ip6mh_proto, &inet_protocol_type),
diff --git a/src/fib.c b/src/fib.c
index f2bfef1d..e95271c9 100644
--- a/src/fib.c
+++ b/src/fib.c
@@ -1,20 +1,21 @@
/*
* FIB expression.
*
- * Copyright (c) Red Hat GmbH. Author: Florian Westphal <fw@strlen.de>
+ * Copyright (c) Red Hat GmbH. Author: Florian Westphal <fw@strlen.de>
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
*/
+#include <nft.h>
+
#include <nftables.h>
#include <erec.h>
#include <expression.h>
#include <datatype.h>
#include <gmputil.h>
#include <utils.h>
-#include <string.h>
#include <fib.h>
#include <linux/rtnetlink.h>
@@ -91,7 +92,7 @@ static void fib_expr_print(const struct expr *expr, struct output_ctx *octx)
static bool fib_expr_cmp(const struct expr *e1, const struct expr *e2)
{
- return e1->fib.result == e2->fib.result &&
+ return e1->fib.result == e2->fib.result &&
e1->fib.flags == e2->fib.flags;
}
@@ -101,6 +102,60 @@ static void fib_expr_clone(struct expr *new, const struct expr *expr)
new->fib.flags= expr->fib.flags;
}
+#define NFTNL_UDATA_FIB_RESULT 0
+#define NFTNL_UDATA_FIB_FLAGS 1
+#define NFTNL_UDATA_FIB_MAX 2
+
+static int fib_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_FIB_RESULT, expr->fib.result);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_FIB_FLAGS, expr->fib.flags);
+
+ return 0;
+}
+
+static int fib_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_FIB_RESULT:
+ case NFTNL_UDATA_FIB_FLAGS:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *fib_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_FIB_MAX + 1] = {};
+ uint32_t flags, result;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ fib_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_FIB_RESULT] ||
+ !ud[NFTNL_UDATA_FIB_FLAGS])
+ return NULL;
+
+ result = nftnl_udata_get_u32(ud[NFTNL_UDATA_FIB_RESULT]);
+ flags = nftnl_udata_get_u32(ud[NFTNL_UDATA_FIB_FLAGS]);
+
+ return fib_expr_alloc(&internal_location, flags, result);
+}
+
const struct expr_ops fib_expr_ops = {
.type = EXPR_FIB,
.name = "fib",
@@ -108,6 +163,8 @@ const struct expr_ops fib_expr_ops = {
.json = fib_expr_json,
.cmp = fib_expr_cmp,
.clone = fib_expr_clone,
+ .parse_udata = fib_expr_parse_udata,
+ .build_udata = fib_expr_build_udata,
};
struct expr *fib_expr_alloc(const struct location *loc,
diff --git a/src/gmputil.c b/src/gmputil.c
index b356460f..b4529259 100644
--- a/src/gmputil.c
+++ b/src/gmputil.c
@@ -8,12 +8,12 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <stddef.h>
-#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
-#include <string.h>
#include <nftables.h>
#include <datatype.h>
@@ -184,7 +184,7 @@ int mpz_vfprintf(FILE *fp, const char *f, va_list args)
str = mpz_get_str(NULL, base, *value);
ok = str && fwrite(str, 1, len, fp) == len;
- free(str);
+ nft_gmp_free(str);
if (!ok)
return -1;
@@ -197,12 +197,21 @@ int mpz_vfprintf(FILE *fp, const char *f, va_list args)
}
#endif
-static void *gmp_xrealloc(void *ptr, size_t old_size, size_t new_size)
+void nft_gmp_free(void *ptr)
{
- return xrealloc(ptr, new_size);
-}
+ void (*free_fcn)(void *, size_t);
-void gmp_init(void)
-{
- mp_set_memory_functions(xmalloc, gmp_xrealloc, NULL);
+ /* When we get allocated memory from gmp, it was allocated via the
+ * allocator() from mp_set_memory_functions(). We should pair the free
+ * with the corresponding free function, which we get via
+ * mp_get_memory_functions().
+ *
+ * It's not clear what the correct blk_size is. The default allocator
+ * function of gmp just wraps free() and ignores the extra argument.
+ * Assume 0 is fine.
+ */
+
+ mp_get_memory_functions(NULL, NULL, &free_fcn);
+
+ (*free_fcn)(ptr, 0);
}
diff --git a/src/hash.c b/src/hash.c
index 08e09099..1c8c00aa 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -4,10 +4,12 @@
* Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
*/
+#include <nft.h>
+
#include <nftables.h>
#include <expression.h>
#include <datatype.h>
@@ -61,6 +63,76 @@ static void hash_expr_destroy(struct expr *expr)
expr_free(expr->hash.expr);
}
+#define NFTNL_UDATA_HASH_TYPE 0
+#define NFTNL_UDATA_HASH_OFFSET 1
+#define NFTNL_UDATA_HASH_MOD 2
+#define NFTNL_UDATA_HASH_SEED 3
+#define NFTNL_UDATA_HASH_SEED_SET 4
+#define NFTNL_UDATA_HASH_MAX 5
+
+static int hash_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_HASH_TYPE, expr->hash.type);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_HASH_OFFSET, expr->hash.offset);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_HASH_MOD, expr->hash.mod);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_HASH_SEED, expr->hash.seed);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_HASH_SEED_SET, expr->hash.seed_set);
+
+ return 0;
+}
+
+static int hash_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_HASH_TYPE:
+ case NFTNL_UDATA_HASH_OFFSET:
+ case NFTNL_UDATA_HASH_SEED:
+ case NFTNL_UDATA_HASH_SEED_SET:
+ case NFTNL_UDATA_HASH_MOD:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *hash_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_HASH_MAX + 1] = {};
+ uint32_t type, seed, seed_set, mod, offset;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ hash_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_HASH_TYPE] ||
+ !ud[NFTNL_UDATA_HASH_OFFSET] ||
+ !ud[NFTNL_UDATA_HASH_SEED] ||
+ !ud[NFTNL_UDATA_HASH_MOD] ||
+ !ud[NFTNL_UDATA_HASH_SEED_SET])
+ return NULL;
+
+ type = nftnl_udata_get_u32(ud[NFTNL_UDATA_HASH_TYPE]);
+ offset = nftnl_udata_get_u32(ud[NFTNL_UDATA_HASH_OFFSET]);
+ seed = nftnl_udata_get_u32(ud[NFTNL_UDATA_HASH_SEED]);
+ seed_set = nftnl_udata_get_u32(ud[NFTNL_UDATA_HASH_SEED_SET]);
+ mod = nftnl_udata_get_u32(ud[NFTNL_UDATA_HASH_MOD]);
+
+ return hash_expr_alloc(&internal_location, mod, seed_set, seed,
+ offset, type);
+}
+
const struct expr_ops hash_expr_ops = {
.type = EXPR_HASH,
.name = "hash",
@@ -69,6 +141,8 @@ const struct expr_ops hash_expr_ops = {
.cmp = hash_expr_cmp,
.clone = hash_expr_clone,
.destroy = hash_expr_destroy,
+ .parse_udata = hash_expr_parse_udata,
+ .build_udata = hash_expr_build_udata,
};
struct expr *hash_expr_alloc(const struct location *loc,
diff --git a/src/iface.c b/src/iface.c
index d0e1834c..428acaae 100644
--- a/src/iface.c
+++ b/src/iface.c
@@ -2,15 +2,15 @@
* Copyright (c) 2015 Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
*/
+#include <nft.h>
+
#include <stdio.h>
-#include <stdlib.h>
#include <net/if.h>
#include <time.h>
-#include <string.h>
#include <errno.h>
#include <libmnl/libmnl.h>
@@ -59,13 +59,13 @@ static int data_cb(const struct nlmsghdr *nlh, void *data)
return MNL_CB_OK;
}
-void iface_cache_update(void)
+static int iface_mnl_talk(struct mnl_socket *nl, uint32_t portid)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
- struct mnl_socket *nl;
struct nlmsghdr *nlh;
struct rtgenmsg *rt;
- uint32_t seq, portid;
+ bool eintr = false;
+ uint32_t seq;
int ret;
nlh = mnl_nlmsg_put_header(buf);
@@ -75,6 +75,38 @@ void iface_cache_update(void)
rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
rt->rtgen_family = AF_PACKET;
+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
+ return -1;
+
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ while (ret > 0) {
+ ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL);
+ if (ret == 0)
+ break;
+ if (ret < 0) {
+ if (errno != EINTR)
+ return ret;
+
+ /* process all pending messages before reporting EINTR */
+ eintr = true;
+ }
+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
+ }
+
+ if (eintr) {
+ ret = -1;
+ errno = EINTR;
+ }
+
+ return ret;
+}
+
+void iface_cache_update(void)
+{
+ struct mnl_socket *nl;
+ uint32_t portid;
+ int ret;
+
nl = mnl_socket_open(NETLINK_ROUTE);
if (nl == NULL)
netlink_init_error();
@@ -84,16 +116,10 @@ void iface_cache_update(void)
portid = mnl_socket_get_portid(nl);
- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
- netlink_init_error();
+ do {
+ ret = iface_mnl_talk(nl, portid);
+ } while (ret < 0 && errno == EINTR);
- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
- while (ret > 0) {
- ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL);
- if (ret <= MNL_CB_STOP)
- break;
- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
- }
if (ret == -1)
netlink_init_error();
diff --git a/src/intervals.c b/src/intervals.c
new file mode 100644
index 00000000..6c3f36fe
--- /dev/null
+++ b/src/intervals.c
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 2022 Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <nftables.h>
+#include <expression.h>
+#include <intervals.h>
+#include <rule.h>
+
+static void set_to_range(struct expr *init);
+
+static void setelem_expr_to_range(struct expr *expr)
+{
+ unsigned char data[sizeof(struct in6_addr) * BITS_PER_BYTE];
+ struct expr *key, *value;
+ mpz_t rop;
+
+ assert(expr->etype == EXPR_SET_ELEM);
+
+ switch (expr->key->etype) {
+ case EXPR_SET_ELEM_CATCHALL:
+ case EXPR_RANGE:
+ break;
+ case EXPR_PREFIX:
+ if (expr->key->prefix->etype != EXPR_VALUE)
+ BUG("Prefix for unexpected type %d", expr->key->prefix->etype);
+
+ mpz_init(rop);
+ mpz_bitmask(rop, expr->key->len - expr->key->prefix_len);
+ if (expr_basetype(expr)->type == TYPE_STRING)
+ mpz_switch_byteorder(expr->key->prefix->value, expr->len / BITS_PER_BYTE);
+
+ mpz_ior(rop, rop, expr->key->prefix->value);
+ mpz_export_data(data, rop, expr->key->prefix->byteorder,
+ expr->key->prefix->len / BITS_PER_BYTE);
+ mpz_clear(rop);
+ value = constant_expr_alloc(&expr->location,
+ expr->key->prefix->dtype,
+ expr->key->prefix->byteorder,
+ expr->key->prefix->len, data);
+ key = range_expr_alloc(&expr->location,
+ expr_get(expr->key->prefix),
+ value);
+ expr_free(expr->key);
+ expr->key = key;
+ break;
+ case EXPR_VALUE:
+ if (expr_basetype(expr)->type == TYPE_STRING)
+ mpz_switch_byteorder(expr->key->value, expr->len / BITS_PER_BYTE);
+
+ key = range_expr_alloc(&expr->location,
+ expr_clone(expr->key),
+ expr_get(expr->key));
+ expr_free(expr->key);
+ expr->key = key;
+ break;
+ default:
+ BUG("unhandled key type %d\n", expr->key->etype);
+ }
+}
+
+struct set_automerge_ctx {
+ struct set *set;
+ struct expr *init;
+ struct expr *purge;
+ unsigned int debug_mask;
+};
+
+static void purge_elem(struct set_automerge_ctx *ctx, struct expr *i)
+{
+ if (ctx->debug_mask & NFT_DEBUG_SEGTREE) {
+ pr_gmp_debug("remove: [%Zx-%Zx]\n",
+ i->key->left->value,
+ i->key->right->value);
+ }
+ list_move_tail(&i->list, &ctx->purge->expressions);
+}
+
+static void remove_overlapping_range(struct set_automerge_ctx *ctx,
+ struct expr *prev, struct expr *i)
+{
+ if (i->flags & EXPR_F_KERNEL) {
+ purge_elem(ctx, i);
+ return;
+ }
+ list_del(&i->list);
+ expr_free(i);
+ ctx->init->size--;
+}
+
+struct range {
+ mpz_t low;
+ mpz_t high;
+};
+
+static bool merge_ranges(struct set_automerge_ctx *ctx,
+ struct expr *prev, struct expr *i,
+ struct range *prev_range, struct range *range)
+{
+ if (prev->flags & EXPR_F_KERNEL) {
+ purge_elem(ctx, prev);
+ expr_free(i->key->left);
+ i->key->left = expr_get(prev->key->left);
+ mpz_set(prev_range->high, range->high);
+ return true;
+ } else if (i->flags & EXPR_F_KERNEL) {
+ purge_elem(ctx, i);
+ expr_free(prev->key->right);
+ prev->key->right = expr_get(i->key->right);
+ mpz_set(prev_range->high, range->high);
+ } else {
+ expr_free(prev->key->right);
+ prev->key->right = expr_get(i->key->right);
+ mpz_set(prev_range->high, range->high);
+ list_del(&i->list);
+ expr_free(i);
+ ctx->init->size--;
+ }
+ return false;
+}
+
+static void set_sort_splice(struct expr *init, struct set *set)
+{
+ struct set *existing_set = set->existing_set;
+
+ set_to_range(init);
+ list_expr_sort(&init->expressions);
+
+ if (!existing_set || existing_set->errors)
+ return;
+
+ if (existing_set->init) {
+ set_to_range(existing_set->init);
+ list_splice_sorted(&existing_set->init->expressions,
+ &init->expressions);
+ init_list_head(&existing_set->init->expressions);
+ } else {
+ existing_set->init = set_expr_alloc(&internal_location, set);
+ }
+}
+
+static void setelem_automerge(struct set_automerge_ctx *ctx)
+{
+ struct expr *i, *next, *prev = NULL;
+ struct range range, prev_range;
+ mpz_t rop;
+
+ mpz_init(prev_range.low);
+ mpz_init(prev_range.high);
+ mpz_init(range.low);
+ mpz_init(range.high);
+ mpz_init(rop);
+
+ list_for_each_entry_safe(i, next, &ctx->init->expressions, list) {
+ if (i->key->etype == EXPR_SET_ELEM_CATCHALL)
+ continue;
+
+ range_expr_value_low(range.low, i);
+ range_expr_value_high(range.high, i);
+
+ if (!prev) {
+ prev = i;
+ mpz_set(prev_range.low, range.low);
+ mpz_set(prev_range.high, range.high);
+ continue;
+ }
+
+ if (mpz_cmp(prev_range.low, range.low) <= 0 &&
+ mpz_cmp(prev_range.high, range.high) >= 0) {
+ remove_overlapping_range(ctx, prev, i);
+ continue;
+ } else if (mpz_cmp(range.low, prev_range.high) <= 0) {
+ if (merge_ranges(ctx, prev, i, &prev_range, &range))
+ prev = i;
+ continue;
+ } else if (ctx->set->automerge) {
+ mpz_sub(rop, range.low, prev_range.high);
+ /* two contiguous ranges */
+ if (mpz_cmp_ui(rop, 1) == 0) {
+ if (merge_ranges(ctx, prev, i, &prev_range, &range))
+ prev = i;
+ continue;
+ }
+ }
+
+ prev = i;
+ mpz_set(prev_range.low, range.low);
+ mpz_set(prev_range.high, range.high);
+ }
+
+ mpz_clear(prev_range.low);
+ mpz_clear(prev_range.high);
+ mpz_clear(range.low);
+ mpz_clear(range.high);
+ mpz_clear(rop);
+}
+
+static struct expr *interval_expr_key(struct expr *i)
+{
+ struct expr *elem;
+
+ switch (i->etype) {
+ case EXPR_MAPPING:
+ elem = i->left;
+ break;
+ case EXPR_SET_ELEM:
+ elem = i;
+ break;
+ default:
+ BUG("unhandled expression type %d\n", i->etype);
+ return NULL;
+ }
+
+ return elem;
+}
+
+static void set_to_range(struct expr *init)
+{
+ struct expr *i, *elem;
+
+ list_for_each_entry(i, &init->expressions, list) {
+ elem = interval_expr_key(i);
+ setelem_expr_to_range(elem);
+ }
+}
+
+int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
+ struct expr *init, unsigned int debug_mask)
+{
+ struct set *existing_set = set->existing_set;
+ struct set_automerge_ctx ctx = {
+ .set = set,
+ .init = init,
+ .debug_mask = debug_mask,
+ };
+ struct expr *i, *next, *clone;
+ struct cmd *purge_cmd;
+ struct handle h = {};
+
+ if (set->flags & NFT_SET_MAP) {
+ set_to_range(init);
+ list_expr_sort(&init->expressions);
+ return 0;
+ }
+
+ set_sort_splice(init, set);
+
+ ctx.purge = set_expr_alloc(&internal_location, set);
+
+ setelem_automerge(&ctx);
+
+ list_for_each_entry_safe(i, next, &init->expressions, list) {
+ if (i->flags & EXPR_F_KERNEL) {
+ list_move_tail(&i->list, &existing_set->init->expressions);
+ } else if (existing_set) {
+ if (debug_mask & NFT_DEBUG_SEGTREE) {
+ pr_gmp_debug("add: [%Zx-%Zx]\n",
+ i->key->left->value, i->key->right->value);
+ }
+ clone = expr_clone(i);
+ clone->flags |= EXPR_F_KERNEL;
+ list_add_tail(&clone->list, &existing_set->init->expressions);
+ }
+ }
+
+ if (list_empty(&ctx.purge->expressions)) {
+ expr_free(ctx.purge);
+ return 0;
+ }
+
+ handle_merge(&h, &set->handle);
+ purge_cmd = cmd_alloc(CMD_DELETE, CMD_OBJ_ELEMENTS, &h, &init->location, ctx.purge);
+ purge_cmd->elem.set = set_get(set);
+ list_add_tail(&purge_cmd->list, &cmd->list);
+
+ return 0;
+}
+
+static void remove_elem(struct expr *prev, struct set *set, struct expr *purge)
+{
+ struct expr *clone;
+
+ if (prev->flags & EXPR_F_KERNEL) {
+ clone = expr_clone(prev);
+ list_move_tail(&clone->list, &purge->expressions);
+ }
+}
+
+static void __adjust_elem_left(struct set *set, struct expr *prev, struct expr *i)
+{
+ prev->flags &= ~EXPR_F_KERNEL;
+ expr_free(prev->key->left);
+ prev->key->left = expr_get(i->key->right);
+ mpz_add_ui(prev->key->left->value, prev->key->left->value, 1);
+ list_move(&prev->list, &set->existing_set->init->expressions);
+}
+
+static void adjust_elem_left(struct set *set, struct expr *prev, struct expr *i,
+ struct expr *purge)
+{
+ remove_elem(prev, set, purge);
+ __adjust_elem_left(set, prev, i);
+
+ list_del(&i->list);
+ expr_free(i);
+}
+
+static void __adjust_elem_right(struct set *set, struct expr *prev, struct expr *i)
+{
+ prev->flags &= ~EXPR_F_KERNEL;
+ expr_free(prev->key->right);
+ prev->key->right = expr_get(i->key->left);
+ mpz_sub_ui(prev->key->right->value, prev->key->right->value, 1);
+ list_move(&prev->list, &set->existing_set->init->expressions);
+}
+
+static void adjust_elem_right(struct set *set, struct expr *prev, struct expr *i,
+ struct expr *purge)
+{
+ remove_elem(prev, set, purge);
+ __adjust_elem_right(set, prev, i);
+
+ list_del(&i->list);
+ expr_free(i);
+}
+
+static void split_range(struct set *set, struct expr *prev, struct expr *i,
+ struct expr *purge)
+{
+ struct expr *clone;
+
+ if (prev->flags & EXPR_F_KERNEL) {
+ clone = expr_clone(prev);
+ list_move_tail(&clone->list, &purge->expressions);
+ }
+
+ prev->flags &= ~EXPR_F_KERNEL;
+ clone = expr_clone(prev);
+ expr_free(clone->key->left);
+ clone->key->left = expr_get(i->key->right);
+ mpz_add_ui(clone->key->left->value, i->key->right->value, 1);
+ list_add_tail(&clone->list, &set->existing_set->init->expressions);
+
+ expr_free(prev->key->right);
+ prev->key->right = expr_get(i->key->left);
+ mpz_sub_ui(prev->key->right->value, i->key->left->value, 1);
+ list_move(&prev->list, &set->existing_set->init->expressions);
+
+ list_del(&i->list);
+ expr_free(i);
+}
+
+static int setelem_adjust(struct set *set, struct expr *purge,
+ struct range *prev_range, struct range *range,
+ struct expr *prev, struct expr *i)
+{
+ if (mpz_cmp(prev_range->low, range->low) == 0 &&
+ mpz_cmp(prev_range->high, range->high) > 0) {
+ if (i->flags & EXPR_F_REMOVE)
+ adjust_elem_left(set, prev, i, purge);
+ } else if (mpz_cmp(prev_range->low, range->low) < 0 &&
+ mpz_cmp(prev_range->high, range->high) == 0) {
+ if (i->flags & EXPR_F_REMOVE)
+ adjust_elem_right(set, prev, i, purge);
+ } else if (mpz_cmp(prev_range->low, range->low) < 0 &&
+ mpz_cmp(prev_range->high, range->high) > 0) {
+ if (i->flags & EXPR_F_REMOVE)
+ split_range(set, prev, i, purge);
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int setelem_delete(struct list_head *msgs, struct set *set,
+ struct expr *purge, struct expr *elems,
+ unsigned int debug_mask)
+{
+ struct expr *i, *next, *prev = NULL;
+ struct range range, prev_range;
+ int err = 0;
+ mpz_t rop;
+
+ mpz_init(prev_range.low);
+ mpz_init(prev_range.high);
+ mpz_init(range.low);
+ mpz_init(range.high);
+ mpz_init(rop);
+
+ list_for_each_entry_safe(i, next, &elems->expressions, list) {
+ if (i->key->etype == EXPR_SET_ELEM_CATCHALL)
+ continue;
+
+ range_expr_value_low(range.low, i);
+ range_expr_value_high(range.high, i);
+
+ if (!prev && i->flags & EXPR_F_REMOVE) {
+ expr_error(msgs, i, "element does not exist");
+ err = -1;
+ goto err;
+ }
+
+ if (!(i->flags & EXPR_F_REMOVE)) {
+ prev = i;
+ mpz_set(prev_range.low, range.low);
+ mpz_set(prev_range.high, range.high);
+ continue;
+ }
+
+ if (mpz_cmp(prev_range.low, range.low) == 0 &&
+ mpz_cmp(prev_range.high, range.high) == 0) {
+ if (i->flags & EXPR_F_REMOVE) {
+ if (prev->flags & EXPR_F_KERNEL)
+ list_move_tail(&prev->list, &purge->expressions);
+
+ list_del(&i->list);
+ expr_free(i);
+ }
+ } else if (set->automerge) {
+ if (setelem_adjust(set, purge, &prev_range, &range, prev, i) < 0) {
+ expr_error(msgs, i, "element does not exist");
+ err = -1;
+ goto err;
+ }
+ } else if (i->flags & EXPR_F_REMOVE) {
+ expr_error(msgs, i, "element does not exist");
+ err = -1;
+ goto err;
+ }
+ prev = NULL;
+ }
+err:
+ mpz_clear(prev_range.low);
+ mpz_clear(prev_range.high);
+ mpz_clear(range.low);
+ mpz_clear(range.high);
+ mpz_clear(rop);
+
+ return err;
+}
+
+static void automerge_delete(struct list_head *msgs, struct set *set,
+ struct expr *init, unsigned int debug_mask)
+{
+ struct set_automerge_ctx ctx = {
+ .set = set,
+ .init = init,
+ .debug_mask = debug_mask,
+ };
+
+ ctx.purge = set_expr_alloc(&internal_location, set);
+ list_expr_sort(&init->expressions);
+ setelem_automerge(&ctx);
+ expr_free(ctx.purge);
+}
+
+static int __set_delete(struct list_head *msgs, struct expr *i, struct set *set,
+ struct expr *init, struct set *existing_set,
+ unsigned int debug_mask)
+{
+ i->flags |= EXPR_F_REMOVE;
+ list_move_tail(&i->list, &existing_set->init->expressions);
+ list_expr_sort(&existing_set->init->expressions);
+
+ return setelem_delete(msgs, set, init, existing_set->init, debug_mask);
+}
+
+/* detection for unexisting intervals already exists in Linux kernels >= 5.7. */
+int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set,
+ struct expr *init, unsigned int debug_mask)
+{
+ struct set *existing_set = set->existing_set;
+ struct expr *i, *next, *add, *clone;
+ struct handle h = {};
+ struct cmd *add_cmd;
+ LIST_HEAD(del_list);
+ int err;
+
+ set_to_range(init);
+ if (set->automerge)
+ automerge_delete(msgs, set, init, debug_mask);
+
+ if (existing_set->init) {
+ set_to_range(existing_set->init);
+ } else {
+ existing_set->init = set_expr_alloc(&internal_location, set);
+ }
+
+ list_splice_init(&init->expressions, &del_list);
+
+ list_for_each_entry_safe(i, next, &del_list, list) {
+ err = __set_delete(msgs, i, set, init, existing_set, debug_mask);
+ if (err < 0) {
+ list_splice(&del_list, &init->expressions);
+ return err;
+ }
+ }
+
+ add = set_expr_alloc(&internal_location, set);
+ list_for_each_entry(i, &existing_set->init->expressions, list) {
+ if (!(i->flags & EXPR_F_KERNEL)) {
+ clone = expr_clone(i);
+ list_add_tail(&clone->list, &add->expressions);
+ i->flags |= EXPR_F_KERNEL;
+ }
+ }
+
+ if (debug_mask & NFT_DEBUG_SEGTREE) {
+ list_for_each_entry(i, &init->expressions, list)
+ pr_gmp_debug("remove: [%Zx-%Zx]\n",
+ i->key->left->value, i->key->right->value);
+ list_for_each_entry(i, &add->expressions, list)
+ pr_gmp_debug("add: [%Zx-%Zx]\n",
+ i->key->left->value, i->key->right->value);
+ list_for_each_entry(i, &existing_set->init->expressions, list)
+ pr_gmp_debug("existing: [%Zx-%Zx]\n",
+ i->key->left->value, i->key->right->value);
+ }
+
+ if (list_empty(&add->expressions)) {
+ expr_free(add);
+ return 0;
+ }
+
+ handle_merge(&h, &cmd->handle);
+ add_cmd = cmd_alloc(CMD_ADD, CMD_OBJ_ELEMENTS, &h, &cmd->location, add);
+ add_cmd->elem.set = set_get(set);
+ list_add(&add_cmd->list, &cmd->list);
+
+ return 0;
+}
+
+static int setelem_overlap(struct list_head *msgs, struct set *set,
+ struct expr *init)
+{
+ struct expr *i, *next, *elem, *prev = NULL;
+ struct range range, prev_range;
+ int err = 0;
+ mpz_t rop;
+
+ mpz_init(prev_range.low);
+ mpz_init(prev_range.high);
+ mpz_init(range.low);
+ mpz_init(range.high);
+ mpz_init(rop);
+
+ list_for_each_entry_safe(elem, next, &init->expressions, list) {
+ i = interval_expr_key(elem);
+
+ if (i->key->etype == EXPR_SET_ELEM_CATCHALL)
+ continue;
+
+ range_expr_value_low(range.low, i);
+ range_expr_value_high(range.high, i);
+
+ if (!prev) {
+ prev = elem;
+ mpz_set(prev_range.low, range.low);
+ mpz_set(prev_range.high, range.high);
+ continue;
+ }
+
+ if (mpz_cmp(prev_range.low, range.low) == 0 &&
+ mpz_cmp(prev_range.high, range.high) == 0)
+ goto next;
+
+ if (mpz_cmp(prev_range.low, range.low) <= 0 &&
+ mpz_cmp(prev_range.high, range.high) >= 0) {
+ if (prev->flags & EXPR_F_KERNEL)
+ expr_error(msgs, i, "interval overlaps with an existing one");
+ else if (elem->flags & EXPR_F_KERNEL)
+ expr_error(msgs, prev, "interval overlaps with an existing one");
+ else
+ expr_binary_error(msgs, i, prev,
+ "conflicting intervals specified");
+ err = -1;
+ goto err_out;
+ } else if (mpz_cmp(range.low, prev_range.high) <= 0) {
+ if (prev->flags & EXPR_F_KERNEL)
+ expr_error(msgs, i, "interval overlaps with an existing one");
+ else if (elem->flags & EXPR_F_KERNEL)
+ expr_error(msgs, prev, "interval overlaps with an existing one");
+ else
+ expr_binary_error(msgs, i, prev,
+ "conflicting intervals specified");
+ err = -1;
+ goto err_out;
+ }
+next:
+ prev = elem;
+ mpz_set(prev_range.low, range.low);
+ mpz_set(prev_range.high, range.high);
+ }
+
+err_out:
+ mpz_clear(prev_range.low);
+ mpz_clear(prev_range.high);
+ mpz_clear(range.low);
+ mpz_clear(range.high);
+ mpz_clear(rop);
+
+ return err;
+}
+
+/* overlap detection for intervals already exists in Linux kernels >= 5.7. */
+int set_overlap(struct list_head *msgs, struct set *set, struct expr *init)
+{
+ struct set *existing_set = set->existing_set;
+ struct expr *i, *n, *clone;
+ int err;
+
+ set_sort_splice(init, set);
+
+ err = setelem_overlap(msgs, set, init);
+
+ list_for_each_entry_safe(i, n, &init->expressions, list) {
+ if (i->flags & EXPR_F_KERNEL)
+ list_move_tail(&i->list, &existing_set->init->expressions);
+ else if (existing_set) {
+ clone = expr_clone(i);
+ clone->flags |= EXPR_F_KERNEL;
+ list_add_tail(&clone->list, &existing_set->init->expressions);
+ }
+ }
+
+ return err;
+}
+
+static bool segtree_needs_first_segment(const struct set *set,
+ const struct expr *init, bool add)
+{
+ if (add && !set->root) {
+ /* Add the first segment in four situations:
+ *
+ * 1) This is an anonymous set.
+ * 2) This set exists and it is empty.
+ * 3) New empty set and, separately, new elements are added.
+ * 4) This set is created with a number of initial elements.
+ */
+ if ((set_is_anonymous(set->flags)) ||
+ (set->init && set->init->size == 0) ||
+ (set->init == NULL && init) ||
+ (set->init == init)) {
+ return true;
+ }
+ }
+ /* This is an update for a set that already contains elements, so don't
+ * add the first non-matching elements otherwise we hit EEXIST.
+ */
+ return false;
+}
+
+int set_to_intervals(const struct set *set, struct expr *init, bool add)
+{
+ struct expr *i, *n, *prev = NULL, *elem, *newelem = NULL, *root, *expr;
+ LIST_HEAD(intervals);
+ uint32_t flags;
+ mpz_t p, q;
+
+ mpz_init2(p, set->key->len);
+ mpz_init2(q, set->key->len);
+
+ list_for_each_entry_safe(i, n, &init->expressions, list) {
+ flags = 0;
+
+ elem = interval_expr_key(i);
+
+ if (elem->key->etype == EXPR_SET_ELEM_CATCHALL)
+ continue;
+
+ if (!prev && segtree_needs_first_segment(set, init, add) &&
+ mpz_cmp_ui(elem->key->left->value, 0)) {
+ mpz_set_ui(p, 0);
+ expr = constant_expr_alloc(&internal_location,
+ set->key->dtype,
+ set->key->byteorder,
+ set->key->len, NULL);
+ mpz_set(expr->value, p);
+ root = set_elem_expr_alloc(&internal_location, expr);
+ if (i->etype == EXPR_MAPPING) {
+ root = mapping_expr_alloc(&internal_location,
+ root,
+ expr_get(i->right));
+ }
+ root->flags |= EXPR_F_INTERVAL_END;
+ list_add(&root->list, &intervals);
+ init->size++;
+ }
+
+ if (newelem) {
+ mpz_set(p, interval_expr_key(newelem)->key->value);
+ if (set->key->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(p, set->key->len / BITS_PER_BYTE);
+
+ if (!(set->flags & NFT_SET_ANONYMOUS) ||
+ mpz_cmp(p, elem->key->left->value) != 0)
+ list_add_tail(&newelem->list, &intervals);
+ else
+ expr_free(newelem);
+ }
+ newelem = NULL;
+
+ if (mpz_scan0(elem->key->right->value, 0) != set->key->len) {
+ mpz_add_ui(p, elem->key->right->value, 1);
+ expr = constant_expr_alloc(&elem->key->location, set->key->dtype,
+ set->key->byteorder, set->key->len,
+ NULL);
+ mpz_set(expr->value, p);
+ if (set->key->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(expr->value, set->key->len / BITS_PER_BYTE);
+
+ newelem = set_elem_expr_alloc(&expr->location, expr);
+ if (i->etype == EXPR_MAPPING) {
+ newelem = mapping_expr_alloc(&expr->location,
+ newelem,
+ expr_get(i->right));
+ }
+ newelem->flags |= EXPR_F_INTERVAL_END;
+ } else {
+ flags = NFTNL_SET_ELEM_F_INTERVAL_OPEN;
+ }
+
+ expr = constant_expr_alloc(&elem->key->location, set->key->dtype,
+ set->key->byteorder, set->key->len, NULL);
+
+ mpz_set(expr->value, elem->key->left->value);
+ if (set->key->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(expr->value, set->key->len / BITS_PER_BYTE);
+
+ expr_free(elem->key);
+ elem->key = expr;
+ i->elem_flags |= flags;
+ init->size++;
+ list_move_tail(&i->list, &intervals);
+
+ prev = i;
+ }
+
+ if (newelem)
+ list_add_tail(&newelem->list, &intervals);
+
+ list_splice_init(&intervals, &init->expressions);
+
+ mpz_clear(p);
+ mpz_clear(q);
+
+ return 0;
+}
diff --git a/src/ipopt.c b/src/ipopt.c
index b3d0279d..37f779d4 100644
--- a/src/ipopt.c
+++ b/src/ipopt.c
@@ -1,4 +1,5 @@
-#include <stdint.h>
+#include <nft.h>
+
#include <netinet/in.h>
#include <netinet/ip.h>
@@ -66,27 +67,8 @@ const struct exthdr_desc *ipopt_protocols[UINT8_MAX] = {
[IPOPT_RA] = &ipopt_ra,
};
-static unsigned int calc_offset(const struct exthdr_desc *desc,
- const struct proto_hdr_template *tmpl,
- unsigned int arg)
-{
- if (!desc || tmpl == &ipopt_unknown_template)
- return 0;
-
- switch (desc->type) {
- case IPOPT_RR:
- case IPOPT_LSRR:
- case IPOPT_SSRR:
- if (tmpl == &desc->templates[IPOPT_FIELD_ADDR_0])
- return (tmpl->offset < 24) ? 0 : arg;
- return 0;
- default:
- return 0;
- }
-}
-
struct expr *ipopt_expr_alloc(const struct location *loc, uint8_t type,
- uint8_t field, uint8_t ptr)
+ uint8_t field)
{
const struct proto_hdr_template *tmpl;
const struct exthdr_desc *desc;
@@ -97,12 +79,16 @@ struct expr *ipopt_expr_alloc(const struct location *loc, uint8_t type,
if (!tmpl)
return NULL;
+ if (!tmpl->len)
+ return NULL;
+
expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
BYTEORDER_BIG_ENDIAN, tmpl->len);
expr->exthdr.desc = desc;
expr->exthdr.tmpl = tmpl;
expr->exthdr.op = NFT_EXTHDR_OP_IPV4;
- expr->exthdr.offset = calc_offset(desc, tmpl, ptr);
+ expr->exthdr.offset = tmpl->offset;
+ expr->exthdr.raw_type = desc->type;
return expr;
}
diff --git a/src/json.c b/src/json.c
index 13a06424..37530171 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1,11 +1,21 @@
-#define _GNU_SOURCE
-#include <string.h>
+/*
+ * Copyright (c) Red Hat GmbH. Author: Phil Sutter <phil@nwl.cc>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <stdio.h>
#include <expression.h>
#include <list.h>
#include <netlink.h>
#include <rule.h>
#include <rt.h>
+#include "nftutils.h"
#include <netdb.h>
#include <netinet/icmp6.h>
@@ -42,7 +52,8 @@ static json_t *expr_print_json(const struct expr *expr, struct output_ctx *octx)
if (ops->json)
return ops->json(expr, octx);
- printf("warning: expr ops %s have no json callback\n", expr_name(expr));
+ fprintf(stderr, "warning: expr ops %s have no json callback\n",
+ expr_name(expr));
fp = octx->output_fp;
octx->output_fp = fmemopen(buf, 1024, "w");
@@ -59,34 +70,76 @@ static json_t *set_dtype_json(const struct expr *key)
{
char *namedup = xstrdup(key->dtype->name), *tok;
json_t *root = NULL;
+ char *tok_safe;
- tok = strtok(namedup, " .");
+ tok = strtok_r(namedup, " .", &tok_safe);
while (tok) {
- json_t *jtok = json_string(xstrdup(tok));
+ json_t *jtok = json_string(tok);
if (!root)
root = jtok;
else if (json_is_string(root))
root = json_pack("[o, o]", root, jtok);
else
json_array_append_new(root, jtok);
- tok = strtok(NULL, " .");
+ tok = strtok_r(NULL, " .", &tok_safe);
}
- xfree(namedup);
+ free(namedup);
return root;
}
-static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
+static json_t *stmt_print_json(const struct stmt *stmt, struct output_ctx *octx)
{
+ char buf[1024];
+ FILE *fp;
+
+ if (stmt->ops->json)
+ return stmt->ops->json(stmt, octx);
+
+ fprintf(stderr, "warning: stmt ops %s have no json callback\n",
+ stmt->ops->name);
+
+ fp = octx->output_fp;
+ octx->output_fp = fmemopen(buf, 1024, "w");
+
+ stmt->ops->print(stmt, octx);
+
+ fclose(octx->output_fp);
+ octx->output_fp = fp;
+
+ return json_pack("s", buf);
+}
+
+static json_t *set_stmt_list_json(const struct list_head *stmt_list,
+ struct output_ctx *octx)
+{
+ unsigned int flags = octx->flags;
json_t *root, *tmp;
- const char *type, *datatype_ext = NULL;
+ struct stmt *i;
+
+ root = json_array();
+ octx->flags |= NFT_CTX_OUTPUT_STATELESS;
+
+ list_for_each_entry(i, stmt_list, list) {
+ tmp = stmt_print_json(i, octx);
+ json_array_append_new(root, tmp);
+ }
+ octx->flags = flags;
+
+ return root;
+}
+
+static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
+{
+ json_t *root, *tmp, *datatype_ext = NULL;
+ const char *type;
if (set_is_datamap(set->flags)) {
type = "map";
- datatype_ext = set->datatype->name;
+ datatype_ext = set_dtype_json(set->data);
} else if (set_is_objmap(set->flags)) {
type = "map";
- datatype_ext = obj_type_name(set->objtype);
- } else if (set->flags & NFT_SET_EVAL) {
+ datatype_ext = json_string(obj_type_name(set->objtype));
+ } else if (set_is_meter(set->flags)) {
type = "meter";
} else {
type = "set";
@@ -98,8 +151,11 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
"table", set->handle.table.name,
"type", set_dtype_json(set->key),
"handle", set->handle.handle.id);
+
+ if (set->comment)
+ json_object_set_new(root, "comment", json_string(set->comment));
if (datatype_ext)
- json_object_set_new(root, "map", json_string(datatype_ext));
+ json_object_set_new(root, "map", datatype_ext);
if (!(set->flags & (NFT_SET_CONSTANT))) {
if (set->policy != NFT_SET_POL_PERFORMANCE) {
@@ -119,6 +175,8 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
json_array_append_new(tmp, json_pack("s", "interval"));
if (set->flags & NFT_SET_TIMEOUT)
json_array_append_new(tmp, json_pack("s", "timeout"));
+ if (set->flags & NFT_SET_EVAL)
+ json_array_append_new(tmp, json_pack("s", "dynamic"));
if (json_array_size(tmp) > 0) {
json_object_set_new(root, "flags", tmp);
@@ -136,8 +194,10 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
tmp = json_pack("i", set->gc_int / 1000);
json_object_set_new(root, "gc-interval", tmp);
}
+ if (set->automerge)
+ json_object_set_new(root, "auto-merge", json_true());
- if (set->init && set->init->size > 0) {
+ if (!nft_output_terse(octx) && set->init && set->init->size > 0) {
json_t *array = json_array();
const struct expr *i;
@@ -147,6 +207,11 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
json_object_set_new(root, "elem", array);
}
+ if (!list_empty(&set->stmt_list)) {
+ json_object_set_new(root, "stmt",
+ set_stmt_list_json(&set->stmt_list, octx));
+ }
+
return json_pack("{s:o}", type, root);
}
@@ -163,34 +228,6 @@ static json_t *element_print_json(struct output_ctx *octx,
"elem", root);
}
-static json_t *stmt_print_json(const struct stmt *stmt, struct output_ctx *octx)
-{
- char buf[1024];
- FILE *fp;
-
- /* XXX: Can't be supported at this point:
- * xt_stmt_xlate() ignores output_fp.
- */
- if (stmt->ops->type == STMT_XT)
- return json_pack("{s:n}", "xt");
-
- if (stmt->ops->json)
- return stmt->ops->json(stmt, octx);
-
- printf("warning: stmt ops %s have no json callback\n",
- stmt->ops->name);
-
- fp = octx->output_fp;
- octx->output_fp = fmemopen(buf, 1024, "w");
-
- stmt->ops->print(stmt, octx);
-
- fclose(octx->output_fp);
- octx->output_fp = fp;
-
- return json_pack("s", buf);
-}
-
static json_t *rule_print_json(struct output_ctx *octx,
const struct rule *rule)
{
@@ -222,9 +259,8 @@ static json_t *rule_print_json(struct output_ctx *octx,
static json_t *chain_print_json(const struct chain *chain)
{
- json_t *root, *tmp;
- int priority;
- int policy;
+ json_t *root, *tmp, *devs = NULL;
+ int priority, policy, i;
root = json_pack("{s:s, s:s, s:s, s:I}",
"family", family2str(chain->handle.family),
@@ -232,19 +268,33 @@ static json_t *chain_print_json(const struct chain *chain)
"name", chain->handle.chain.name,
"handle", chain->handle.handle.id);
+ if (chain->comment)
+ json_object_set_new(root, "comment", json_string(chain->comment));
+
if (chain->flags & CHAIN_F_BASECHAIN) {
mpz_export_data(&priority, chain->priority.expr->value,
BYTEORDER_HOST_ENDIAN, sizeof(int));
mpz_export_data(&policy, chain->policy->value,
BYTEORDER_HOST_ENDIAN, sizeof(int));
tmp = json_pack("{s:s, s:s, s:i, s:s}",
- "type", chain->type,
+ "type", chain->type.str,
"hook", hooknum2str(chain->handle.family,
- chain->hooknum),
+ chain->hook.num),
"prio", priority,
"policy", chain_policy2str(policy));
- if (chain->dev)
- json_object_set_new(tmp, "dev", json_string(chain->dev));
+
+ for (i = 0; i < chain->dev_array_len; i++) {
+ const char *dev = chain->dev_array[i];
+ if (!devs)
+ devs = json_string(dev);
+ else if (json_is_string(devs))
+ devs = json_pack("[o, s]", devs, dev);
+ else
+ json_array_append_new(devs, json_string(dev));
+ }
+ if (devs)
+ json_object_set_new(root, "dev", devs);
+
json_object_update(root, tmp);
json_decref(tmp);
}
@@ -254,10 +304,10 @@ static json_t *chain_print_json(const struct chain *chain)
static json_t *proto_name_json(uint8_t proto)
{
- const struct protoent *p = getprotobynumber(proto);
+ char name[NFT_PROTONAME_MAXSIZE];
- if (p)
- return json_string(p->p_name);
+ if (nft_getprotobynumber(proto, name, sizeof(name)))
+ return json_string(name);
return json_integer(proto);
}
@@ -291,6 +341,12 @@ static json_t *obj_print_json(const struct obj *obj)
"table", obj->handle.table.name,
"handle", obj->handle.handle.id);
+ if (obj->comment) {
+ tmp = json_pack("{s:s}", "comment", obj->comment);
+ json_object_update(root, tmp);
+ json_decref(tmp);
+ }
+
switch (obj->type) {
case NFT_OBJECT_COUNTER:
tmp = json_pack("{s:I, s:I}",
@@ -401,11 +457,12 @@ static json_t *flowtable_print_json(const struct flowtable *ftable)
mpz_export_data(&priority, ftable->priority.expr->value,
BYTEORDER_HOST_ENDIAN, sizeof(int));
- root = json_pack("{s:s, s:s, s:s, s:s, s:i}",
+ root = json_pack("{s:s, s:s, s:s, s:I, s:s, s:i}",
"family", family2str(ftable->handle.family),
- "name", ftable->handle.flowtable,
+ "name", ftable->handle.flowtable.name,
"table", ftable->handle.table.name,
- "hook", hooknum2str(NFPROTO_NETDEV, ftable->hooknum),
+ "handle", ftable->handle.handle.id,
+ "hook", hooknum2str(NFPROTO_NETDEV, ftable->hook.num),
"prio", priority);
for (i = 0; i < ftable->dev_array_len; i++) {
@@ -431,7 +488,7 @@ static json_t *table_flags_json(const struct table *table)
while (flags) {
if (flags & 0x1) {
- tmp = json_string(table_flags_name[i]);
+ tmp = json_string(table_flag_name(i));
json_array_append_new(root, tmp);
}
flags >>= 1;
@@ -442,7 +499,7 @@ static json_t *table_flags_json(const struct table *table)
json_decref(root);
return NULL;
case 1:
- json_unpack(root, "[o]", &tmp);
+ json_unpack(root, "[O]", &tmp);
json_decref(root);
root = tmp;
break;
@@ -463,14 +520,44 @@ static json_t *table_print_json(const struct table *table)
if (tmp)
json_object_set_new(root, "flags", tmp);
+ if (table->comment)
+ json_object_set_new(root, "comment", json_string(table->comment));
+
return json_pack("{s:o}", "table", root);
}
+json_t *flagcmp_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ json_t *left;
+
+ left = json_pack("{s:[o, o]}", expr_op_symbols[OP_AND],
+ expr_print_json(expr->flagcmp.expr, octx),
+ expr_print_json(expr->flagcmp.mask, octx));
+
+ return json_pack("{s:{s:s, s:o, s:o}}", "match",
+ "op", expr_op_symbols[expr->op] ? : "in",
+ "left", left,
+ "right", expr_print_json(expr->flagcmp.value, octx));
+}
+
+static json_t *
+__binop_expr_json(int op, const struct expr *expr, struct output_ctx *octx)
+{
+ json_t *a = json_array();
+
+ if (expr->etype == EXPR_BINOP && expr->op == op) {
+ json_array_extend(a, __binop_expr_json(op, expr->left, octx));
+ json_array_extend(a, __binop_expr_json(op, expr->right, octx));
+ } else {
+ json_array_append_new(a, expr_print_json(expr, octx));
+ }
+ return a;
+}
+
json_t *binop_expr_json(const struct expr *expr, struct output_ctx *octx)
{
- return json_pack("{s:[o, o]}", expr_op_symbols[expr->op],
- expr_print_json(expr->left, octx),
- expr_print_json(expr->right, octx));
+ return json_pack("{s:o}", expr_op_symbols[expr->op],
+ __binop_expr_json(expr->op, expr, octx));
}
json_t *relational_expr_json(const struct expr *expr, struct output_ctx *octx)
@@ -506,15 +593,23 @@ json_t *payload_expr_json(const struct expr *expr, struct output_ctx *octx)
{
json_t *root;
- if (payload_is_known(expr))
- root = json_pack("{s:s, s:s}",
- "protocol", expr->payload.desc->name,
- "field", expr->payload.tmpl->token);
- else
+ if (payload_is_known(expr)) {
+ if (expr->payload.inner_desc) {
+ root = json_pack("{s:s, s:s, s:s}",
+ "tunnel", expr->payload.inner_desc->name,
+ "protocol", expr->payload.desc->name,
+ "field", expr->payload.tmpl->token);
+ } else {
+ root = json_pack("{s:s, s:s}",
+ "protocol", expr->payload.desc->name,
+ "field", expr->payload.tmpl->token);
+ }
+ } else {
root = json_pack("{s:s, s:i, s:i}",
"base", proto_base_tokens[expr->payload.base],
"offset", expr->payload.offset,
"len", expr->len);
+ }
return json_pack("{s:o}", "payload", root);
}
@@ -570,13 +665,15 @@ json_t *set_ref_expr_json(const struct expr *expr, struct output_ctx *octx)
json_t *set_elem_expr_json(const struct expr *expr, struct output_ctx *octx)
{
json_t *root = expr_print_json(expr->key, octx);
+ struct stmt *stmt;
json_t *tmp;
if (!root)
return NULL;
/* these element attributes require formal set elem syntax */
- if (expr->timeout || expr->expiration || expr->comment) {
+ if (expr->timeout || expr->expiration || expr->comment ||
+ !list_empty(&expr->stmt_list)) {
root = json_pack("{s:o}", "val", root);
if (expr->timeout) {
@@ -591,6 +688,14 @@ json_t *set_elem_expr_json(const struct expr *expr, struct output_ctx *octx)
tmp = json_string(expr->comment);
json_object_set_new(root, "comment", tmp);
}
+ list_for_each_entry(stmt, &expr->stmt_list, list) {
+ tmp = stmt_print_json(stmt, octx);
+ /* XXX: detect and complain about clashes? */
+ json_object_update_missing(root, tmp);
+ json_decref(tmp);
+ /* TODO: only one statement per element. */
+ break;
+ }
return json_pack("{s:o}", "elem", root);
}
@@ -635,7 +740,7 @@ json_t *map_expr_json(const struct expr *expr, struct output_ctx *octx)
const char *type = "map";
if (expr->mappings->etype == EXPR_SET_REF &&
- expr->mappings->set->datatype->type == TYPE_VERDICT)
+ expr->mappings->set->data->dtype->type == TYPE_VERDICT)
type = "vmap";
return json_pack("{s:{s:o, s:o}}", type,
@@ -646,47 +751,51 @@ json_t *map_expr_json(const struct expr *expr, struct output_ctx *octx)
json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx)
{
const char *desc = expr->exthdr.desc ?
- expr->exthdr.desc->name :
- "unknown-exthdr";
+ expr->exthdr.desc->name : NULL;
const char *field = expr->exthdr.tmpl->token;
json_t *root;
bool is_exists = expr->exthdr.flags & NFT_EXTHDR_F_PRESENT;
if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT) {
+ static const char *offstrs[] = { "", "1", "2", "3" };
unsigned int offset = expr->exthdr.offset / 64;
+ const char *offstr = "";
- if (offset) {
- const char *offstrs[] = { "0", "1", "2", "3" };
- const char *offstr = "";
-
+ if (desc) {
if (offset < 4)
offstr = offstrs[offset];
root = json_pack("{s:s+}", "name", desc, offstr);
+
+ if (!is_exists)
+ json_object_set_new(root, "field", json_string(field));
} else {
- root = json_pack("{s:s}", "name", desc);
+ root = json_pack("{s:i, s:i, s:i}",
+ "base", expr->exthdr.raw_type,
+ "offset", expr->exthdr.offset,
+ "len", expr->len);
}
- if (!is_exists)
- json_object_set_new(root, "field", json_string(field));
-
return json_pack("{s:o}", "tcp option", root);
}
- if (expr->exthdr.op == NFT_EXTHDR_OP_IPV4) {
- root = json_pack("{s:s}", "name", desc);
-
- if (!is_exists)
- json_object_set_new(root, "field", json_string(field));
- return json_pack("{s:o}", "ip option", root);
+ if (expr->exthdr.op == NFT_EXTHDR_OP_DCCP) {
+ root = json_pack("{s:i}", "type", expr->exthdr.raw_type);
+ return json_pack("{s:o}", "dccp option", root);
}
- root = json_pack("{s:s}",
- "name", desc);
+ root = json_pack("{s:s}", "name", desc);
if (!is_exists)
json_object_set_new(root, "field", json_string(field));
- return json_pack("{s:o}", "exthdr", root);
+ switch (expr->exthdr.op) {
+ case NFT_EXTHDR_OP_IPV4:
+ return json_pack("{s:o}", "ip option", root);
+ case NFT_EXTHDR_OP_SCTP:
+ return json_pack("{s:o}", "sctp chunk", root);
+ default:
+ return json_pack("{s:o}", "exthdr", root);
+ }
}
json_t *verdict_expr_json(const struct expr *expr, struct output_ctx *octx)
@@ -852,6 +961,11 @@ static json_t *symbolic_constant_json(const struct symbol_table *tbl,
return json_string(s->identifier);
}
+json_t *set_elem_catchall_expr_json(const struct expr *expr, struct output_ctx *octx)
+{
+ return json_string("*");
+}
+
static json_t *datatype_json(const struct expr *expr, struct output_ctx *octx)
{
const struct datatype *dtype = expr->dtype;
@@ -999,35 +1113,25 @@ json_t *boolean_type_json(const struct expr *expr, struct output_ctx *octx)
json_t *inet_protocol_type_json(const struct expr *expr,
struct output_ctx *octx)
{
- struct protoent *p;
-
if (!nft_output_numeric_proto(octx)) {
- p = getprotobynumber(mpz_get_uint8(expr->value));
- if (p != NULL)
- return json_string(p->p_name);
+ char name[NFT_PROTONAME_MAXSIZE];
+
+ if (nft_getprotobynumber(mpz_get_uint8(expr->value), name, sizeof(name)))
+ return json_string(name);
}
return integer_type_json(expr, octx);
}
json_t *inet_service_type_json(const struct expr *expr, struct output_ctx *octx)
{
- struct sockaddr_in sin = {
- .sin_family = AF_INET,
- .sin_port = mpz_get_be16(expr->value),
- };
- char buf[NI_MAXSERV];
+ uint16_t port = mpz_get_be16(expr->value);
+ char name[NFT_SERVNAME_MAXSIZE];
if (!nft_output_service(octx) ||
- getnameinfo((struct sockaddr *)&sin, sizeof(sin),
- NULL, 0, buf, sizeof(buf), 0))
- return json_integer(ntohs(sin.sin_port));
-
- if (htons(atoi(buf)) == sin.sin_port ||
- getnameinfo((struct sockaddr *)&sin, sizeof(sin),
- NULL, 0, buf, sizeof(buf), NI_DGRAM))
- return json_integer(ntohs(sin.sin_port));
+ !nft_getservbyport(port, NULL, name, sizeof(name)))
+ return json_integer(ntohs(port));
- return json_string(buf);
+ return json_string(name);
}
json_t *mark_type_json(const struct expr *expr, struct output_ctx *octx)
@@ -1088,6 +1192,13 @@ json_t *expr_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
return expr_print_json(stmt->expr, octx);
}
+json_t *flow_offload_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ return json_pack("{s:{s:s, s:s+}}", "flow",
+ "op", "add", "flowtable",
+ "@", stmt->flow.table_name);
+}
+
json_t *payload_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
{
return json_pack("{s: {s:o, s:o}}", "mangle",
@@ -1152,19 +1263,17 @@ json_t *limit_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
burst_unit = get_rate(stmt->limit.burst, &burst);
}
- root = json_pack("{s:I, s:s}",
+ root = json_pack("{s:I, s:I, s:s}",
"rate", rate,
+ "burst", burst,
"per", get_unit(stmt->limit.unit));
if (inv)
json_object_set_new(root, "inv", json_boolean(inv));
if (rate_unit)
json_object_set_new(root, "rate_unit", json_string(rate_unit));
- if (burst && burst != 5) {
- json_object_set_new(root, "burst", json_integer(burst));
- if (burst_unit)
- json_object_set_new(root, "burst_unit",
- json_string(burst_unit));
- }
+ if (burst_unit)
+ json_object_set_new(root, "burst_unit",
+ json_string(burst_unit));
return json_pack("{s:o}", "limit", root);
}
@@ -1223,9 +1332,12 @@ json_t *log_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
{
json_t *root = json_object(), *flags;
- if (stmt->log.flags & STMT_LOG_PREFIX)
- json_object_set_new(root, "prefix",
- json_string(stmt->log.prefix));
+ if (stmt->log.flags & STMT_LOG_PREFIX) {
+ char prefix[NF_LOG_PREFIXLEN] = {};
+
+ expr_to_string(stmt->log.prefix, prefix);
+ json_object_set_new(root, "prefix", json_string(prefix));
+ }
if (stmt->log.flags & STMT_LOG_GROUP)
json_object_set_new(root, "group",
json_integer(stmt->log.group));
@@ -1275,7 +1387,7 @@ json_t *log_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
return json_pack("{s:o}", "log", root);
}
-static json_t *nat_flags_json(int flags)
+static json_t *nat_flags_json(uint32_t flags)
{
json_t *array = json_array();
@@ -1285,9 +1397,33 @@ static json_t *nat_flags_json(int flags)
json_array_append_new(array, json_string("fully-random"));
if (flags & NF_NAT_RANGE_PERSISTENT)
json_array_append_new(array, json_string("persistent"));
+ if (flags & NF_NAT_RANGE_NETMAP)
+ json_array_append_new(array, json_string("netmap"));
+ return array;
+}
+
+static json_t *nat_type_flags_json(uint32_t type_flags)
+{
+ json_t *array = json_array();
+
+ if (type_flags & STMT_NAT_F_PREFIX)
+ json_array_append_new(array, json_string("prefix"));
+
return array;
}
+static void nat_stmt_add_array(json_t *root, const char *name, json_t *array)
+{
+ if (json_array_size(array) > 1) {
+ json_object_set_new(root, name, array);
+ } else {
+ if (json_array_size(array))
+ json_object_set(root, name,
+ json_array_get(array, 0));
+ json_decref(array);
+ }
+}
+
json_t *nat_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
{
json_t *root = json_object();
@@ -1309,13 +1445,12 @@ json_t *nat_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
json_object_set_new(root, "port",
expr_print_json(stmt->nat.proto, octx));
- if (json_array_size(array) > 1) {
- json_object_set_new(root, "flags", array);
- } else {
- if (json_array_size(array))
- json_object_set(root, "flags",
- json_array_get(array, 0));
- json_decref(array);
+ nat_stmt_add_array(root, "flags", array);
+
+ if (stmt->nat.type_flags) {
+ array = nat_type_flags_json(stmt->nat.type_flags);
+
+ nat_stmt_add_array(root, "type_flags", array);
}
if (!json_object_size(root)) {
@@ -1336,24 +1471,16 @@ json_t *reject_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
type = "tcp reset";
break;
case NFT_REJECT_ICMPX_UNREACH:
- if (stmt->reject.icmp_code == NFT_REJECT_ICMPX_PORT_UNREACH)
- break;
type = "icmpx";
jexpr = expr_print_json(stmt->reject.expr, octx);
break;
case NFT_REJECT_ICMP_UNREACH:
switch (stmt->reject.family) {
case NFPROTO_IPV4:
- if (!stmt->reject.verbose_print &&
- stmt->reject.icmp_code == ICMP_PORT_UNREACH)
- break;
type = "icmp";
jexpr = expr_print_json(stmt->reject.expr, octx);
break;
case NFPROTO_IPV6:
- if (!stmt->reject.verbose_print &&
- stmt->reject.icmp_code == ICMP6_DST_UNREACH_NOPORT)
- break;
type = "icmpv6";
jexpr = expr_print_json(stmt->reject.expr, octx);
break;
@@ -1382,12 +1509,49 @@ json_t *counter_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
"bytes", stmt->counter.bytes);
}
+json_t *last_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ if (nft_output_stateless(octx) || stmt->last.set == 0)
+ return json_pack("{s:n}", "last");
+
+ return json_pack("{s:{s:I}}", "last", "used", stmt->last.used);
+}
+
json_t *set_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
{
- return json_pack("{s:{s:s, s:o, s:s+}}", "set",
+ json_t *root;
+
+ root = json_pack("{s:s, s:o, s:s+}",
"op", set_stmt_op_names[stmt->set.op],
"elem", expr_print_json(stmt->set.key, octx),
"set", "@", stmt->set.set->set->handle.set.name);
+
+ if (!list_empty(&stmt->set.stmt_list)) {
+ json_object_set_new(root, "stmt",
+ set_stmt_list_json(&stmt->set.stmt_list,
+ octx));
+ }
+
+ return json_pack("{s:o}", "set", root);
+}
+
+json_t *map_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ json_t *root;
+
+ root = json_pack("{s:s, s:o, s:o, s:s+}",
+ "op", set_stmt_op_names[stmt->map.op],
+ "elem", expr_print_json(stmt->map.key, octx),
+ "data", expr_print_json(stmt->map.data, octx),
+ "map", "@", stmt->map.set->set->handle.set.name);
+
+ if (!list_empty(&stmt->map.stmt_list)) {
+ json_object_set_new(root, "stmt",
+ set_stmt_list_json(&stmt->map.stmt_list,
+ octx));
+ }
+
+ return json_pack("{s:o}", "map", root);
}
json_t *objref_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
@@ -1521,10 +1685,29 @@ json_t *synproxy_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
return json_pack("{s:o}", "synproxy", root);
}
+json_t *optstrip_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ return json_pack("{s:o}", "reset",
+ expr_print_json(stmt->optstrip.expr, octx));
+}
+
+json_t *xt_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
+{
+ static const char *xt_typename[NFT_XT_MAX] = {
+ [NFT_XT_MATCH] = "match",
+ [NFT_XT_TARGET] = "target",
+ [NFT_XT_WATCHER] = "watcher",
+ };
+
+ return json_pack("{s:{s:s, s:s}}", "xt",
+ "type", xt_typename[stmt->xt.type],
+ "name", stmt->xt.name);
+}
+
static json_t *table_print_json_full(struct netlink_ctx *ctx,
struct table *table)
{
- json_t *root = json_array(), *tmp;
+ json_t *root = json_array(), *rules = json_array(), *tmp;
struct flowtable *flowtable;
struct chain *chain;
struct rule *rule;
@@ -1534,45 +1717,52 @@ static json_t *table_print_json_full(struct netlink_ctx *ctx,
tmp = table_print_json(table);
json_array_append_new(root, tmp);
- list_for_each_entry(obj, &table->objs, list) {
+ /* both maps and rules may refer to chains, list them first */
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
+ tmp = chain_print_json(chain);
+ json_array_append_new(root, tmp);
+ }
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
tmp = obj_print_json(obj);
json_array_append_new(root, tmp);
}
- list_for_each_entry(set, &table->sets, list) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
if (set_is_anonymous(set->flags))
continue;
tmp = set_print_json(&ctx->nft->output, set);
json_array_append_new(root, tmp);
}
- list_for_each_entry(flowtable, &table->flowtables, list) {
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
tmp = flowtable_print_json(flowtable);
json_array_append_new(root, tmp);
}
- list_for_each_entry(chain, &table->chains, list) {
- tmp = chain_print_json(chain);
- json_array_append_new(root, tmp);
-
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
list_for_each_entry(rule, &chain->rules, list) {
tmp = rule_print_json(&ctx->nft->output, rule);
- json_array_append_new(root, tmp);
+ json_array_append_new(rules, tmp);
}
}
+ json_array_extend(root, rules);
+ json_decref(rules);
+
return root;
}
static json_t *do_list_ruleset_json(struct netlink_ctx *ctx, struct cmd *cmd)
{
unsigned int family = cmd->handle.family;
- json_t *root = json_array();
+ json_t *root = json_array(), *tmp;
struct table *table;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (family != NFPROTO_UNSPEC &&
table->handle.family != family)
continue;
- json_array_extend(root, table_print_json_full(ctx, table));
+ tmp = table_print_json_full(ctx, table);
+ json_array_extend(root, tmp);
+ json_decref(tmp);
}
return root;
@@ -1584,7 +1774,7 @@ static json_t *do_list_tables_json(struct netlink_ctx *ctx, struct cmd *cmd)
json_t *root = json_array();
struct table *table;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (family != NFPROTO_UNSPEC &&
table->handle.family != family)
continue;
@@ -1608,7 +1798,7 @@ static json_t *do_list_chain_json(struct netlink_ctx *ctx,
struct chain *chain;
struct rule *rule;
- list_for_each_entry(chain, &table->chains, list) {
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
if (chain->handle.family != cmd->handle.family ||
strcmp(cmd->handle.chain.name, chain->handle.chain.name))
continue;
@@ -1631,12 +1821,12 @@ static json_t *do_list_chains_json(struct netlink_ctx *ctx, struct cmd *cmd)
struct table *table;
struct chain *chain;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
- list_for_each_entry(chain, &table->chains, list) {
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
json_t *tmp = chain_print_json(chain);
json_array_append_new(root, tmp);
@@ -1649,10 +1839,13 @@ static json_t *do_list_chains_json(struct netlink_ctx *ctx, struct cmd *cmd)
static json_t *do_list_set_json(struct netlink_ctx *ctx,
struct cmd *cmd, struct table *table)
{
- struct set *set = set_lookup(table, cmd->handle.set.name);
+ struct set *set = cmd->set;
- if (set == NULL)
- return json_null();
+ if (!set) {
+ set = set_cache_find(table, cmd->handle.set.name);
+ if (set == NULL)
+ return json_null();
+ }
return json_pack("[o]", set_print_json(&ctx->nft->output, set));
}
@@ -1664,17 +1857,17 @@ static json_t *do_list_sets_json(struct netlink_ctx *ctx, struct cmd *cmd)
struct table *table;
struct set *set;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
- list_for_each_entry(set, &table->sets, list) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
if (cmd->obj == CMD_OBJ_SETS &&
!set_is_literal(set->flags))
continue;
if (cmd->obj == CMD_OBJ_METERS &&
- !(set->flags & NFT_SET_EVAL))
+ !set_is_meter(set->flags))
continue;
if (cmd->obj == CMD_OBJ_MAPS &&
!map_is_literal(set->flags))
@@ -1693,7 +1886,7 @@ static json_t *do_list_obj_json(struct netlink_ctx *ctx,
struct table *table;
struct obj *obj;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
@@ -1702,7 +1895,7 @@ static json_t *do_list_obj_json(struct netlink_ctx *ctx,
strcmp(cmd->handle.table.name, table->handle.table.name))
continue;
- list_for_each_entry(obj, &table->objs, list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
if (obj->type != type ||
(cmd->handle.obj.name &&
strcmp(cmd->handle.obj.name, obj->handle.obj.name)))
@@ -1715,18 +1908,33 @@ static json_t *do_list_obj_json(struct netlink_ctx *ctx,
return root;
}
+static json_t *do_list_flowtable_json(struct netlink_ctx *ctx,
+ struct cmd *cmd, struct table *table)
+{
+ json_t *root = json_array();
+ struct flowtable *ft;
+
+ ft = ft_cache_find(table, cmd->handle.flowtable.name);
+ if (!ft)
+ return json_null();
+
+ json_array_append_new(root, flowtable_print_json(ft));
+
+ return root;
+}
+
static json_t *do_list_flowtables_json(struct netlink_ctx *ctx, struct cmd *cmd)
{
json_t *root = json_array(), *tmp;
struct flowtable *flowtable;
struct table *table;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
- list_for_each_entry(flowtable, &table->flowtables, list) {
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
tmp = flowtable_print_json(flowtable);
json_array_append_new(root, tmp);
}
@@ -1749,7 +1957,9 @@ int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
json_t *root;
if (cmd->handle.table.name)
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
switch (cmd->obj) {
case CMD_OBJ_TABLE:
@@ -1771,6 +1981,7 @@ int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_SET:
root = do_list_set_json(ctx, cmd, table);
break;
+ case CMD_OBJ_RULES:
case CMD_OBJ_RULESET:
root = do_list_ruleset_json(ctx, cmd);
break;
@@ -1806,6 +2017,9 @@ int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_SECMARKS:
root = do_list_obj_json(ctx, cmd, NFT_OBJECT_SECMARK);
break;
+ case CMD_OBJ_FLOWTABLE:
+ root = do_list_flowtable_json(ctx, cmd, table);
+ break;
case CMD_OBJ_FLOWTABLES:
root = do_list_flowtables_json(ctx, cmd);
break;
@@ -1833,9 +2047,15 @@ int do_command_list_json(struct netlink_ctx *ctx, struct cmd *cmd)
static void monitor_print_json(struct netlink_mon_handler *monh,
const char *cmd, json_t *obj)
{
+ struct nft_ctx *nft = monh->ctx->nft;
+
obj = json_pack("{s:o}", cmd, obj);
- json_dumpf(obj, monh->ctx->nft->output.output_fp, 0);
- json_decref(obj);
+ if (nft_output_echo(&nft->output) && !nft->json_root) {
+ json_array_append_new(nft->json_echo, obj);
+ } else {
+ json_dumpf(obj, nft->output.output_fp, 0);
+ json_decref(obj);
+ }
}
void monitor_print_table_json(struct netlink_mon_handler *monh,
@@ -1879,3 +2099,10 @@ void monitor_print_rule_json(struct netlink_mon_handler *monh,
monitor_print_json(monh, cmd, rule_print_json(octx, r));
}
+
+void json_alloc_echo(struct nft_ctx *nft)
+{
+ nft->json_echo = json_array();
+ if (!nft->json_echo)
+ memory_allocation_error();
+}
diff --git a/src/libnftables.c b/src/libnftables.c
index e2037243..0dee1bac 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -2,26 +2,26 @@
* Copyright (c) 2017 Eric Leblond <eric@regit.org>
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
*/
+
+#include <nft.h>
+
#include <nftables/libnftables.h>
#include <erec.h>
#include <mnl.h>
#include <parser.h>
#include <utils.h>
#include <iface.h>
-
+#include <cmd.h>
#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
+#include <sys/stat.h>
static int nft_netlink(struct nft_ctx *nft,
- struct list_head *cmds, struct list_head *msgs,
- struct mnl_socket *nf_sock)
+ struct list_head *cmds, struct list_head *msgs)
{
- uint32_t batch_seqnum, seqnum = 0, num_cmds = 0;
+ uint32_t batch_seqnum, seqnum = 0, last_seqnum = UINT32_MAX, num_cmds = 0;
struct netlink_ctx ctx = {
.nft = nft,
.msgs = msgs,
@@ -56,6 +56,13 @@ static int nft_netlink(struct nft_ctx *nft,
ret = mnl_batch_talk(&ctx, &err_list, num_cmds);
if (ret < 0) {
+ if (ctx.maybe_emsgsize && errno == EMSGSIZE) {
+ netlink_io_error(&ctx, NULL,
+ "Could not process rule: %s\n"
+ "Please, rise /proc/sys/net/core/wmem_max on the host namespace. Hint: %d bytes",
+ strerror(errno), round_pow_2(ctx.maybe_emsgsize));
+ goto out;
+ }
netlink_io_error(&ctx, NULL,
"Could not process rule: %s", strerror(errno));
goto out;
@@ -65,12 +72,17 @@ static int nft_netlink(struct nft_ctx *nft,
ret = -1;
list_for_each_entry_safe(err, tmp, &err_list, head) {
- list_for_each_entry(cmd, cmds, list) {
+ /* cmd seqnums are monotonic: only reset the starting position
+ * if the error seqnum is lower than the previous one.
+ */
+ if (err->seqnum < last_seqnum)
+ cmd = list_first_entry(cmds, struct cmd, list);
+
+ list_for_each_entry_from(cmd, cmds, list) {
+ last_seqnum = cmd->seqnum;
if (err->seqnum == cmd->seqnum ||
err->seqnum == batch_seqnum) {
- netlink_io_error(&ctx, &cmd->location,
- "Could not process rule: %s",
- strerror(err->err));
+ nft_cmd_error(&ctx, cmd, err);
errno = err->err;
if (err->seqnum == cmd->seqnum) {
mnl_err_list_free(err);
@@ -78,7 +90,18 @@ static int nft_netlink(struct nft_ctx *nft,
}
}
}
+
+ if (&cmd->list == cmds) {
+ /* not found, rewind */
+ last_seqnum = UINT32_MAX;
+ }
}
+ /* nfnetlink uses the first netlink message header in the batch whose
+ * sequence number is zero to report for EOPNOTSUPP and EPERM errors in
+ * some scenarios. Now it is safe to release pending errors here.
+ */
+ list_for_each_entry_safe(err, tmp, &err_list, head)
+ mnl_err_list_free(err);
out:
mnl_batch_reset(ctx.batch);
return ret;
@@ -94,21 +117,57 @@ static void nft_init(struct nft_ctx *ctx)
static void nft_exit(struct nft_ctx *ctx)
{
+ cache_free(&ctx->cache.table_cache);
ct_label_table_exit(ctx);
realm_table_rt_exit(ctx);
devgroup_table_exit(ctx);
mark_table_exit(ctx);
}
+EXPORT_SYMBOL(nft_ctx_add_var);
+int nft_ctx_add_var(struct nft_ctx *ctx, const char *var)
+{
+ char *separator = strchr(var, '=');
+ int pcount = ctx->num_vars;
+ struct nft_vars *tmp;
+ const char *value;
+
+ if (!separator)
+ return -1;
+
+ tmp = xrealloc(ctx->vars, (pcount + 1) * sizeof(struct nft_vars));
+
+ *separator = '\0';
+ value = separator + 1;
+
+ ctx->vars = tmp;
+ ctx->vars[pcount].key = xstrdup(var);
+ ctx->vars[pcount].value = xstrdup(value);
+ ctx->num_vars++;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(nft_ctx_clear_vars);
+void nft_ctx_clear_vars(struct nft_ctx *ctx)
+{
+ unsigned int i;
+
+ for (i = 0; i < ctx->num_vars; i++) {
+ free_const(ctx->vars[i].key);
+ free_const(ctx->vars[i].value);
+ }
+ ctx->num_vars = 0;
+ free(ctx->vars);
+}
+
EXPORT_SYMBOL(nft_ctx_add_include_path);
int nft_ctx_add_include_path(struct nft_ctx *ctx, const char *path)
{
char **tmp;
int pcount = ctx->num_include_paths;
- tmp = realloc(ctx->include_paths, (pcount + 1) * sizeof(char *));
- if (!tmp)
- return -1;
+ tmp = xrealloc(ctx->include_paths, (pcount + 1) * sizeof(char *));
ctx->include_paths = tmp;
@@ -123,30 +182,20 @@ EXPORT_SYMBOL(nft_ctx_clear_include_paths);
void nft_ctx_clear_include_paths(struct nft_ctx *ctx)
{
while (ctx->num_include_paths)
- xfree(ctx->include_paths[--ctx->num_include_paths]);
+ free(ctx->include_paths[--ctx->num_include_paths]);
- xfree(ctx->include_paths);
+ free(ctx->include_paths);
ctx->include_paths = NULL;
}
-static void nft_ctx_netlink_init(struct nft_ctx *ctx)
-{
- ctx->nf_sock = nft_mnl_socket_open();
-}
-
EXPORT_SYMBOL(nft_ctx_new);
struct nft_ctx *nft_ctx_new(uint32_t flags)
{
- static bool init_once;
struct nft_ctx *ctx;
- if (!init_once) {
- init_once = true;
- gmp_init();
#ifdef HAVE_LIBXTABLES
- xt_init();
+ xt_init();
#endif
- }
ctx = xzalloc(sizeof(struct nft_ctx));
nft_init(ctx);
@@ -154,13 +203,14 @@ struct nft_ctx *nft_ctx_new(uint32_t flags)
ctx->state = xzalloc(sizeof(struct parser_state));
nft_ctx_add_include_path(ctx, DEFAULT_INCLUDE_PATH);
ctx->parser_max_errors = 10;
- init_list_head(&ctx->cache.list);
+ cache_init(&ctx->cache.table_cache);
+ ctx->top_scope = scope_alloc();
ctx->flags = flags;
ctx->output.output_fp = stdout;
ctx->output.error_fp = stderr;
+ init_list_head(&ctx->vars_ctx.indesc_list);
- if (flags == NFT_CTX_DEFAULT)
- nft_ctx_netlink_init(ctx);
+ ctx->nf_sock = nft_mnl_socket_open();
return ctx;
}
@@ -284,17 +334,18 @@ const char *nft_ctx_get_error_buffer(struct nft_ctx *ctx)
EXPORT_SYMBOL(nft_ctx_free);
void nft_ctx_free(struct nft_ctx *ctx)
{
- if (ctx->nf_sock)
- mnl_socket_close(ctx->nf_sock);
+ mnl_socket_close(ctx->nf_sock);
exit_cookie(&ctx->output.output_cookie);
exit_cookie(&ctx->output.error_cookie);
iface_cache_release();
- cache_release(&ctx->cache);
+ nft_cache_release(&ctx->cache);
+ nft_ctx_clear_vars(ctx);
nft_ctx_clear_include_paths(ctx);
- xfree(ctx->state);
+ scope_free(ctx->top_scope);
+ free(ctx->state);
nft_exit(ctx);
- xfree(ctx);
+ free(ctx);
}
EXPORT_SYMBOL(nft_ctx_set_output);
@@ -335,6 +386,34 @@ void nft_ctx_set_dry_run(struct nft_ctx *ctx, bool dry)
ctx->check = dry;
}
+EXPORT_SYMBOL(nft_ctx_get_optimize);
+uint32_t nft_ctx_get_optimize(struct nft_ctx *ctx)
+{
+ return ctx->optimize_flags;
+}
+
+EXPORT_SYMBOL(nft_ctx_set_optimize);
+void nft_ctx_set_optimize(struct nft_ctx *ctx, uint32_t flags)
+{
+ ctx->optimize_flags = flags;
+}
+
+EXPORT_SYMBOL(nft_ctx_input_get_flags);
+unsigned int nft_ctx_input_get_flags(struct nft_ctx *ctx)
+{
+ return ctx->input.flags;
+}
+
+EXPORT_SYMBOL(nft_ctx_input_set_flags);
+unsigned int nft_ctx_input_set_flags(struct nft_ctx *ctx, unsigned int flags)
+{
+ unsigned int old_flags;
+
+ old_flags = ctx->input.flags;
+ ctx->input.flags = flags;
+ return old_flags;
+}
+
EXPORT_SYMBOL(nft_ctx_output_get_flags);
unsigned int nft_ctx_output_get_flags(struct nft_ctx *ctx)
{
@@ -364,13 +443,14 @@ static const struct input_descriptor indesc_cmdline = {
};
static int nft_parse_bison_buffer(struct nft_ctx *nft, const char *buf,
- struct list_head *msgs, struct list_head *cmds)
+ struct list_head *msgs, struct list_head *cmds,
+ const struct input_descriptor *indesc)
{
int ret;
- parser_init(nft, nft->state, msgs, cmds);
+ parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
nft->scanner = scanner_init(nft->state);
- scanner_push_buffer(nft->scanner, &indesc_cmdline, buf);
+ scanner_push_buffer(nft->scanner, indesc, buf);
ret = nft_parse(nft, nft->scanner, nft->state);
if (ret != 0 || nft->state->nerrs > 0)
@@ -379,12 +459,43 @@ static int nft_parse_bison_buffer(struct nft_ctx *nft, const char *buf,
return 0;
}
+static char *stdin_to_buffer(void)
+{
+ unsigned int bufsiz = 16384, consumed = 0;
+ int numbytes;
+ char *buf;
+
+ buf = xmalloc(bufsiz);
+
+ numbytes = read(STDIN_FILENO, buf, bufsiz);
+ while (numbytes > 0) {
+ consumed += numbytes;
+ if (consumed == bufsiz) {
+ bufsiz *= 2;
+ buf = xrealloc(buf, bufsiz);
+ }
+ numbytes = read(STDIN_FILENO, buf + consumed, bufsiz - consumed);
+ }
+ buf[consumed] = '\0';
+
+ return buf;
+}
+
+static const struct input_descriptor indesc_stdin = {
+ .type = INDESC_STDIN,
+ .name = "/dev/stdin",
+};
+
static int nft_parse_bison_filename(struct nft_ctx *nft, const char *filename,
struct list_head *msgs, struct list_head *cmds)
{
int ret;
- parser_init(nft, nft->state, msgs, cmds);
+ if (nft->stdin_buf)
+ return nft_parse_bison_buffer(nft, nft->stdin_buf, msgs, cmds,
+ &indesc_stdin);
+
+ parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
nft->scanner = scanner_init(nft->state);
if (scanner_read_file(nft, filename, &internal_location) < 0)
return -1;
@@ -399,28 +510,53 @@ static int nft_parse_bison_filename(struct nft_ctx *nft, const char *filename,
static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
struct list_head *cmds)
{
+ struct nft_cache_filter *filter;
+ struct cmd *cmd, *next;
+ bool collapsed = false;
unsigned int flags;
- struct cmd *cmd;
+ int err = 0;
- flags = cache_evaluate(nft, cmds);
- if (cache_update(nft, flags, msgs) < 0)
+ filter = nft_cache_filter_init();
+ if (nft_cache_evaluate(nft, cmds, msgs, filter, &flags) < 0) {
+ nft_cache_filter_fini(filter);
return -1;
+ }
+ if (nft_cache_update(nft, flags, msgs, filter) < 0) {
+ nft_cache_filter_fini(filter);
+ return -1;
+ }
+
+ nft_cache_filter_fini(filter);
+
+ if (nft_cmd_collapse(cmds))
+ collapsed = true;
list_for_each_entry(cmd, cmds, list) {
+ if (cmd->op != CMD_ADD &&
+ cmd->op != CMD_CREATE)
+ continue;
+
+ nft_cmd_expand(cmd);
+ }
+
+ list_for_each_entry_safe(cmd, next, cmds, list) {
struct eval_ctx ectx = {
.nft = nft,
.msgs = msgs,
};
+
if (cmd_evaluate(&ectx, cmd) < 0 &&
- ++nft->state->nerrs == nft->parser_max_errors)
- return -1;
+ ++nft->state->nerrs == nft->parser_max_errors) {
+ err = -1;
+ break;
+ }
}
- if (nft->state->nerrs)
- return -1;
+ if (collapsed)
+ nft_cmd_uncollapse(cmds);
- list_for_each_entry(cmd, cmds, list)
- nft_cmd_expand(cmd);
+ if (err < 0 || nft->state->nerrs)
+ return -1;
return 0;
}
@@ -437,23 +573,29 @@ int nft_run_cmd_from_buffer(struct nft_ctx *nft, const char *buf)
nlbuf = xzalloc(strlen(buf) + 2);
sprintf(nlbuf, "%s\n", buf);
- if (nft_output_json(&nft->output))
+ if (nft_output_json(&nft->output) || nft_input_json(&nft->input))
rc = nft_parse_json_buffer(nft, nlbuf, &msgs, &cmds);
if (rc == -EINVAL)
- rc = nft_parse_bison_buffer(nft, nlbuf, &msgs, &cmds);
+ rc = nft_parse_bison_buffer(nft, nlbuf, &msgs, &cmds,
+ &indesc_cmdline);
parser_rc = rc;
rc = nft_evaluate(nft, &msgs, &cmds);
- if (rc < 0)
+ if (rc < 0) {
+ if (errno == EPERM) {
+ fprintf(stderr, "%s (you must be root)\n",
+ strerror(errno));
+ }
goto err;
+ }
if (parser_rc) {
rc = parser_rc;
goto err;
}
- if (nft_netlink(nft, &cmds, &msgs, nft->nf_sock) != 0)
+ if (nft_netlink(nft, &cmds, &msgs) != 0)
rc = -1;
err:
erec_print_list(&nft->output, &msgs, nft->debug_mask);
@@ -472,30 +614,109 @@ err:
nft_output_json(&nft->output) &&
nft_output_echo(&nft->output))
json_print_echo(nft);
- if (rc)
- cache_release(&nft->cache);
+
+ if (rc || nft->check)
+ nft_cache_release(&nft->cache);
+
return rc;
}
-EXPORT_SYMBOL(nft_run_cmd_from_filename);
-int nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename)
+static int load_cmdline_vars(struct nft_ctx *ctx, struct list_head *msgs)
+{
+ unsigned int bufsize, ret, i, offset = 0;
+ LIST_HEAD(cmds);
+ char *buf;
+ int rc;
+
+ if (ctx->num_vars == 0)
+ return 0;
+
+ bufsize = 1024;
+ buf = xzalloc(bufsize + 1);
+ for (i = 0; i < ctx->num_vars; i++) {
+retry:
+ ret = snprintf(buf + offset, bufsize - offset,
+ "define %s=%s; ",
+ ctx->vars[i].key, ctx->vars[i].value);
+ if (ret >= bufsize - offset) {
+ bufsize *= 2;
+ buf = xrealloc(buf, bufsize + 1);
+ goto retry;
+ }
+ offset += ret;
+ }
+ snprintf(buf + offset, bufsize - offset, "\n");
+
+ rc = nft_parse_bison_buffer(ctx, buf, msgs, &cmds, &indesc_cmdline);
+
+ assert(list_empty(&cmds));
+ /* Stash the buffer that contains the variable definitions and zap the
+ * list of input descriptors before releasing the scanner state,
+ * otherwise error reporting path walks over released objects.
+ */
+ ctx->vars_ctx.buf = buf;
+ list_splice_init(&ctx->state->indesc_list, &ctx->vars_ctx.indesc_list);
+ scanner_destroy(ctx);
+ ctx->scanner = NULL;
+
+ return rc;
+}
+
+/* need to use stat() to, fopen() will block for named fifos and
+ * libjansson makes no checks before or after open either.
+ */
+static struct error_record *filename_is_useable(struct nft_ctx *nft, const char *name)
{
+ unsigned int type;
+ struct stat sb;
+ int err;
+
+ err = stat(name, &sb);
+ if (err)
+ return error(&internal_location, "Could not open file \"%s\": %s\n",
+ name, strerror(errno));
+
+ type = sb.st_mode & S_IFMT;
+
+ if (type == S_IFREG || type == S_IFIFO)
+ return NULL;
+
+ if (type == S_IFCHR && 0 == strcmp(name, "/dev/stdin"))
+ return NULL;
+
+ return error(&internal_location, "Not a regular file: \"%s\"\n", name);
+}
+
+static int __nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename)
+{
+ struct error_record *erec;
struct cmd *cmd, *next;
int rc, parser_rc;
LIST_HEAD(msgs);
LIST_HEAD(cmds);
- if (!strcmp(filename, "-"))
- filename = "/dev/stdin";
+ erec = filename_is_useable(nft, filename);
+ if (erec) {
+ erec_print(&nft->output, erec, nft->debug_mask);
+ erec_destroy(erec);
+ return -1;
+ }
+
+ rc = load_cmdline_vars(nft, &msgs);
+ if (rc < 0)
+ goto err;
rc = -EINVAL;
- if (nft_output_json(&nft->output))
+ if (nft_output_json(&nft->output) || nft_input_json(&nft->input))
rc = nft_parse_json_filename(nft, filename, &msgs, &cmds);
if (rc == -EINVAL)
rc = nft_parse_bison_filename(nft, filename, &msgs, &cmds);
parser_rc = rc;
+ if (nft->optimize_flags)
+ nft_optimize(nft, &cmds);
+
rc = nft_evaluate(nft, &msgs, &cmds);
if (rc < 0)
goto err;
@@ -505,7 +726,7 @@ int nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename)
goto err;
}
- if (nft_netlink(nft, &cmds, &msgs, nft->nf_sock) != 0)
+ if (nft_netlink(nft, &cmds, &msgs) != 0)
rc = -1;
err:
erec_print_list(&nft->output, &msgs, nft->debug_mask);
@@ -518,12 +739,73 @@ err:
scanner_destroy(nft);
nft->scanner = NULL;
}
+ if (!list_empty(&nft->vars_ctx.indesc_list)) {
+ struct input_descriptor *indesc, *next;
+
+ list_for_each_entry_safe(indesc, next, &nft->vars_ctx.indesc_list, list) {
+ if (indesc->name)
+ free_const(indesc->name);
+
+ free(indesc);
+ }
+ }
+ free_const(nft->vars_ctx.buf);
if (!rc &&
nft_output_json(&nft->output) &&
nft_output_echo(&nft->output))
json_print_echo(nft);
- if (rc)
- cache_release(&nft->cache);
+
+ if (rc || nft->check)
+ nft_cache_release(&nft->cache);
+
+ scope_release(nft->state->scopes[0]);
+
return rc;
}
+
+static int nft_run_optimized_file(struct nft_ctx *nft, const char *filename)
+{
+ uint32_t optimize_flags;
+ bool check;
+ int ret;
+
+ check = nft->check;
+ nft->check = true;
+ optimize_flags = nft->optimize_flags;
+ nft->optimize_flags = 0;
+
+ /* First check the original ruleset loads fine as is. */
+ ret = __nft_run_cmd_from_filename(nft, filename);
+ if (ret < 0)
+ return ret;
+
+ nft->check = check;
+ nft->optimize_flags = optimize_flags;
+
+ return __nft_run_cmd_from_filename(nft, filename);
+}
+
+EXPORT_SYMBOL(nft_run_cmd_from_filename);
+int nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename)
+{
+ int ret;
+
+ if (!strcmp(filename, "-"))
+ filename = "/dev/stdin";
+
+ if (!strcmp(filename, "/dev/stdin") &&
+ !nft_output_json(&nft->output))
+ nft->stdin_buf = stdin_to_buffer();
+
+ if (nft->optimize_flags) {
+ ret = nft_run_optimized_file(nft, filename);
+ free_const(nft->stdin_buf);
+ return ret;
+ }
+
+ ret = __nft_run_cmd_from_filename(nft, filename);
+ free_const(nft->stdin_buf);
+
+ return ret;
+}
diff --git a/src/libnftables.map b/src/libnftables.map
index 955af380..9369f44f 100644
--- a/src/libnftables.map
+++ b/src/libnftables.map
@@ -1,7 +1,7 @@
LIBNFTABLES_1 {
global:
nft_ctx_add_include_path;
- nft_ctx_clear_include_pat;
+ nft_ctx_clear_include_paths;
nft_ctx_new;
nft_ctx_buffer_output;
nft_ctx_unbuffer_output;
@@ -23,3 +23,18 @@ global:
local: *;
};
+
+LIBNFTABLES_2 {
+ nft_ctx_add_var;
+ nft_ctx_clear_vars;
+} LIBNFTABLES_1;
+
+LIBNFTABLES_3 {
+ nft_ctx_set_optimize;
+ nft_ctx_get_optimize;
+} LIBNFTABLES_2;
+
+LIBNFTABLES_4 {
+ nft_ctx_input_get_flags;
+ nft_ctx_input_set_flags;
+} LIBNFTABLES_3;
diff --git a/src/main.c b/src/main.c
index f77d8a82..d3491cda 100644
--- a/src/main.c
+++ b/src/main.c
@@ -8,12 +8,12 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
-#include <stdlib.h>
+#include <nft.h>
+
#include <stddef.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
-#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/types.h>
@@ -24,11 +24,48 @@
static struct nft_ctx *nft;
+enum opt_indices {
+ /* General options */
+ IDX_HELP,
+ IDX_VERSION,
+ IDX_VERSION_LONG,
+ /* Ruleset input handling */
+ IDX_FILE,
+#define IDX_RULESET_INPUT_START IDX_FILE
+ IDX_DEFINE,
+ IDX_INTERACTIVE,
+ IDX_INCLUDEPATH,
+ IDX_CHECK,
+ IDX_OPTIMIZE,
+#define IDX_RULESET_INPUT_END IDX_OPTIMIZE
+ /* Ruleset list formatting */
+ IDX_HANDLE,
+#define IDX_RULESET_LIST_START IDX_HANDLE
+ IDX_STATELESS,
+ IDX_TERSE,
+ IDX_SERVICE,
+ IDX_REVERSEDNS,
+ IDX_GUID,
+ IDX_NUMERIC,
+ IDX_NUMERIC_PRIO,
+ IDX_NUMERIC_PROTO,
+ IDX_NUMERIC_TIME,
+#define IDX_RULESET_LIST_END IDX_NUMERIC_TIME
+ /* Command output formatting */
+ IDX_ECHO,
+#define IDX_CMD_OUTPUT_START IDX_ECHO
+ IDX_JSON,
+ IDX_DEBUG,
+#define IDX_CMD_OUTPUT_END IDX_DEBUG
+};
+
enum opt_vals {
OPT_HELP = 'h',
OPT_VERSION = 'v',
+ OPT_VERSION_LONG = 'V',
OPT_CHECK = 'c',
OPT_FILE = 'f',
+ OPT_DEFINE = 'D',
OPT_INTERACTIVE = 'i',
OPT_INCLUDEPATH = 'I',
OPT_JSON = 'j',
@@ -42,116 +79,198 @@ enum opt_vals {
OPT_GUID = 'u',
OPT_NUMERIC_PRIO = 'y',
OPT_NUMERIC_PROTO = 'p',
- OPT_NUMERIC_TIME = 't',
+ OPT_NUMERIC_TIME = 'T',
+ OPT_TERSE = 't',
+ OPT_OPTIMIZE = 'o',
OPT_INVALID = '?',
};
-#define OPTSTRING "hvcf:iI:jvnsNaeSupypt"
-static const struct option options[] = {
- {
- .name = "help",
- .val = OPT_HELP,
- },
- {
- .name = "version",
- .val = OPT_VERSION,
- },
- {
- .name = "check",
- .val = OPT_CHECK,
- },
- {
- .name = "file",
- .val = OPT_FILE,
- .has_arg = 1,
- },
- {
- .name = "interactive",
- .val = OPT_INTERACTIVE,
- },
- {
- .name = "numeric",
- .val = OPT_NUMERIC,
- },
- {
- .name = "stateless",
- .val = OPT_STATELESS,
- },
- {
- .name = "reversedns",
- .val = OPT_IP2NAME,
- },
- {
- .name = "service",
- .val = OPT_SERVICE,
- },
- {
- .name = "includepath",
- .val = OPT_INCLUDEPATH,
- .has_arg = 1,
- },
- {
- .name = "debug",
- .val = OPT_DEBUG,
- .has_arg = 1,
- },
- {
- .name = "handle",
- .val = OPT_HANDLE_OUTPUT,
- },
- {
- .name = "echo",
- .val = OPT_ECHO,
- },
- {
- .name = "json",
- .val = OPT_JSON,
- },
- {
- .name = "guid",
- .val = OPT_GUID,
- },
- {
- .name = "numeric-priority",
- .val = OPT_NUMERIC_PRIO,
- },
- {
- .name = "numeric-time",
- .val = OPT_NUMERIC_TIME,
- },
- {
- .name = NULL
- }
+struct nft_opt {
+ const char *name;
+ enum opt_vals val;
+ const char *arg;
+ const char *help;
};
+#define NFT_OPT(n, v, a, h) \
+ (struct nft_opt) { .name = n, .val = v, .arg = a, .help = h }
+
+static const struct nft_opt nft_options[] = {
+ [IDX_HELP] = NFT_OPT("help", OPT_HELP, NULL,
+ "Show this help"),
+ [IDX_VERSION] = NFT_OPT("version", OPT_VERSION, NULL,
+ "Show version information"),
+ [IDX_VERSION_LONG] = NFT_OPT(NULL, OPT_VERSION_LONG, NULL,
+ "Show extended version information"),
+ [IDX_FILE] = NFT_OPT("file", OPT_FILE, "<filename>",
+ "Read input from <filename>"),
+ [IDX_DEFINE] = NFT_OPT("define", OPT_DEFINE, "<name=value>",
+ "Define variable, e.g. --define foo=1.2.3.4"),
+ [IDX_INTERACTIVE] = NFT_OPT("interactive", OPT_INTERACTIVE, NULL,
+ "Read input from interactive CLI"),
+ [IDX_INCLUDEPATH] = NFT_OPT("includepath", OPT_INCLUDEPATH, "<directory>",
+ "Add <directory> to the paths searched for include files. Default is: " DEFAULT_INCLUDE_PATH),
+ [IDX_CHECK] = NFT_OPT("check", OPT_CHECK, NULL,
+ "Check commands validity without actually applying the changes."),
+ [IDX_HANDLE] = NFT_OPT("handle", OPT_HANDLE_OUTPUT, NULL,
+ "Output rule handle."),
+ [IDX_STATELESS] = NFT_OPT("stateless", OPT_STATELESS, NULL,
+ "Omit stateful information of ruleset."),
+ [IDX_TERSE] = NFT_OPT("terse", OPT_TERSE, NULL,
+ "Omit contents of sets."),
+ [IDX_SERVICE] = NFT_OPT("service", OPT_SERVICE, NULL,
+ "Translate ports to service names as described in /etc/services."),
+ [IDX_REVERSEDNS] = NFT_OPT("reversedns", OPT_IP2NAME, NULL,
+ "Translate IP addresses to names."),
+ [IDX_GUID] = NFT_OPT("guid", OPT_GUID, NULL,
+ "Print UID/GID as defined in /etc/passwd and /etc/group."),
+ [IDX_NUMERIC] = NFT_OPT("numeric", OPT_NUMERIC, NULL,
+ "Print fully numerical output."),
+ [IDX_NUMERIC_PRIO] = NFT_OPT("numeric-priority", OPT_NUMERIC_PRIO, NULL,
+ "Print chain priority numerically."),
+ [IDX_NUMERIC_PROTO] = NFT_OPT("numeric-protocol", OPT_NUMERIC_PROTO, NULL,
+ "Print layer 4 protocols numerically."),
+ [IDX_NUMERIC_TIME] = NFT_OPT("numeric-time", OPT_NUMERIC_TIME, NULL,
+ "Print time values numerically."),
+ [IDX_ECHO] = NFT_OPT("echo", OPT_ECHO, NULL,
+ "Echo what has been added, inserted or replaced."),
+ [IDX_JSON] = NFT_OPT("json", OPT_JSON, NULL,
+ "Format output in JSON"),
+ [IDX_DEBUG] = NFT_OPT("debug", OPT_DEBUG, "<level [,level...]>",
+ "Specify debugging level (scanner, parser, eval, netlink, mnl, proto-ctx, segtree, all)"),
+ [IDX_OPTIMIZE] = NFT_OPT("optimize", OPT_OPTIMIZE, NULL,
+ "Optimize ruleset"),
+};
+
+#define NR_NFT_OPTIONS (sizeof(nft_options) / sizeof(nft_options[0]))
+
+static const char *get_optstring(void)
+{
+ static char optstring[2 * NR_NFT_OPTIONS + 2];
+
+ if (!optstring[0]) {
+ size_t i, j;
+
+ optstring[0] = '+';
+ for (i = 0, j = 1; i < NR_NFT_OPTIONS && j < sizeof(optstring); i++)
+ j += snprintf(optstring + j, sizeof(optstring) - j, "%c%s",
+ nft_options[i].val,
+ nft_options[i].arg ? ":" : "");
+
+ assert(j < sizeof(optstring));
+ }
+ return optstring;
+}
+
+static const struct option *get_options(void)
+{
+ static struct option options[NR_NFT_OPTIONS + 1];
+
+ if (!options[0].name) {
+ size_t i, j;
+
+ for (i = 0, j = 0; i < NR_NFT_OPTIONS; ++i) {
+ if (nft_options[i].name) {
+ options[j].name = nft_options[i].name;
+ options[j].val = nft_options[i].val;
+ options[j].has_arg = nft_options[i].arg != NULL;
+ j++;
+ }
+ }
+ }
+ return options;
+}
+
+static void print_option(const struct nft_opt *opt)
+{
+ char optbuf[35] = "";
+ int i;
+
+ i = snprintf(optbuf, sizeof(optbuf), " -%c", opt->val);
+ if (opt->name)
+ i += snprintf(optbuf + i, sizeof(optbuf) - i, ", --%s",
+ opt->name);
+ if (opt->arg)
+ i += snprintf(optbuf + i, sizeof(optbuf) - i, " %s", opt->arg);
+
+ printf("%-34s%s\n", optbuf, opt->help);
+}
+
static void show_help(const char *name)
{
- printf(
-"Usage: %s [ options ] [ cmds... ]\n"
-"\n"
-"Options:\n"
-" -h, --help Show this help\n"
-" -v, --version Show version information\n"
-"\n"
-" -c, --check Check commands validity without actually applying the changes.\n"
-" -f, --file <filename> Read input from <filename>\n"
-" -i, --interactive Read input from interactive CLI\n"
-"\n"
-" -j, --json Format output in JSON\n"
-" -n, --numeric Print fully numerical output.\n"
-" -s, --stateless Omit stateful information of ruleset.\n"
-" -u, --guid Print UID/GID as defined in /etc/passwd and /etc/group.\n"
-" -N Translate IP addresses to names.\n"
-" -S, --service Translate ports to service names as described in /etc/services.\n"
-" -p, --numeric-protocol Print layer 4 protocols numerically.\n"
-" -y, --numeric-priority Print chain priority numerically.\n"
-" -t, --numeric-time Print time values numerically.\n"
-" -a, --handle Output rule handle.\n"
-" -e, --echo Echo what has been added, inserted or replaced.\n"
-" -I, --includepath <directory> Add <directory> to the paths searched for include files. Default is: %s\n"
-" --debug <level [,level...]> Specify debugging level (scanner, parser, eval, netlink, mnl, proto-ctx, segtree, all)\n"
-"\n",
- name, DEFAULT_INCLUDE_PATH);
+ int i;
+
+ printf("Usage: %s [ options ] [ cmds... ]\n"
+ "\n"
+ "Options (general):\n", name);
+
+ print_option(&nft_options[IDX_HELP]);
+ print_option(&nft_options[IDX_VERSION]);
+ print_option(&nft_options[IDX_VERSION_LONG]);
+
+ printf("\n"
+ "Options (ruleset input handling):"
+ "\n");
+
+ for (i = IDX_RULESET_INPUT_START; i <= IDX_RULESET_INPUT_END; i++)
+ print_option(&nft_options[i]);
+
+ printf("\n"
+ "Options (ruleset list formatting):"
+ "\n");
+
+ for (i = IDX_RULESET_LIST_START; i <= IDX_RULESET_LIST_END; i++)
+ print_option(&nft_options[i]);
+
+ printf("\n"
+ "Options (command output formatting):"
+ "\n");
+
+ for (i = IDX_CMD_OUTPUT_START; i <= IDX_CMD_OUTPUT_END; i++)
+ print_option(&nft_options[i]);
+
+ fputs("\n", stdout);
+}
+
+static void show_version(void)
+{
+ const char *cli, *minigmp, *json, *xt;
+
+#if defined(HAVE_LIBREADLINE)
+ cli = "readline";
+#elif defined(HAVE_LIBEDIT)
+ cli = "editline";
+#elif defined(HAVE_LIBLINENOISE)
+ cli = "linenoise";
+#else
+ cli = "no";
+#endif
+
+#if defined(HAVE_MINIGMP)
+ minigmp = "yes";
+#else
+ minigmp = "no";
+#endif
+
+#if defined(HAVE_JSON)
+ json = "yes";
+#else
+ json = "no";
+#endif
+
+#if defined(HAVE_XTABLES)
+ xt = "yes";
+#else
+ xt = "no";
+#endif
+
+ printf("%s v%s (%s)\n"
+ " cli: %s\n"
+ " json: %s\n"
+ " minigmp: %s\n"
+ " libxtables: %s\n",
+ PACKAGE_NAME, PACKAGE_VERSION, RELEASE_NAME,
+ cli, json, minigmp, xt);
}
static const struct {
@@ -192,37 +311,113 @@ static const struct {
},
};
+static void nft_options_error(int argc, char * const argv[], int pos)
+{
+ int i;
+
+ fprintf(stderr, "Error: syntax error, options must be specified before commands\n");
+ for (i = 0; i < argc; i++)
+ fprintf(stderr, "%s ", argv[i]);
+ printf("\n%4c%*s\n", '^', pos - 2, "~~");
+}
+
+static bool nft_options_check(int argc, char * const argv[])
+{
+ bool skip = false, nonoption = false;
+ int pos = 0, i;
+ size_t j;
+
+ for (i = 1; i < argc; i++) {
+ pos += strlen(argv[i - 1]) + 1;
+ if (argv[i][0] == '{') {
+ break;
+ } else if (skip) {
+ skip = false;
+ continue;
+ } else if (argv[i][0] != '-') {
+ nonoption = true;
+ continue;
+ }
+ if (nonoption) {
+ nft_options_error(argc, argv, pos);
+ return false;
+ }
+ for (j = 0; j < NR_NFT_OPTIONS; j++) {
+ if (nft_options[j].arg &&
+ (argv[i][1] == (char)nft_options[j].val ||
+ (argv[i][1] == '-' &&
+ !strcmp(argv[i] + 2, nft_options[j].name)))) {
+ skip = true;
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
int main(int argc, char * const *argv)
{
- char *buf = NULL, *filename = NULL;
+ const struct option *options = get_options();
+ bool interactive = false, define = false;
+ const char *optstring = get_optstring();
unsigned int output_flags = 0;
- bool interactive = false;
+ int i, val, rc = EXIT_SUCCESS;
unsigned int debug_mask;
+ char *filename = NULL;
unsigned int len;
- int i, val, rc;
+
+ /* nftables cannot be used with setuid in a safe way. */
+ if (getuid() != geteuid())
+ _exit(111);
+
+ if (!nft_options_check(argc, argv))
+ exit(EXIT_FAILURE);
nft = nft_ctx_new(NFT_CTX_DEFAULT);
while (1) {
- val = getopt_long(argc, argv, OPTSTRING, options, NULL);
+ val = getopt_long(argc, argv, optstring, options, NULL);
if (val == -1)
break;
switch (val) {
case OPT_HELP:
show_help(argv[0]);
- exit(EXIT_SUCCESS);
+ goto out;
case OPT_VERSION:
printf("%s v%s (%s)\n",
PACKAGE_NAME, PACKAGE_VERSION, RELEASE_NAME);
- exit(EXIT_SUCCESS);
+ goto out;
+ case OPT_VERSION_LONG:
+ show_version();
+ goto out;
+ case OPT_DEFINE:
+ if (nft_ctx_add_var(nft, optarg)) {
+ fprintf(stderr,
+ "Failed to define variable '%s'\n",
+ optarg);
+ goto out_fail;
+ }
+ define = true;
+ break;
case OPT_CHECK:
nft_ctx_set_dry_run(nft, true);
break;
case OPT_FILE:
+ if (interactive) {
+ fprintf(stderr,
+ "Error: -i/--interactive and -f/--file options cannot be combined\n");
+ goto out_fail;
+ }
filename = optarg;
break;
case OPT_INTERACTIVE:
+ if (filename) {
+ fprintf(stderr,
+ "Error: -i/--interactive and -f/--file options cannot be combined\n");
+ goto out_fail;
+ }
interactive = true;
break;
case OPT_INCLUDEPATH:
@@ -230,12 +425,11 @@ int main(int argc, char * const *argv)
fprintf(stderr,
"Failed to add include path '%s'\n",
optarg);
- exit(EXIT_FAILURE);
+ goto out_fail;
}
break;
case OPT_NUMERIC:
output_flags |= NFT_CTX_OUTPUT_NUMERIC_ALL;
- output_flags |= NFT_CTX_OUTPUT_NUMERIC_TIME;
break;
case OPT_STATELESS:
output_flags |= NFT_CTX_OUTPUT_STATELESS;
@@ -266,7 +460,7 @@ int main(int argc, char * const *argv)
if (i == array_size(debug_param)) {
fprintf(stderr, "invalid debug parameter `%s'\n",
optarg);
- exit(EXIT_FAILURE);
+ goto out_fail;
}
if (end == NULL)
@@ -286,7 +480,7 @@ int main(int argc, char * const *argv)
output_flags |= NFT_CTX_OUTPUT_JSON;
#else
fprintf(stderr, "JSON support not compiled-in\n");
- exit(EXIT_FAILURE);
+ goto out_fail;
#endif
break;
case OPT_GUID:
@@ -301,14 +495,27 @@ int main(int argc, char * const *argv)
case OPT_NUMERIC_TIME:
output_flags |= NFT_CTX_OUTPUT_NUMERIC_TIME;
break;
+ case OPT_TERSE:
+ output_flags |= NFT_CTX_OUTPUT_TERSE;
+ break;
+ case OPT_OPTIMIZE:
+ nft_ctx_set_optimize(nft, 0x1);
+ break;
case OPT_INVALID:
- exit(EXIT_FAILURE);
+ goto out_fail;
}
}
+ if (!filename && define) {
+ fprintf(stderr, "Error: -D/--define can only be used with -f/--filename\n");
+ goto out_fail;
+ }
+
nft_ctx_output_set_flags(nft, output_flags);
if (optind != argc) {
+ char *buf;
+
for (len = 0, i = optind; i < argc; i++)
len += strlen(argv[i]) + strlen(" ");
@@ -316,7 +523,7 @@ int main(int argc, char * const *argv)
if (buf == NULL) {
fprintf(stderr, "%s:%u: Memory allocation failure\n",
__FILE__, __LINE__);
- exit(EXIT_FAILURE);
+ goto out_fail;
}
for (i = optind; i < argc; i++) {
strcat(buf, argv[i]);
@@ -324,22 +531,24 @@ int main(int argc, char * const *argv)
strcat(buf, " ");
}
rc = !!nft_run_cmd_from_buffer(nft, buf);
+ free(buf);
} else if (filename != NULL) {
rc = !!nft_run_cmd_from_filename(nft, filename);
} else if (interactive) {
if (cli_init(nft) < 0) {
fprintf(stderr, "%s: interactive CLI not supported in this build\n",
argv[0]);
- exit(EXIT_FAILURE);
+ goto out_fail;
}
- return EXIT_SUCCESS;
} else {
fprintf(stderr, "%s: no command specified\n", argv[0]);
- exit(EXIT_FAILURE);
+ goto out_fail;
}
- free(buf);
+out:
nft_ctx_free(nft);
-
return rc;
+out_fail:
+ nft_ctx_free(nft);
+ return EXIT_FAILURE;
}
diff --git a/src/mergesort.c b/src/mergesort.c
index 649b7806..5e676be1 100644
--- a/src/mergesort.c
+++ b/src/mergesort.c
@@ -2,53 +2,75 @@
* Copyright (c) 2017 Elise Lennion <elise.lennion@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
*/
-#include <stdint.h>
+#include <nft.h>
+
#include <expression.h>
#include <gmputil.h>
#include <list.h>
-static int expr_msort_cmp(const struct expr *e1, const struct expr *e2);
-
-static int concat_expr_msort_cmp(const struct expr *e1, const struct expr *e2)
+static void concat_expr_msort_value(const struct expr *expr, mpz_t value)
{
- struct list_head *l = (&e2->expressions)->next;
- const struct expr *i1, *i2;
- int ret;
-
- list_for_each_entry(i1, &e1->expressions, list) {
- i2 = list_entry(l, typeof(struct expr), list);
-
- ret = expr_msort_cmp(i1, i2);
- if (ret)
- return ret;
-
- l = l->next;
+ unsigned int len = 0, ilen;
+ const struct expr *i;
+ char data[512];
+
+ list_for_each_entry(i, &expr->expressions, list) {
+ ilen = div_round_up(i->len, BITS_PER_BYTE);
+ mpz_export_data(data + len, i->value, i->byteorder, ilen);
+ len += ilen;
}
- return false;
+ mpz_import_data(value, data, BYTEORDER_HOST_ENDIAN, len);
}
-static int expr_msort_cmp(const struct expr *e1, const struct expr *e2)
+static mpz_srcptr expr_msort_value(const struct expr *expr, mpz_t value)
{
- switch (e1->etype) {
+ switch (expr->etype) {
case EXPR_SET_ELEM:
- return expr_msort_cmp(e1->key, e2->key);
+ return expr_msort_value(expr->key, value);
+ case EXPR_BINOP:
+ case EXPR_MAPPING:
+ case EXPR_RANGE:
+ return expr_msort_value(expr->left, value);
case EXPR_VALUE:
- return mpz_cmp(e1->value, e2->value);
+ return expr->value;
case EXPR_CONCAT:
- return concat_expr_msort_cmp(e1, e2);
- case EXPR_MAPPING:
- return expr_msort_cmp(e1->left, e2->left);
+ concat_expr_msort_value(expr, value);
+ break;
+ case EXPR_SET_ELEM_CATCHALL:
+ /* max value to ensure listing shows it in the last position */
+ mpz_bitmask(value, expr->len);
+ break;
default:
- BUG("Unknown expression %s\n", expr_name(e1));
+ BUG("Unknown expression %s\n", expr_name(expr));
}
+ return value;
+}
+
+static int expr_msort_cmp(const struct expr *e1, const struct expr *e2)
+{
+ mpz_srcptr value1;
+ mpz_srcptr value2;
+ mpz_t value1_tmp;
+ mpz_t value2_tmp;
+ int ret;
+
+ mpz_init(value1_tmp);
+ mpz_init(value2_tmp);
+ value1 = expr_msort_value(e1, value1_tmp);
+ value2 = expr_msort_value(e2, value2_tmp);
+ ret = mpz_cmp(value1, value2);
+ mpz_clear(value1_tmp);
+ mpz_clear(value2_tmp);
+
+ return ret;
}
-static void list_splice_sorted(struct list_head *list, struct list_head *head)
+void list_splice_sorted(struct list_head *list, struct list_head *head)
{
struct list_head *h = head->next;
struct list_head *l = list->next;
@@ -56,7 +78,7 @@ static void list_splice_sorted(struct list_head *list, struct list_head *head)
while (l != list) {
if (h == head ||
expr_msort_cmp(list_entry(l, typeof(struct expr), list),
- list_entry(h, typeof(struct expr), list)) < 0) {
+ list_entry(h, typeof(struct expr), list)) <= 0) {
l = l->next;
list_add_tail(l->prev, h);
continue;
diff --git a/src/meta.c b/src/meta.c
index f54b818e..a17bacf0 100644
--- a/src/meta.c
+++ b/src/meta.c
@@ -10,13 +10,12 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <errno.h>
#include <limits.h>
#include <stddef.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <pwd.h>
@@ -25,6 +24,7 @@
#include <linux/netfilter.h>
#include <linux/pkt_sched.h>
#include <linux/if_packet.h>
+#include <time.h>
#include <nftables.h>
#include <expression.h>
@@ -37,10 +37,6 @@
#include <iface.h>
#include <json.h>
-#define _XOPEN_SOURCE
-#define __USE_XOPEN
-#include <time.h>
-
static void tchandle_type_print(const struct expr *expr,
struct output_ctx *octx)
{
@@ -66,50 +62,39 @@ static struct error_record *tchandle_type_parse(struct parse_ctx *ctx,
struct expr **res)
{
uint32_t handle;
- char *str = NULL;
if (strcmp(sym->identifier, "root") == 0)
handle = TC_H_ROOT;
else if (strcmp(sym->identifier, "none") == 0)
handle = TC_H_UNSPEC;
else if (strchr(sym->identifier, ':')) {
- uint16_t tmp;
- char *colon;
-
- str = xstrdup(sym->identifier);
-
- colon = strchr(str, ':');
- if (!colon)
- goto err;
-
- *colon = '\0';
+ char *colon, *end;
+ uint32_t tmp;
errno = 0;
- tmp = strtoull(str, NULL, 16);
- if (errno != 0)
+ tmp = strtoul(sym->identifier, &colon, 16);
+ if (errno != 0 || sym->identifier == colon)
goto err;
- handle = (tmp << 16);
- if (str[strlen(str) - 1] == ':')
- goto out;
+ if (*colon != ':')
+ goto err;
+ handle = tmp << 16;
errno = 0;
- tmp = strtoull(colon + 1, NULL, 16);
- if (errno != 0)
+ tmp = strtoul(colon + 1, &end, 16);
+ if (errno != 0 || *end)
goto err;
handle |= tmp;
} else {
handle = strtoull(sym->identifier, NULL, 0);
}
-out:
- xfree(str);
+
*res = constant_expr_alloc(&sym->location, sym->dtype,
BYTEORDER_HOST_ENDIAN,
sizeof(handle) * BITS_PER_BYTE, &handle);
return NULL;
err:
- xfree(str);
return error(&sym->location, "Could not parse %s", sym->dtype->desc);
}
@@ -220,18 +205,20 @@ static struct error_record *uid_type_parse(struct parse_ctx *ctx,
struct expr **res)
{
struct passwd *pw;
- uint64_t uid;
+ uid_t uid;
char *endptr = NULL;
pw = getpwnam(sym->identifier);
if (pw != NULL)
uid = pw->pw_uid;
else {
- uid = strtoull(sym->identifier, &endptr, 10);
- if (uid > UINT32_MAX)
+ uint64_t _uid = strtoull(sym->identifier, &endptr, 10);
+
+ if (_uid > UINT32_MAX)
return error(&sym->location, "Value too large");
else if (*endptr)
return error(&sym->location, "User does not exist");
+ uid = _uid;
}
*res = constant_expr_alloc(&sym->location, sym->dtype,
@@ -274,18 +261,20 @@ static struct error_record *gid_type_parse(struct parse_ctx *ctx,
struct expr **res)
{
struct group *gr;
- uint64_t gid;
+ gid_t gid;
char *endptr = NULL;
gr = getgrnam(sym->identifier);
if (gr != NULL)
gid = gr->gr_gid;
else {
- gid = strtoull(sym->identifier, &endptr, 0);
- if (gid > UINT32_MAX)
+ uint64_t _gid = strtoull(sym->identifier, &endptr, 0);
+
+ if (_gid > UINT32_MAX)
return error(&sym->location, "Value too large");
else if (*endptr)
return error(&sym->location, "Group does not exist");
+ gid = _gid;
}
*res = constant_expr_alloc(&sym->location, sym->dtype,
@@ -336,7 +325,7 @@ const struct datatype pkttype_type = {
void devgroup_table_init(struct nft_ctx *ctx)
{
- ctx->output.tbl.devgroup = rt_symbol_table_init("/etc/iproute2/group");
+ ctx->output.tbl.devgroup = rt_symbol_table_init("group");
}
void devgroup_table_exit(struct nft_ctx *ctx)
@@ -357,17 +346,23 @@ static struct error_record *devgroup_type_parse(struct parse_ctx *ctx,
return symbolic_constant_parse(ctx, sym, ctx->tbl->devgroup, res);
}
+static void devgroup_type_describe(struct output_ctx *octx)
+{
+ rt_symbol_table_describe(octx, "group",
+ octx->tbl.devgroup, &devgroup_type);
+}
+
const struct datatype devgroup_type = {
.type = TYPE_DEVGROUP,
.name = "devgroup",
.desc = "devgroup name",
+ .describe = devgroup_type_describe,
.byteorder = BYTEORDER_HOST_ENDIAN,
.size = 4 * BITS_PER_BYTE,
.basetype = &integer_type,
.print = devgroup_type_print,
.json = devgroup_type_json,
.parse = devgroup_type_parse,
- .flags = DTYPE_F_PREFIX,
};
const struct datatype ifname_type = {
@@ -381,51 +376,43 @@ const struct datatype ifname_type = {
static void date_type_print(const struct expr *expr, struct output_ctx *octx)
{
- uint64_t tstamp = mpz_get_uint64(expr->value);
- struct tm *tm, *cur_tm;
+ uint64_t tstamp64 = mpz_get_uint64(expr->value);
char timestr[21];
+ time_t tstamp;
+ struct tm tm;
/* Convert from nanoseconds to seconds */
- tstamp /= 1000000000L;
-
- if (!nft_output_seconds(octx)) {
- /* Obtain current tm, to add tm_gmtoff to the timestamp */
- cur_tm = localtime((time_t *) &tstamp);
+ tstamp64 /= 1000000000L;
- if (cur_tm)
- tstamp += cur_tm->tm_gmtoff;
-
- if ((tm = gmtime((time_t *) &tstamp)) != NULL &&
- strftime(timestr, sizeof(timestr) - 1, "%F %T", tm))
- nft_print(octx, "\"%s\"", timestr);
- else
- nft_print(octx, "Error converting timestamp to printed time");
-
- return;
- }
+ /* Obtain current tm, to add tm_gmtoff to the timestamp */
+ tstamp = tstamp64;
+ if (localtime_r(&tstamp, &tm))
+ tstamp64 += tm.tm_gmtoff;
- /*
- * Do our own printing. The default print function will print in
- * nanoseconds, which is ugly.
- */
- nft_print(octx, "%lu", tstamp);
+ tstamp = tstamp64;
+ if (gmtime_r(&tstamp, &tm) &&
+ strftime(timestr, sizeof(timestr) - 1, "%Y-%m-%d %T", &tm))
+ nft_print(octx, "\"%s\"", timestr);
+ else
+ nft_print(octx, "Error converting timestamp to printed time");
}
-static time_t parse_iso_date(const char *sym)
+static bool parse_iso_date(uint64_t *tstamp, const char *sym)
{
- struct tm tm, *cur_tm;
+ struct tm cur_tm;
+ struct tm tm;
time_t ts;
memset(&tm, 0, sizeof(struct tm));
- if (strptime(sym, "%F %T", &tm))
+ if (strptime(sym, "%Y-%m-%d %T", &tm))
goto success;
- if (strptime(sym, "%F %R", &tm))
+ if (strptime(sym, "%Y-%m-%d %R", &tm))
goto success;
- if (strptime(sym, "%F", &tm))
+ if (strptime(sym, "%Y-%m-%d", &tm))
goto success;
- return -1;
+ return false;
success:
/*
@@ -435,14 +422,17 @@ success:
*/
ts = timegm(&tm);
- /* Obtain current tm as well (at the specified time), so that we can substract tm_gmtoff */
- cur_tm = localtime(&ts);
+ if (ts == (time_t) -1)
+ return false;
- if (ts == (time_t) -1 || cur_tm == NULL)
- return ts;
+ /* Obtain current tm as well (at the specified time), so that we can substract tm_gmtoff */
+ if (!localtime_r(&ts, &cur_tm))
+ return false;
/* Substract tm_gmtoff to get the current time */
- return ts - cur_tm->tm_gmtoff;
+ *tstamp = ts - cur_tm.tm_gmtoff;
+
+ return true;
}
static struct error_record *date_type_parse(struct parse_ctx *ctx,
@@ -450,9 +440,9 @@ static struct error_record *date_type_parse(struct parse_ctx *ctx,
struct expr **res)
{
const char *endptr = sym->identifier;
- time_t tstamp;
+ uint64_t tstamp;
- if ((tstamp = parse_iso_date(sym->identifier)) != -1)
+ if (parse_iso_date(&tstamp, sym->identifier))
goto success;
tstamp = strtoul(sym->identifier, (char **) &endptr, 10);
@@ -490,46 +480,35 @@ static void day_type_print(const struct expr *expr, struct output_ctx *octx)
return symbolic_constant_print(&day_type_tbl, expr, true, octx);
}
-static void __hour_type_print_r(int hours, int minutes, int seconds, char *out, size_t buflen)
-{
- if (minutes == 60)
- return __hour_type_print_r(++hours, 0, seconds, out, buflen);
- else if (minutes > 60)
- return __hour_type_print_r((int) (minutes / 60), minutes % 60, seconds, out, buflen);
-
- if (seconds == 60)
- return __hour_type_print_r(hours, ++minutes, 0, out, buflen);
- else if (seconds > 60)
- return __hour_type_print_r(hours, (int) (seconds / 60), seconds % 60, out, buflen);
-
- if (seconds == 0)
- snprintf(out, buflen, "%02d:%02d", hours, minutes);
- else
- snprintf(out, buflen, "%02d:%02d:%02d", hours, minutes, seconds);
-}
+#define SECONDS_PER_DAY (60 * 60 * 24)
static void hour_type_print(const struct expr *expr, struct output_ctx *octx)
{
- uint32_t seconds = mpz_get_uint32(expr->value);
- struct tm *cur_tm;
- char out[32];
+ uint32_t seconds = mpz_get_uint32(expr->value), minutes, hours;
+ struct tm cur_tm;
time_t ts;
- if (!nft_output_seconds(octx)) {
- /* Obtain current tm, so that we can add tm_gmtoff */
- ts = time(NULL);
- cur_tm = localtime(&ts);
-
- if (cur_tm)
- seconds = (seconds + cur_tm->tm_gmtoff) % 86400;
+ /* Obtain current tm, so that we can add tm_gmtoff */
+ ts = time(NULL);
+ if (ts != ((time_t) -1) && localtime_r(&ts, &cur_tm)) {
+ int32_t adj = seconds + cur_tm.tm_gmtoff;
- __hour_type_print_r(0, 0, seconds, out, sizeof(out));
- nft_print(octx, "\"%s\"", out);
+ if (adj < 0)
+ adj += SECONDS_PER_DAY;
+ else if (adj >= SECONDS_PER_DAY)
+ adj -= SECONDS_PER_DAY;
- return;
+ seconds = adj;
}
-
- expr_basetype(expr)->print(expr, octx);
+ minutes = seconds / 60;
+ seconds %= 60;
+ hours = minutes / 60;
+ minutes %= 60;
+
+ nft_print(octx, "\"%02d:%02d", hours, minutes);
+ if (seconds)
+ nft_print(octx, ":%02d", seconds);
+ nft_print(octx, "\"");
}
static struct error_record *hour_type_parse(struct parse_ctx *ctx,
@@ -537,9 +516,12 @@ static struct error_record *hour_type_parse(struct parse_ctx *ctx,
struct expr **res)
{
struct error_record *er;
- struct tm tm, *cur_tm;
- uint64_t result = 0;
+ struct tm cur_tm_data;
+ struct tm *cur_tm;
+ uint32_t result;
+ uint64_t tmp;
char *endptr;
+ struct tm tm;
time_t ts;
memset(&tm, 0, sizeof(struct tm));
@@ -553,7 +535,10 @@ static struct error_record *hour_type_parse(struct parse_ctx *ctx,
/* Obtain current tm, so that we can substract tm_gmtoff */
ts = time(NULL);
- cur_tm = localtime(&ts);
+ if (ts != ((time_t) -1) && localtime_r(&ts, &cur_tm_data))
+ cur_tm = &cur_tm_data;
+ else
+ cur_tm = NULL;
endptr = strptime(sym->identifier, "%T", &tm);
if (endptr && *endptr == '\0')
@@ -566,8 +551,8 @@ static struct error_record *hour_type_parse(struct parse_ctx *ctx,
if (endptr && *endptr)
return error(&sym->location, "Can't parse trailing input: \"%s\"\n", endptr);
- if ((er = time_parse(&sym->location, sym->identifier, &result)) == NULL) {
- result /= 1000;
+ if ((er = time_parse(&sym->location, sym->identifier, &tmp)) == NULL) {
+ result = tmp / 1000;
goto convert;
}
@@ -621,7 +606,7 @@ const struct datatype hour_type = {
.name = "hour",
.desc = "Hour of day of packet reception",
.byteorder = BYTEORDER_HOST_ENDIAN,
- .size = sizeof(uint64_t) * BITS_PER_BYTE,
+ .size = sizeof(uint32_t) * BITS_PER_BYTE,
.basetype = &integer_type,
.print = hour_type_print,
.parse = hour_type_parse,
@@ -709,6 +694,16 @@ const struct meta_template meta_templates[] = {
[NFT_META_TIME_HOUR] = META_TEMPLATE("hour", &hour_type,
4 * BITS_PER_BYTE,
BYTEORDER_HOST_ENDIAN),
+ [NFT_META_SECMARK] = META_TEMPLATE("secmark", &integer_type,
+ 32, BYTEORDER_HOST_ENDIAN),
+ [NFT_META_SDIF] = META_TEMPLATE("sdif", &ifindex_type,
+ sizeof(int) * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_SDIFNAME] = META_TEMPLATE("sdifname", &ifname_type,
+ IFNAMSIZ * BITS_PER_BYTE,
+ BYTEORDER_HOST_ENDIAN),
+ [NFT_META_BRI_BROUTE] = META_TEMPLATE("broute", &integer_type,
+ 1 , BYTEORDER_HOST_ENDIAN),
};
static bool meta_key_is_unqualified(enum nft_meta_keys key)
@@ -728,12 +723,16 @@ static bool meta_key_is_unqualified(enum nft_meta_keys key)
static void meta_expr_print(const struct expr *expr, struct output_ctx *octx)
{
- if (meta_key_is_unqualified(expr->meta.key))
- nft_print(octx, "%s",
- meta_templates[expr->meta.key].token);
+ const char *token = "unknown";
+ uint32_t key = expr->meta.key;
+
+ if (key < array_size(meta_templates))
+ token = meta_templates[key].token;
+
+ if (meta_key_is_unqualified(key))
+ nft_print(octx, "%s", token);
else
- nft_print(octx, "meta %s",
- meta_templates[expr->meta.key].token);
+ nft_print(octx, "meta %s", token);
}
static bool meta_expr_cmp(const struct expr *e1, const struct expr *e2)
@@ -745,6 +744,7 @@ static void meta_expr_clone(struct expr *new, const struct expr *expr)
{
new->meta.key = expr->meta.key;
new->meta.base = expr->meta.base;
+ new->meta.inner_desc = expr->meta.inner_desc;
}
/**
@@ -756,10 +756,11 @@ static void meta_expr_clone(struct expr *new, const struct expr *expr)
* Update LL protocol context based on IIFTYPE meta match in non-LL hooks.
*/
static void meta_expr_pctx_update(struct proto_ctx *ctx,
- const struct expr *expr)
+ const struct location *loc,
+ const struct expr *left,
+ const struct expr *right)
{
const struct hook_proto_desc *h = &hook_proto_desc[ctx->family];
- const struct expr *left = expr->left, *right = expr->right;
const struct proto_desc *desc;
uint8_t protonum;
@@ -774,10 +775,15 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
if (desc == NULL)
desc = &proto_unknown;
- proto_ctx_update(ctx, PROTO_BASE_LL_HDR, &expr->location, desc);
+ proto_ctx_update(ctx, PROTO_BASE_LL_HDR, loc, desc);
break;
case NFT_META_NFPROTO:
protonum = mpz_get_uint8(right->value);
+ if (protonum == NFPROTO_IPV4 && h->desc == &proto_ip)
+ break;
+ else if (protonum == NFPROTO_IPV6 && h->desc == &proto_ip6)
+ break;
+
desc = proto_find_upper(h->desc, protonum);
if (desc == NULL) {
desc = &proto_unknown;
@@ -787,7 +793,7 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
desc = h->desc;
}
- proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, &expr->location, desc);
+ proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, loc, desc);
break;
case NFT_META_L4PROTO:
desc = proto_find_upper(&proto_inet_service,
@@ -795,7 +801,7 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
if (desc == NULL)
desc = &proto_unknown;
- proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR, &expr->location, desc);
+ proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR, loc, desc);
break;
case NFT_META_PROTOCOL:
if (h->base != PROTO_BASE_LL_HDR)
@@ -809,13 +815,78 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
if (desc == NULL)
desc = &proto_unknown;
- proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, &expr->location, desc);
+ proto_ctx_update(ctx, PROTO_BASE_NETWORK_HDR, loc, desc);
break;
default:
break;
}
}
+#define NFTNL_UDATA_META_KEY 0
+#define NFTNL_UDATA_META_INNER_DESC 1
+#define NFTNL_UDATA_META_MAX 2
+
+static int meta_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_META_KEY, expr->meta.key);
+
+ if (expr->meta.inner_desc) {
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_META_INNER_DESC,
+ expr->meta.inner_desc->id);
+ }
+
+ return 0;
+}
+
+static int meta_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_META_KEY:
+ case NFTNL_UDATA_META_INNER_DESC:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *meta_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_META_MAX + 1] = {};
+ const struct proto_desc *desc;
+ struct expr *expr;
+ uint32_t key;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ meta_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_META_KEY])
+ return NULL;
+
+ key = nftnl_udata_get_u32(ud[NFTNL_UDATA_META_KEY]);
+
+ expr = meta_expr_alloc(&internal_location, key);
+
+ if (ud[NFTNL_UDATA_META_INNER_DESC]) {
+ desc = find_proto_desc(ud[NFTNL_UDATA_META_INNER_DESC]);
+ expr->meta.inner_desc = desc;
+ }
+
+ return expr;
+}
+
const struct expr_ops meta_expr_ops = {
.type = EXPR_META,
.name = "meta",
@@ -824,6 +895,8 @@ const struct expr_ops meta_expr_ops = {
.cmp = meta_expr_cmp,
.clone = meta_expr_clone,
.pctx_update = meta_expr_pctx_update,
+ .build_udata = meta_expr_build_udata,
+ .parse_udata = meta_expr_parse_udata,
};
struct expr *meta_expr_alloc(const struct location *loc, enum nft_meta_keys key)
@@ -860,12 +933,16 @@ struct expr *meta_expr_alloc(const struct location *loc, enum nft_meta_keys key)
static void meta_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
{
+ const char *token = "unknown";
+ uint32_t key = stmt->meta.key;
+
+ if (key < array_size(meta_templates))
+ token = meta_templates[key].token;
+
if (meta_key_is_unqualified(stmt->meta.key))
- nft_print(octx, "%s set ",
- meta_templates[stmt->meta.key].token);
+ nft_print(octx, "%s set ", token);
else
- nft_print(octx, "meta %s set ",
- meta_templates[stmt->meta.key].token);
+ nft_print(octx, "meta %s set ", token);
expr_print(stmt->meta.expr, octx);
}
@@ -890,8 +967,11 @@ struct stmt *meta_stmt_alloc(const struct location *loc, enum nft_meta_keys key,
stmt = stmt_alloc(loc, &meta_stmt_ops);
stmt->meta.key = key;
- stmt->meta.tmpl = &meta_templates[key];
stmt->meta.expr = expr;
+
+ if (key < array_size(meta_templates))
+ stmt->meta.tmpl = &meta_templates[key];
+
return stmt;
}
@@ -919,11 +999,11 @@ struct error_record *meta_key_parse(const struct location *loc,
const char *str,
unsigned int *value)
{
- int ret, len, offset = 0;
const char *sep = "";
+ size_t offset = 0;
unsigned int i;
char buf[1024];
- size_t size;
+ size_t len;
for (i = 0; i < array_size(meta_templates); i++) {
if (!meta_templates[i].token || strcmp(meta_templates[i].token, str))
@@ -946,9 +1026,10 @@ struct error_record *meta_key_parse(const struct location *loc,
}
len = (int)sizeof(buf);
- size = sizeof(buf);
for (i = 0; i < array_size(meta_templates); i++) {
+ int ret;
+
if (!meta_templates[i].token)
continue;
@@ -956,8 +1037,8 @@ struct error_record *meta_key_parse(const struct location *loc,
sep = ", ";
ret = snprintf(buf+offset, len, "%s%s", sep, meta_templates[i].token);
- SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
- assert(offset < (int)sizeof(buf));
+ SNPRINTF_BUFFER_SIZE(ret, &len, &offset);
+ assert(len > 0);
}
return error(loc, "syntax error, unexpected %s, known keys are %s", str, buf);
diff --git a/src/mini-gmp.c b/src/mini-gmp.c
index 04bed3f5..186dc3a4 100644
--- a/src/mini-gmp.c
+++ b/src/mini-gmp.c
@@ -41,12 +41,12 @@ see https://www.gnu.org/licenses/. */
mpn/generic/sbpi1_div_qr.c, mpn/generic/sub_n.c,
mpn/generic/submul_1.c. */
+#include <nft.h>
+
#include <assert.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include "mini-gmp.h"
diff --git a/src/misspell.c b/src/misspell.c
index 6536d755..f5354fa8 100644
--- a/src/misspell.c
+++ b/src/misspell.c
@@ -1,5 +1,13 @@
-#include <stdlib.h>
-#include <string.h>
+/*
+ * Copyright (c) 2018 Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
#include <limits.h>
#include <utils.h>
#include <misspell.h>
@@ -64,7 +72,7 @@ static unsigned int string_distance(const char *a, const char *b)
ret = DISTANCE(len_a, len_b);
- xfree(distance);
+ free(distance);
return ret;
}
diff --git a/src/mnl.c b/src/mnl.c
index 14fa4a71..9e4bfcd9 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -2,12 +2,14 @@
* Copyright (c) 2013-2017 Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
*
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <libmnl/libmnl.h>
#include <libnftnl/common.h>
#include <libnftnl/ruleset.h>
@@ -22,20 +24,37 @@
#include <libnftnl/udata.h>
#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_hook.h>
#include <linux/netfilter/nf_tables.h>
#include <mnl.h>
-#include <string.h>
+#include <cmd.h>
+#include <net/if.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#include <utils.h>
#include <nftables.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_arp.h>
+
+struct basehook {
+ struct list_head list;
+ const char *module_name;
+ const char *hookfn;
+ const char *table;
+ const char *chain;
+ int family;
+ int chain_family;
+ uint32_t num;
+ int prio;
+};
struct mnl_socket *nft_mnl_socket_open(void)
{
struct mnl_socket *nf_sock;
+ int one = 1;
nf_sock = mnl_socket_open(NETLINK_NETFILTER);
if (!nf_sock)
@@ -44,14 +63,9 @@ struct mnl_socket *nft_mnl_socket_open(void)
if (fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK))
netlink_init_error();
- return nf_sock;
-}
-
-struct mnl_socket *nft_mnl_socket_reopen(struct mnl_socket *nf_sock)
-{
- mnl_socket_close(nf_sock);
+ mnl_socket_setsockopt(nf_sock, NETLINK_EXT_ACK, &one, sizeof(one));
- return nft_mnl_socket_open();
+ return nf_sock;
}
uint32_t mnl_seqnum_alloc(unsigned int *seqnum)
@@ -72,20 +86,31 @@ nft_mnl_recv(struct netlink_ctx *ctx, uint32_t portid,
int (*cb)(const struct nlmsghdr *nlh, void *data), void *cb_data)
{
char buf[NFT_NLMSG_MAXSIZE];
+ bool eintr = false;
int ret;
ret = mnl_socket_recvfrom(ctx->nft->nf_sock, buf, sizeof(buf));
while (ret > 0) {
ret = mnl_cb_run(buf, ret, ctx->seqnum, portid, cb, cb_data);
- if (ret <= 0)
- goto out;
+ if (ret == 0)
+ break;
+ if (ret < 0) {
+ if (errno == EAGAIN) {
+ ret = 0;
+ break;
+ }
+ if (errno != EINTR)
+ break;
+ /* process all pending messages before reporting EINTR */
+ eintr = true;
+ }
ret = mnl_socket_recvfrom(ctx->nft->nf_sock, buf, sizeof(buf));
}
-out:
- if (ret < 0 && errno == EAGAIN)
- return 0;
-
+ if (eintr) {
+ ret = -1;
+ errno = EINTR;
+ }
return ret;
}
@@ -151,11 +176,11 @@ static int check_genid(const struct nlmsghdr *nlh)
* Batching
*/
-/* selected batch page is 256 Kbytes long to load ruleset of
- * half a million rules without hitting -EMSGSIZE due to large
- * iovec.
+/* Selected batch page is 2 Mbytes long to support loading a ruleset of 3.5M
+ * rules matching on source and destination address as well as input and output
+ * interfaces. This is what legacy iptables supports.
*/
-#define BATCH_PAGE_SIZE getpagesize() * 32
+#define BATCH_PAGE_SIZE 2 * 1024 * 1024
struct nftnl_batch *mnl_batch_init(void)
{
@@ -203,11 +228,13 @@ void mnl_batch_reset(struct nftnl_batch *batch)
}
static void mnl_err_list_node_add(struct list_head *err_list, int error,
- int seqnum)
+ int seqnum, uint32_t offset,
+ const char *errmsg)
{
struct mnl_err *err = xmalloc(sizeof(struct mnl_err));
err->seqnum = seqnum;
+ err->offset = offset;
err->err = error;
list_add_tail(&err->head, err_list);
}
@@ -215,12 +242,13 @@ static void mnl_err_list_node_add(struct list_head *err_list, int error,
void mnl_err_list_free(struct mnl_err *err)
{
list_del(&err->head);
- xfree(err);
+ free(err);
}
-static void mnl_set_sndbuffer(const struct mnl_socket *nl,
- struct nftnl_batch *batch)
+static void mnl_set_sndbuffer(struct netlink_ctx *ctx)
{
+ struct mnl_socket *nl = ctx->nft->nf_sock;
+ struct nftnl_batch *batch = ctx->batch;
socklen_t len = sizeof(int);
int sndnlbuffsiz = 0;
int newbuffsiz;
@@ -233,9 +261,15 @@ static void mnl_set_sndbuffer(const struct mnl_socket *nl,
return;
/* Rise sender buffer length to avoid hitting -EMSGSIZE */
+ setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_SNDBUF,
+ &newbuffsiz, sizeof(socklen_t));
+
+ /* unpriviledged containers check for CAP_NET_ADMIN on the init_user_ns. */
if (setsockopt(mnl_socket_get_fd(nl), SOL_SOCKET, SO_SNDBUFFORCE,
- &newbuffsiz, sizeof(socklen_t)) < 0)
- return;
+ &newbuffsiz, sizeof(socklen_t)) < 0) {
+ if (errno == EPERM)
+ ctx->maybe_emsgsize = newbuffsiz;
+ }
}
static unsigned int nlsndbufsiz;
@@ -266,24 +300,16 @@ static int mnl_set_rcvbuffer(const struct mnl_socket *nl, socklen_t bufsiz)
return ret;
}
-static size_t mnl_nft_batch_to_msg(struct netlink_ctx *ctx, struct msghdr *msg,
- const struct sockaddr_nl *snl,
- struct iovec *iov, unsigned int iov_len)
+static void mnl_nft_batch_to_msg(struct netlink_ctx *ctx, struct msghdr *msg,
+ const struct sockaddr_nl *snl,
+ struct iovec *iov, unsigned int iov_len)
{
- unsigned int i;
- size_t len = 0;
-
msg->msg_name = (struct sockaddr_nl *)snl;
msg->msg_namelen = sizeof(*snl);
msg->msg_iov = iov;
msg->msg_iovlen = iov_len;
nftnl_batch_iovec(ctx->batch, iov, iov_len);
-
- for (i = 0; i < iov_len; i++)
- len += msg->msg_iov[i].iov_len;
-
- return len;
}
static ssize_t mnl_nft_socket_sendmsg(struct netlink_ctx *ctx,
@@ -304,7 +330,65 @@ static ssize_t mnl_nft_socket_sendmsg(struct netlink_ctx *ctx,
return sendmsg(mnl_socket_get_fd(ctx->nft->nf_sock), msg, 0);
}
-#define NFT_MNL_ECHO_RCVBUFF_DEFAULT (MNL_SOCKET_BUFFER_SIZE * 1024)
+static int err_attr_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ uint16_t type;
+
+ if (mnl_attr_type_valid(attr, NLMSGERR_ATTR_MAX) < 0)
+ return MNL_CB_ERROR;
+
+ type = mnl_attr_get_type(attr);
+ switch (type) {
+ case NLMSGERR_ATTR_OFFS:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ return MNL_CB_ERROR;
+ break;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int mnl_batch_extack_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct netlink_cb_data *cb_data = data;
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
+ const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
+ unsigned int hlen = sizeof(*err);
+ const char *msg = NULL;
+ uint32_t off = 0;
+ int errval;
+
+ if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr)))
+ return MNL_CB_ERROR;
+
+ if (err->error < 0)
+ errval = -err->error;
+ else
+ errval = err->error;
+
+ if (errval == 0)
+ return MNL_CB_STOP;
+
+ if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
+ hlen += mnl_nlmsg_get_payload_len(&err->msg);
+
+ if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
+ return MNL_CB_ERROR;
+
+ if (tb[NLMSGERR_ATTR_OFFS])
+ off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
+
+ mnl_err_list_node_add(cb_data->err_list, errval,
+ nlh->nlmsg_seq, off, msg);
+ return MNL_CB_ERROR;
+}
+
+#define NFT_MNL_ECHO_RCVBUFF_DEFAULT (MNL_SOCKET_BUFFER_SIZE * 1024U)
+#define NFT_MNL_ACK_MAXSIZE ((sizeof(struct nlmsghdr) + \
+ sizeof(struct nfgenmsg) + (1 << 16)) + \
+ MNL_SOCKET_BUFFER_SIZE)
int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
uint32_t num_cmds)
@@ -312,7 +396,7 @@ int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
struct mnl_socket *nl = ctx->nft->nf_sock;
int ret, fd = mnl_socket_get_fd(nl), portid = mnl_socket_get_portid(nl);
uint32_t iov_len = nftnl_batch_iovec_len(ctx->batch);
- char rcv_buf[MNL_SOCKET_BUFFER_SIZE];
+ char rcv_buf[NFT_MNL_ACK_MAXSIZE];
const struct sockaddr_nl snl = {
.nl_family = AF_NETLINK
};
@@ -323,19 +407,23 @@ int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
struct iovec iov[iov_len];
struct msghdr msg = {};
unsigned int rcvbufsiz;
- size_t batch_size;
fd_set readfds;
+ static mnl_cb_t cb_ctl_array[NLMSG_MIN_TYPE] = {
+ [NLMSG_ERROR] = mnl_batch_extack_cb,
+ };
+ struct netlink_cb_data cb_data = {
+ .err_list = err_list,
+ .nl_ctx = ctx,
+ };
- mnl_set_sndbuffer(ctx->nft->nf_sock, ctx->batch);
+ mnl_set_sndbuffer(ctx);
- batch_size = mnl_nft_batch_to_msg(ctx, &msg, &snl, iov, iov_len);
+ mnl_nft_batch_to_msg(ctx, &msg, &snl, iov, iov_len);
+ rcvbufsiz = num_cmds * 1024;
if (nft_output_echo(&ctx->nft->output)) {
- rcvbufsiz = num_cmds * 1024;
if (rcvbufsiz < NFT_MNL_ECHO_RCVBUFF_DEFAULT)
rcvbufsiz = NFT_MNL_ECHO_RCVBUFF_DEFAULT;
- } else {
- rcvbufsiz = num_cmds * div_round_up(batch_size, num_cmds) * 4;
}
mnl_set_rcvbuffer(ctx->nft->nf_sock, rcvbufsiz);
@@ -360,32 +448,69 @@ int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
if (ret == -1)
return -1;
- ret = mnl_cb_run(rcv_buf, ret, 0, portid, &netlink_echo_callback, ctx);
/* Continue on error, make sure we get all acknowledgments */
- if (ret == -1) {
- struct nlmsghdr *nlh = (struct nlmsghdr *)rcv_buf;
-
- mnl_err_list_node_add(err_list, errno, nlh->nlmsg_seq);
- }
+ ret = mnl_cb_run2(rcv_buf, ret, 0, portid,
+ netlink_echo_callback, &cb_data,
+ cb_ctl_array, MNL_ARRAY_SIZE(cb_ctl_array));
}
return 0;
}
-int mnl_nft_rule_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+struct mnl_nft_rule_build_ctx {
+ struct netlink_linearize_ctx *lctx;
+ struct nlmsghdr *nlh;
+ struct cmd *cmd;
+};
+
+static int mnl_nft_expr_build_cb(struct nftnl_expr *nle, void *data)
+{
+ struct mnl_nft_rule_build_ctx *ctx = data;
+ struct nlmsghdr *nlh = ctx->nlh;
+ struct cmd *cmd = ctx->cmd;
+ struct nft_expr_loc *eloc;
+ struct nlattr *nest;
+
+ eloc = nft_expr_loc_find(nle, ctx->lctx);
+ if (eloc)
+ cmd_add_loc(cmd, nlh->nlmsg_len, eloc->loc);
+
+ nest = mnl_attr_nest_start(nlh, NFTA_LIST_ELEM);
+ nftnl_expr_build_payload(nlh, nle);
+ mnl_attr_nest_end(nlh, nest);
+
+ nftnl_rule_del_expr(nle);
+ nftnl_expr_free(nle);
+
+ return 0;
+}
+
+static void mnl_nft_rule_build_ctx_init(struct mnl_nft_rule_build_ctx *rule_ctx,
+ struct nlmsghdr *nlh,
+ struct cmd *cmd,
+ struct netlink_linearize_ctx *lctx)
+{
+ memset(rule_ctx, 0, sizeof(*rule_ctx));
+ rule_ctx->nlh = nlh;
+ rule_ctx->cmd = cmd;
+ rule_ctx->lctx = lctx;
+}
+
+int mnl_nft_rule_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
+ struct mnl_nft_rule_build_ctx rule_ctx;
+ struct netlink_linearize_ctx lctx;
struct rule *rule = cmd->rule;
struct handle *h = &rule->handle;
struct nftnl_rule *nlr;
struct nlmsghdr *nlh;
+ struct nlattr *nest;
nlr = nftnl_rule_alloc();
if (!nlr)
memory_allocation_error();
nftnl_rule_set_u32(nlr, NFTNL_RULE_FAMILY, h->family);
- nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, h->table.name);
- nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, h->chain.name);
if (h->position.id)
nftnl_rule_set_u64(nlr, NFTNL_RULE_POSITION, h->position.id);
if (h->rule_id)
@@ -393,26 +518,47 @@ int mnl_nft_rule_add(struct netlink_ctx *ctx, const struct cmd *cmd,
if (h->position_id)
nftnl_rule_set_u32(nlr, NFTNL_RULE_POSITION_ID, h->position_id);
- netlink_linearize_rule(ctx, nlr, rule);
+ netlink_linearize_init(&lctx, nlr);
+ netlink_linearize_rule(ctx, rule, &lctx);
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_NEWRULE,
cmd->handle.family,
NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, h->table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->chain.location);
+
+ if (h->chain_id)
+ mnl_attr_put_u32(nlh, NFTA_RULE_CHAIN_ID, htonl(h->chain_id));
+ else
+ mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, h->chain.name);
+
+ mnl_nft_rule_build_ctx_init(&rule_ctx, nlh, cmd, &lctx);
+
+ nest = mnl_attr_nest_start(nlh, NFTA_RULE_EXPRESSIONS);
+ nftnl_expr_foreach(nlr, mnl_nft_expr_build_cb, &rule_ctx);
+ mnl_attr_nest_end(nlh, nest);
+
nftnl_rule_nlmsg_build_payload(nlh, nlr);
nftnl_rule_free(nlr);
+ netlink_linearize_fini(&lctx);
mnl_nft_batch_continue(ctx->batch);
return 0;
}
-int mnl_nft_rule_replace(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_rule_replace(struct netlink_ctx *ctx, struct cmd *cmd)
{
+ struct mnl_nft_rule_build_ctx rule_ctx;
+ struct netlink_linearize_ctx lctx;
struct rule *rule = cmd->rule;
struct handle *h = &rule->handle;
unsigned int flags = 0;
struct nftnl_rule *nlr;
struct nlmsghdr *nlh;
+ struct nlattr *nest;
if (nft_output_echo(&ctx->nft->output))
flags |= NLM_F_ECHO;
@@ -422,26 +568,40 @@ int mnl_nft_rule_replace(struct netlink_ctx *ctx, const struct cmd *cmd)
memory_allocation_error();
nftnl_rule_set_u32(nlr, NFTNL_RULE_FAMILY, h->family);
- nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, h->table.name);
- nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, h->chain.name);
- nftnl_rule_set_u64(nlr, NFTNL_RULE_HANDLE, h->handle.id);
- netlink_linearize_rule(ctx, nlr, rule);
+ netlink_linearize_init(&lctx, nlr);
+ netlink_linearize_rule(ctx, rule, &lctx);
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_NEWRULE,
cmd->handle.family,
NLM_F_REPLACE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, h->table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->chain.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, h->chain.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->handle.location);
+ mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(h->handle.id));
+
+ mnl_nft_rule_build_ctx_init(&rule_ctx, nlh, cmd, &lctx);
+
+ nest = mnl_attr_nest_start(nlh, NFTA_RULE_EXPRESSIONS);
+ nftnl_expr_foreach(nlr, mnl_nft_expr_build_cb, &rule_ctx);
+ mnl_attr_nest_end(nlh, nest);
+
nftnl_rule_nlmsg_build_payload(nlh, nlr);
nftnl_rule_free(nlr);
+ netlink_linearize_fini(&lctx);
mnl_nft_batch_continue(ctx->batch);
return 0;
}
-int mnl_nft_rule_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_rule_del(struct netlink_ctx *ctx, struct cmd *cmd)
{
- const struct handle *h = &cmd->handle;
+ enum nf_tables_msg_types msg_type = NFT_MSG_DELRULE;
+ struct handle *h = &cmd->handle;
struct nftnl_rule *nlr;
struct nlmsghdr *nlh;
@@ -450,16 +610,26 @@ int mnl_nft_rule_del(struct netlink_ctx *ctx, const struct cmd *cmd)
memory_allocation_error();
nftnl_rule_set_u32(nlr, NFTNL_RULE_FAMILY, h->family);
- nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, h->table.name);
- if (h->chain.name)
- nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, h->chain.name);
- if (h->handle.id)
- nftnl_rule_set_u64(nlr, NFTNL_RULE_HANDLE, h->handle.id);
+
+ if (cmd->op == CMD_DESTROY)
+ msg_type = NFT_MSG_DESTROYRULE;
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
- NFT_MSG_DELRULE,
+ msg_type,
nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY),
0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, h->table.name);
+ if (h->chain.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->chain.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, h->chain.name);
+ }
+ if (h->handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->handle.location);
+ mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(h->handle.id));
+ }
+
nftnl_rule_nlmsg_build_payload(nlh, nlr);
nftnl_rule_free(nlr);
@@ -495,20 +665,45 @@ err_free:
return MNL_CB_OK;
}
-struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx,
- int family)
+struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
+ const char *table, const char *chain,
+ uint64_t rule_handle,
+ bool dump, bool reset)
{
+ uint16_t nl_flags = dump ? NLM_F_DUMP : NLM_F_ACK;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nftnl_rule_list *nlr_list;
+ struct nftnl_rule *nlr = NULL;
struct nlmsghdr *nlh;
- int ret;
+ int msg_type, ret;
+
+ if (reset)
+ msg_type = NFT_MSG_GETRULE_RESET;
+ else
+ msg_type = NFT_MSG_GETRULE;
+
+ if (table) {
+ nlr = nftnl_rule_alloc();
+ if (!nlr)
+ memory_allocation_error();
+
+ nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, table);
+ if (chain)
+ nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, chain);
+ if (rule_handle)
+ nftnl_rule_set_u64(nlr, NFTNL_RULE_HANDLE, rule_handle);
+ }
nlr_list = nftnl_rule_list_alloc();
if (nlr_list == NULL)
memory_allocation_error();
- nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, family,
- NLM_F_DUMP, ctx->seqnum);
+ nlh = nftnl_nlmsg_build_hdr(buf, msg_type, family,
+ nl_flags, ctx->seqnum);
+ if (nlr) {
+ nftnl_rule_nlmsg_build_payload(nlh, nlr);
+ nftnl_rule_free(nlr);
+ }
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, rule_cb, nlr_list);
if (ret < 0)
@@ -523,41 +718,120 @@ err:
/*
* Chain
*/
-int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+
+struct nft_dev {
+ const char *ifname;
+ const struct location *location;
+};
+
+static void nft_dev_add(struct nft_dev *dev_array, const struct expr *expr, int i)
+{
+ unsigned int ifname_len;
+ char ifname[IFNAMSIZ];
+
+ ifname_len = div_round_up(expr->len, BITS_PER_BYTE);
+ memset(ifname, 0, sizeof(ifname));
+ mpz_export_data(ifname, expr->value, BYTEORDER_HOST_ENDIAN, ifname_len);
+ dev_array[i].ifname = xstrdup(ifname);
+ dev_array[i].location = &expr->location;
+}
+
+static struct nft_dev *nft_dev_array(const struct expr *dev_expr, int *num_devs)
+{
+ struct nft_dev *dev_array;
+ int i = 0, len = 1;
+ struct expr *expr;
+
+ switch (dev_expr->etype) {
+ case EXPR_SET:
+ case EXPR_LIST:
+ list_for_each_entry(expr, &dev_expr->expressions, list)
+ len++;
+
+ dev_array = xmalloc(sizeof(struct nft_dev) * len);
+
+ list_for_each_entry(expr, &dev_expr->expressions, list) {
+ nft_dev_add(dev_array, expr, i);
+ i++;
+ }
+ break;
+ case EXPR_VALUE:
+ len++;
+ dev_array = xmalloc(sizeof(struct nft_dev) * len);
+ nft_dev_add(dev_array, dev_expr, i);
+ i++;
+ break;
+ default:
+ assert(0);
+ }
+
+ dev_array[i].ifname = NULL;
+ *num_devs = i;
+
+ return dev_array;
+}
+
+static void nft_dev_array_free(const struct nft_dev *dev_array)
+{
+ int i = 0;
+
+ while (dev_array[i].ifname != NULL)
+ free_const(dev_array[i++].ifname);
+
+ free_const(dev_array);
+}
+
+static void mnl_nft_chain_devs_build(struct nlmsghdr *nlh, struct cmd *cmd)
+{
+ const struct expr *dev_expr = cmd->chain->dev_expr;
+ const struct nft_dev *dev_array;
+ struct nlattr *nest_dev;
+ int i, num_devs = 0;
+
+ dev_array = nft_dev_array(dev_expr, &num_devs);
+ if (num_devs == 1) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, dev_array[0].location);
+ mnl_attr_put_strz(nlh, NFTA_HOOK_DEV, dev_array[0].ifname);
+ } else {
+ nest_dev = mnl_attr_nest_start(nlh, NFTA_HOOK_DEVS);
+ for (i = 0; i < num_devs; i++) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, dev_array[i].location);
+ mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev_array[i].ifname);
+ mnl_attr_nest_end(nlh, nest_dev);
+ }
+ }
+ nft_dev_array_free(dev_array);
+}
+
+int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
+ struct nftnl_udata_buf *udbuf;
struct nftnl_chain *nlc;
struct nlmsghdr *nlh;
- int priority;
- int policy;
+ int priority, policy;
nlc = nftnl_chain_alloc();
if (nlc == NULL)
memory_allocation_error();
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FAMILY, cmd->handle.family);
- nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, cmd->handle.table.name);
- nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME, cmd->handle.chain.name);
if (cmd->chain) {
- if (cmd->chain->flags & CHAIN_F_BASECHAIN) {
- nftnl_chain_set_u32(nlc, NFTNL_CHAIN_HOOKNUM,
- cmd->chain->hooknum);
- mpz_export_data(&priority,
- cmd->chain->priority.expr->value,
- BYTEORDER_HOST_ENDIAN, sizeof(int));
- nftnl_chain_set_s32(nlc, NFTNL_CHAIN_PRIO, priority);
- nftnl_chain_set_str(nlc, NFTNL_CHAIN_TYPE,
- cmd->chain->type);
+ if (cmd->chain->flags & CHAIN_F_HW_OFFLOAD) {
+ nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FLAGS,
+ CHAIN_F_HW_OFFLOAD);
}
- if (cmd->chain->policy) {
- mpz_export_data(&policy, cmd->chain->policy->value,
- BYTEORDER_HOST_ENDIAN, sizeof(int));
- nftnl_chain_set_u32(nlc, NFTNL_CHAIN_POLICY, policy);
+ if (cmd->chain->comment) {
+ udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
+ if (!udbuf)
+ memory_allocation_error();
+ if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_CHAIN_COMMENT, cmd->chain->comment))
+ memory_allocation_error();
+ nftnl_chain_set_data(nlc, NFTNL_CHAIN_USERDATA, nftnl_udata_buf_data(udbuf),
+ nftnl_udata_buf_len(udbuf));
+ nftnl_udata_buf_free(udbuf);
}
- if (cmd->chain->dev != NULL)
- nftnl_chain_set_str(nlc, NFTNL_CHAIN_DEV,
- cmd->chain->dev);
}
netlink_dump_chain(nlc, ctx);
@@ -565,7 +839,57 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
NFT_MSG_NEWCHAIN,
cmd->handle.family,
NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, cmd->handle.table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.chain.location);
+
+ if (!cmd->chain || !(cmd->chain->flags & CHAIN_F_BINDING)) {
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, cmd->handle.chain.name);
+ } else {
+ if (cmd->handle.chain.name)
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME,
+ cmd->handle.chain.name);
+
+ mnl_attr_put_u32(nlh, NFTA_CHAIN_ID, htonl(cmd->handle.chain_id));
+ if (cmd->chain->flags)
+ nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FLAGS, cmd->chain->flags);
+ }
+
+ if (cmd->chain && cmd->chain->policy) {
+ mpz_export_data(&policy, cmd->chain->policy->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->chain->policy->location);
+ mnl_attr_put_u32(nlh, NFTA_CHAIN_POLICY, htonl(policy));
+ }
+
+ nftnl_chain_unset(nlc, NFTNL_CHAIN_TYPE);
+
nftnl_chain_nlmsg_build_payload(nlh, nlc);
+
+ if (cmd->chain && cmd->chain->flags & CHAIN_F_BASECHAIN) {
+ struct nlattr *nest;
+
+ if (cmd->chain->type.str) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->chain->type.loc);
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_TYPE, cmd->chain->type.str);
+ }
+
+ nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_HOOK);
+
+ if (cmd->chain->type.str) {
+ mnl_attr_put_u32(nlh, NFTA_HOOK_HOOKNUM, htonl(cmd->chain->hook.num));
+ mpz_export_data(&priority, cmd->chain->priority.expr->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ mnl_attr_put_u32(nlh, NFTA_HOOK_PRIORITY, htonl(priority));
+ }
+
+ if (cmd->chain && cmd->chain->dev_expr)
+ mnl_nft_chain_devs_build(nlh, cmd);
+
+ mnl_attr_nest_end(nlh, nest);
+ }
+
nftnl_chain_free(nlc);
mnl_nft_batch_continue(ctx->batch);
@@ -603,8 +927,9 @@ int mnl_nft_chain_rename(struct netlink_ctx *ctx, const struct cmd *cmd,
return 0;
}
-int mnl_nft_chain_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_chain_del(struct netlink_ctx *ctx, struct cmd *cmd)
{
+ enum nf_tables_msg_types msg_type = NFT_MSG_DELCHAIN;
struct nftnl_chain *nlc;
struct nlmsghdr *nlh;
@@ -613,18 +938,35 @@ int mnl_nft_chain_del(struct netlink_ctx *ctx, const struct cmd *cmd)
memory_allocation_error();
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FAMILY, cmd->handle.family);
- nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, cmd->handle.table.name);
- if (cmd->handle.chain.name)
- nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME,
- cmd->handle.chain.name);
- else if (cmd->handle.handle.id)
- nftnl_chain_set_u64(nlc, NFTNL_CHAIN_HANDLE,
- cmd->handle.handle.id);
+
+ if (cmd->op == CMD_DESTROY)
+ msg_type = NFT_MSG_DESTROYCHAIN;
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
- NFT_MSG_DELCHAIN,
+ msg_type,
cmd->handle.family,
0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, cmd->handle.table.name);
+ if (cmd->handle.chain.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.chain.location);
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, cmd->handle.chain.name);
+ } else if (cmd->handle.handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_CHAIN_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+
+ if (cmd->op == CMD_DELETE &&
+ cmd->chain && cmd->chain->dev_expr) {
+ struct nlattr *nest;
+
+ nest = mnl_attr_nest_start(nlh, NFTA_CHAIN_HOOK);
+ mnl_nft_chain_devs_build(nlh, cmd);
+ mnl_attr_nest_end(nlh, nest);
+ }
+
nftnl_chain_nlmsg_build_payload(nlh, nlc);
nftnl_chain_free(nlc);
@@ -657,10 +999,12 @@ err_free:
}
struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
- int family)
+ int family, const char *table,
+ const char *chain)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nftnl_chain_list *nlc_list;
+ struct nftnl_chain *nlc = NULL;
struct nlmsghdr *nlh;
int ret;
@@ -668,11 +1012,24 @@ struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
if (nlc_list == NULL)
memory_allocation_error();
+ if (table && chain) {
+ nlc = nftnl_chain_alloc();
+ if (!nlc)
+ memory_allocation_error();
+
+ nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, table);
+ nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME, chain);
+ }
+
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, family,
- NLM_F_DUMP, ctx->seqnum);
+ nlc ? NLM_F_ACK : NLM_F_DUMP, ctx->seqnum);
+ if (nlc) {
+ nftnl_chain_nlmsg_build_payload(nlh, nlc);
+ nftnl_chain_free(nlc);
+ }
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, chain_cb, nlc_list);
- if (ret < 0)
+ if (ret < 0 && errno != ENOENT)
goto err;
return nlc_list;
@@ -684,9 +1041,10 @@ err:
/*
* Table
*/
-int mnl_nft_table_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_table_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
+ struct nftnl_udata_buf *udbuf;
struct nftnl_table *nlt;
struct nlmsghdr *nlh;
@@ -695,16 +1053,30 @@ int mnl_nft_table_add(struct netlink_ctx *ctx, const struct cmd *cmd,
memory_allocation_error();
nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, cmd->handle.family);
- nftnl_table_set(nlt, NFTNL_TABLE_NAME, cmd->handle.table.name);
- if (cmd->table)
+ if (cmd->table) {
nftnl_table_set_u32(nlt, NFTNL_TABLE_FLAGS, cmd->table->flags);
- else
+
+ if (cmd->table->comment) {
+ udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
+ if (!udbuf)
+ memory_allocation_error();
+ if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_TABLE_COMMENT, cmd->table->comment))
+ memory_allocation_error();
+ nftnl_table_set_data(nlt, NFTNL_TABLE_USERDATA, nftnl_udata_buf_data(udbuf),
+ nftnl_udata_buf_len(udbuf));
+ nftnl_udata_buf_free(udbuf);
+ }
+ } else {
nftnl_table_set_u32(nlt, NFTNL_TABLE_FLAGS, 0);
+ }
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_NEWTABLE,
cmd->handle.family,
flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, cmd->handle.table.name);
nftnl_table_nlmsg_build_payload(nlh, nlt);
nftnl_table_free(nlt);
@@ -713,8 +1085,9 @@ int mnl_nft_table_add(struct netlink_ctx *ctx, const struct cmd *cmd,
return 0;
}
-int mnl_nft_table_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_table_del(struct netlink_ctx *ctx, struct cmd *cmd)
{
+ enum nf_tables_msg_types msg_type = NFT_MSG_DELTABLE;
struct nftnl_table *nlt;
struct nlmsghdr *nlh;
@@ -723,16 +1096,21 @@ int mnl_nft_table_del(struct netlink_ctx *ctx, const struct cmd *cmd)
memory_allocation_error();
nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, cmd->handle.family);
- if (cmd->handle.table.name)
- nftnl_table_set(nlt, NFTNL_TABLE_NAME, cmd->handle.table.name);
- else if (cmd->handle.handle.id)
- nftnl_table_set_u64(nlt, NFTNL_TABLE_HANDLE,
- cmd->handle.handle.id);
- nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
- NFT_MSG_DELTABLE,
- cmd->handle.family,
- 0, ctx->seqnum);
+ if (cmd->op == CMD_DESTROY)
+ msg_type = NFT_MSG_DESTROYTABLE;
+
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch), msg_type,
+ cmd->handle.family, 0, ctx->seqnum);
+
+ if (cmd->handle.table.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, cmd->handle.table.name);
+ } else if (cmd->handle.handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_TABLE_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
nftnl_table_nlmsg_build_payload(nlh, nlt);
nftnl_table_free(nlt);
@@ -765,10 +1143,12 @@ err_free:
}
struct nftnl_table_list *mnl_nft_table_dump(struct netlink_ctx *ctx,
- int family)
+ int family, const char *table)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nftnl_table_list *nlt_list;
+ struct nftnl_table *nlt = NULL;
+ int flags = NLM_F_DUMP;
struct nlmsghdr *nlh;
int ret;
@@ -776,11 +1156,25 @@ struct nftnl_table_list *mnl_nft_table_dump(struct netlink_ctx *ctx,
if (nlt_list == NULL)
return NULL;
+ if (table) {
+ nlt = nftnl_table_alloc();
+ if (!nlt)
+ memory_allocation_error();
+
+ nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, family);
+ nftnl_table_set_str(nlt, NFTNL_TABLE_NAME, table);
+ flags = NLM_F_ACK;
+ }
+
nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, family,
- NLM_F_DUMP, ctx->seqnum);
+ flags, ctx->seqnum);
+ if (nlt) {
+ nftnl_table_nlmsg_build_payload(nlh, nlt);
+ nftnl_table_free(nlt);
+ }
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, table_cb, nlt_list);
- if (ret < 0)
+ if (ret < 0 && errno != ENOENT)
goto err;
return nlt_list;
@@ -789,17 +1183,37 @@ err:
return NULL;
}
+static void set_key_expression(struct netlink_ctx *ctx,
+ struct expr *expr, uint32_t set_flags,
+ struct nftnl_udata_buf *udbuf,
+ unsigned int type)
+{
+ struct nftnl_udata *nest1, *nest2;
+
+ if (!expr_ops(expr)->build_udata)
+ return;
+
+ nest1 = nftnl_udata_nest_start(udbuf, type);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_TYPEOF_EXPR, expr->etype);
+ nest2 = nftnl_udata_nest_start(udbuf, NFTNL_UDATA_SET_TYPEOF_DATA);
+ expr_ops(expr)->build_udata(udbuf, expr);
+ nftnl_udata_nest_end(udbuf, nest2);
+ nftnl_udata_nest_end(udbuf, nest1);
+}
+
/*
* Set
*/
-int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_set_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
- const struct handle *h = &cmd->handle;
+ struct handle *h = &cmd->handle;
struct nftnl_udata_buf *udbuf;
struct set *set = cmd->set;
struct nftnl_set *nls;
struct nlmsghdr *nlh;
+ struct stmt *stmt;
+ int num_stmts = 0;
nls = nftnl_set_alloc();
if (!nls)
@@ -817,9 +1231,9 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
div_round_up(set->key->len, BITS_PER_BYTE));
if (set_is_datamap(set->flags)) {
nftnl_set_set_u32(nls, NFTNL_SET_DATA_TYPE,
- dtype_map_to_kernel(set->datatype));
+ dtype_map_to_kernel(set->data->dtype));
nftnl_set_set_u32(nls, NFTNL_SET_DATA_LEN,
- set->datalen / BITS_PER_BYTE);
+ div_round_up(set->data->len, BITS_PER_BYTE));
}
if (set_is_objmap(set->flags))
nftnl_set_set_u32(nls, NFTNL_SET_OBJ_TYPE, set->objtype);
@@ -851,7 +1265,7 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
if (set_is_datamap(set->flags) &&
!nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_DATABYTEORDER,
- set->datatype->byteorder))
+ set->data->byteorder))
memory_allocation_error();
if (set->automerge &&
@@ -859,16 +1273,58 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
set->automerge))
memory_allocation_error();
+ set_key_expression(ctx, set->key, set->flags, udbuf, NFTNL_UDATA_SET_KEY_TYPEOF);
+ if (set->data) {
+ set_key_expression(ctx, set->data, set->flags, udbuf, NFTNL_UDATA_SET_DATA_TYPEOF);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_DATA_INTERVAL,
+ !!(set->data->flags & EXPR_F_INTERVAL));
+ }
+
+ if (set->desc.field_len[0]) {
+ nftnl_set_set_data(nls, NFTNL_SET_DESC_CONCAT,
+ set->desc.field_len,
+ set->desc.field_count *
+ sizeof(set->desc.field_len[0]));
+ }
+
+ if (set->comment) {
+ if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_SET_COMMENT, set->comment))
+ memory_allocation_error();
+ }
+
nftnl_set_set_data(nls, NFTNL_SET_USERDATA, nftnl_udata_buf_data(udbuf),
nftnl_udata_buf_len(udbuf));
nftnl_udata_buf_free(udbuf);
+ list_for_each_entry(stmt, &set->stmt_list, list)
+ num_stmts++;
+
+ if (num_stmts == 1) {
+ list_for_each_entry(stmt, &set->stmt_list, list) {
+ nftnl_set_set_data(nls, NFTNL_SET_EXPR,
+ netlink_gen_stmt_stateful(stmt), 0);
+ break;
+ }
+ } else if (num_stmts > 1) {
+ list_for_each_entry(stmt, &set->stmt_list, list)
+ nftnl_set_add_expr(nls, netlink_gen_stmt_stateful(stmt));
+ }
+
netlink_dump_set(nls, ctx);
+ nftnl_set_unset(nls, NFTNL_SET_TABLE);
+ nftnl_set_unset(nls, NFTNL_SET_NAME);
+
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_NEWSET,
h->family,
NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location);
+ mnl_attr_put_strz(nlh, NFTA_SET_TABLE, h->table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->set.location);
+ mnl_attr_put_strz(nlh, NFTA_SET_NAME, h->set.name);
+
nftnl_set_nlmsg_build_payload(nlh, nls);
nftnl_set_free(nls);
@@ -877,8 +1333,9 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
return 0;
}
-int mnl_nft_set_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_set_del(struct netlink_ctx *ctx, struct cmd *cmd)
{
+ enum nf_tables_msg_types msg_type = NFT_MSG_DELSET;
const struct handle *h = &cmd->handle;
struct nftnl_set *nls;
struct nlmsghdr *nlh;
@@ -888,16 +1345,26 @@ int mnl_nft_set_del(struct netlink_ctx *ctx, const struct cmd *cmd)
memory_allocation_error();
nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
- nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
- if (h->set.name)
- nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
- else if (h->handle.id)
- nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
+
+ if (cmd->op == CMD_DESTROY)
+ msg_type = NFT_MSG_DESTROYSET;
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
- NFT_MSG_DELSET,
+ msg_type,
h->family,
0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_SET_TABLE, cmd->handle.table.name);
+ if (h->set.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.set.location);
+ mnl_attr_put_strz(nlh, NFTA_SET_NAME, cmd->handle.set.name);
+ } else if (h->handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_SET_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+
nftnl_set_nlmsg_build_payload(nlh, nls);
nftnl_set_free(nls);
@@ -930,10 +1397,12 @@ err_free:
}
struct nftnl_set_list *
-mnl_nft_set_dump(struct netlink_ctx *ctx, int family, const char *table)
+mnl_nft_set_dump(struct netlink_ctx *ctx, int family,
+ const char *table, const char *set)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nftnl_set_list *nls_list;
+ int flags = NLM_F_DUMP;
struct nlmsghdr *nlh;
struct nftnl_set *s;
int ret;
@@ -942,10 +1411,15 @@ mnl_nft_set_dump(struct netlink_ctx *ctx, int family, const char *table)
if (s == NULL)
memory_allocation_error();
- nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSET, family,
- NLM_F_DUMP, ctx->seqnum);
if (table != NULL)
- nftnl_set_set(s, NFTNL_SET_TABLE, table);
+ nftnl_set_set_str(s, NFTNL_SET_TABLE, table);
+ if (set) {
+ nftnl_set_set_str(s, NFTNL_SET_NAME, set);
+ flags = NLM_F_ACK;
+ }
+
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSET, family,
+ flags, ctx->seqnum);
nftnl_set_nlmsg_build_payload(nlh, s);
nftnl_set_free(s);
@@ -954,7 +1428,7 @@ mnl_nft_set_dump(struct netlink_ctx *ctx, int family, const char *table)
memory_allocation_error();
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, set_cb, nls_list);
- if (ret < 0)
+ if (ret < 0 && errno != ENOENT)
goto err;
return nls_list;
@@ -963,10 +1437,11 @@ err:
return NULL;
}
-int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_obj_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
struct obj *obj = cmd->object;
+ struct nftnl_udata_buf *udbuf;
struct nftnl_obj *nlo;
struct nlmsghdr *nlh;
@@ -975,10 +1450,19 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
memory_allocation_error();
nftnl_obj_set_u32(nlo, NFTNL_OBJ_FAMILY, cmd->handle.family);
- nftnl_obj_set_str(nlo, NFTNL_OBJ_TABLE, cmd->handle.table.name);
- nftnl_obj_set_str(nlo, NFTNL_OBJ_NAME, cmd->handle.obj.name);
nftnl_obj_set_u32(nlo, NFTNL_OBJ_TYPE, obj->type);
+ if (obj->comment) {
+ udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
+ if (!udbuf)
+ memory_allocation_error();
+ if (!nftnl_udata_put_strz(udbuf, NFTNL_UDATA_OBJ_COMMENT, obj->comment))
+ memory_allocation_error();
+ nftnl_obj_set_data(nlo, NFTNL_OBJ_USERDATA, nftnl_udata_buf_data(udbuf),
+ nftnl_udata_buf_len(udbuf));
+ nftnl_udata_buf_free(udbuf);
+ }
+
switch (obj->type) {
case NFT_OBJECT_COUNTER:
nftnl_obj_set_u64(nlo, NFTNL_OBJ_CTR_PKTS,
@@ -1016,8 +1500,9 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
if (obj->ct_timeout.l3proto)
nftnl_obj_set_u16(nlo, NFTNL_OBJ_CT_TIMEOUT_L3PROTO,
obj->ct_timeout.l3proto);
- nftnl_obj_set(nlo, NFTNL_OBJ_CT_TIMEOUT_ARRAY,
- obj->ct_timeout.timeout);
+ nftnl_obj_set_data(nlo, NFTNL_OBJ_CT_TIMEOUT_ARRAY,
+ obj->ct_timeout.timeout,
+ sizeof(obj->ct_timeout.timeout));
break;
case NFT_OBJECT_CT_EXPECT:
if (obj->ct_expect.l3proto)
@@ -1053,6 +1538,12 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_NEWOBJ, cmd->handle.family,
NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_OBJ_TABLE, cmd->handle.table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.obj.location);
+ mnl_attr_put_strz(nlh, NFTA_OBJ_NAME, cmd->handle.obj.name);
+
nftnl_obj_nlmsg_build_payload(nlh, nlo);
nftnl_obj_free(nlo);
@@ -1061,8 +1552,9 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
return 0;
}
-int mnl_nft_obj_del(struct netlink_ctx *ctx, const struct cmd *cmd, int type)
+int mnl_nft_obj_del(struct netlink_ctx *ctx, struct cmd *cmd, int type)
{
+ enum nf_tables_msg_types msg_type = NFT_MSG_DELOBJ;
struct nftnl_obj *nlo;
struct nlmsghdr *nlh;
@@ -1071,16 +1563,27 @@ int mnl_nft_obj_del(struct netlink_ctx *ctx, const struct cmd *cmd, int type)
memory_allocation_error();
nftnl_obj_set_u32(nlo, NFTNL_OBJ_FAMILY, cmd->handle.family);
- nftnl_obj_set_str(nlo, NFTNL_OBJ_TABLE, cmd->handle.table.name);
nftnl_obj_set_u32(nlo, NFTNL_OBJ_TYPE, type);
- if (cmd->handle.obj.name)
- nftnl_obj_set_str(nlo, NFTNL_OBJ_NAME, cmd->handle.obj.name);
- else if (cmd->handle.handle.id)
- nftnl_obj_set_u64(nlo, NFTNL_OBJ_HANDLE, cmd->handle.handle.id);
+
+ if (cmd->op == CMD_DESTROY)
+ msg_type = NFT_MSG_DESTROYOBJ;
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
- NFT_MSG_DELOBJ, cmd->handle.family,
+ msg_type, cmd->handle.family,
0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_OBJ_TABLE, cmd->handle.table.name);
+
+ if (cmd->handle.obj.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.obj.location);
+ mnl_attr_put_strz(nlh, NFTA_OBJ_NAME, cmd->handle.obj.name);
+ } else if (cmd->handle.handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_OBJ_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+
nftnl_obj_nlmsg_build_payload(nlh, nlo);
nftnl_obj_free(nlo);
@@ -1171,39 +1674,114 @@ static int set_elem_cb(const struct nlmsghdr *nlh, void *data)
return MNL_CB_OK;
}
-static int mnl_nft_setelem_batch(struct nftnl_set *nls,
+static bool mnl_nft_attr_nest_overflow(struct nlmsghdr *nlh,
+ const struct nlattr *from,
+ const struct nlattr *to)
+{
+ int len = (void *)to + to->nla_len - (void *)from;
+
+ /* The attribute length field is 16 bits long, thus the maximum payload
+ * that an attribute can convey is UINT16_MAX. In case of overflow,
+ * discard the last attribute that did not fit into the nest.
+ */
+ if (len > UINT16_MAX) {
+ nlh->nlmsg_len -= to->nla_len;
+ return true;
+ }
+ return false;
+}
+
+static void netlink_dump_setelem(const struct nftnl_set_elem *nlse,
+ struct netlink_ctx *ctx)
+{
+ FILE *fp = ctx->nft->output.output_fp;
+ char buf[4096];
+
+ if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
+ return;
+
+ nftnl_set_elem_snprintf(buf, sizeof(buf), nlse, NFTNL_OUTPUT_DEFAULT, 0);
+ fprintf(fp, "\t%s", buf);
+}
+
+static void netlink_dump_setelem_done(struct netlink_ctx *ctx)
+{
+ FILE *fp = ctx->nft->output.output_fp;
+
+ if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
+ return;
+
+ fprintf(fp, "\n");
+}
+
+static int mnl_nft_setelem_batch(const struct nftnl_set *nls, struct cmd *cmd,
struct nftnl_batch *batch,
- enum nf_tables_msg_types cmd,
- unsigned int flags, uint32_t seqnum)
+ enum nf_tables_msg_types msg_type,
+ unsigned int flags, uint32_t seqnum,
+ const struct expr *set,
+ struct netlink_ctx *ctx)
{
+ struct nlattr *nest1, *nest2;
+ struct nftnl_set_elem *nlse;
struct nlmsghdr *nlh;
- struct nftnl_set_elems_iter *iter;
- int ret;
-
- iter = nftnl_set_elems_iter_create(nls);
- if (iter == NULL)
- memory_allocation_error();
+ struct expr *expr = NULL;
+ int i = 0;
- if (cmd == NFT_MSG_NEWSETELEM)
+ if (msg_type == NFT_MSG_NEWSETELEM)
flags |= NLM_F_CREATE;
- while (nftnl_set_elems_iter_cur(iter)) {
- nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch), cmd,
- nftnl_set_get_u32(nls, NFTNL_SET_FAMILY),
- flags, seqnum);
- ret = nftnl_set_elems_nlmsg_build_payload_iter(nlh, iter);
- mnl_nft_batch_continue(batch);
- if (ret <= 0)
- break;
+ if (set)
+ expr = list_first_entry(&set->expressions, struct expr, list);
+
+next:
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch), msg_type,
+ nftnl_set_get_u32(nls, NFTNL_SET_FAMILY),
+ flags, seqnum);
+
+ if (nftnl_set_is_set(nls, NFTNL_SET_TABLE)) {
+ mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_TABLE,
+ nftnl_set_get_str(nls, NFTNL_SET_TABLE));
+ }
+ if (nftnl_set_is_set(nls, NFTNL_SET_NAME)) {
+ mnl_attr_put_strz(nlh, NFTA_SET_ELEM_LIST_SET,
+ nftnl_set_get_str(nls, NFTNL_SET_NAME));
+ }
+ if (nftnl_set_is_set(nls, NFTNL_SET_ID)) {
+ mnl_attr_put_u32(nlh, NFTA_SET_ELEM_LIST_SET_ID,
+ htonl(nftnl_set_get_u32(nls, NFTNL_SET_ID)));
}
- nftnl_set_elems_iter_destroy(iter);
+ if (!set || list_empty(&set->expressions))
+ return 0;
+
+ assert(expr);
+ nest1 = mnl_attr_nest_start(nlh, NFTA_SET_ELEM_LIST_ELEMENTS);
+ list_for_each_entry_from(expr, &set->expressions, list) {
+ nlse = alloc_nftnl_setelem(set, expr);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &expr->location);
+ nest2 = mnl_attr_nest_start(nlh, ++i);
+ nftnl_set_elem_nlmsg_build_payload(nlh, nlse);
+ mnl_attr_nest_end(nlh, nest2);
+
+ netlink_dump_setelem(nlse, ctx);
+ nftnl_set_elem_free(nlse);
+ if (mnl_nft_attr_nest_overflow(nlh, nest1, nest2)) {
+ mnl_attr_nest_end(nlh, nest1);
+ mnl_nft_batch_continue(batch);
+ goto next;
+ }
+ }
+ mnl_attr_nest_end(nlh, nest1);
+ mnl_nft_batch_continue(batch);
+ netlink_dump_setelem_done(ctx);
return 0;
}
-int mnl_nft_setelem_add(struct netlink_ctx *ctx, const struct set *set,
- const struct expr *expr, unsigned int flags)
+int mnl_nft_setelem_add(struct netlink_ctx *ctx, struct cmd *cmd,
+ const struct set *set, const struct expr *expr,
+ unsigned int flags)
{
const struct handle *h = &set->handle;
struct nftnl_set *nls;
@@ -1218,12 +1796,14 @@ int mnl_nft_setelem_add(struct netlink_ctx *ctx, const struct set *set,
nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
if (h->set_id)
nftnl_set_set_u32(nls, NFTNL_SET_ID, h->set_id);
+ if (set_is_datamap(set->flags))
+ nftnl_set_set_u32(nls, NFTNL_SET_DATA_TYPE,
+ dtype_map_to_kernel(set->data->dtype));
- alloc_setelem_cache(expr, nls);
netlink_dump_set(nls, ctx);
- err = mnl_nft_setelem_batch(nls, ctx->batch, NFT_MSG_NEWSETELEM, flags,
- ctx->seqnum);
+ err = mnl_nft_setelem_batch(nls, cmd, ctx->batch, NFT_MSG_NEWSETELEM,
+ flags, ctx->seqnum, expr, ctx);
nftnl_set_free(nls);
return err;
@@ -1259,9 +1839,10 @@ int mnl_nft_setelem_flush(struct netlink_ctx *ctx, const struct cmd *cmd)
return 0;
}
-int mnl_nft_setelem_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_setelem_del(struct netlink_ctx *ctx, struct cmd *cmd,
+ const struct handle *h, const struct expr *init)
{
- const struct handle *h = &cmd->handle;
+ enum nf_tables_msg_types msg_type = NFT_MSG_DELSETELEM;
struct nftnl_set *nls;
int err;
@@ -1276,26 +1857,34 @@ int mnl_nft_setelem_del(struct netlink_ctx *ctx, const struct cmd *cmd)
else if (h->handle.id)
nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
- if (cmd->expr)
- alloc_setelem_cache(cmd->expr, nls);
netlink_dump_set(nls, ctx);
- err = mnl_nft_setelem_batch(nls, ctx->batch, NFT_MSG_DELSETELEM, 0,
- ctx->seqnum);
+ if (cmd->op == CMD_DESTROY)
+ msg_type = NFT_MSG_DESTROYSETELEM;
+
+ err = mnl_nft_setelem_batch(nls, cmd, ctx->batch, msg_type, 0,
+ ctx->seqnum, init, ctx);
nftnl_set_free(nls);
return err;
}
struct nftnl_set *mnl_nft_setelem_get_one(struct netlink_ctx *ctx,
- struct nftnl_set *nls_in)
+ struct nftnl_set *nls_in,
+ bool reset)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nftnl_set *nls_out;
struct nlmsghdr *nlh;
+ int msg_type;
int err;
- nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM,
+ if (reset)
+ msg_type = NFT_MSG_GETSETELEM_RESET;
+ else
+ msg_type = NFT_MSG_GETSETELEM;
+
+ nlh = nftnl_nlmsg_build_hdr(buf, msg_type,
nftnl_set_get_u32(nls_in, NFTNL_SET_FAMILY),
NLM_F_ACK, ctx->seqnum);
nftnl_set_elems_nlmsg_build_payload(nlh, nls_in);
@@ -1318,12 +1907,19 @@ struct nftnl_set *mnl_nft_setelem_get_one(struct netlink_ctx *ctx,
return nls_out;
}
-int mnl_nft_setelem_get(struct netlink_ctx *ctx, struct nftnl_set *nls)
+int mnl_nft_setelem_get(struct netlink_ctx *ctx, struct nftnl_set *nls,
+ bool reset)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
+ int msg_type;
- nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETSETELEM,
+ if (reset)
+ msg_type = NFT_MSG_GETSETELEM_RESET;
+ else
+ msg_type = NFT_MSG_GETSETELEM;
+
+ nlh = nftnl_nlmsg_build_hdr(buf, msg_type,
nftnl_set_get_u32(nls, NFTNL_SET_FAMILY),
NLM_F_DUMP, ctx->seqnum);
nftnl_set_elems_nlmsg_build_payload(nlh, nls);
@@ -1355,11 +1951,13 @@ err_free:
}
struct nftnl_flowtable_list *
-mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table)
+mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family,
+ const char *table, const char *ft)
{
struct nftnl_flowtable_list *nln_list;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nftnl_flowtable *n;
+ int flags = NLM_F_DUMP;
struct nlmsghdr *nlh;
int ret;
@@ -1367,10 +1965,14 @@ mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table)
if (n == NULL)
memory_allocation_error();
- nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETFLOWTABLE, family,
- NLM_F_DUMP, ctx->seqnum);
if (table != NULL)
nftnl_flowtable_set_str(n, NFTNL_FLOWTABLE_TABLE, table);
+ if (ft) {
+ nftnl_flowtable_set_str(n, NFTNL_FLOWTABLE_NAME, ft);
+ flags = NLM_F_ACK;
+ }
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETFLOWTABLE, family,
+ flags, ctx->seqnum);
nftnl_flowtable_nlmsg_build_payload(nlh, n);
nftnl_flowtable_free(n);
@@ -1379,7 +1981,7 @@ mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table)
memory_allocation_error();
ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, flowtable_cb, nln_list);
- if (ret < 0)
+ if (ret < 0 && errno != ENOENT)
goto err;
return nln_list;
@@ -1388,15 +1990,31 @@ err:
return NULL;
}
-int mnl_nft_flowtable_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+static void mnl_nft_ft_devs_build(struct nlmsghdr *nlh, struct cmd *cmd)
+{
+ const struct expr *dev_expr = cmd->flowtable->dev_expr;
+ const struct nft_dev *dev_array;
+ struct nlattr *nest_dev;
+ int i, num_devs= 0;
+
+ dev_array = nft_dev_array(dev_expr, &num_devs);
+ nest_dev = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK_DEVS);
+ for (i = 0; i < num_devs; i++) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, dev_array[i].location);
+ mnl_attr_put_strz(nlh, NFTA_DEVICE_NAME, dev_array[i].ifname);
+ }
+
+ mnl_attr_nest_end(nlh, nest_dev);
+ nft_dev_array_free(dev_array);
+}
+
+int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
struct nftnl_flowtable *flo;
- const char *dev_array[8];
struct nlmsghdr *nlh;
- struct expr *expr;
+ struct nlattr *nest;
int priority;
- int i = 0;
flo = nftnl_flowtable_alloc();
if (!flo)
@@ -1404,28 +2022,37 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, const struct cmd *cmd,
nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
cmd->handle.family);
- nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_TABLE,
- cmd->handle.table.name);
- nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_NAME,
- cmd->handle.flowtable);
- nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM,
- cmd->flowtable->hooknum);
- mpz_export_data(&priority, cmd->flowtable->priority.expr->value,
- BYTEORDER_HOST_ENDIAN, sizeof(int));
- nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, priority);
-
- list_for_each_entry(expr, &cmd->flowtable->dev_expr->expressions, list)
- dev_array[i++] = expr->identifier;
-
- dev_array[i] = NULL;
- nftnl_flowtable_set(flo, NFTNL_FLOWTABLE_DEVICES, dev_array);
+
+ nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FLAGS,
+ cmd->flowtable->flags);
netlink_dump_flowtable(flo, ctx);
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_NEWFLOWTABLE, cmd->handle.family,
NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, cmd->handle.table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.flowtable.location);
+ mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME, cmd->handle.flowtable.name);
+
nftnl_flowtable_nlmsg_build_payload(nlh, flo);
+
+ nest = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK);
+
+ if (cmd->flowtable && cmd->flowtable->priority.expr) {
+ mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_NUM, htonl(cmd->flowtable->hook.num));
+ mpz_export_data(&priority, cmd->flowtable->priority.expr->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ mnl_attr_put_u32(nlh, NFTA_FLOWTABLE_HOOK_PRIORITY, htonl(priority));
+ }
+
+ if (cmd->flowtable->dev_expr)
+ mnl_nft_ft_devs_build(nlh, cmd);
+
+ mnl_attr_nest_end(nlh, nest);
+
nftnl_flowtable_free(flo);
mnl_nft_batch_continue(ctx->batch);
@@ -1433,10 +2060,12 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, const struct cmd *cmd,
return 0;
}
-int mnl_nft_flowtable_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd)
{
+ enum nf_tables_msg_types msg_type = NFT_MSG_DELFLOWTABLE;
struct nftnl_flowtable *flo;
struct nlmsghdr *nlh;
+ struct nlattr *nest;
flo = nftnl_flowtable_alloc();
if (!flo)
@@ -1444,15 +2073,37 @@ int mnl_nft_flowtable_del(struct netlink_ctx *ctx, const struct cmd *cmd)
nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
cmd->handle.family);
- nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_TABLE,
- cmd->handle.table.name);
- nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_NAME,
- cmd->handle.flowtable);
+
+ if (cmd->op == CMD_DESTROY)
+ msg_type = NFT_MSG_DESTROYFLOWTABLE;
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
- NFT_MSG_DELFLOWTABLE, cmd->handle.family,
+ msg_type, cmd->handle.family,
0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, cmd->handle.table.name);
+
+ if (cmd->handle.flowtable.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len,
+ &cmd->handle.flowtable.location);
+ mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME,
+ cmd->handle.flowtable.name);
+ } else if (cmd->handle.handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_FLOWTABLE_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+
nftnl_flowtable_nlmsg_build_payload(nlh, flo);
+
+ if (cmd->op == CMD_DELETE &&
+ cmd->flowtable && cmd->flowtable->dev_expr) {
+ nest = mnl_attr_nest_start(nlh, NFTA_FLOWTABLE_HOOK);
+ mnl_nft_ft_devs_build(nlh, cmd);
+ mnl_attr_nest_end(nlh, nest);
+ }
+
nftnl_flowtable_free(flo);
mnl_nft_batch_continue(ctx->batch);
@@ -1471,7 +2122,7 @@ int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
void *cb_data)
{
/* Set netlink socket buffer size to 16 Mbytes to reduce chances of
- * message loss due to ENOBUFS.
+ * message loss due to ENOBUFS.
*/
unsigned int bufsiz = NFTABLES_NLEVENT_BUFSIZ;
int fd = mnl_socket_get_fd(nf_sock);
@@ -1515,3 +2166,504 @@ int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
}
return ret;
}
+
+static struct basehook *basehook_alloc(void)
+{
+ return xzalloc(sizeof(struct basehook));
+}
+
+static void basehook_free(struct basehook *b)
+{
+ list_del(&b->list);
+ free_const(b->module_name);
+ free_const(b->hookfn);
+ free_const(b->chain);
+ free_const(b->table);
+ free(b);
+}
+
+static void basehook_list_add_tail(struct basehook *b, struct list_head *head)
+{
+ struct basehook *hook;
+
+ list_for_each_entry(hook, head, list) {
+ if (hook->family != b->family)
+ continue;
+ if (hook->num != b->num)
+ continue;
+ if (hook->prio < b->prio)
+ continue;
+
+ list_add(&b->list, &hook->list);
+ return;
+ }
+
+ list_add_tail(&b->list, head);
+}
+
+static int dump_nf_attr_cb(const struct nlattr *attr, void *data)
+{
+ int type = mnl_attr_get_type(attr);
+ const struct nlattr **tb = data;
+
+ if (mnl_attr_type_valid(attr, NFNLA_HOOK_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case NFNLA_HOOK_HOOKNUM:
+ case NFNLA_HOOK_PRIORITY:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ return MNL_CB_ERROR;
+ break;
+ case NFNLA_HOOK_DEV:
+ if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
+ return MNL_CB_ERROR;
+ break;
+ case NFNLA_HOOK_MODULE_NAME:
+ case NFNLA_HOOK_FUNCTION_NAME:
+ if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
+ return MNL_CB_ERROR;
+ break;
+ case NFNLA_HOOK_CHAIN_INFO:
+ if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+ return MNL_CB_ERROR;
+ break;
+ default:
+ return MNL_CB_OK;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int dump_nf_chain_info_cb(const struct nlattr *attr, void *data)
+{
+ int type = mnl_attr_get_type(attr);
+ const struct nlattr **tb = data;
+
+ if (mnl_attr_type_valid(attr, NFNLA_HOOK_INFO_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case NFNLA_HOOK_INFO_DESC:
+ if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
+ return MNL_CB_ERROR;
+ break;
+ case NFNLA_HOOK_INFO_TYPE:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ return MNL_CB_ERROR;
+ break;
+ default:
+ return MNL_CB_OK;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int dump_nf_attr_chain_cb(const struct nlattr *attr, void *data)
+{
+ int type = mnl_attr_get_type(attr);
+ const struct nlattr **tb = data;
+
+ if (mnl_attr_type_valid(attr, NFNLA_CHAIN_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case NFNLA_CHAIN_TABLE:
+ case NFNLA_CHAIN_NAME:
+ if (mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
+ return MNL_CB_ERROR;
+ break;
+ case NFNLA_CHAIN_FAMILY:
+ if (mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
+ return MNL_CB_ERROR;
+ break;
+ default:
+ return MNL_CB_OK;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int dump_nf_attr_bpf_cb(const struct nlattr *attr, void *data)
+{
+ int type = mnl_attr_get_type(attr);
+ const struct nlattr **tb = data;
+
+ if (mnl_attr_type_valid(attr, NFNLA_HOOK_BPF_MAX) < 0)
+ return MNL_CB_OK;
+
+ switch(type) {
+ case NFNLA_HOOK_BPF_ID:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ return MNL_CB_ERROR;
+ break;
+ default:
+ return MNL_CB_OK;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+struct dump_nf_hook_data {
+ struct list_head *hook_list;
+ int family;
+};
+
+static int dump_nf_hooks(const struct nlmsghdr *nlh, void *_data)
+{
+ const struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+ struct nlattr *tb[NFNLA_HOOK_MAX + 1] = {};
+ struct dump_nf_hook_data *data = _data;
+ struct basehook *hook;
+
+ /* NB: Don't check the nft generation ID, this is not
+ * an nftables subsystem.
+ */
+ if (mnl_attr_parse(nlh, sizeof(*nfg), dump_nf_attr_cb, tb) < 0)
+ return -1;
+
+ if (!tb[NFNLA_HOOK_PRIORITY])
+ netlink_abi_error();
+
+ hook = basehook_alloc();
+ hook->prio = ntohl(mnl_attr_get_u32(tb[NFNLA_HOOK_PRIORITY]));
+
+ if (tb[NFNLA_HOOK_FUNCTION_NAME])
+ hook->hookfn = xstrdup(mnl_attr_get_str(tb[NFNLA_HOOK_FUNCTION_NAME]));
+
+ if (tb[NFNLA_HOOK_MODULE_NAME])
+ hook->module_name = xstrdup(mnl_attr_get_str(tb[NFNLA_HOOK_MODULE_NAME]));
+
+ if (tb[NFNLA_HOOK_CHAIN_INFO]) {
+ struct nlattr *nested[NFNLA_HOOK_INFO_MAX + 1] = {};
+ uint32_t type;
+
+ if (mnl_attr_parse_nested(tb[NFNLA_HOOK_CHAIN_INFO],
+ dump_nf_chain_info_cb, nested) < 0) {
+ basehook_free(hook);
+ return -1;
+ }
+
+ type = ntohl(mnl_attr_get_u32(nested[NFNLA_HOOK_INFO_TYPE]));
+ if (type == NFNL_HOOK_TYPE_NFTABLES) {
+ struct nlattr *info[NFNLA_CHAIN_MAX + 1] = {};
+ const char *tablename, *chainname;
+
+ if (mnl_attr_parse_nested(nested[NFNLA_HOOK_INFO_DESC],
+ dump_nf_attr_chain_cb,
+ info) < 0) {
+ basehook_free(hook);
+ return -1;
+ }
+
+ tablename = mnl_attr_get_str(info[NFNLA_CHAIN_TABLE]);
+ chainname = mnl_attr_get_str(info[NFNLA_CHAIN_NAME]);
+ if (tablename && chainname) {
+ hook->table = xstrdup(tablename);
+ hook->chain = xstrdup(chainname);
+ }
+ hook->chain_family = mnl_attr_get_u8(info[NFNLA_CHAIN_FAMILY]);
+ } else if (type == NFNL_HOOK_TYPE_BPF) {
+ struct nlattr *info[NFNLA_HOOK_BPF_MAX + 1] = {};
+
+ if (mnl_attr_parse_nested(nested[NFNLA_HOOK_INFO_DESC],
+ dump_nf_attr_bpf_cb, info) < 0) {
+ basehook_free(hook);
+ return -1;
+ }
+
+ if (info[NFNLA_HOOK_BPF_ID]) {
+ char tmpbuf[16];
+
+ snprintf(tmpbuf, sizeof(tmpbuf), "id %u",
+ ntohl(mnl_attr_get_u32(info[NFNLA_HOOK_BPF_ID])));
+
+ hook->chain = xstrdup(tmpbuf);
+ }
+ }
+ }
+ if (tb[NFNLA_HOOK_HOOKNUM])
+ hook->num = ntohl(mnl_attr_get_u32(tb[NFNLA_HOOK_HOOKNUM]));
+
+ hook->family = nfg->nfgen_family;
+
+ /* Netdev hooks potentially interfer with this family datapath. */
+ if (hook->family == NFPROTO_NETDEV) {
+ switch (data->family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ case NFPROTO_INET:
+ case NFPROTO_BRIDGE:
+ hook->family = data->family;
+ hook->num = NF_INET_INGRESS;
+ break;
+ case NFPROTO_ARP:
+ if (hook->chain_family == NFPROTO_NETDEV) {
+ hook->family = data->family;
+ hook->num = __NF_ARP_INGRESS;
+ }
+ break;
+ }
+ }
+
+ basehook_list_add_tail(hook, data->hook_list);
+
+ return MNL_CB_OK;
+}
+
+static struct nlmsghdr *nf_hook_dump_request(char *buf, uint8_t family, uint32_t seq)
+{
+ struct nlmsghdr *nlh = mnl_nlmsg_put_header(buf);
+ struct nfgenmsg *nfg;
+
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ nlh->nlmsg_type = NFNL_SUBSYS_HOOK << 8;
+ nlh->nlmsg_seq = seq;
+
+ nfg = mnl_nlmsg_put_extra_header(nlh, sizeof(*nfg));
+ nfg->nfgen_family = family;
+ nfg->version = NFNETLINK_V0;
+
+ return nlh;
+}
+
+static int __mnl_nft_dump_nf_hooks(struct netlink_ctx *ctx, uint8_t query_family,
+ uint8_t family, uint8_t hooknum,
+ const char *devname,
+ struct list_head *hook_list)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct dump_nf_hook_data data = {
+ .hook_list = hook_list,
+ .family = query_family,
+ };
+ struct nlmsghdr *nlh;
+
+ nlh = nf_hook_dump_request(buf, family, ctx->seqnum);
+ if (devname)
+ mnl_attr_put_strz(nlh, NFNLA_HOOK_DEV, devname);
+
+ mnl_attr_put_u32(nlh, NFNLA_HOOK_HOOKNUM, htonl(hooknum));
+
+ return nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, dump_nf_hooks, &data);
+}
+
+static void print_hooks(struct netlink_ctx *ctx, int family, struct list_head *hook_list)
+{
+ struct basehook *hook, *tmp, *prev = NULL;
+ bool same, family_in_use = false;
+ int prio;
+ FILE *fp;
+
+ fp = ctx->nft->output.output_fp;
+
+ list_for_each_entry_safe(hook, tmp, hook_list, list) {
+ if (hook->family == family) {
+ family_in_use = true;
+ break;
+ }
+ }
+
+ if (!family_in_use)
+ return;
+
+ fprintf(fp, "family %s {\n", family2str(family));
+
+ list_for_each_entry_safe(hook, tmp, hook_list, list) {
+ if (hook->family != family)
+ continue;
+
+ if (prev) {
+ if (prev->num == hook->num) {
+ fprintf(fp, "\n");
+ same = true;
+ } else {
+ same = false;
+ fprintf(fp, "\n\t}\n");
+ }
+ } else {
+ same = false;
+ }
+ prev = hook;
+
+ if (!same) {
+ fprintf(fp, "\thook %s {\n",
+ hooknum2str(family, hook->num));
+ }
+
+ prio = hook->prio;
+ if (prio < 0)
+ fprintf(fp, "\t\t%011d", prio); /* outputs a '-' sign */
+ else if (prio == 0)
+ fprintf(fp, "\t\t %010u", prio);
+ else
+ fprintf(fp, "\t\t+%010u", prio);
+
+ if (hook->table && hook->chain)
+ fprintf(fp, " chain %s %s %s", family2str(hook->chain_family), hook->table, hook->chain);
+ else if (hook->hookfn && hook->chain)
+ fprintf(fp, " %s %s", hook->hookfn, hook->chain);
+ else if (hook->hookfn) {
+ fprintf(fp, " %s", hook->hookfn);
+ }
+ if (hook->module_name)
+ fprintf(fp, " [%s]", hook->module_name);
+ }
+
+ fprintf(fp, "\n\t}\n");
+ fprintf(fp, "}\n");
+}
+
+#define HOOK_FAMILY_MAX 5
+
+static uint8_t hook_family[HOOK_FAMILY_MAX] = {
+ NFPROTO_IPV4,
+ NFPROTO_IPV6,
+ NFPROTO_BRIDGE,
+ NFPROTO_ARP,
+};
+
+static int mnl_nft_dump_nf(struct netlink_ctx *ctx, int family, int hook,
+ const char *devname, struct list_head *hook_list,
+ int *ret)
+{
+ int i, err;
+
+ /* show ingress in first place in hook listing. */
+ err = __mnl_nft_dump_nf_hooks(ctx, family, NFPROTO_NETDEV, NF_NETDEV_INGRESS, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+
+ for (i = 0; i <= NF_INET_POST_ROUTING; i++) {
+ err = __mnl_nft_dump_nf_hooks(ctx, family, family, i, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+ }
+
+ return err;
+}
+
+static int mnl_nft_dump_nf_arp(struct netlink_ctx *ctx, int family, int hook,
+ const char *devname, struct list_head *hook_list,
+ int *ret)
+{
+ int err;
+
+ /* show ingress in first place in hook listing. */
+ err = __mnl_nft_dump_nf_hooks(ctx, family, NFPROTO_NETDEV, NF_NETDEV_INGRESS, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+
+ err = __mnl_nft_dump_nf_hooks(ctx, family, family, NF_ARP_IN, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+ err = __mnl_nft_dump_nf_hooks(ctx, family, family, NF_ARP_OUT, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+
+ return err;
+}
+
+static int mnl_nft_dump_nf_netdev(struct netlink_ctx *ctx, int family, int hook,
+ const char *devname, struct list_head *hook_list,
+ int *ret)
+{
+ int err;
+
+ err = __mnl_nft_dump_nf_hooks(ctx, family, NFPROTO_NETDEV, NF_NETDEV_INGRESS, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+
+ return err;
+}
+
+static int mnl_nft_dump_nf_decnet(struct netlink_ctx *ctx, int family, int hook,
+ const char *devname, struct list_head *hook_list,
+ int *ret)
+{
+ int i, err;
+
+ /* show ingress in first place in hook listing. */
+ err = __mnl_nft_dump_nf_hooks(ctx, family, NFPROTO_NETDEV, NF_NETDEV_INGRESS, devname, hook_list);
+ if (err < 0)
+ *ret = err;
+
+#define NF_DN_NUMHOOKS 7
+ for (i = 0; i < NF_DN_NUMHOOKS; i++) {
+ err = __mnl_nft_dump_nf_hooks(ctx, family, family, i, devname, hook_list);
+ if (err < 0) {
+ *ret = err;
+ return err;
+ }
+ }
+
+ return err;
+}
+
+static void release_hook_list(struct list_head *hook_list)
+{
+ struct basehook *hook, *next;
+
+ list_for_each_entry_safe(hook, next, hook_list, list)
+ basehook_free(hook);
+}
+
+int mnl_nft_dump_nf_hooks(struct netlink_ctx *ctx, int family, int hook, const char *devname)
+{
+ LIST_HEAD(hook_list);
+ unsigned int i;
+ int ret;
+
+ errno = 0;
+ ret = 0;
+
+ switch (family) {
+ case NFPROTO_UNSPEC:
+ mnl_nft_dump_nf(ctx, NFPROTO_IPV4, hook, devname, &hook_list, &ret);
+ mnl_nft_dump_nf(ctx, NFPROTO_IPV6, hook, devname, &hook_list, &ret);
+ mnl_nft_dump_nf(ctx, NFPROTO_BRIDGE, hook, devname, &hook_list, &ret);
+ mnl_nft_dump_nf_decnet(ctx, NFPROTO_DECNET, hook, devname, &hook_list, &ret);
+ break;
+ case NFPROTO_INET:
+ mnl_nft_dump_nf(ctx, NFPROTO_IPV4, hook, devname, &hook_list, &ret);
+ mnl_nft_dump_nf(ctx, NFPROTO_IPV6, hook, devname, &hook_list, &ret);
+ break;
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ case NFPROTO_BRIDGE:
+ mnl_nft_dump_nf(ctx, family, hook, devname, &hook_list, &ret);
+ break;
+ case NFPROTO_ARP:
+ mnl_nft_dump_nf_arp(ctx, family, hook, devname, &hook_list, &ret);
+ break;
+ case NFPROTO_NETDEV:
+ mnl_nft_dump_nf_netdev(ctx, family, hook, devname, &hook_list, &ret);
+ break;
+ case NFPROTO_DECNET:
+ mnl_nft_dump_nf_decnet(ctx, family, hook, devname, &hook_list, &ret);
+ break;
+ }
+
+ switch (family) {
+ case NFPROTO_UNSPEC:
+ for (i = 0; i < HOOK_FAMILY_MAX; i++)
+ print_hooks(ctx, hook_family[i], &hook_list);
+ break;
+ case NFPROTO_INET:
+ print_hooks(ctx, NFPROTO_IPV4, &hook_list);
+ print_hooks(ctx, NFPROTO_IPV6, &hook_list);
+ break;
+ default:
+ print_hooks(ctx, family, &hook_list);
+ break;
+ }
+
+ release_hook_list(&hook_list);
+ ret = 0;
+
+ return ret;
+}
diff --git a/src/monitor.c b/src/monitor.c
index 40c38114..2fc16d67 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -2,17 +2,17 @@
* Copyright (c) 2015 Arturo Borrero Gonzalez <arturo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
*/
-#include <string.h>
+#include <nft.h>
+
#include <fcntl.h>
#include <errno.h>
#include <libmnl/libmnl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <stdlib.h>
#include <inttypes.h>
#include <libnftnl/table.h>
@@ -40,6 +40,13 @@
#include <iface.h>
#include <json.h>
+enum {
+ NFT_OF_EVENT_ADD,
+ NFT_OF_EVENT_INSERT,
+ NFT_OF_EVENT_DEL,
+ NFT_OF_EVENT_CREATE,
+};
+
#define nft_mon_print(monh, ...) nft_print(&monh->ctx->nft->output, __VA_ARGS__)
struct nftnl_table *netlink_table_alloc(const struct nlmsghdr *nlh)
@@ -120,17 +127,24 @@ struct nftnl_obj *netlink_obj_alloc(const struct nlmsghdr *nlh)
return nlo;
}
-static uint32_t netlink_msg2nftnl_of(uint32_t msg)
+static uint32_t netlink_msg2nftnl_of(uint32_t type, uint16_t flags)
{
- switch (msg) {
+ switch (type) {
+ case NFT_MSG_NEWRULE:
+ if (flags & NLM_F_APPEND)
+ return NFT_OF_EVENT_ADD;
+ else
+ return NFT_OF_EVENT_INSERT;
case NFT_MSG_NEWTABLE:
case NFT_MSG_NEWCHAIN:
case NFT_MSG_NEWSET:
case NFT_MSG_NEWSETELEM:
- case NFT_MSG_NEWRULE:
case NFT_MSG_NEWOBJ:
case NFT_MSG_NEWFLOWTABLE:
- return NFTNL_OF_EVENT_NEW;
+ if (flags & NLM_F_EXCL)
+ return NFT_OF_EVENT_CREATE;
+ else
+ return NFT_OF_EVENT_ADD;
case NFT_MSG_DELTABLE:
case NFT_MSG_DELCHAIN:
case NFT_MSG_DELSET:
@@ -147,18 +161,22 @@ static uint32_t netlink_msg2nftnl_of(uint32_t msg)
static const char *nftnl_of2cmd(uint32_t of)
{
switch (of) {
- case NFTNL_OF_EVENT_NEW:
+ case NFT_OF_EVENT_ADD:
return "add";
- case NFTNL_OF_EVENT_DEL:
+ case NFT_OF_EVENT_CREATE:
+ return "create";
+ case NFT_OF_EVENT_INSERT:
+ return "insert";
+ case NFT_OF_EVENT_DEL:
return "delete";
default:
return "???";
}
}
-static const char *netlink_msg2cmd(uint32_t msg)
+static const char *netlink_msg2cmd(uint32_t type, uint16_t flags)
{
- return nftnl_of2cmd(netlink_msg2nftnl_of(msg));
+ return nftnl_of2cmd(netlink_msg2nftnl_of(type, flags));
}
static void nlr_for_each_set(struct nftnl_rule *nlr,
@@ -206,7 +224,7 @@ static int netlink_events_table_cb(const struct nlmsghdr *nlh, int type,
nlt = netlink_table_alloc(nlh);
t = netlink_delinearize_table(monh->ctx, nlt);
- cmd = netlink_msg2cmd(type);
+ cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
switch (monh->format) {
case NFTNL_OUTPUT_DEFAULT:
@@ -214,15 +232,21 @@ static int netlink_events_table_cb(const struct nlmsghdr *nlh, int type,
nft_mon_print(monh, "%s %s", family2str(t->handle.family),
t->handle.table.name);
+
+ if (t->flags & TABLE_F_DORMANT)
+ nft_mon_print(monh, " { flags dormant; }");
+
if (nft_output_handle(&monh->ctx->nft->output))
nft_mon_print(monh, " # handle %" PRIu64 "",
t->handle.handle.id);
+ nft_mon_print(monh, "\n");
break;
case NFTNL_OUTPUT_JSON:
monitor_print_table_json(monh, cmd, t);
+ if (!nft_output_echo(&monh->ctx->nft->output))
+ nft_mon_print(monh, "\n");
break;
}
- nft_mon_print(monh, "\n");
table_free(t);
nftnl_table_free(nlt);
return MNL_CB_OK;
@@ -237,7 +261,7 @@ static int netlink_events_chain_cb(const struct nlmsghdr *nlh, int type,
nlc = netlink_chain_alloc(nlh);
c = netlink_delinearize_chain(monh->ctx, nlc);
- cmd = netlink_msg2cmd(type);
+ cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
switch (monh->format) {
case NFTNL_OUTPUT_DEFAULT:
@@ -248,18 +272,23 @@ static int netlink_events_chain_cb(const struct nlmsghdr *nlh, int type,
chain_print_plain(c, &monh->ctx->nft->output);
break;
case NFT_MSG_DELCHAIN:
- nft_mon_print(monh, "chain %s %s %s",
- family2str(c->handle.family),
- c->handle.table.name,
- c->handle.chain.name);
+ if (c->dev_array_len > 0)
+ chain_print_plain(c, &monh->ctx->nft->output);
+ else
+ nft_mon_print(monh, "chain %s %s %s",
+ family2str(c->handle.family),
+ c->handle.table.name,
+ c->handle.chain.name);
break;
}
+ nft_mon_print(monh, "\n");
break;
case NFTNL_OUTPUT_JSON:
monitor_print_chain_json(monh, cmd, c);
+ if (!nft_output_echo(&monh->ctx->nft->output))
+ nft_mon_print(monh, "\n");
break;
}
- nft_mon_print(monh, "\n");
chain_free(c);
nftnl_chain_free(nlc);
return MNL_CB_OK;
@@ -284,7 +313,7 @@ static int netlink_events_set_cb(const struct nlmsghdr *nlh, int type,
return MNL_CB_ERROR;
}
family = family2str(set->handle.family);
- cmd = netlink_msg2cmd(type);
+ cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
switch (monh->format) {
case NFTNL_OUTPUT_DEFAULT:
@@ -300,12 +329,14 @@ static int netlink_events_set_cb(const struct nlmsghdr *nlh, int type,
set->handle.set.name);
break;
}
+ nft_mon_print(monh, "\n");
break;
case NFTNL_OUTPUT_JSON:
monitor_print_set_json(monh, cmd, set);
+ if (!nft_output_echo(&monh->ctx->nft->output))
+ nft_mon_print(monh, "\n");
break;
}
- nft_mon_print(monh, "\n");
set_free(set);
out:
nftnl_set_free(nls);
@@ -359,13 +390,19 @@ static bool netlink_event_range_cache(struct set *cached_set,
/* don't cache half-open range elements */
elem = list_entry(dummyset->init->expressions.prev, struct expr, list);
- if (!set_elem_is_open_interval(elem)) {
+ if (!set_elem_is_open_interval(elem) &&
+ dummyset->desc.field_count <= 1) {
cached_set->rg_cache = expr_clone(elem);
return true;
}
out_decompose:
- interval_map_decompose(dummyset->init);
+ if (dummyset->flags & NFT_SET_INTERVAL &&
+ dummyset->desc.field_count > 1)
+ concat_range_aggregate(dummyset->init);
+ else
+ interval_map_decompose(dummyset->init);
+
return false;
}
@@ -384,11 +421,11 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
table = nftnl_set_get_str(nls, NFTNL_SET_TABLE);
setname = nftnl_set_get_str(nls, NFTNL_SET_NAME);
family = nftnl_set_get_u32(nls, NFTNL_SET_FAMILY);
- cmd = netlink_msg2cmd(type);
+ cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
set = set_lookup_global(family, table, setname, &monh->ctx->nft->cache);
if (set == NULL) {
- fprintf(stderr, "W: Received event for an unknown set.");
+ fprintf(stderr, "W: Received event for an unknown set.\n");
goto out;
}
@@ -400,10 +437,13 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
* used by named sets, so use a dummy set.
*/
dummyset = set_alloc(monh->loc);
+ handle_merge(&dummyset->handle, &set->handle);
dummyset->key = expr_clone(set->key);
- dummyset->datatype = set->datatype;
+ if (set->data)
+ dummyset->data = expr_clone(set->data);
dummyset->flags = set->flags;
dummyset->init = set_expr_alloc(monh->loc, set);
+ dummyset->desc.field_count = set->desc.field_count;
nlsei = nftnl_set_elems_iter_create(nls);
if (nlsei == NULL)
@@ -436,6 +476,7 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
nft_mon_print(monh, "%s element %s %s %s ",
cmd, family2str(family), table, setname);
expr_print(dummyset->init, &monh->ctx->nft->output);
+ nft_mon_print(monh, "\n");
break;
case NFTNL_OUTPUT_JSON:
dummyset->handle.family = family;
@@ -445,9 +486,10 @@ static int netlink_events_setelem_cb(const struct nlmsghdr *nlh, int type,
/* prevent set_free() from trying to free those */
dummyset->handle.set.name = NULL;
dummyset->handle.table.name = NULL;
+ if (!nft_output_echo(&monh->ctx->nft->output))
+ nft_mon_print(monh, "\n");
break;
}
- nft_mon_print(monh, "\n");
set_free(dummyset);
out:
nftnl_set_free(nls);
@@ -464,12 +506,12 @@ static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type,
nlo = netlink_obj_alloc(nlh);
obj = netlink_delinearize_obj(monh->ctx, nlo);
- if (obj == NULL) {
+ if (!obj) {
nftnl_obj_free(nlo);
return MNL_CB_ERROR;
}
family = family2str(obj->handle.family);
- cmd = netlink_msg2cmd(type);
+ cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
switch (monh->format) {
case NFTNL_OUTPUT_DEFAULT:
@@ -487,12 +529,14 @@ static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type,
obj->handle.obj.name);
break;
}
+ nft_mon_print(monh, "\n");
break;
case NFTNL_OUTPUT_JSON:
monitor_print_obj_json(monh, cmd, obj);
+ if (!nft_output_echo(&monh->ctx->nft->output))
+ nft_mon_print(monh, "\n");
break;
}
- nft_mon_print(monh, "\n");
obj_free(obj);
nftnl_obj_free(nlo);
return MNL_CB_OK;
@@ -500,8 +544,13 @@ static int netlink_events_obj_cb(const struct nlmsghdr *nlh, int type,
static void rule_map_decompose_cb(struct set *s, void *data)
{
- if (s->flags & NFT_SET_INTERVAL)
+ if (!set_is_anonymous(s->flags))
+ return;
+
+ if (set_is_non_concat_range(s))
interval_map_decompose(s->init);
+ else if (set_is_interval(s->flags))
+ concat_range_aggregate(s->init);
}
static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
@@ -513,9 +562,13 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
nlr = netlink_rule_alloc(nlh);
r = netlink_delinearize_rule(monh->ctx, nlr);
+ if (!r) {
+ fprintf(stderr, "W: Received event for an unknown table.\n");
+ goto out_free_nlr;
+ }
nlr_for_each_set(nlr, rule_map_decompose_cb, NULL,
&monh->ctx->nft->cache);
- cmd = netlink_msg2cmd(type);
+ cmd = netlink_msg2cmd(type, nlh->nlmsg_flags);
switch (monh->format) {
case NFTNL_OUTPUT_DEFAULT:
@@ -526,7 +579,10 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
family,
r->handle.table.name,
r->handle.chain.name);
-
+ if (r->handle.position.id) {
+ nft_mon_print(monh, "handle %" PRIu64" ",
+ r->handle.position.id);
+ }
switch (type) {
case NFT_MSG_NEWRULE:
rule_print(r, &monh->ctx->nft->output);
@@ -537,13 +593,16 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
r->handle.handle.id);
break;
}
+ nft_mon_print(monh, "\n");
break;
case NFTNL_OUTPUT_JSON:
monitor_print_rule_json(monh, cmd, r);
+ if (!nft_output_echo(&monh->ctx->nft->output))
+ nft_mon_print(monh, "\n");
break;
}
- nft_mon_print(monh, "\n");
rule_free(r);
+out_free_nlr:
nftnl_rule_free(nlr);
return MNL_CB_OK;
}
@@ -558,7 +617,7 @@ static void netlink_events_cache_addtable(struct netlink_mon_handler *monh,
t = netlink_delinearize_table(monh->ctx, nlt);
nftnl_table_free(nlt);
- table_add_hash(t, &monh->ctx->nft->cache);
+ table_cache_add(t, &monh->ctx->nft->cache);
}
static void netlink_events_cache_deltable(struct netlink_mon_handler *monh,
@@ -572,11 +631,12 @@ static void netlink_events_cache_deltable(struct netlink_mon_handler *monh,
h.family = nftnl_table_get_u32(nlt, NFTNL_TABLE_FAMILY);
h.table.name = nftnl_table_get_str(nlt, NFTNL_TABLE_NAME);
- t = table_lookup(&h, &monh->ctx->nft->cache);
+ t = table_cache_find(&monh->ctx->nft->cache.table_cache,
+ h.table.name, h.family);
if (t == NULL)
goto out;
- list_del(&t->list);
+ table_cache_del(t);
table_free(t);
out:
nftnl_table_free(nlt);
@@ -594,6 +654,7 @@ static void netlink_events_cache_addset(struct netlink_mon_handler *monh,
memset(&set_tmpctx, 0, sizeof(set_tmpctx));
init_list_head(&set_tmpctx.list);
init_list_head(&msgs);
+ set_tmpctx.nft = monh->ctx->nft;
set_tmpctx.msgs = &msgs;
nls = netlink_set_alloc(nlh);
@@ -602,14 +663,21 @@ static void netlink_events_cache_addset(struct netlink_mon_handler *monh,
goto out;
s->init = set_expr_alloc(monh->loc, s);
- t = table_lookup(&s->handle, &monh->ctx->nft->cache);
+ t = table_cache_find(&monh->ctx->nft->cache.table_cache,
+ s->handle.table.name, s->handle.family);
if (t == NULL) {
fprintf(stderr, "W: Unable to cache set: table not found.\n");
set_free(s);
goto out;
}
- set_add_hash(s, t);
+ if (nft_output_echo(&monh->ctx->nft->output) &&
+ !set_is_anonymous(s->flags)) {
+ set_free(s);
+ goto out;
+ }
+
+ set_cache_add(s, t);
out:
nftnl_set_free(nls);
}
@@ -636,6 +704,10 @@ static void netlink_events_cache_addsetelem(struct netlink_mon_handler *monh,
goto out;
}
+ if (nft_output_echo(&monh->ctx->nft->output) &&
+ !set_is_anonymous(set->flags))
+ goto out;
+
nlsei = nftnl_set_elems_iter_create(nls);
if (nlsei == NULL)
memory_allocation_error();
@@ -660,7 +732,7 @@ out:
static void netlink_events_cache_delset_cb(struct set *s,
void *data)
{
- list_del(&s->list);
+ set_cache_del(s);
set_free(s);
}
@@ -693,14 +765,15 @@ static void netlink_events_cache_addobj(struct netlink_mon_handler *monh,
if (obj == NULL)
goto out;
- t = table_lookup(&obj->handle, &monh->ctx->nft->cache);
+ t = table_cache_find(&monh->ctx->nft->cache.table_cache,
+ obj->handle.table.name, obj->handle.family);
if (t == NULL) {
fprintf(stderr, "W: Unable to cache object: table not found.\n");
obj_free(obj);
goto out;
}
- obj_add_hash(obj, t);
+ obj_cache_add(obj, t);
out:
nftnl_obj_free(nlo);
}
@@ -723,19 +796,20 @@ static void netlink_events_cache_delobj(struct netlink_mon_handler *monh,
type = nftnl_obj_get_u32(nlo, NFTNL_OBJ_TYPE);
h.handle.id = nftnl_obj_get_u64(nlo, NFTNL_OBJ_HANDLE);
- t = table_lookup(&h, &monh->ctx->nft->cache);
+ t = table_cache_find(&monh->ctx->nft->cache.table_cache,
+ h.table.name, h.family);
if (t == NULL) {
fprintf(stderr, "W: Unable to cache object: table not found.\n");
goto out;
}
- obj = obj_lookup(t, name, type);
+ obj = obj_cache_find(t, name, type);
if (obj == NULL) {
fprintf(stderr, "W: Unable to find object in cache\n");
goto out;
}
- list_del(&obj->list);
+ obj_cache_del(obj);
obj_free(obj);
out:
nftnl_obj_free(nlo);
@@ -744,7 +818,8 @@ out:
static void netlink_events_cache_update(struct netlink_mon_handler *monh,
const struct nlmsghdr *nlh, int type)
{
- if (!monh->cache_needed)
+ if (nft_output_echo(&monh->ctx->nft->output) &&
+ type != NFT_MSG_NEWSET && type != NFT_MSG_NEWSETELEM)
return;
switch (type) {
@@ -814,6 +889,9 @@ static int netlink_events_newgen_cb(const struct nlmsghdr *nlh, int type,
char name[256] = "";
int genid = -1, pid = -1;
+ if (monh->format != NFTNL_OUTPUT_DEFAULT)
+ return MNL_CB_OK;
+
mnl_attr_for_each(attr, nlh, sizeof(struct nfgenmsg)) {
switch (mnl_attr_get_type(attr)) {
case NFTA_GEN_ID:
@@ -894,7 +972,10 @@ static int netlink_events_cb(const struct nlmsghdr *nlh, void *data)
int netlink_echo_callback(const struct nlmsghdr *nlh, void *data)
{
- struct netlink_ctx *ctx = data;
+ struct netlink_cb_data *nl_cb_data = data;
+ struct netlink_ctx *ctx = nl_cb_data->nl_ctx;
+ struct nft_ctx *nft = ctx->nft;
+
struct netlink_mon_handler echo_monh = {
.format = NFTNL_OUTPUT_DEFAULT,
.ctx = ctx,
@@ -905,8 +986,13 @@ int netlink_echo_callback(const struct nlmsghdr *nlh, void *data)
if (!nft_output_echo(&echo_monh.ctx->nft->output))
return MNL_CB_OK;
- if (nft_output_json(&ctx->nft->output))
- return json_events_cb(nlh, &echo_monh);
+ if (nft_output_json(&nft->output)) {
+ if (nft->json_root)
+ return json_events_cb(nlh, &echo_monh);
+ if (!nft->json_echo)
+ json_alloc_echo(nft);
+ echo_monh.format = NFTNL_OUTPUT_JSON;
+ }
return netlink_events_cb(nlh, &echo_monh);
}
diff --git a/src/netlink.c b/src/netlink.c
index 1e669e5d..0088b742 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -9,12 +9,12 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
-#include <string.h>
+#include <nft.h>
+
#include <errno.h>
#include <libmnl/libmnl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
-#include <stdlib.h>
#include <inttypes.h>
#include <libnftnl/table.h>
@@ -27,11 +27,13 @@
#include <libnftnl/udata.h>
#include <libnftnl/ruleset.h>
#include <libnftnl/common.h>
+#include <libnftnl/udata.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter.h>
#include <nftables.h>
+#include <parser.h>
#include <netlink.h>
#include <mnl.h>
#include <expression.h>
@@ -57,7 +59,7 @@ void __noreturn __netlink_abi_error(const char *file, int line,
{
fprintf(stderr, "E: Contact urgently your Linux kernel vendor. "
"Netlink ABI is broken: %s:%d %s\n", file, line, reason);
- exit(NFT_EXIT_FAILURE);
+ abort();
}
int netlink_io_error(struct netlink_ctx *ctx, const struct location *loc,
@@ -94,14 +96,22 @@ struct nftnl_expr *alloc_nft_expr(const char *name)
return nle;
}
+static void netlink_gen_key(const struct expr *expr,
+ struct nft_data_linearize *data);
+static void __netlink_gen_data(const struct expr *expr,
+ struct nft_data_linearize *data, bool expand);
-static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
- const struct expr *expr)
+struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
+ const struct expr *expr)
{
- const struct expr *elem, *key, *data;
+ const struct expr *elem, *data;
struct nftnl_set_elem *nlse;
struct nft_data_linearize nld;
struct nftnl_udata_buf *udbuf = NULL;
+ uint32_t flags = 0;
+ int num_exprs = 0;
+ struct stmt *stmt;
+ struct expr *key;
nlse = nftnl_set_elem_alloc();
if (nlse == NULL)
@@ -115,16 +125,56 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
} else {
elem = expr;
}
+ if (elem->etype != EXPR_SET_ELEM)
+ BUG("Unexpected expression type: got %d\n", elem->etype);
+
key = elem->key;
- netlink_gen_data(key, &nld);
- nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len);
+ switch (key->etype) {
+ case EXPR_SET_ELEM_CATCHALL:
+ break;
+ default:
+ if (set->set_flags & NFT_SET_INTERVAL &&
+ key->etype == EXPR_CONCAT && key->field_count > 1) {
+ key->flags |= EXPR_F_INTERVAL;
+ netlink_gen_key(key, &nld);
+ key->flags &= ~EXPR_F_INTERVAL;
+
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len);
+
+ key->flags |= EXPR_F_INTERVAL_END;
+ netlink_gen_key(key, &nld);
+ key->flags &= ~EXPR_F_INTERVAL_END;
+
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY_END,
+ &nld.value, nld.len);
+ } else {
+ netlink_gen_key(key, &nld);
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len);
+ }
+ break;
+ }
+
if (elem->timeout)
nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_TIMEOUT,
elem->timeout);
if (elem->expiration)
nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_EXPIRATION,
elem->expiration);
+ list_for_each_entry(stmt, &elem->stmt_list, list)
+ num_exprs++;
+
+ if (num_exprs == 1) {
+ list_for_each_entry(stmt, &elem->stmt_list, list) {
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_EXPR,
+ netlink_gen_stmt_stateful(stmt), 0);
+ }
+ } else if (num_exprs > 1) {
+ list_for_each_entry(stmt, &elem->stmt_list, list) {
+ nftnl_set_elem_add_expr(nlse,
+ netlink_gen_stmt_stateful(stmt));
+ }
+ }
if (elem->comment || expr->elem_flags) {
udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
if (!udbuf)
@@ -147,7 +197,7 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
nftnl_udata_buf_free(udbuf);
}
if (set_is_datamap(set->set_flags) && data != NULL) {
- netlink_gen_data(data, &nld);
+ __netlink_gen_data(data, &nld, !(data->flags & EXPR_F_SINGLETON));
switch (data->etype) {
case EXPR_VERDICT:
nftnl_set_elem_set_u32(nlse, NFTNL_SET_ELEM_VERDICT,
@@ -156,7 +206,12 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_CHAIN,
nld.chain, strlen(nld.chain));
break;
+ case EXPR_CONCAT:
+ assert(nld.len > 0);
+ /* fallthrough */
case EXPR_VALUE:
+ case EXPR_RANGE:
+ case EXPR_PREFIX:
nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_DATA,
nld.value, nld.len);
break;
@@ -172,8 +227,12 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
}
if (expr->flags & EXPR_F_INTERVAL_END)
- nftnl_set_elem_set_u32(nlse, NFTNL_SET_ELEM_FLAGS,
- NFT_SET_ELEM_INTERVAL_END);
+ flags |= NFT_SET_ELEM_INTERVAL_END;
+ if (key->etype == EXPR_SET_ELEM_CATCHALL)
+ flags |= NFT_SET_ELEM_CATCHALL;
+
+ if (flags)
+ nftnl_set_elem_set_u32(nlse, NFTNL_SET_ELEM_FLAGS, flags);
return nlse;
}
@@ -186,28 +245,166 @@ void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
data->len = len;
}
-static void netlink_gen_concat_data(const struct expr *expr,
+static int netlink_export_pad(unsigned char *data, const mpz_t v,
+ const struct expr *i)
+{
+ mpz_export_data(data, v, i->byteorder,
+ div_round_up(i->len, BITS_PER_BYTE));
+
+ return netlink_padded_len(i->len) / BITS_PER_BYTE;
+}
+
+static void byteorder_switch_expr_value(mpz_t v, const struct expr *e)
+{
+ mpz_switch_byteorder(v, div_round_up(e->len, BITS_PER_BYTE));
+}
+
+static int __netlink_gen_concat_key(uint32_t flags, const struct expr *i,
+ unsigned char *data)
+{
+ struct expr *expr;
+
+ switch (i->etype) {
+ case EXPR_RANGE:
+ if (flags & EXPR_F_INTERVAL_END)
+ expr = i->right;
+ else
+ expr = i->left;
+
+ if (expr_basetype(expr)->type == TYPE_INTEGER &&
+ expr->byteorder == BYTEORDER_HOST_ENDIAN)
+ byteorder_switch_expr_value(expr->value, expr);
+
+ i = expr;
+ break;
+ case EXPR_PREFIX:
+ if (flags & EXPR_F_INTERVAL_END) {
+ int count;
+ mpz_t v;
+
+ mpz_init_bitmask(v, i->len - i->prefix_len);
+
+ if (i->byteorder == BYTEORDER_HOST_ENDIAN)
+ byteorder_switch_expr_value(v, i);
+
+ mpz_add(v, i->prefix->value, v);
+ count = netlink_export_pad(data, v, i);
+ mpz_clear(v);
+ return count;
+ }
+ return netlink_export_pad(data, i->prefix->value, i);
+ case EXPR_VALUE:
+ /* Switch byteorder only once for singleton values when the set
+ * contains concatenation of intervals.
+ */
+ if (!(flags & EXPR_F_INTERVAL))
+ break;
+
+ expr = (struct expr *)i;
+ if (expr_basetype(expr)->type == TYPE_INTEGER &&
+ expr->byteorder == BYTEORDER_HOST_ENDIAN)
+ byteorder_switch_expr_value(expr->value, expr);
+ break;
+ default:
+ BUG("invalid expression type '%s' in set", expr_ops(i)->name);
+ }
+
+ return netlink_export_pad(data, i->value, i);
+}
+
+static void nft_data_memcpy(struct nft_data_linearize *nld,
+ const void *src, unsigned int len)
+{
+ if (len > sizeof(nld->value))
+ BUG("nld buffer overflow: want to copy %u, max %u\n", len, (unsigned int)sizeof(nld->value));
+
+ memcpy(nld->value, src, len);
+ nld->len = len;
+}
+
+static void netlink_gen_concat_key(const struct expr *expr,
struct nft_data_linearize *nld)
{
+ unsigned int len = expr->len / BITS_PER_BYTE, offset = 0;
+ unsigned char data[len];
const struct expr *i;
- unsigned int len, offset;
-
- len = expr->len / BITS_PER_BYTE;
- if (1) {
- unsigned char data[len];
-
- memset(data, 0, sizeof(data));
- offset = 0;
- list_for_each_entry(i, &expr->expressions, list) {
- assert(i->etype == EXPR_VALUE);
- mpz_export_data(data + offset, i->value, i->byteorder,
- div_round_up(i->len, BITS_PER_BYTE));
- offset += netlink_padded_len(i->len) / BITS_PER_BYTE;
- }
- memcpy(nld->value, data, len);
- nld->len = len;
+ memset(data, 0, len);
+
+ list_for_each_entry(i, &expr->expressions, list)
+ offset += __netlink_gen_concat_key(expr->flags, i, data + offset);
+
+ nft_data_memcpy(nld, data, len);
+}
+
+static int __netlink_gen_concat_data(int end, const struct expr *i,
+ unsigned char *data)
+{
+ switch (i->etype) {
+ case EXPR_RANGE:
+ i = end ? i->right : i->left;
+ break;
+ case EXPR_PREFIX:
+ if (end) {
+ int count;
+ mpz_t v;
+
+ mpz_init_bitmask(v, i->len - i->prefix_len);
+ mpz_add(v, i->prefix->value, v);
+ count = netlink_export_pad(data, v, i);
+ mpz_clear(v);
+ return count;
+ }
+ return netlink_export_pad(data, i->prefix->value, i);
+ case EXPR_VALUE:
+ break;
+ default:
+ BUG("invalid expression type '%s' in set", expr_ops(i)->name);
}
+
+ return netlink_export_pad(data, i->value, i);
+}
+
+static void __netlink_gen_concat_expand(const struct expr *expr,
+ struct nft_data_linearize *nld)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE) * 2, offset = 0;
+ unsigned char data[len];
+ const struct expr *i;
+
+ memset(data, 0, len);
+
+ list_for_each_entry(i, &expr->expressions, list)
+ offset += __netlink_gen_concat_data(false, i, data + offset);
+
+ list_for_each_entry(i, &expr->expressions, list)
+ offset += __netlink_gen_concat_data(true, i, data + offset);
+
+ nft_data_memcpy(nld, data, len);
+}
+
+static void __netlink_gen_concat(const struct expr *expr,
+ struct nft_data_linearize *nld)
+{
+ unsigned int len = expr->len / BITS_PER_BYTE, offset = 0;
+ unsigned char data[len];
+ const struct expr *i;
+
+ memset(data, 0, len);
+
+ list_for_each_entry(i, &expr->expressions, list)
+ offset += __netlink_gen_concat_data(expr->flags, i, data + offset);
+
+ nft_data_memcpy(nld, data, len);
+}
+
+static void netlink_gen_concat_data(const struct expr *expr,
+ struct nft_data_linearize *nld, bool expand)
+{
+ if (expand)
+ __netlink_gen_concat_expand(expr, nld);
+ else
+ __netlink_gen_concat(expr, nld);
}
static void netlink_gen_constant_data(const struct expr *expr,
@@ -218,49 +415,119 @@ static void netlink_gen_constant_data(const struct expr *expr,
div_round_up(expr->len, BITS_PER_BYTE), data);
}
-static void netlink_gen_verdict(const struct expr *expr,
- struct nft_data_linearize *data)
+static void netlink_gen_chain(const struct expr *expr,
+ struct nft_data_linearize *data)
{
char chain[NFT_CHAIN_MAXNAMELEN];
unsigned int len;
+ len = expr->chain->len / BITS_PER_BYTE;
+
+ if (!len)
+ BUG("chain length is 0");
+
+ if (len > sizeof(chain))
+ BUG("chain is too large (%u, %u max)",
+ len, (unsigned int)sizeof(chain));
+
+ memset(chain, 0, sizeof(chain));
+
+ mpz_export_data(chain, expr->chain->value,
+ BYTEORDER_HOST_ENDIAN, len);
+ snprintf(data->chain, NFT_CHAIN_MAXNAMELEN, "%s", chain);
+}
+
+static void netlink_gen_verdict(const struct expr *expr,
+ struct nft_data_linearize *data)
+{
+
data->verdict = expr->verdict;
switch (expr->verdict) {
case NFT_JUMP:
case NFT_GOTO:
- len = expr->chain->len / BITS_PER_BYTE;
+ if (expr->chain)
+ netlink_gen_chain(expr, data);
+ else
+ data->chain_id = expr->chain_id;
+ break;
+ }
+}
- if (!len)
- BUG("chain length is 0");
+static void netlink_gen_range(const struct expr *expr,
+ struct nft_data_linearize *nld)
+{
+ unsigned int len = div_round_up(expr->left->len, BITS_PER_BYTE) * 2;
+ unsigned char data[len];
+ unsigned int offset = 0;
+
+ memset(data, 0, len);
+ offset = netlink_export_pad(data, expr->left->value, expr->left);
+ netlink_export_pad(data + offset, expr->right->value, expr->right);
+ nft_data_memcpy(nld, data, len);
+}
+
+static void netlink_gen_prefix(const struct expr *expr,
+ struct nft_data_linearize *nld)
+{
+ unsigned int len = (netlink_padded_len(expr->len) / BITS_PER_BYTE) * 2;
+ unsigned char data[NFT_MAX_EXPR_LEN_BYTES];
+ int offset;
+ mpz_t v;
- if (len > sizeof(chain))
- BUG("chain is too large (%u, %u max)",
- len, (unsigned int)sizeof(chain));
+ if (len > sizeof(data))
+ BUG("Value export of %u bytes would overflow", len);
- memset(chain, 0, sizeof(chain));
+ offset = netlink_export_pad(data, expr->prefix->value, expr);
+ mpz_init_bitmask(v, expr->len - expr->prefix_len);
+ mpz_add(v, expr->prefix->value, v);
+ netlink_export_pad(data + offset, v, expr->prefix);
+ mpz_clear(v);
- mpz_export_data(chain, expr->chain->value,
- BYTEORDER_HOST_ENDIAN, len);
- snprintf(data->chain, NFT_CHAIN_MAXNAMELEN, "%s", chain);
- break;
+ nft_data_memcpy(nld, data, len);
+}
+
+static void netlink_gen_key(const struct expr *expr,
+ struct nft_data_linearize *data)
+{
+ switch (expr->etype) {
+ case EXPR_VALUE:
+ return netlink_gen_constant_data(expr, data);
+ case EXPR_CONCAT:
+ return netlink_gen_concat_key(expr, data);
+ case EXPR_RANGE:
+ return netlink_gen_range(expr, data);
+ case EXPR_PREFIX:
+ return netlink_gen_prefix(expr, data);
+ default:
+ BUG("invalid data expression type %s\n", expr_name(expr));
}
}
-void netlink_gen_data(const struct expr *expr, struct nft_data_linearize *data)
+static void __netlink_gen_data(const struct expr *expr,
+ struct nft_data_linearize *data, bool expand)
{
switch (expr->etype) {
case EXPR_VALUE:
return netlink_gen_constant_data(expr, data);
case EXPR_CONCAT:
- return netlink_gen_concat_data(expr, data);
+ return netlink_gen_concat_data(expr, data, expand);
case EXPR_VERDICT:
return netlink_gen_verdict(expr, data);
+ case EXPR_RANGE:
+ return netlink_gen_range(expr, data);
+ case EXPR_PREFIX:
+ return netlink_gen_prefix(expr, data);
default:
BUG("invalid data expression type %s\n", expr_name(expr));
}
}
+void netlink_gen_data(const struct expr *expr, struct nft_data_linearize *data)
+{
+ __netlink_gen_data(expr, data, false);
+}
+
struct expr *netlink_alloc_value(const struct location *loc,
const struct nft_data_delinearize *nld)
{
@@ -322,82 +589,74 @@ void netlink_dump_expr(const struct nftnl_expr *nle,
fprintf(fp, "\n");
}
-static int list_rule_cb(struct nftnl_rule *nlr, void *arg)
+void netlink_dump_chain(const struct nftnl_chain *nlc, struct netlink_ctx *ctx)
{
- struct netlink_ctx *ctx = arg;
- const struct handle *h = ctx->data;
- struct rule *rule;
- const char *table, *chain;
- uint32_t family;
-
- family = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
- table = nftnl_rule_get_str(nlr, NFTNL_RULE_TABLE);
- chain = nftnl_rule_get_str(nlr, NFTNL_RULE_CHAIN);
-
- if (h->family != family ||
- strcmp(table, h->table.name) != 0 ||
- (h->chain.name && strcmp(chain, h->chain.name) != 0))
- return 0;
+ FILE *fp = ctx->nft->output.output_fp;
- netlink_dump_rule(nlr, ctx);
- rule = netlink_delinearize_rule(ctx, nlr);
- list_add_tail(&rule->list, &ctx->list);
+ if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
+ return;
- return 0;
+ nftnl_chain_fprintf(fp, nlc, 0, 0);
+ fprintf(fp, "\n");
}
-int netlink_list_rules(struct netlink_ctx *ctx, const struct handle *h)
+static int chain_parse_udata_cb(const struct nftnl_udata *attr, void *data)
{
- struct nftnl_rule_list *rule_cache;
-
- rule_cache = mnl_nft_rule_dump(ctx, h->family);
- if (rule_cache == NULL) {
- if (errno == EINTR)
- return -1;
+ unsigned char *value = nftnl_udata_get(attr);
+ uint8_t type = nftnl_udata_type(attr);
+ const struct nftnl_udata **tb = data;
+ uint8_t len = nftnl_udata_len(attr);
- return 0;
+ switch (type) {
+ case NFTNL_UDATA_CHAIN_COMMENT:
+ if (value[len - 1] != '\0')
+ return -1;
+ break;
+ default:
+ return 0;
}
-
- ctx->data = h;
- nftnl_rule_list_foreach(rule_cache, list_rule_cb, ctx);
- nftnl_rule_list_free(rule_cache);
+ tb[type] = attr;
return 0;
}
-void netlink_dump_chain(const struct nftnl_chain *nlc, struct netlink_ctx *ctx)
+static int qsort_device_cmp(const void *a, const void *b)
{
- FILE *fp = ctx->nft->output.output_fp;
+ const char **x = (const char **)a;
+ const char **y = (const char **)b;
- if (!(ctx->nft->debug_mask & NFT_DEBUG_NETLINK) || !fp)
- return;
-
- nftnl_chain_fprintf(fp, nlc, 0, 0);
- fprintf(fp, "\n");
+ return strcmp(*x, *y);
}
struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
const struct nftnl_chain *nlc)
{
+ const struct nftnl_udata *ud[NFTNL_UDATA_CHAIN_MAX + 1] = {};
+ int priority, policy, len = 0, i;
+ const char * const *dev_array;
struct chain *chain;
- int priority;
- int policy;
+ const char *udata;
+ uint32_t ulen;
- chain = chain_alloc(nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME));
+ chain = chain_alloc();
chain->handle.family =
nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY);
chain->handle.table.name =
xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE));
+ chain->handle.chain.name =
+ xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME));
chain->handle.handle.id =
nftnl_chain_get_u64(nlc, NFTNL_CHAIN_HANDLE);
+ if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_FLAGS))
+ chain->flags = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FLAGS);
if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_HOOKNUM) &&
nftnl_chain_is_set(nlc, NFTNL_CHAIN_PRIO) &&
nftnl_chain_is_set(nlc, NFTNL_CHAIN_TYPE) &&
nftnl_chain_is_set(nlc, NFTNL_CHAIN_POLICY)) {
- chain->hooknum =
+ chain->hook.num =
nftnl_chain_get_u32(nlc, NFTNL_CHAIN_HOOKNUM);
- chain->hookstr =
- hooknum2str(chain->handle.family, chain->hooknum);
+ chain->hook.name =
+ hooknum2str(chain->handle.family, chain->hook.num);
priority = nftnl_chain_get_s32(nlc, NFTNL_CHAIN_PRIO);
chain->priority.expr =
constant_expr_alloc(&netlink_location,
@@ -405,7 +664,7 @@ struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
BYTEORDER_HOST_ENDIAN,
sizeof(int) * BITS_PER_BYTE,
&priority);
- chain->type =
+ chain->type.str =
xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_TYPE));
policy = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY);
chain->policy = constant_expr_alloc(&netlink_location,
@@ -415,68 +674,89 @@ struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
&policy);
nftnl_chain_get_u32(nlc, NFTNL_CHAIN_POLICY);
if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEV)) {
- chain->dev =
+ chain->dev_array = xmalloc(sizeof(char *) * 2);
+ chain->dev_array_len = 1;
+ chain->dev_array[0] =
xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_DEV));
+ chain->dev_array[1] = NULL;
+ } else if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_DEVICES)) {
+ dev_array = nftnl_chain_get(nlc, NFTNL_CHAIN_DEVICES);
+ while (dev_array[len])
+ len++;
+
+ chain->dev_array = xmalloc((len + 1)* sizeof(char *));
+ for (i = 0; i < len; i++)
+ chain->dev_array[i] = xstrdup(dev_array[i]);
+
+ chain->dev_array[i] = NULL;
+ chain->dev_array_len = len;
}
chain->flags |= CHAIN_F_BASECHAIN;
- }
-
- return chain;
-}
-static int list_chain_cb(struct nftnl_chain *nlc, void *arg)
-{
- struct netlink_ctx *ctx = arg;
- const struct handle *h = ctx->data;
- const char *table;
- const char *name;
- struct chain *chain;
- uint32_t family;
-
- table = nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE);
- name = nftnl_chain_get_str(nlc, NFTNL_CHAIN_NAME);
- family = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FAMILY);
-
- if (h->family != family || strcmp(table, h->table.name) != 0)
- return 0;
- if (h->chain.name && strcmp(name, h->chain.name) != 0)
- return 0;
+ if (chain->dev_array_len) {
+ qsort(chain->dev_array, chain->dev_array_len,
+ sizeof(char *), qsort_device_cmp);
+ }
+ }
- chain = netlink_delinearize_chain(ctx, nlc);
- list_add_tail(&chain->list, &ctx->list);
+ if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_USERDATA)) {
+ udata = nftnl_chain_get_data(nlc, NFTNL_CHAIN_USERDATA, &ulen);
+ if (nftnl_udata_parse(udata, ulen, chain_parse_udata_cb, ud) < 0) {
+ netlink_io_error(ctx, NULL, "Cannot parse userdata");
+ chain_free(chain);
+ return NULL;
+ }
+ if (ud[NFTNL_UDATA_CHAIN_COMMENT])
+ chain->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_CHAIN_COMMENT]));
+ }
- return 0;
+ return chain;
}
-int netlink_list_chains(struct netlink_ctx *ctx, const struct handle *h)
+static int table_parse_udata_cb(const struct nftnl_udata *attr, void *data)
{
- struct nftnl_chain_list *chain_cache;
-
- chain_cache = mnl_nft_chain_dump(ctx, h->family);
- if (chain_cache == NULL) {
- if (errno == EINTR)
- return -1;
+ unsigned char *value = nftnl_udata_get(attr);
+ const struct nftnl_udata **tb = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
- return 0;
+ switch (type) {
+ case NFTNL_UDATA_TABLE_COMMENT:
+ if (value[len - 1] != '\0')
+ return -1;
+ break;
+ default:
+ return 0;
}
-
- ctx->data = h;
- nftnl_chain_list_foreach(chain_cache, list_chain_cb, ctx);
- nftnl_chain_list_free(chain_cache);
-
+ tb[type] = attr;
return 0;
}
struct table *netlink_delinearize_table(struct netlink_ctx *ctx,
const struct nftnl_table *nlt)
{
+ const struct nftnl_udata *ud[NFTNL_UDATA_TABLE_MAX + 1] = {};
struct table *table;
+ const char *udata;
+ uint32_t ulen;
table = table_alloc();
table->handle.family = nftnl_table_get_u32(nlt, NFTNL_TABLE_FAMILY);
table->handle.table.name = xstrdup(nftnl_table_get_str(nlt, NFTNL_TABLE_NAME));
table->flags = nftnl_table_get_u32(nlt, NFTNL_TABLE_FLAGS);
table->handle.handle.id = nftnl_table_get_u64(nlt, NFTNL_TABLE_HANDLE);
+ table->owner = nftnl_table_get_u32(nlt, NFTNL_TABLE_OWNER);
+
+ if (nftnl_table_is_set(nlt, NFTNL_TABLE_USERDATA)) {
+ udata = nftnl_table_get_data(nlt, NFTNL_TABLE_USERDATA, &ulen);
+ if (nftnl_udata_parse(udata, ulen, table_parse_udata_cb, ud) < 0) {
+ netlink_io_error(ctx, NULL, "Cannot parse userdata");
+ table_free(table);
+ return NULL;
+ }
+ if (ud[NFTNL_UDATA_TABLE_COMMENT])
+ table->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_TABLE_COMMENT]));
+ }
return table;
}
@@ -492,16 +772,24 @@ static int list_table_cb(struct nftnl_table *nlt, void *arg)
return 0;
}
-int netlink_list_tables(struct netlink_ctx *ctx, const struct handle *h)
+int netlink_list_tables(struct netlink_ctx *ctx, const struct handle *h,
+ const struct nft_cache_filter *filter)
{
struct nftnl_table_list *table_cache;
+ uint32_t family = h->family;
+ const char *table = NULL;
- table_cache = mnl_nft_table_dump(ctx, h->family);
+ if (filter) {
+ family = filter->list.family;
+ table = filter->list.table;
+ }
+
+ table_cache = mnl_nft_table_dump(ctx, family, table);
if (table_cache == NULL) {
if (errno == EINTR)
return -1;
- return 0;
+ return -1;
}
ctx->data = h;
@@ -520,15 +808,19 @@ enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype)
}
}
-const struct datatype *dtype_map_from_kernel(enum nft_data_types type)
+static const struct datatype *dtype_map_from_kernel(enum nft_data_types type)
{
+ /* The function always returns ownership of a reference. But for
+ * &verdict_Type and datatype_lookup(), those are static instances,
+ * we can omit the datatype_get() call.
+ */
switch (type) {
case NFT_DATA_VERDICT:
return &verdict_type;
default:
if (type & ~TYPE_MASK)
return concat_type_alloc(type);
- return datatype_lookup(type);
+ return datatype_lookup((enum datatypes) type);
}
}
@@ -545,6 +837,7 @@ void netlink_dump_set(const struct nftnl_set *nls, struct netlink_ctx *ctx)
static int set_parse_udata_cb(const struct nftnl_udata *attr, void *data)
{
+ unsigned char *value = nftnl_udata_get(attr);
const struct nftnl_udata **tb = data;
uint8_t type = nftnl_udata_type(attr);
uint8_t len = nftnl_udata_len(attr);
@@ -553,9 +846,39 @@ static int set_parse_udata_cb(const struct nftnl_udata *attr, void *data)
case NFTNL_UDATA_SET_KEYBYTEORDER:
case NFTNL_UDATA_SET_DATABYTEORDER:
case NFTNL_UDATA_SET_MERGE_ELEMENTS:
+ case NFTNL_UDATA_SET_DATA_INTERVAL:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ case NFTNL_UDATA_SET_KEY_TYPEOF:
+ case NFTNL_UDATA_SET_DATA_TYPEOF:
+ if (len < 3)
+ return -1;
+ break;
+ case NFTNL_UDATA_SET_COMMENT:
+ if (value[len - 1] != '\0')
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+ tb[type] = attr;
+ return 0;
+}
+
+static int set_key_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **tb = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_SET_TYPEOF_EXPR:
if (len != sizeof(uint32_t))
return -1;
break;
+ case NFTNL_UDATA_SET_TYPEOF_DATA:
+ break;
default:
return 0;
}
@@ -563,18 +886,85 @@ static int set_parse_udata_cb(const struct nftnl_udata *attr, void *data)
return 0;
}
+static struct expr *set_make_key(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_SET_TYPEOF_MAX + 1] = {};
+ const struct expr_ops *ops;
+ struct expr *expr;
+ uint32_t etype;
+ int err;
+
+ if (!attr)
+ return NULL;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ set_key_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_SET_TYPEOF_EXPR] ||
+ !ud[NFTNL_UDATA_SET_TYPEOF_DATA])
+ return NULL;
+
+ etype = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_TYPEOF_EXPR]);
+ ops = expr_ops_by_type_u32(etype);
+ if (!ops)
+ return NULL;
+
+ expr = ops->parse_udata(ud[NFTNL_UDATA_SET_TYPEOF_DATA]);
+ if (!expr)
+ return NULL;
+
+ return expr;
+}
+
+static bool set_udata_key_valid(const struct expr *e, uint32_t len)
+{
+ if (!e)
+ return false;
+
+ return div_round_up(e->len, BITS_PER_BYTE) == len / BITS_PER_BYTE;
+}
+
+struct setelem_parse_ctx {
+ struct set *set;
+ struct nft_cache *cache;
+ struct list_head stmt_list;
+};
+
+static int set_elem_parse_expressions(struct nftnl_expr *e, void *data)
+{
+ struct setelem_parse_ctx *setelem_parse_ctx = data;
+ struct nft_cache *cache = setelem_parse_ctx->cache;
+ struct set *set = setelem_parse_ctx->set;
+ struct stmt *stmt;
+
+ stmt = netlink_parse_set_expr(set, cache, e);
+ list_add_tail(&stmt->list, &setelem_parse_ctx->stmt_list);
+
+ return 0;
+}
+
struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
const struct nftnl_set *nls)
{
const struct nftnl_udata *ud[NFTNL_UDATA_SET_MAX + 1] = {};
- uint32_t flags, key, data, data_len, objtype = 0;
enum byteorder keybyteorder = BYTEORDER_INVALID;
enum byteorder databyteorder = BYTEORDER_INVALID;
- const struct datatype *keytype, *datatype;
+ struct setelem_parse_ctx set_parse_ctx;
+ const struct datatype *datatype = NULL;
+ const struct datatype *keytype = NULL;
+ const struct datatype *dtype2 = NULL;
+ const struct datatype *dtype = NULL;
+ struct expr *typeof_expr_data = NULL;
+ struct expr *typeof_expr_key = NULL;
+ const char *udata, *comment = NULL;
+ uint32_t flags, key, objtype = 0;
+ uint32_t data_interval = 0;
bool automerge = false;
- const char *udata;
struct set *set;
uint32_t ulen;
+ uint32_t klen;
if (nftnl_set_is_set(nls, NFTNL_SET_USERDATA)) {
udata = nftnl_set_get_data(nls, NFTNL_SET_USERDATA, &ulen);
@@ -590,8 +980,14 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
GET_U32_UDATA(keybyteorder, NFTNL_UDATA_SET_KEYBYTEORDER);
GET_U32_UDATA(databyteorder, NFTNL_UDATA_SET_DATABYTEORDER);
GET_U32_UDATA(automerge, NFTNL_UDATA_SET_MERGE_ELEMENTS);
+ GET_U32_UDATA(data_interval, NFTNL_UDATA_SET_DATA_INTERVAL);
#undef GET_U32_UDATA
+ typeof_expr_key = set_make_key(ud[NFTNL_UDATA_SET_KEY_TYPEOF]);
+ if (ud[NFTNL_UDATA_SET_DATA_TYPEOF])
+ typeof_expr_data = set_make_key(ud[NFTNL_UDATA_SET_DATA_TYPEOF]);
+ if (ud[NFTNL_UDATA_SET_COMMENT])
+ comment = nftnl_udata_get(ud[NFTNL_UDATA_SET_COMMENT]);
}
key = nftnl_set_get_u32(nls, NFTNL_SET_KEY_TYPE);
@@ -604,19 +1000,22 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
if (set_is_datamap(flags)) {
+ uint32_t data;
+
data = nftnl_set_get_u32(nls, NFTNL_SET_DATA_TYPE);
datatype = dtype_map_from_kernel(data);
if (datatype == NULL) {
netlink_io_error(ctx, NULL,
"Unknown data type in set key %u",
data);
- return NULL;
+ set = NULL;
+ goto out;
}
- } else
- datatype = NULL;
+ }
if (set_is_objmap(flags)) {
objtype = nftnl_set_get_u32(nls, NFTNL_SET_OBJ_TYPE);
+ assert(!datatype);
datatype = &string_type;
}
@@ -625,28 +1024,77 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
set->handle.table.name = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_TABLE));
set->handle.set.name = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_NAME));
set->automerge = automerge;
+ if (comment)
+ set->comment = xstrdup(comment);
- set->key = constant_expr_alloc(&netlink_location,
- set_datatype_alloc(keytype, keybyteorder),
- keybyteorder,
- nftnl_set_get_u32(nls, NFTNL_SET_KEY_LEN) * BITS_PER_BYTE,
- NULL);
- set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
- set->handle.handle.id = nftnl_set_get_u64(nls, NFTNL_SET_HANDLE);
+ init_list_head(&set_parse_ctx.stmt_list);
- set->objtype = objtype;
+ if (nftnl_set_is_set(nls, NFTNL_SET_EXPR)) {
+ const struct nftnl_expr *nle;
+ struct stmt *stmt;
+
+ nle = nftnl_set_get(nls, NFTNL_SET_EXPR);
+ stmt = netlink_parse_set_expr(set, &ctx->nft->cache, nle);
+ list_add_tail(&stmt->list, &set_parse_ctx.stmt_list);
+ } else if (nftnl_set_is_set(nls, NFTNL_SET_EXPRESSIONS)) {
+ set_parse_ctx.cache = &ctx->nft->cache;
+ set_parse_ctx.set = set;
+ nftnl_set_expr_foreach(nls, set_elem_parse_expressions,
+ &set_parse_ctx);
+ }
+ list_splice_tail(&set_parse_ctx.stmt_list, &set->stmt_list);
- if (datatype)
- set->datatype = datatype_get(set_datatype_alloc(datatype,
- databyteorder));
- else
- set->datatype = NULL;
+ set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
+
+ if (datatype) {
+ uint32_t dlen;
+
+ dtype2 = set_datatype_alloc(datatype, databyteorder);
+ klen = nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN) * BITS_PER_BYTE;
+
+ dlen = data_interval ? klen / 2 : klen;
+
+ if (set_udata_key_valid(typeof_expr_data, dlen)) {
+ typeof_expr_data->len = klen;
+ set->data = typeof_expr_data;
+ typeof_expr_data = NULL;
+ } else if (set->flags & NFT_SET_OBJECT) {
+ set->data = constant_expr_alloc(&netlink_location,
+ dtype2,
+ databyteorder, klen,
+ NULL);
+ } else {
+ set->data = constant_expr_alloc(&netlink_location,
+ dtype2,
+ databyteorder, klen,
+ NULL);
+
+ /* Can't use 'typeof' keyword, so discard key too */
+ expr_free(typeof_expr_key);
+ typeof_expr_key = NULL;
+ }
- if (nftnl_set_is_set(nls, NFTNL_SET_DATA_LEN)) {
- data_len = nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN);
- set->datalen = data_len * BITS_PER_BYTE;
+ if (data_interval)
+ set->data->flags |= EXPR_F_INTERVAL;
}
+ dtype = set_datatype_alloc(keytype, keybyteorder);
+ klen = nftnl_set_get_u32(nls, NFTNL_SET_KEY_LEN) * BITS_PER_BYTE;
+
+ if (set_udata_key_valid(typeof_expr_key, klen)) {
+ set->key = typeof_expr_key;
+ typeof_expr_key = NULL;
+ set->key_typeof_valid = true;
+ } else {
+ set->key = constant_expr_alloc(&netlink_location, dtype,
+ keybyteorder, klen,
+ NULL);
+ }
+
+ set->handle.handle.id = nftnl_set_get_u64(nls, NFTNL_SET_HANDLE);
+
+ set->objtype = objtype;
+
if (nftnl_set_is_set(nls, NFTNL_SET_TIMEOUT))
set->timeout = nftnl_set_get_u64(nls, NFTNL_SET_TIMEOUT);
if (nftnl_set_is_set(nls, NFTNL_SET_GC_INTERVAL))
@@ -658,76 +1106,225 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
if (nftnl_set_is_set(nls, NFTNL_SET_DESC_SIZE))
set->desc.size = nftnl_set_get_u32(nls, NFTNL_SET_DESC_SIZE);
+ if (nftnl_set_is_set(nls, NFTNL_SET_DESC_CONCAT)) {
+ uint32_t len = NFT_REG32_COUNT;
+ const uint8_t *data;
+
+ data = nftnl_set_get_data(nls, NFTNL_SET_DESC_CONCAT, &len);
+ if (data) {
+ memcpy(set->desc.field_len, data, len);
+ set->desc.field_count = len;
+ }
+ }
+
+out:
+ expr_free(typeof_expr_data);
+ expr_free(typeof_expr_key);
+ datatype_free(datatype);
+ datatype_free(keytype);
+ datatype_free(dtype2);
+ datatype_free(dtype);
return set;
}
-static int list_set_cb(struct nftnl_set *nls, void *arg)
+void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls)
{
- struct netlink_ctx *ctx = arg;
- struct set *set;
+ struct nftnl_set_elem *nlse;
+ const struct expr *expr;
- set = netlink_delinearize_set(ctx, nls);
- if (set == NULL)
- return -1;
- list_add_tail(&set->list, &ctx->list);
- return 0;
+ list_for_each_entry(expr, &set->expressions, list) {
+ nlse = alloc_nftnl_setelem(set, expr);
+ nftnl_set_elem_add(nls, nlse);
+ }
}
-int netlink_list_sets(struct netlink_ctx *ctx, const struct handle *h)
+static bool range_expr_is_prefix(const struct expr *range, uint32_t *prefix_len)
{
- struct nftnl_set_list *set_cache;
- int err;
+ const struct expr *right = range->right;
+ const struct expr *left = range->left;
+ uint32_t len = left->len;
+ unsigned long n1, n2;
+ uint32_t plen;
+ mpz_t bitmask;
- set_cache = mnl_nft_set_dump(ctx, h->family, h->table.name);
- if (set_cache == NULL) {
- if (errno == EINTR)
- return -1;
+ mpz_init2(bitmask, left->len);
+ mpz_xor(bitmask, left->value, right->value);
- return 0;
+ n1 = mpz_scan0(bitmask, 0);
+ if (n1 == ULONG_MAX)
+ goto not_a_prefix;
+
+ n2 = mpz_scan1(bitmask, n1 + 1);
+ if (n2 < len)
+ goto not_a_prefix;
+
+ plen = len - n1;
+
+ if (mpz_scan1(left->value, 0) < len - plen)
+ goto not_a_prefix;
+
+ mpz_clear(bitmask);
+ *prefix_len = plen;
+
+ return true;
+
+not_a_prefix:
+ mpz_clear(bitmask);
+
+ return false;
+}
+
+struct expr *range_expr_to_prefix(struct expr *range)
+{
+ struct expr *prefix;
+ uint32_t prefix_len;
+
+ if (range_expr_is_prefix(range, &prefix_len)) {
+ prefix = prefix_expr_alloc(&range->location,
+ expr_get(range->left),
+ prefix_len);
+ expr_free(range);
+ return prefix;
}
- ctx->data = h;
- err = nftnl_set_list_foreach(set_cache, list_set_cb, ctx);
- nftnl_set_list_free(set_cache);
- return err;
+ return range;
}
-void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls)
+static struct expr *range_expr_reduce(struct expr *range)
{
- struct nftnl_set_elem *nlse;
- const struct expr *expr;
+ struct expr *expr;
- list_for_each_entry(expr, &set->expressions, list) {
- nlse = alloc_nftnl_setelem(set, expr);
- nftnl_set_elem_add(nls, nlse);
+ if (!mpz_cmp(range->left->value, range->right->value)) {
+ expr = expr_get(range->left);
+ expr_free(range);
+ return expr;
}
+
+ if (range->left->dtype->type != TYPE_IPADDR &&
+ range->left->dtype->type != TYPE_IP6ADDR)
+ return range;
+
+ return range_expr_to_prefix(range);
}
-static struct expr *netlink_parse_concat_elem(const struct datatype *dtype,
- struct expr *data)
+static struct expr *netlink_parse_interval_elem(const struct set *set,
+ struct expr *expr)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ const struct datatype *dtype = set->data->dtype;
+ struct expr *range, *left, *right;
+ char data[len];
+
+ mpz_export_data(data, expr->value, dtype->byteorder, len);
+ left = constant_expr_alloc(&internal_location, dtype,
+ dtype->byteorder,
+ (len / 2) * BITS_PER_BYTE, &data[0]);
+ right = constant_expr_alloc(&internal_location, dtype,
+ dtype->byteorder,
+ (len / 2) * BITS_PER_BYTE, &data[len / 2]);
+ range = range_expr_alloc(&expr->location, left, right);
+ expr_free(expr);
+
+ return range_expr_to_prefix(range);
+}
+
+static struct expr *concat_elem_expr(const struct set *set, struct expr *key,
+ const struct datatype *dtype,
+ struct expr *data, int *off)
{
const struct datatype *subtype;
- struct expr *concat, *expr;
+ unsigned int sub_length;
+ struct expr *expr;
+
+ if (key) {
+ (*off)--;
+ sub_length = round_up(key->len, BITS_PER_BYTE);
+
+ expr = constant_expr_splice(data, sub_length);
+ expr->dtype = datatype_get(key->dtype);
+ expr->byteorder = key->byteorder;
+ expr->len = key->len;
+ } else {
+ subtype = concat_subtype_lookup(dtype->type, --(*off));
+ sub_length = round_up(subtype->size, BITS_PER_BYTE);
+ expr = constant_expr_splice(data, sub_length);
+ expr->dtype = subtype;
+ expr->byteorder = subtype->byteorder;
+ }
+
+ if (expr_basetype(expr)->type == TYPE_STRING ||
+ (!(set->flags & NFT_SET_INTERVAL) &&
+ expr->byteorder == BYTEORDER_HOST_ENDIAN))
+ mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+
+ if (expr->dtype->basetype != NULL &&
+ expr->dtype->basetype->type == TYPE_BITMASK)
+ expr = bitmask_expr_to_binops(expr);
+
+ data->len -= netlink_padding_len(sub_length);
+
+ return expr;
+}
+
+static struct expr *netlink_parse_concat_elem_key(const struct set *set,
+ struct expr *data)
+{
+ const struct datatype *dtype = set->key->dtype;
+ struct expr *concat, *expr, *n = NULL;
int off = dtype->subtypes;
+ if (set->key->etype == EXPR_CONCAT)
+ n = list_first_entry(&set->key->expressions, struct expr, list);
+
concat = concat_expr_alloc(&data->location);
while (off > 0) {
- subtype = concat_subtype_lookup(dtype->type, --off);
+ expr = concat_elem_expr(set, n, dtype, data, &off);
+ compound_expr_add(concat, expr);
+ if (set->key->etype == EXPR_CONCAT)
+ n = list_next_entry(n, list);
+ }
- expr = constant_expr_splice(data, subtype->size);
- expr->dtype = subtype;
- expr->byteorder = subtype->byteorder;
+ expr_free(data);
- if (expr->byteorder == BYTEORDER_HOST_ENDIAN)
- mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+ return concat;
+}
- if (expr->dtype->basetype != NULL &&
- expr->dtype->basetype->type == TYPE_BITMASK)
- expr = bitmask_expr_to_binops(expr);
+static struct expr *netlink_parse_concat_elem(const struct set *set,
+ struct expr *data)
+{
+ const struct datatype *dtype = set->data->dtype;
+ struct expr *concat, *expr, *left, *range;
+ struct list_head expressions;
+ int off = dtype->subtypes;
- compound_expr_add(concat, expr);
- data->len -= netlink_padding_len(expr->len);
+ init_list_head(&expressions);
+
+ concat = concat_expr_alloc(&data->location);
+ while (off > 0) {
+ expr = concat_elem_expr(set, NULL, dtype, data, &off);
+ list_add_tail(&expr->list, &expressions);
}
+
+ if (set->data->flags & EXPR_F_INTERVAL) {
+ assert(!list_empty(&expressions));
+
+ off = dtype->subtypes;
+
+ while (off > 0) {
+ left = list_first_entry(&expressions, struct expr, list);
+
+ expr = concat_elem_expr(set, NULL, dtype, data, &off);
+ list_del(&left->list);
+
+ range = range_expr_alloc(&data->location, left, expr);
+ range = range_expr_reduce(range);
+ compound_expr_add(concat, range);
+ }
+ assert(list_empty(&expressions));
+ } else {
+ list_splice_tail(&expressions, &concat->expressions);
+ }
+
expr_free(data);
return concat;
@@ -776,32 +1373,50 @@ static void set_elem_parse_udata(struct nftnl_set_elem *nlse,
}
int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
- const struct set *set, struct nft_cache *cache)
+ struct set *set, struct nft_cache *cache)
{
+ struct setelem_parse_ctx setelem_parse_ctx = {
+ .set = set,
+ .cache = cache,
+ };
struct nft_data_delinearize nld;
struct expr *expr, *key, *data;
uint32_t flags = 0;
- nld.value =
- nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_KEY, &nld.len);
+ init_list_head(&setelem_parse_ctx.stmt_list);
+
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY))
+ nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_KEY, &nld.len);
if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_FLAGS))
flags = nftnl_set_elem_get_u32(nlse, NFTNL_SET_ELEM_FLAGS);
- key = netlink_alloc_value(&netlink_location, &nld);
- datatype_set(key, set->key->dtype);
- key->byteorder = set->key->byteorder;
- if (set->key->dtype->subtypes)
- key = netlink_parse_concat_elem(set->key->dtype, key);
-
- if (!(set->flags & NFT_SET_INTERVAL) &&
- key->byteorder == BYTEORDER_HOST_ENDIAN)
- mpz_switch_byteorder(key->value, key->len / BITS_PER_BYTE);
-
- if (key->dtype->basetype != NULL &&
- key->dtype->basetype->type == TYPE_BITMASK)
- key = bitmask_expr_to_binops(key);
+key_end:
+ if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY)) {
+ key = netlink_alloc_value(&netlink_location, &nld);
+ datatype_set(key, set->key->dtype);
+ key->byteorder = set->key->byteorder;
+ if (set->key->dtype->subtypes)
+ key = netlink_parse_concat_elem_key(set, key);
+
+ if (!(set->flags & NFT_SET_INTERVAL) &&
+ key->byteorder == BYTEORDER_HOST_ENDIAN)
+ mpz_switch_byteorder(key->value, key->len / BITS_PER_BYTE);
+
+ if (key->dtype->basetype != NULL &&
+ key->dtype->basetype->type == TYPE_BITMASK)
+ key = bitmask_expr_to_binops(key);
+ } else if (flags & NFT_SET_ELEM_CATCHALL) {
+ key = set_elem_catchall_expr_alloc(&netlink_location);
+ datatype_set(key, set->key->dtype);
+ key->byteorder = set->key->byteorder;
+ key->len = set->key->len;
+ } else {
+ BUG("Unexpected set element with no key\n");
+ }
expr = set_elem_expr_alloc(&netlink_location, key);
+ expr->flags |= EXPR_F_KERNEL;
+
if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_TIMEOUT))
expr->timeout = nftnl_set_elem_get_u64(nlse, NFTNL_SET_ELEM_TIMEOUT);
if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPIRATION))
@@ -810,12 +1425,22 @@ int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
set_elem_parse_udata(nlse, expr);
if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPR)) {
const struct nftnl_expr *nle;
+ struct stmt *stmt;
nle = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_EXPR, NULL);
- expr->stmt = netlink_parse_set_expr(set, cache, nle);
+ stmt = netlink_parse_set_expr(set, cache, nle);
+ list_add_tail(&stmt->list, &setelem_parse_ctx.stmt_list);
+ } else if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_EXPRESSIONS)) {
+ nftnl_set_elem_expr_foreach(nlse, set_elem_parse_expressions,
+ &setelem_parse_ctx);
}
- if (flags & NFT_SET_ELEM_INTERVAL_END)
+ list_splice_tail_init(&setelem_parse_ctx.stmt_list, &expr->stmt_list);
+
+ if (flags & NFT_SET_ELEM_INTERVAL_END) {
expr->flags |= EXPR_F_INTERVAL_END;
+ if (mpz_cmp_ui(set->key->value, 0) == 0)
+ set->root = true;
+ }
if (set_is_datamap(set->flags)) {
if (nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_DATA)) {
@@ -830,10 +1455,16 @@ int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
goto out;
data = netlink_alloc_data(&netlink_location, &nld,
- set->datatype->type == TYPE_VERDICT ?
+ set->data->dtype->type == TYPE_VERDICT ?
NFT_REG_VERDICT : NFT_REG_1);
- datatype_set(data, set->datatype);
- data->byteorder = set->datatype->byteorder;
+ datatype_set(data, set->data->dtype);
+ data->byteorder = set->data->byteorder;
+
+ if (set->data->dtype->subtypes) {
+ data = netlink_parse_concat_elem(set, data);
+ } else if (set->data->flags & EXPR_F_INTERVAL)
+ data = netlink_parse_interval_elem(set, data);
+
if (data->byteorder == BYTEORDER_HOST_ENDIAN)
mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
@@ -855,6 +1486,15 @@ int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
}
out:
compound_expr_add(set->init, expr);
+
+ if (!(flags & NFT_SET_ELEM_INTERVAL_END) &&
+ nftnl_set_elem_is_set(nlse, NFTNL_SET_ELEM_KEY_END)) {
+ flags |= NFT_SET_ELEM_INTERVAL_END;
+ nld.value = nftnl_set_elem_get(nlse, NFTNL_SET_ELEM_KEY_END,
+ &nld.len);
+ goto key_end;
+ }
+
return 0;
}
@@ -864,8 +1504,44 @@ static int list_setelem_cb(struct nftnl_set_elem *nlse, void *arg)
return netlink_delinearize_setelem(nlse, ctx->set, &ctx->nft->cache);
}
+static int list_setelem_debug_cb(struct nftnl_set_elem *nlse, void *arg)
+{
+ int r;
+
+ r = list_setelem_cb(nlse, arg);
+ if (r == 0) {
+ struct netlink_ctx *ctx = arg;
+ FILE *fp = ctx->nft->output.output_fp;
+
+ fprintf(fp, "\t");
+ nftnl_set_elem_fprintf(fp, nlse, 0, 0);
+ fprintf(fp, "\n");
+ }
+
+ return r;
+}
+
+static int list_setelements(struct nftnl_set *s, struct netlink_ctx *ctx)
+{
+ FILE *fp = ctx->nft->output.output_fp;
+
+ if (fp && (ctx->nft->debug_mask & NFT_DEBUG_NETLINK)) {
+ const char *table, *name;
+ uint32_t family = nftnl_set_get_u32(s, NFTNL_SET_FAMILY);
+
+ table = nftnl_set_get_str(s, NFTNL_SET_TABLE);
+ name = nftnl_set_get_str(s, NFTNL_SET_NAME);
+
+ fprintf(fp, "%s %s @%s\n", family2str(family), table, name);
+
+ return nftnl_set_elem_foreach(s, list_setelem_debug_cb, ctx);
+ }
+
+ return nftnl_set_elem_foreach(s, list_setelem_cb, ctx);
+}
+
int netlink_list_setelems(struct netlink_ctx *ctx, const struct handle *h,
- struct set *set)
+ struct set *set, bool reset)
{
struct nftnl_set *nls;
int err;
@@ -880,7 +1556,7 @@ int netlink_list_setelems(struct netlink_ctx *ctx, const struct handle *h,
if (h->handle.id)
nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
- err = mnl_nft_setelem_get(ctx, nls);
+ err = mnl_nft_setelem_get(ctx, nls, reset);
if (err < 0) {
nftnl_set_free(nls);
if (errno == EINTR)
@@ -891,25 +1567,27 @@ int netlink_list_setelems(struct netlink_ctx *ctx, const struct handle *h,
ctx->set = set;
set->init = set_expr_alloc(&internal_location, set);
- nftnl_set_elem_foreach(nls, list_setelem_cb, ctx);
+ list_setelements(nls, ctx);
- if (!(set->flags & NFT_SET_INTERVAL))
+ if (set->flags & NFT_SET_INTERVAL && set->desc.field_count > 1)
+ concat_range_aggregate(set->init);
+ else if (set->flags & NFT_SET_INTERVAL)
+ interval_map_decompose(set->init);
+ else
list_expr_sort(&ctx->set->init->expressions);
nftnl_set_free(nls);
ctx->set = NULL;
- if (set->flags & NFT_SET_INTERVAL)
- interval_map_decompose(set->init);
-
return 0;
}
int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h,
- const struct location *loc, struct table *table,
- struct set *set, struct expr *init)
+ const struct location *loc, struct set *cache_set,
+ struct set *set, struct expr *init, bool reset)
{
struct nftnl_set *nls, *nls_out = NULL;
+ int err = 0;
nls = nftnl_set_alloc();
if (nls == NULL)
@@ -925,26 +1603,28 @@ int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h,
netlink_dump_set(nls, ctx);
- nls_out = mnl_nft_setelem_get_one(ctx, nls);
- if (!nls_out)
+ nls_out = mnl_nft_setelem_get_one(ctx, nls, reset);
+ if (!nls_out) {
+ nftnl_set_free(nls);
return -1;
+ }
ctx->set = set;
set->init = set_expr_alloc(loc, set);
- nftnl_set_elem_foreach(nls_out, list_setelem_cb, ctx);
+ list_setelements(nls_out, ctx);
- if (!(set->flags & NFT_SET_INTERVAL))
+ if (set->flags & NFT_SET_INTERVAL && set->desc.field_count > 1)
+ concat_range_aggregate(set->init);
+ else if (set->flags & NFT_SET_INTERVAL)
+ err = get_set_decompose(cache_set, set);
+ else
list_expr_sort(&ctx->set->init->expressions);
nftnl_set_free(nls);
nftnl_set_free(nls_out);
ctx->set = NULL;
- if (set->flags & NFT_SET_INTERVAL &&
- get_set_decompose(table, set) < 0)
- return -1;
-
- return 0;
+ return err;
}
void netlink_dump_obj(struct nftnl_obj *nln, struct netlink_ctx *ctx)
@@ -958,11 +1638,33 @@ void netlink_dump_obj(struct nftnl_obj *nln, struct netlink_ctx *ctx)
fprintf(fp, "\n");
}
+static int obj_parse_udata_cb(const struct nftnl_udata *attr, void *data)
+{
+ unsigned char *value = nftnl_udata_get(attr);
+ uint8_t type = nftnl_udata_type(attr);
+ const struct nftnl_udata **tb = data;
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_OBJ_COMMENT:
+ if (value[len - 1] != '\0')
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+ tb[type] = attr;
+ return 0;
+}
+
struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
struct nftnl_obj *nlo)
{
+ const struct nftnl_udata *ud[NFTNL_UDATA_OBJ_MAX + 1] = {};
+ const char *udata;
struct obj *obj;
uint32_t type;
+ uint32_t ulen;
obj = obj_alloc(&netlink_location);
obj->handle.family = nftnl_obj_get_u32(nlo, NFTNL_OBJ_FAMILY);
@@ -972,6 +1674,16 @@ struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
xstrdup(nftnl_obj_get_str(nlo, NFTNL_OBJ_NAME));
obj->handle.handle.id =
nftnl_obj_get_u64(nlo, NFTNL_OBJ_HANDLE);
+ if (nftnl_obj_is_set(nlo, NFTNL_OBJ_USERDATA)) {
+ udata = nftnl_obj_get_data(nlo, NFTNL_OBJ_USERDATA, &ulen);
+ if (nftnl_udata_parse(udata, ulen, obj_parse_udata_cb, ud) < 0) {
+ netlink_io_error(ctx, NULL, "Cannot parse userdata");
+ obj_free(obj);
+ return NULL;
+ }
+ if (ud[NFTNL_UDATA_OBJ_COMMENT])
+ obj->comment = xstrdup(nftnl_udata_get(ud[NFTNL_UDATA_OBJ_COMMENT]));
+ }
type = nftnl_obj_get_u32(nlo, NFTNL_OBJ_TYPE);
switch (type) {
@@ -1000,6 +1712,7 @@ struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx,
obj->ct_helper.l4proto = nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_HELPER_L4PROTO);
break;
case NFT_OBJECT_CT_TIMEOUT:
+ init_list_head(&obj->ct_timeout.timeout_list);
obj->ct_timeout.l3proto = nftnl_obj_get_u16(nlo, NFTNL_OBJ_CT_TIMEOUT_L3PROTO);
obj->ct_timeout.l4proto = nftnl_obj_get_u8(nlo, NFTNL_OBJ_CT_TIMEOUT_L4PROTO);
memcpy(obj->ct_timeout.timeout,
@@ -1068,25 +1781,6 @@ static int list_obj_cb(struct nftnl_obj *nls, void *arg)
return 0;
}
-int netlink_list_objs(struct netlink_ctx *ctx, const struct handle *h)
-{
- struct nftnl_obj_list *obj_cache;
- int err;
-
- obj_cache = mnl_nft_obj_dump(ctx, h->family,
- h->table.name, NULL, 0, true, false);
- if (obj_cache == NULL) {
- if (errno == EINTR)
- return -1;
-
- return 0;
- }
-
- err = nftnl_obj_list_foreach(obj_cache, list_obj_cb, ctx);
- nftnl_obj_list_free(obj_cache);
- return err;
-}
-
int netlink_reset_objs(struct netlink_ctx *ctx, const struct cmd *cmd,
uint32_t type, bool dump)
{
@@ -1104,7 +1798,56 @@ int netlink_reset_objs(struct netlink_ctx *ctx, const struct cmd *cmd,
return err;
}
-static struct flowtable *
+int netlink_reset_rules(struct netlink_ctx *ctx, const struct cmd *cmd,
+ bool dump)
+{
+ const struct handle *h = &cmd->handle;
+ struct nft_cache_filter f = {
+ .list.table = h->table.name,
+ .list.chain = h->chain.name,
+ .list.rule_handle = h->handle.id,
+ };
+ struct rule *rule, *next, *crule, *cnext;
+ struct table *table;
+ struct chain *chain;
+ int ret;
+
+ ret = rule_cache_dump(ctx, h, &f, dump, true);
+
+ list_for_each_entry_safe(rule, next, &ctx->list, list) {
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ rule->handle.table.name,
+ rule->handle.family);
+ if (!table)
+ continue;
+
+ chain = chain_cache_find(table, rule->handle.chain.name);
+ if (!chain)
+ continue;
+
+ list_del(&rule->list);
+ list_for_each_entry_safe(crule, cnext, &chain->rules, list) {
+ if (crule->handle.handle.id != rule->handle.handle.id)
+ continue;
+
+ list_replace(&crule->list, &rule->list);
+ rule_free(crule);
+ rule = NULL;
+ break;
+ }
+ if (rule) {
+ list_add_tail(&rule->list, &chain->rules);
+ }
+ }
+ list_for_each_entry_safe(rule, next, &ctx->list, list) {
+ list_del(&rule->list);
+ rule_free(rule);
+ }
+
+ return ret;
+}
+
+struct flowtable *
netlink_delinearize_flowtable(struct netlink_ctx *ctx,
struct nftnl_flowtable *nlo)
{
@@ -1117,18 +1860,28 @@ netlink_delinearize_flowtable(struct netlink_ctx *ctx,
nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FAMILY);
flowtable->handle.table.name =
xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_TABLE));
- flowtable->handle.flowtable =
+ flowtable->handle.flowtable.name =
xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_NAME));
+ flowtable->handle.handle.id =
+ nftnl_flowtable_get_u64(nlo, NFTNL_FLOWTABLE_HANDLE);
+ if (nftnl_flowtable_is_set(nlo, NFTNL_FLOWTABLE_FLAGS))
+ flowtable->flags = nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FLAGS);
dev_array = nftnl_flowtable_get(nlo, NFTNL_FLOWTABLE_DEVICES);
while (dev_array[len])
len++;
- flowtable->dev_array = calloc(1, len * sizeof(char *));
+ if (len)
+ flowtable->dev_array = xmalloc(len * sizeof(char *));
for (i = 0; i < len; i++)
flowtable->dev_array[i] = xstrdup(dev_array[i]);
flowtable->dev_array_len = len;
+ if (flowtable->dev_array_len) {
+ qsort(flowtable->dev_array, flowtable->dev_array_len,
+ sizeof(char *), qsort_device_cmp);
+ }
+
priority = nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_PRIO);
flowtable->priority.expr =
constant_expr_alloc(&netlink_location,
@@ -1137,8 +1890,10 @@ netlink_delinearize_flowtable(struct netlink_ctx *ctx,
sizeof(int) *
BITS_PER_BYTE,
&priority);
- flowtable->hooknum =
+ flowtable->hook.num =
nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_HOOKNUM);
+ flowtable->flags =
+ nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FLAGS);
return flowtable;
}
@@ -1160,7 +1915,8 @@ int netlink_list_flowtables(struct netlink_ctx *ctx, const struct handle *h)
struct nftnl_flowtable_list *flowtable_cache;
int err;
- flowtable_cache = mnl_nft_flowtable_dump(ctx, h->family, h->table.name);
+ flowtable_cache = mnl_nft_flowtable_dump(ctx, h->family,
+ h->table.name, NULL);
if (flowtable_cache == NULL) {
if (errno == EINTR)
return -1;
@@ -1244,38 +2000,50 @@ static void trace_print_policy(const struct nftnl_trace *nlt,
expr_free(expr);
}
-static void trace_print_rule(const struct nftnl_trace *nlt,
- struct output_ctx *octx, struct nft_cache *cache)
+static struct rule *trace_lookup_rule(const struct nftnl_trace *nlt,
+ uint64_t rule_handle,
+ struct nft_cache *cache)
{
- const struct table *table;
- uint64_t rule_handle;
struct chain *chain;
- struct rule *rule;
+ struct table *table;
struct handle h;
h.family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
- h.table.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE);
- h.chain.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN);
+ h.table.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE);
+ h.chain.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN);
if (!h.table.name)
- return;
+ return NULL;
- table = table_lookup(&h, cache);
+ table = table_cache_find(&cache->table_cache, h.table.name, h.family);
if (!table)
- return;
+ return NULL;
- chain = chain_lookup(table, &h);
+ chain = chain_cache_find(table, h.chain.name);
if (!chain)
- return;
+ return NULL;
+
+ return rule_lookup(chain, rule_handle);
+}
+
+static void trace_print_rule(const struct nftnl_trace *nlt,
+ struct output_ctx *octx, struct nft_cache *cache)
+{
+ uint64_t rule_handle;
+ struct rule *rule;
rule_handle = nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE);
- rule = rule_lookup(chain, rule_handle);
- if (!rule)
- return;
+ rule = trace_lookup_rule(nlt, rule_handle, cache);
trace_print_hdr(nlt, octx);
- nft_print(octx, "rule ");
- rule_print(rule, octx);
+
+ if (rule) {
+ nft_print(octx, "rule ");
+ rule_print(rule, octx);
+ } else {
+ nft_print(octx, "unknown rule handle %" PRIu64, rule_handle);
+ }
+
nft_print(octx, " (");
trace_print_verdict(nlt, octx);
nft_print(octx, ")\n");
@@ -1294,7 +2062,6 @@ static void trace_gen_stmts(struct list_head *stmts,
const void *hdr;
uint32_t hlen;
unsigned int n;
- bool stacked;
if (!nftnl_trace_is_set(nlt, attr))
return;
@@ -1349,6 +2116,8 @@ restart:
n = 0;
next:
list_for_each_entry(stmt, &unordered, list) {
+ enum proto_bases b = base;
+
rel = stmt->expr;
lhs = rel->left;
@@ -1361,16 +2130,14 @@ next:
list_move_tail(&stmt->list, stmts);
n++;
- stacked = payload_is_stacked(desc, rel);
+ if (payload_is_stacked(desc, rel))
+ b--;
- if (lhs->flags & EXPR_F_PROTOCOL &&
- pctx->pbase == PROTO_BASE_INVALID) {
- payload_dependency_store(pctx, stmt, base - stacked);
- } else {
+ /* Don't strip 'icmp type' from payload dump. */
+ if (pctx->icmp_type == 0)
payload_dependency_kill(pctx, lhs, ctx->family);
- if (lhs->flags & EXPR_F_PROTOCOL)
- payload_dependency_store(pctx, stmt, base - stacked);
- }
+ if (lhs->flags & EXPR_F_PROTOCOL)
+ payload_dependency_store(pctx, stmt, b);
goto next;
}
@@ -1399,7 +2166,7 @@ static void trace_print_packet(const struct nftnl_trace *nlt,
meta_expr_alloc(&netlink_location,
NFT_META_OIF), octx);
- proto_ctx_init(&ctx, nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY), 0);
+ proto_ctx_init(&ctx, nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY), 0, false);
ll_desc = ctx.protocol[PROTO_BASE_LL_HDR].desc;
if ((ll_desc == &proto_inet || ll_desc == &proto_netdev) &&
nftnl_trace_is_set(nlt, NFTNL_TRACE_NFPROTO)) {
@@ -1445,12 +2212,12 @@ int netlink_events_trace_cb(const struct nlmsghdr *nlh, int type,
if (nftnl_trace_nlmsg_parse(nlh, nlt) < 0)
netlink_abi_error();
+ if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) ||
+ nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER))
+ trace_print_packet(nlt, &monh->ctx->nft->output);
+
switch (nftnl_trace_get_u32(nlt, NFTNL_TRACE_TYPE)) {
case NFT_TRACETYPE_RULE:
- if (nftnl_trace_is_set(nlt, NFTNL_TRACE_LL_HEADER) ||
- nftnl_trace_is_set(nlt, NFTNL_TRACE_NETWORK_HEADER))
- trace_print_packet(nlt, &monh->ctx->nft->output);
-
if (nftnl_trace_is_set(nlt, NFTNL_TRACE_RULE_HANDLE))
trace_print_rule(nlt, &monh->ctx->nft->output,
&monh->ctx->nft->cache);
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index f7d328a8..da9f7a91 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -9,12 +9,12 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
+#include <nft.h>
+
#include <limits.h>
#include <linux/netfilter/nf_tables.h>
#include <arpa/inet.h>
+#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter.h>
#include <net/ethernet.h>
#include <netlink.h>
@@ -26,8 +26,19 @@
#include <erec.h>
#include <sys/socket.h>
#include <libnftnl/udata.h>
+#include <cache.h>
#include <xt.h>
+struct dl_proto_ctx *dl_proto_ctx(struct rule_pp_ctx *ctx)
+{
+ return ctx->dl;
+}
+
+static struct dl_proto_ctx *dl_proto_ctx_outer(struct rule_pp_ctx *ctx)
+{
+ return &ctx->_dl[0];
+}
+
static int netlink_parse_expr(const struct nftnl_expr *nle,
struct netlink_parse_ctx *ctx);
@@ -70,8 +81,7 @@ static void netlink_set_register(struct netlink_parse_ctx *ctx,
return;
}
- if (ctx->registers[reg] != NULL)
- expr_free(ctx->registers[reg]);
+ expr_free(ctx->registers[reg]);
ctx->registers[reg] = expr;
}
@@ -98,7 +108,7 @@ static void netlink_release_registers(struct netlink_parse_ctx *ctx)
{
int i;
- for (i = 0; i < MAX_REGS; i++)
+ for (i = 0; i <= MAX_REGS; i++)
expr_free(ctx->registers[i]);
}
@@ -132,6 +142,50 @@ err:
return NULL;
}
+static struct expr *netlink_parse_concat_key(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ unsigned int reg,
+ const struct expr *key)
+{
+ uint32_t type = key->dtype->type;
+ unsigned int n, len = key->len;
+ struct expr *concat, *expr;
+ unsigned int consumed;
+
+ concat = concat_expr_alloc(loc);
+ n = div_round_up(fls(type), TYPE_BITS);
+
+ while (len > 0) {
+ const struct datatype *i;
+
+ expr = netlink_get_register(ctx, loc, reg);
+ if (expr == NULL) {
+ netlink_error(ctx, loc,
+ "Concat expression size mismatch");
+ goto err;
+ }
+
+ if (n > 0 && concat_subtype_id(type, --n)) {
+ i = concat_subtype_lookup(type, n);
+
+ expr_set_type(expr, i, i->byteorder);
+ }
+
+ compound_expr_add(concat, expr);
+
+ consumed = netlink_padded_len(expr->len);
+ assert(consumed > 0);
+ len -= consumed;
+ reg += netlink_register_space(expr->len);
+ }
+
+ return concat;
+
+err:
+ expr_free(concat);
+ return NULL;
+}
+
static struct expr *netlink_parse_concat_data(struct netlink_parse_ctx *ctx,
const struct location *loc,
unsigned int reg,
@@ -154,6 +208,7 @@ static struct expr *netlink_parse_concat_data(struct netlink_parse_ctx *ctx,
len -= netlink_padded_len(expr->len);
reg += netlink_register_space(expr->len);
+ expr_free(expr);
}
return concat;
@@ -162,6 +217,31 @@ err:
return NULL;
}
+static void netlink_parse_chain_verdict(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ struct expr *expr,
+ enum nft_verdicts verdict)
+{
+ char chain_name[NFT_CHAIN_MAXNAMELEN] = {};
+ struct chain *chain;
+
+ expr_chain_export(expr->chain, chain_name);
+ chain = chain_binding_lookup(ctx->table, chain_name);
+
+ /* Special case: 'nft list chain x y' needs to pull in implicit chains */
+ if (!chain && !strncmp(chain_name, "__chain", strlen("__chain"))) {
+ nft_chain_cache_update(ctx->nlctx, ctx->table, chain_name);
+ chain = chain_binding_lookup(ctx->table, chain_name);
+ }
+
+ if (chain) {
+ ctx->stmt = chain_stmt_alloc(loc, chain, verdict);
+ expr_free(expr);
+ } else {
+ ctx->stmt = verdict_stmt_alloc(loc, expr);
+ }
+}
+
static void netlink_parse_immediate(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
@@ -171,7 +251,7 @@ static void netlink_parse_immediate(struct netlink_parse_ctx *ctx,
struct expr *expr;
if (nftnl_expr_is_set(nle, NFTNL_EXPR_IMM_VERDICT)) {
- nld.verdict = nftnl_expr_get_u32(nle, NFTNL_EXPR_IMM_VERDICT);
+ nld.verdict = nftnl_expr_get_u32(nle, NFTNL_EXPR_IMM_VERDICT);
if (nftnl_expr_is_set(nle, NFTNL_EXPR_IMM_CHAIN)) {
nld.chain = nftnl_expr_get(nle, NFTNL_EXPR_IMM_CHAIN,
&nld.len);
@@ -181,12 +261,23 @@ static void netlink_parse_immediate(struct netlink_parse_ctx *ctx,
}
dreg = netlink_parse_register(nle, NFTNL_EXPR_IMM_DREG);
-
expr = netlink_alloc_data(loc, &nld, dreg);
- if (dreg == NFT_REG_VERDICT)
- ctx->stmt = verdict_stmt_alloc(loc, expr);
- else
+
+ if (dreg == NFT_REG_VERDICT) {
+ switch (expr->verdict) {
+ case NFT_JUMP:
+ netlink_parse_chain_verdict(ctx, loc, expr, NFT_JUMP);
+ break;
+ case NFT_GOTO:
+ netlink_parse_chain_verdict(ctx, loc, expr, NFT_GOTO);
+ break;
+ default:
+ ctx->stmt = verdict_stmt_alloc(loc, expr);
+ break;
+ }
+ } else {
netlink_set_register(ctx, dreg, expr);
+ }
}
static void netlink_parse_xfrm(struct netlink_parse_ctx *ctx,
@@ -274,7 +365,7 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
{
struct nft_data_delinearize nld;
enum nft_registers sreg;
- struct expr *expr, *left, *right;
+ struct expr *expr, *left, *right, *tmp;
enum ops op;
sreg = netlink_parse_register(nle, NFTNL_EXPR_CMP_SREG);
@@ -291,19 +382,27 @@ static void netlink_parse_cmp(struct netlink_parse_ctx *ctx,
if (left->len > right->len &&
expr_basetype(left) != &string_type) {
- return netlink_error(ctx, loc, "Relational expression size mismatch");
+ mpz_lshift_ui(right->value, left->len - right->len);
+ right = prefix_expr_alloc(loc, right, right->len);
+ right->prefix->len = left->len;
} else if (left->len > 0 && left->len < right->len) {
expr_free(left);
left = netlink_parse_concat_expr(ctx, loc, sreg, right->len);
if (left == NULL)
- return;
- right = netlink_parse_concat_data(ctx, loc, sreg, right->len, right);
- if (right == NULL)
- return;
+ goto err_free;
+ tmp = netlink_parse_concat_data(ctx, loc, sreg, right->len, right);
+ if (tmp == NULL)
+ goto err_free;
+ expr_free(right);
+ right = tmp;
}
expr = relational_expr_alloc(loc, op, left, right);
ctx->stmt = expr_stmt_alloc(loc, expr);
+ return;
+err_free:
+ expr_free(left);
+ expr_free(right);
}
static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
@@ -317,7 +416,7 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
uint32_t flag;
name = nftnl_expr_get_str(nle, NFTNL_EXPR_LOOKUP_SET);
- set = set_lookup(ctx->table, name);
+ set = set_cache_find(ctx->table, name);
if (set == NULL)
return netlink_error(ctx, loc,
"Unknown set '%s' in lookup expression",
@@ -356,22 +455,17 @@ static void netlink_parse_lookup(struct netlink_parse_ctx *ctx,
ctx->stmt = expr_stmt_alloc(loc, expr);
}
-static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx,
- const struct location *loc,
- const struct nftnl_expr *nle)
+static struct expr *netlink_parse_bitwise_bool(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle,
+ enum nft_registers sreg,
+ struct expr *left)
+
{
struct nft_data_delinearize nld;
- enum nft_registers sreg, dreg;
- struct expr *expr, *left, *mask, *xor, *or;
+ struct expr *expr, *mask, *xor, *or;
mpz_t m, x, o;
- sreg = netlink_parse_register(nle, NFTNL_EXPR_BITWISE_SREG);
- left = netlink_get_register(ctx, loc, sreg);
- if (left == NULL)
- return netlink_error(ctx, loc,
- "Bitwise expression has no left "
- "hand side");
-
expr = left;
nld.value = nftnl_expr_get(nle, NFTNL_EXPR_BITWISE_MASK, &nld.len);
@@ -393,7 +487,7 @@ static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx,
mpz_ior(m, m, o);
}
- if (left->len > 0 && mpz_scan0(m, 0) == left->len) {
+ if (left->len > 0 && mpz_scan0(m, 0) >= left->len) {
/* mask encompasses the entire value */
expr_free(mask);
} else {
@@ -423,6 +517,63 @@ static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx,
mpz_clear(x);
mpz_clear(o);
+ return expr;
+}
+
+static struct expr *netlink_parse_bitwise_shift(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle,
+ enum ops op,
+ enum nft_registers sreg,
+ struct expr *left)
+{
+ struct nft_data_delinearize nld;
+ struct expr *expr, *right;
+
+ nld.value = nftnl_expr_get(nle, NFTNL_EXPR_BITWISE_DATA, &nld.len);
+ right = netlink_alloc_value(loc, &nld);
+ right->byteorder = BYTEORDER_HOST_ENDIAN;
+
+ expr = binop_expr_alloc(loc, op, left, right);
+ expr->len = nftnl_expr_get_u32(nle, NFTNL_EXPR_BITWISE_LEN) * BITS_PER_BYTE;
+
+ return expr;
+}
+
+static void netlink_parse_bitwise(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ enum nft_registers sreg, dreg;
+ struct expr *expr, *left;
+ enum nft_bitwise_ops op;
+
+ sreg = netlink_parse_register(nle, NFTNL_EXPR_BITWISE_SREG);
+ left = netlink_get_register(ctx, loc, sreg);
+ if (left == NULL)
+ return netlink_error(ctx, loc,
+ "Bitwise expression has no left "
+ "hand side");
+
+ op = nftnl_expr_get_u32(nle, NFTNL_EXPR_BITWISE_OP);
+
+ switch (op) {
+ case NFT_BITWISE_BOOL:
+ expr = netlink_parse_bitwise_bool(ctx, loc, nle, sreg,
+ left);
+ break;
+ case NFT_BITWISE_LSHIFT:
+ expr = netlink_parse_bitwise_shift(ctx, loc, nle, OP_LSHIFT,
+ sreg, left);
+ break;
+ case NFT_BITWISE_RSHIFT:
+ expr = netlink_parse_bitwise_shift(ctx, loc, nle, OP_RSHIFT,
+ sreg, left);
+ break;
+ default:
+ BUG("invalid bitwise operation %u\n", op);
+ }
+
dreg = netlink_parse_register(nle, NFTNL_EXPR_BITWISE_DREG);
netlink_set_register(ctx, dreg, expr);
}
@@ -470,6 +621,10 @@ static void netlink_parse_payload_expr(struct netlink_parse_ctx *ctx,
struct expr *expr;
base = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_BASE) + 1;
+
+ if (base == NFT_PAYLOAD_TUN_HEADER + 1)
+ base = NFT_PAYLOAD_INNER_HEADER + 1;
+
offset = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_OFFSET) * BITS_PER_BYTE;
len = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_LEN) * BITS_PER_BYTE;
@@ -477,9 +632,80 @@ static void netlink_parse_payload_expr(struct netlink_parse_ctx *ctx,
payload_init_raw(expr, base, offset, len);
dreg = netlink_parse_register(nle, NFTNL_EXPR_PAYLOAD_DREG);
+
+ if (ctx->inner)
+ ctx->inner_reg = dreg;
+
netlink_set_register(ctx, dreg, expr);
}
+static void netlink_parse_inner(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ const struct proto_desc *inner_desc;
+ const struct nftnl_expr *inner_nle;
+ uint32_t hdrsize, flags, type;
+ struct expr *expr;
+
+ hdrsize = nftnl_expr_get_u32(nle, NFTNL_EXPR_INNER_HDRSIZE);
+ type = nftnl_expr_get_u32(nle, NFTNL_EXPR_INNER_TYPE);
+ flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_INNER_FLAGS);
+
+ inner_nle = nftnl_expr_get(nle, NFTNL_EXPR_INNER_EXPR, NULL);
+ if (!inner_nle) {
+ netlink_error(ctx, loc, "Could not parse inner expression");
+ return;
+ }
+
+ inner_desc = proto_find_inner(type, hdrsize, flags);
+
+ ctx->inner = true;
+ if (netlink_parse_expr(inner_nle, ctx) < 0) {
+ ctx->inner = false;
+ return;
+ }
+ ctx->inner = false;
+
+ expr = netlink_get_register(ctx, loc, ctx->inner_reg);
+ assert(expr);
+
+ if (expr->etype == EXPR_PAYLOAD &&
+ expr->payload.base == PROTO_BASE_INNER_HDR) {
+ const struct proto_hdr_template *tmpl;
+ unsigned int i;
+
+ for (i = 1; i < array_size(inner_desc->templates); i++) {
+ tmpl = &inner_desc->templates[i];
+
+ if (tmpl->len == 0)
+ return;
+
+ if (tmpl->offset != expr->payload.offset ||
+ tmpl->len != expr->len)
+ continue;
+
+ expr->payload.desc = inner_desc;
+ expr->payload.tmpl = tmpl;
+ break;
+ }
+ }
+
+ switch (expr->etype) {
+ case EXPR_PAYLOAD:
+ expr->payload.inner_desc = inner_desc;
+ break;
+ case EXPR_META:
+ expr->meta.inner_desc = inner_desc;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ netlink_set_register(ctx, ctx->inner_reg, expr);
+}
+
static void netlink_parse_payload_stmt(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
@@ -503,8 +729,7 @@ static void netlink_parse_payload_stmt(struct netlink_parse_ctx *ctx,
payload_init_raw(expr, base, offset, len);
stmt = payload_stmt_alloc(loc, expr, val);
-
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ rule_stmt_append(ctx->rule, stmt);
}
static void netlink_parse_payload(struct netlink_parse_ctx *ctx,
@@ -547,7 +772,7 @@ static void netlink_parse_exthdr(struct netlink_parse_ctx *ctx,
sreg = netlink_parse_register(nle, NFTNL_EXPR_EXTHDR_SREG);
val = netlink_get_register(ctx, loc, sreg);
if (val == NULL) {
- xfree(expr);
+ expr_free(expr);
return netlink_error(ctx, loc,
"exthdr statement has no expression");
}
@@ -555,7 +780,11 @@ static void netlink_parse_exthdr(struct netlink_parse_ctx *ctx,
expr_set_type(val, expr->dtype, expr->byteorder);
stmt = exthdr_stmt_alloc(loc, expr, val);
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ rule_stmt_append(ctx->rule, stmt);
+ } else {
+ struct stmt *stmt = optstrip_stmt_alloc(loc, expr);
+
+ rule_stmt_append(ctx->rule, stmt);
}
}
@@ -589,7 +818,7 @@ static void netlink_parse_hash(struct netlink_parse_ctx *ctx,
len = nftnl_expr_get_u32(nle,
NFTNL_EXPR_HASH_LEN) * BITS_PER_BYTE;
if (hexpr->len < len) {
- xfree(hexpr);
+ expr_free(hexpr);
hexpr = netlink_parse_concat_expr(ctx, loc, sreg, len);
if (hexpr == NULL)
goto out_err;
@@ -601,7 +830,7 @@ static void netlink_parse_hash(struct netlink_parse_ctx *ctx,
netlink_set_register(ctx, dreg, expr);
return;
out_err:
- xfree(expr);
+ expr_free(expr);
}
static void netlink_parse_fib(struct netlink_parse_ctx *ctx,
@@ -633,6 +862,9 @@ static void netlink_parse_meta_expr(struct netlink_parse_ctx *ctx,
expr = meta_expr_alloc(loc, key);
dreg = netlink_parse_register(nle, NFTNL_EXPR_META_DREG);
+ if (ctx->inner)
+ ctx->inner_reg = dreg;
+
netlink_set_register(ctx, dreg, expr);
}
@@ -641,11 +873,12 @@ static void netlink_parse_socket(struct netlink_parse_ctx *ctx,
const struct nftnl_expr *nle)
{
enum nft_registers dreg;
- uint32_t key;
+ uint32_t key, level;
struct expr * expr;
key = nftnl_expr_get_u32(nle, NFTNL_EXPR_SOCKET_KEY);
- expr = socket_expr_alloc(loc, key);
+ level = nftnl_expr_get_u32(nle, NFTNL_EXPR_SOCKET_LEVEL);
+ expr = socket_expr_alloc(loc, key, level);
dreg = netlink_parse_register(nle, NFTNL_EXPR_SOCKET_DREG);
netlink_set_register(ctx, dreg, expr);
@@ -685,7 +918,9 @@ static void netlink_parse_meta_stmt(struct netlink_parse_ctx *ctx,
key = nftnl_expr_get_u32(nle, NFTNL_EXPR_META_KEY);
stmt = meta_stmt_alloc(loc, key, expr);
- expr_set_type(expr, stmt->meta.tmpl->dtype, stmt->meta.tmpl->byteorder);
+
+ if (stmt->meta.tmpl)
+ expr_set_type(expr, stmt->meta.tmpl->dtype, stmt->meta.tmpl->byteorder);
ctx->stmt = stmt;
}
@@ -719,8 +954,8 @@ static void netlink_parse_numgen(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
{
- enum nft_registers dreg;
uint32_t type, until, offset;
+ enum nft_registers dreg;
struct expr *expr;
type = nftnl_expr_get_u32(nle, NFTNL_EXPR_NG_TYPE);
@@ -832,6 +1067,19 @@ static void netlink_parse_counter(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
}
+static void netlink_parse_last(struct netlink_parse_ctx *ctx,
+ const struct location *loc,
+ const struct nftnl_expr *nle)
+{
+ struct stmt *stmt;
+
+ stmt = last_stmt_alloc(loc);
+ stmt->last.used = nftnl_expr_get_u64(nle, NFTNL_EXPR_LAST_MSECS);
+ stmt->last.set = nftnl_expr_get_u32(nle, NFTNL_EXPR_LAST_SET);
+
+ ctx->stmt = stmt;
+}
+
static void netlink_parse_log(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
@@ -842,7 +1090,11 @@ static void netlink_parse_log(struct netlink_parse_ctx *ctx,
stmt = log_stmt_alloc(loc);
prefix = nftnl_expr_get_str(nle, NFTNL_EXPR_LOG_PREFIX);
if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOG_PREFIX)) {
- stmt->log.prefix = xstrdup(prefix);
+ stmt->log.prefix = constant_expr_alloc(&internal_location,
+ &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ (strlen(prefix) + 1) * BITS_PER_BYTE,
+ prefix);
stmt->log.flags |= STMT_LOG_PREFIX;
}
if (nftnl_expr_is_set(nle, NFTNL_EXPR_LOG_GROUP)) {
@@ -920,6 +1172,85 @@ static void netlink_parse_reject(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
}
+static bool is_nat_addr_map(const struct expr *addr, uint8_t family,
+ struct stmt *stmt)
+{
+ const struct expr *mappings, *data;
+ const struct set *set;
+
+ if (!addr ||
+ expr_ops(addr)->type != EXPR_MAP)
+ return false;
+
+ mappings = addr->right;
+ if (expr_ops(mappings)->type != EXPR_SET_REF)
+ return false;
+
+ set = mappings->set;
+ data = set->data;
+
+ if (!(data->flags & EXPR_F_INTERVAL))
+ return false;
+
+ stmt->nat.family = family;
+
+ /* if we're dealing with an address:address map,
+ * the length will be bit_sizeof(addr) + 32 (one register).
+ */
+ switch (family) {
+ case NFPROTO_IPV4:
+ if (data->len == 32 + 32) {
+ stmt->nat.type_flags |= STMT_NAT_F_INTERVAL;
+ return true;
+ } else if (data->len == 32 + 32 + 32 + 32) {
+ stmt->nat.type_flags |= STMT_NAT_F_INTERVAL |
+ STMT_NAT_F_CONCAT;
+ return true;
+ }
+ break;
+ case NFPROTO_IPV6:
+ if (data->len == 128 + 128) {
+ stmt->nat.type_flags |= STMT_NAT_F_INTERVAL;
+ return true;
+ } else if (data->len == 128 + 32 + 128 + 32) {
+ stmt->nat.type_flags |= STMT_NAT_F_INTERVAL |
+ STMT_NAT_F_CONCAT;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool is_nat_proto_map(const struct expr *addr, uint8_t family)
+{
+ const struct expr *mappings, *data;
+ const struct set *set;
+
+ if (!addr ||
+ expr_ops(addr)->type != EXPR_MAP)
+ return false;
+
+ mappings = addr->right;
+ if (expr_ops(mappings)->type != EXPR_SET_REF)
+ return false;
+
+ set = mappings->set;
+ data = set->data;
+
+ /* if we're dealing with an address:inet_service map,
+ * the length will be bit_sizeof(addr) + 32 (one register).
+ */
+ switch (family) {
+ case NFPROTO_IPV4:
+ return data->len == 32 + 32;
+ case NFPROTO_IPV6:
+ return data->len == 128 + 32;
+ }
+
+ return false;
+}
+
static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
@@ -940,6 +1271,10 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
if (nftnl_expr_is_set(nle, NFTNL_EXPR_NAT_FLAGS))
stmt->nat.flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_NAT_FLAGS);
+ if (stmt->nat.flags & NF_NAT_RANGE_NETMAP)
+ stmt->nat.type_flags |= STMT_NAT_F_PREFIX;
+
+ addr = NULL;
reg1 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MIN);
if (reg1) {
addr = netlink_get_register(ctx, loc, reg1);
@@ -957,6 +1292,12 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
stmt->nat.addr = addr;
}
+ if (is_nat_addr_map(addr, family, stmt)) {
+ stmt->nat.family = family;
+ ctx->stmt = stmt;
+ return;
+ }
+
reg2 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX);
if (reg2 && reg2 != reg1) {
addr = netlink_get_register(ctx, loc, reg2);
@@ -971,11 +1312,20 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
else
expr_set_type(addr, &ip6addr_type,
BYTEORDER_BIG_ENDIAN);
- if (stmt->nat.addr != NULL)
+ if (stmt->nat.addr != NULL) {
addr = range_expr_alloc(loc, stmt->nat.addr, addr);
+ addr = range_expr_to_prefix(addr);
+ }
stmt->nat.addr = addr;
}
+ if (is_nat_proto_map(addr, family)) {
+ stmt->nat.family = family;
+ stmt->nat.type_flags |= STMT_NAT_F_CONCAT;
+ ctx->stmt = stmt;
+ return;
+ }
+
reg1 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_PROTO_MIN);
if (reg1) {
proto = netlink_get_register(ctx, loc, reg1);
@@ -1007,7 +1357,7 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
return;
out_err:
- xfree(stmt);
+ stmt_free(stmt);
}
static void netlink_parse_synproxy(struct netlink_parse_ctx *ctx,
@@ -1041,6 +1391,8 @@ static void netlink_parse_tproxy(struct netlink_parse_ctx *ctx,
reg = netlink_parse_register(nle, NFTNL_EXPR_TPROXY_REG_ADDR);
if (reg) {
addr = netlink_get_register(ctx, loc, reg);
+ if (addr == NULL)
+ goto err;
switch (stmt->tproxy.family) {
case NFPROTO_IPV4:
@@ -1060,6 +1412,8 @@ static void netlink_parse_tproxy(struct netlink_parse_ctx *ctx,
reg = netlink_parse_register(nle, NFTNL_EXPR_TPROXY_REG_PORT);
if (reg) {
port = netlink_get_register(ctx, loc, reg);
+ if (port == NULL)
+ goto err;
expr_set_type(port, &inet_service_type, BYTEORDER_BIG_ENDIAN);
stmt->tproxy.port = port;
}
@@ -1067,7 +1421,7 @@ static void netlink_parse_tproxy(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
return;
err:
- xfree(stmt);
+ stmt_free(stmt);
}
static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
@@ -1114,7 +1468,7 @@ static void netlink_parse_masq(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
return;
out_err:
- xfree(stmt);
+ stmt_free(stmt);
}
static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
@@ -1165,7 +1519,7 @@ static void netlink_parse_redir(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
return;
out_err:
- xfree(stmt);
+ stmt_free(stmt);
}
static void netlink_parse_dup(struct netlink_parse_ctx *ctx,
@@ -1218,7 +1572,7 @@ static void netlink_parse_dup(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
return;
out_err:
- xfree(stmt);
+ stmt_free(stmt);
}
static void netlink_parse_fwd(struct netlink_parse_ctx *ctx,
@@ -1280,49 +1634,88 @@ static void netlink_parse_fwd(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
return;
out_err:
- xfree(stmt);
+ stmt_free(stmt);
}
static void netlink_parse_queue(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
{
- struct expr *expr, *high;
- struct stmt *stmt;
- uint16_t num, total;
+ struct expr *expr;
+ uint16_t flags;
- num = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_NUM);
- total = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_TOTAL);
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_QUEUE_SREG_QNUM)) {
+ enum nft_registers reg = netlink_parse_register(nle, NFTNL_EXPR_QUEUE_SREG_QNUM);
+
+ expr = netlink_get_register(ctx, loc, reg);
+ if (!expr) {
+ netlink_error(ctx, loc, "queue statement has no sreg expression");
+ return;
+ }
+ } else {
+ uint16_t total = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_TOTAL);
+ uint16_t num = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_NUM);
- expr = constant_expr_alloc(loc, &integer_type,
- BYTEORDER_HOST_ENDIAN, 16, &num);
- if (total > 1) {
- total += num - 1;
- high = constant_expr_alloc(loc, &integer_type,
+ expr = constant_expr_alloc(loc, &integer_type,
+ BYTEORDER_HOST_ENDIAN, 16, &num);
+
+ if (total > 1) {
+ struct expr *high;
+
+ total += num - 1;
+ high = constant_expr_alloc(loc, &integer_type,
BYTEORDER_HOST_ENDIAN, 16, &total);
- expr = range_expr_alloc(loc, expr, high);
+ expr = range_expr_alloc(loc, expr, high);
+ }
}
- stmt = queue_stmt_alloc(loc);
- stmt->queue.queue = expr;
- stmt->queue.flags = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_FLAGS);
+ flags = nftnl_expr_get_u16(nle, NFTNL_EXPR_QUEUE_FLAGS);
+ ctx->stmt = queue_stmt_alloc(loc, expr, flags);
+}
- ctx->stmt = stmt;
+struct dynset_parse_ctx {
+ struct netlink_parse_ctx *nlctx;
+ const struct location *loc;
+ struct list_head stmt_list;
+};
+
+static int dynset_parse_expressions(struct nftnl_expr *e, void *data)
+{
+ struct dynset_parse_ctx *dynset_parse_ctx = data;
+ struct netlink_parse_ctx *ctx = dynset_parse_ctx->nlctx;
+ const struct location *loc = dynset_parse_ctx->loc;
+ struct stmt *stmt;
+
+ if (netlink_parse_expr(e, ctx) < 0 || !ctx->stmt) {
+ netlink_error(ctx, loc, "Could not parse dynset stmt");
+ return -1;
+ }
+ stmt = ctx->stmt;
+
+ list_add_tail(&stmt->list, &dynset_parse_ctx->stmt_list);
+
+ return 0;
}
static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
{
+ struct dynset_parse_ctx dynset_parse_ctx = {
+ .nlctx = ctx,
+ .loc = loc,
+ };
struct expr *expr, *expr_data = NULL;
enum nft_registers sreg, sreg_data;
+ struct stmt *stmt, *dstmt, *next;
const struct nftnl_expr *dnle;
- struct stmt *stmt, *dstmt;
struct set *set;
const char *name;
+ init_list_head(&dynset_parse_ctx.stmt_list);
+
name = nftnl_expr_get_str(nle, NFTNL_EXPR_DYNSET_SET_NAME);
- set = set_lookup(ctx->table, name);
+ set = set_cache_find(ctx->table, name);
if (set == NULL)
return netlink_error(ctx, loc,
"Unknown set '%s' in dynset statement",
@@ -1336,58 +1729,85 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
if (expr->len < set->key->len) {
expr_free(expr);
- expr = netlink_parse_concat_expr(ctx, loc, sreg, set->key->len);
+ expr = netlink_parse_concat_key(ctx, loc, sreg, set->key);
if (expr == NULL)
return;
+ } else if (expr->dtype == &invalid_type) {
+ expr_set_type(expr, datatype_get(set->key->dtype), set->key->byteorder);
}
expr = set_elem_expr_alloc(&expr->location, expr);
expr->timeout = nftnl_expr_get_u64(nle, NFTNL_EXPR_DYNSET_TIMEOUT);
- dstmt = NULL;
- dnle = nftnl_expr_get(nle, NFTNL_EXPR_DYNSET_EXPR, NULL);
- if (dnle != NULL) {
- if (netlink_parse_expr(dnle, ctx) < 0)
- goto out_err;
- if (ctx->stmt == NULL) {
- netlink_error(ctx, loc, "Could not parse dynset stmt");
- goto out_err;
+ if (nftnl_expr_is_set(nle, NFTNL_EXPR_DYNSET_EXPR)) {
+ dstmt = NULL;
+ dnle = nftnl_expr_get(nle, NFTNL_EXPR_DYNSET_EXPR, NULL);
+ if (dnle != NULL) {
+ if (netlink_parse_expr(dnle, ctx) < 0)
+ goto out_err;
+ if (ctx->stmt == NULL) {
+ netlink_error(ctx, loc,
+ "Could not parse dynset stmt");
+ goto out_err;
+ }
+ dstmt = ctx->stmt;
+ list_add_tail(&dstmt->list,
+ &dynset_parse_ctx.stmt_list);
}
- dstmt = ctx->stmt;
+ } else if (nftnl_expr_is_set(nle, NFTNL_EXPR_DYNSET_EXPRESSIONS)) {
+ if (nftnl_expr_expr_foreach(nle, dynset_parse_expressions,
+ &dynset_parse_ctx) < 0)
+ goto out_err;
}
if (nftnl_expr_is_set(nle, NFTNL_EXPR_DYNSET_SREG_DATA)) {
sreg_data = netlink_parse_register(nle, NFTNL_EXPR_DYNSET_SREG_DATA);
expr_data = netlink_get_register(ctx, loc, sreg_data);
+
+ if (expr_data && expr_data->len < set->data->len) {
+ expr_free(expr_data);
+ expr_data = netlink_parse_concat_expr(ctx, loc, sreg_data, set->data->len);
+ if (expr_data == NULL)
+ netlink_error(ctx, loc,
+ "Could not parse dynset map data expressions");
+ }
}
if (expr_data != NULL) {
+ expr_set_type(expr_data, set->data->dtype, set->data->byteorder);
stmt = map_stmt_alloc(loc);
stmt->map.set = set_ref_expr_alloc(loc, set);
stmt->map.key = expr;
stmt->map.data = expr_data;
- stmt->map.stmt = dstmt;
stmt->map.op = nftnl_expr_get_u32(nle, NFTNL_EXPR_DYNSET_OP);
+ list_splice_tail(&dynset_parse_ctx.stmt_list,
+ &stmt->map.stmt_list);
} else {
- if (dstmt != NULL && set->flags & NFT_SET_ANONYMOUS) {
+ if (!list_empty(&dynset_parse_ctx.stmt_list) &&
+ set_is_anonymous(set->flags)) {
stmt = meter_stmt_alloc(loc);
stmt->meter.set = set_ref_expr_alloc(loc, set);
stmt->meter.key = expr;
- stmt->meter.stmt = dstmt;
+ stmt->meter.stmt = list_first_entry(&dynset_parse_ctx.stmt_list,
+ struct stmt, list);
stmt->meter.size = set->desc.size;
} else {
stmt = set_stmt_alloc(loc);
stmt->set.set = set_ref_expr_alloc(loc, set);
stmt->set.op = nftnl_expr_get_u32(nle, NFTNL_EXPR_DYNSET_OP);
stmt->set.key = expr;
- stmt->set.stmt = dstmt;
+ list_splice_tail(&dynset_parse_ctx.stmt_list,
+ &stmt->set.stmt_list);
}
}
ctx->stmt = stmt;
return;
out_err:
- xfree(expr);
+ list_for_each_entry_safe(dstmt, next, &dynset_parse_ctx.stmt_list, list)
+ stmt_free(dstmt);
+
+ expr_free(expr);
}
static void netlink_parse_objref(struct netlink_parse_ctx *ctx,
@@ -1414,7 +1834,7 @@ static void netlink_parse_objref(struct netlink_parse_ctx *ctx,
struct set *set;
name = nftnl_expr_get_str(nle, NFTNL_EXPR_OBJREF_SET_NAME);
- set = set_lookup(ctx->table, name);
+ set = set_cache_find(ctx->table, name);
if (set == NULL)
return netlink_error(ctx, loc,
"Unknown set '%s' in objref expression",
@@ -1449,18 +1869,21 @@ static void netlink_parse_objref(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
}
-static const struct {
+struct expr_handler {
const char *name;
void (*parse)(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle);
-} netlink_parsers[] = {
+};
+
+static const struct expr_handler netlink_parsers[] = {
{ .name = "immediate", .parse = netlink_parse_immediate },
{ .name = "cmp", .parse = netlink_parse_cmp },
{ .name = "lookup", .parse = netlink_parse_lookup },
{ .name = "bitwise", .parse = netlink_parse_bitwise },
{ .name = "byteorder", .parse = netlink_parse_byteorder },
{ .name = "payload", .parse = netlink_parse_payload },
+ { .name = "inner", .parse = netlink_parse_inner },
{ .name = "exthdr", .parse = netlink_parse_exthdr },
{ .name = "meta", .parse = netlink_parse_meta },
{ .name = "socket", .parse = netlink_parse_socket },
@@ -1469,6 +1892,7 @@ static const struct {
{ .name = "ct", .parse = netlink_parse_ct },
{ .name = "connlimit", .parse = netlink_parse_connlimit },
{ .name = "counter", .parse = netlink_parse_counter },
+ { .name = "last", .parse = netlink_parse_last },
{ .name = "log", .parse = netlink_parse_log },
{ .name = "limit", .parse = netlink_parse_limit },
{ .name = "range", .parse = netlink_parse_range },
@@ -1509,11 +1933,13 @@ static int netlink_parse_expr(const struct nftnl_expr *nle,
for (i = 0; i < array_size(netlink_parsers); i++) {
if (strcmp(type, netlink_parsers[i].name))
continue;
+
netlink_parsers[i].parse(ctx, &loc, nle);
+
return 0;
}
-
netlink_error(ctx, &loc, "unknown expression type '%s'", type);
+
return 0;
}
@@ -1526,7 +1952,7 @@ static int netlink_parse_rule_expr(struct nftnl_expr *nle, void *arg)
if (err < 0)
return err;
if (ctx->stmt != NULL) {
- list_add_tail(&ctx->stmt->list, &ctx->rule->stmts);
+ rule_stmt_append(ctx->rule, ctx->stmt);
ctx->stmt = NULL;
}
return 0;
@@ -1537,16 +1963,55 @@ struct stmt *netlink_parse_set_expr(const struct set *set,
const struct nftnl_expr *nle)
{
struct netlink_parse_ctx ctx, *pctx = &ctx;
+ struct handle h = {};
- pctx->rule = rule_alloc(&netlink_location, &set->handle);
- pctx->table = table_lookup(&set->handle, cache);
+ handle_merge(&h, &set->handle);
+ pctx->rule = rule_alloc(&netlink_location, &h);
+ pctx->table = table_cache_find(&cache->table_cache,
+ set->handle.table.name,
+ set->handle.family);
assert(pctx->table != NULL);
if (netlink_parse_expr(nle, pctx) < 0)
return NULL;
+
+ init_list_head(&pctx->rule->stmts);
+ rule_free(pctx->rule);
+
return pctx->stmt;
}
+static bool meta_outer_may_dependency_kill(struct rule_pp_ctx *ctx,
+ const struct expr *expr)
+{
+ struct dl_proto_ctx *dl_outer = dl_proto_ctx_outer(ctx);
+ struct stmt *stmt = dl_outer->pdctx.pdeps[expr->payload.inner_desc->base];
+ struct expr *dep;
+ uint8_t l4proto;
+
+ if (!stmt)
+ return false;
+
+ dep = stmt->expr;
+
+ if (dep->left->meta.key != NFT_META_L4PROTO)
+ return false;
+
+ l4proto = mpz_get_uint8(dep->right->value);
+
+ switch (l4proto) {
+ case IPPROTO_GRE:
+ if (expr->payload.inner_desc == &proto_gre ||
+ expr->payload.inner_desc == &proto_gretap)
+ return true;
+ break;
+ default:
+ break;
+ }
+
+ return false;
+}
+
static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp);
static void payload_match_expand(struct rule_pp_ctx *ctx,
@@ -1555,21 +2020,27 @@ static void payload_match_expand(struct rule_pp_ctx *ctx,
{
struct expr *left = payload, *right = expr->right, *tmp;
struct list_head list = LIST_HEAD_INIT(list);
- struct stmt *nstmt;
- struct expr *nexpr = NULL;
+ struct dl_proto_ctx *dl = dl_proto_ctx(ctx);
enum proto_bases base = left->payload.base;
- bool stacked;
+ struct expr *nexpr = NULL;
+ struct stmt *nstmt;
- payload_expr_expand(&list, left, &ctx->pctx);
+ payload_expr_expand(&list, left, &dl->pctx);
list_for_each_entry(left, &list, list) {
tmp = constant_expr_splice(right, left->len);
expr_set_type(tmp, left->dtype, left->byteorder);
+ if (left->payload.tmpl && (left->len < left->payload.tmpl->len)) {
+ mpz_lshift_ui(tmp->value, left->payload.tmpl->len - left->len);
+ tmp->len = left->payload.tmpl->len;
+ tmp = prefix_expr_alloc(&tmp->location, tmp, left->len);
+ }
+
nexpr = relational_expr_alloc(&expr->location, expr->op,
left, tmp);
if (expr->op == OP_EQ)
- relational_expr_pctx_update(&ctx->pctx, nexpr);
+ relational_expr_pctx_update(&dl->pctx, nexpr);
nstmt = expr_stmt_alloc(&ctx->stmt->location, nexpr);
list_add_tail(&nstmt->list, &ctx->stmt->list);
@@ -1578,36 +2049,95 @@ static void payload_match_expand(struct rule_pp_ctx *ctx,
assert(left->payload.base);
assert(base == left->payload.base);
- stacked = payload_is_stacked(ctx->pctx.protocol[base].desc, nexpr);
+ if (expr->left->payload.inner_desc) {
+ if (expr->left->payload.inner_desc == expr->left->payload.desc) {
+ nexpr->left->payload.desc = expr->left->payload.desc;
+ nexpr->left->payload.tmpl = expr->left->payload.tmpl;
+ }
+ nexpr->left->payload.inner_desc = expr->left->payload.inner_desc;
+
+ if (meta_outer_may_dependency_kill(ctx, expr->left)) {
+ struct dl_proto_ctx *dl_outer = dl_proto_ctx_outer(ctx);
+
+ payload_dependency_release(&dl_outer->pdctx, expr->left->payload.inner_desc->base);
+ }
+ }
+
+ if (payload_is_stacked(dl->pctx.protocol[base].desc, nexpr))
+ base--;
/* Remember the first payload protocol expression to
* kill it later on if made redundant by a higher layer
* payload expression.
*/
- if (ctx->pdctx.pbase == PROTO_BASE_INVALID &&
- expr->op == OP_EQ &&
- left->flags & EXPR_F_PROTOCOL) {
- payload_dependency_store(&ctx->pdctx, nstmt, base - stacked);
- } else {
- payload_dependency_kill(&ctx->pdctx, nexpr->left,
- ctx->pctx.family);
- if (expr->op == OP_EQ && left->flags & EXPR_F_PROTOCOL)
- payload_dependency_store(&ctx->pdctx, nstmt, base - stacked);
- }
+ payload_dependency_kill(&dl->pdctx, nexpr->left,
+ dl->pctx.family);
+ if (expr->op == OP_EQ && left->flags & EXPR_F_PROTOCOL)
+ payload_dependency_store(&dl->pdctx, nstmt, base);
}
list_del(&ctx->stmt->list);
stmt_free(ctx->stmt);
ctx->stmt = NULL;
}
+static void payload_icmp_check(struct rule_pp_ctx *rctx, struct expr *expr, const struct expr *value)
+{
+ struct dl_proto_ctx *dl = dl_proto_ctx(rctx);
+ const struct proto_hdr_template *tmpl;
+ const struct proto_desc *desc;
+ uint8_t icmp_type;
+ unsigned int i;
+
+ assert(expr->etype == EXPR_PAYLOAD);
+ assert(value->etype == EXPR_VALUE);
+
+ if (expr->payload.base != PROTO_BASE_TRANSPORT_HDR)
+ return;
+
+ /* icmp(v6) type is 8 bit, if value is smaller or larger, this is not
+ * a protocol dependency.
+ */
+ if (expr->len != 8 || value->len != 8 || dl->pctx.th_dep.icmp.type)
+ return;
+
+ desc = dl->pctx.protocol[expr->payload.base].desc;
+ if (desc == NULL)
+ return;
+
+ /* not icmp? ignore. */
+ if (desc != &proto_icmp && desc != &proto_icmp6)
+ return;
+
+ assert(desc->base == expr->payload.base);
+
+ icmp_type = mpz_get_uint8(value->value);
+
+ for (i = 1; i < array_size(desc->templates); i++) {
+ tmpl = &desc->templates[i];
+
+ if (tmpl->len == 0)
+ return;
+
+ if (tmpl->offset != expr->payload.offset ||
+ tmpl->len != expr->len)
+ continue;
+
+ /* Matches but doesn't load a protocol key -> ignore. */
+ if (desc->protocol_key != i)
+ return;
+
+ expr->payload.desc = desc;
+ expr->payload.tmpl = tmpl;
+ dl->pctx.th_dep.icmp.type = icmp_type;
+ return;
+ }
+}
+
static void payload_match_postprocess(struct rule_pp_ctx *ctx,
struct expr *expr,
struct expr *payload)
{
- enum proto_bases base = payload->payload.base;
-
- assert(payload->payload.offset >= ctx->pctx.protocol[base].offset);
- payload->payload.offset -= ctx->pctx.protocol[base].offset;
+ struct dl_proto_ctx *dl = dl_proto_ctx(ctx);
switch (expr->op) {
case OP_EQ:
@@ -1615,19 +2145,82 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx,
if (expr->right->etype == EXPR_VALUE) {
payload_match_expand(ctx, expr, payload);
break;
+ } else if (expr->right->etype == EXPR_SET_REF) {
+ struct set *set = expr->right->set;
+
+ if (set_is_anonymous(set->flags) &&
+ set->init &&
+ !list_empty(&set->init->expressions)) {
+ struct expr *elem;
+
+ elem = list_first_entry(&set->init->expressions, struct expr, list);
+
+ if (elem->etype == EXPR_SET_ELEM &&
+ elem->key->etype == EXPR_VALUE)
+ payload_icmp_check(ctx, payload, elem->key);
+ }
}
/* Fall through */
default:
- payload_expr_complete(payload, &ctx->pctx);
+ payload_expr_complete(payload, &dl->pctx);
expr_set_type(expr->right, payload->dtype,
payload->byteorder);
- payload_dependency_kill(&ctx->pdctx, payload, ctx->pctx.family);
+ payload_dependency_kill(&dl->pdctx, payload, dl->pctx.family);
+ break;
+ }
+}
+
+static uint8_t ether_type_to_nfproto(uint16_t l3proto)
+{
+ switch(l3proto) {
+ case ETH_P_IP:
+ return NFPROTO_IPV4;
+ case ETH_P_IPV6:
+ return NFPROTO_IPV6;
+ default:
break;
}
+
+ return NFPROTO_UNSPEC;
+}
+
+static bool __meta_dependency_may_kill(const struct expr *dep, uint8_t *nfproto)
+{
+ uint16_t l3proto;
+
+ switch (dep->left->etype) {
+ case EXPR_META:
+ switch (dep->left->meta.key) {
+ case NFT_META_NFPROTO:
+ *nfproto = mpz_get_uint8(dep->right->value);
+ break;
+ case NFT_META_PROTOCOL:
+ l3proto = mpz_get_uint16(dep->right->value);
+ *nfproto = ether_type_to_nfproto(l3proto);
+ break;
+ default:
+ return true;
+ }
+ break;
+ case EXPR_PAYLOAD:
+ if (dep->left->payload.base != PROTO_BASE_LL_HDR)
+ return true;
+
+ if (dep->left->dtype != &ethertype_type)
+ return true;
+
+ l3proto = mpz_get_uint16(dep->right->value);
+ *nfproto = ether_type_to_nfproto(l3proto);
+ break;
+ default:
+ return true;
+ }
+
+ return false;
}
/* We have seen a protocol key expression that restricts matching at the network
- * base, leave it in place since this is meaninful in bridge, inet and netdev
+ * base, leave it in place since this is meaningful in bridge, inet and netdev
* families. Exceptions are ICMP and ICMPv6 where this code assumes that can
* only happen with IPv4 and IPv6.
*/
@@ -1635,11 +2228,13 @@ static bool meta_may_dependency_kill(struct payload_dep_ctx *ctx,
unsigned int family,
const struct expr *expr)
{
- struct expr *dep = ctx->pdep->expr;
- uint16_t l3proto;
- uint8_t l4proto;
+ uint8_t l4proto, nfproto = NFPROTO_UNSPEC;
+ struct expr *dep = payload_dependency_get(ctx, PROTO_BASE_NETWORK_HDR);
- if (ctx->pbase != PROTO_BASE_NETWORK_HDR)
+ if (!dep)
+ return true;
+
+ if (__meta_dependency_may_kill(dep, &nfproto))
return true;
switch (family) {
@@ -1647,6 +2242,9 @@ static bool meta_may_dependency_kill(struct payload_dep_ctx *ctx,
case NFPROTO_NETDEV:
case NFPROTO_BRIDGE:
break;
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ return family == nfproto;
default:
return true;
}
@@ -1654,32 +2252,6 @@ static bool meta_may_dependency_kill(struct payload_dep_ctx *ctx,
if (expr->left->meta.key != NFT_META_L4PROTO)
return true;
- l3proto = mpz_get_uint16(dep->right->value);
-
- switch (dep->left->etype) {
- case EXPR_META:
- if (dep->left->meta.key != NFT_META_NFPROTO)
- return true;
- break;
- case EXPR_PAYLOAD:
- if (dep->left->payload.base != PROTO_BASE_LL_HDR)
- return true;
-
- switch(l3proto) {
- case ETH_P_IP:
- l3proto = NFPROTO_IPV4;
- break;
- case ETH_P_IPV6:
- l3proto = NFPROTO_IPV6;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
l4proto = mpz_get_uint8(expr->right->value);
switch (l4proto) {
@@ -1690,8 +2262,8 @@ static bool meta_may_dependency_kill(struct payload_dep_ctx *ctx,
return false;
}
- if ((l3proto == NFPROTO_IPV4 && l4proto == IPPROTO_ICMPV6) ||
- (l3proto == NFPROTO_IPV6 && l4proto == IPPROTO_ICMP))
+ if ((nfproto == NFPROTO_IPV4 && l4proto == IPPROTO_ICMPV6) ||
+ (nfproto == NFPROTO_IPV6 && l4proto == IPPROTO_ICMP))
return false;
return true;
@@ -1701,6 +2273,7 @@ static void ct_meta_common_postprocess(struct rule_pp_ctx *ctx,
const struct expr *expr,
enum proto_bases base)
{
+ struct dl_proto_ctx *dl = dl_proto_ctx(ctx);
const struct expr *left = expr->left;
struct expr *right = expr->right;
@@ -1714,18 +2287,16 @@ static void ct_meta_common_postprocess(struct rule_pp_ctx *ctx,
expr->right->etype == EXPR_SET_REF)
break;
- relational_expr_pctx_update(&ctx->pctx, expr);
+ relational_expr_pctx_update(&dl->pctx, expr);
+
+ if (base < PROTO_BASE_TRANSPORT_HDR) {
+ if (payload_dependency_exists(&dl->pdctx, base) &&
+ meta_may_dependency_kill(&dl->pdctx,
+ dl->pctx.family, expr))
+ payload_dependency_release(&dl->pdctx, base);
- if (ctx->pdctx.pbase == PROTO_BASE_INVALID &&
- left->flags & EXPR_F_PROTOCOL) {
- payload_dependency_store(&ctx->pdctx, ctx->stmt, base);
- } else if (ctx->pdctx.pbase < PROTO_BASE_TRANSPORT_HDR) {
- if (payload_dependency_exists(&ctx->pdctx, base) &&
- meta_may_dependency_kill(&ctx->pdctx,
- ctx->pctx.family, expr))
- payload_dependency_release(&ctx->pdctx);
if (left->flags & EXPR_F_PROTOCOL)
- payload_dependency_store(&ctx->pdctx, ctx->stmt, base);
+ payload_dependency_store(&dl->pdctx, ctx->stmt, base);
}
break;
default:
@@ -1810,8 +2381,8 @@ static void binop_adjust_one(const struct expr *binop, struct expr *value,
}
}
-static void __binop_adjust(const struct expr *binop, struct expr *right,
- unsigned int shift)
+static void binop_adjust(const struct expr *binop, struct expr *right,
+ unsigned int shift)
{
struct expr *i;
@@ -1820,6 +2391,9 @@ static void __binop_adjust(const struct expr *binop, struct expr *right,
binop_adjust_one(binop, right, shift);
break;
case EXPR_SET_REF:
+ if (!set_is_anonymous(right->set->flags))
+ break;
+
list_for_each_entry(i, &right->set->init->expressions, list) {
switch (i->key->etype) {
case EXPR_VALUE:
@@ -1830,7 +2404,7 @@ static void __binop_adjust(const struct expr *binop, struct expr *right,
binop_adjust_one(binop, i->key->right, shift);
break;
case EXPR_SET_ELEM:
- __binop_adjust(binop, i->key->key, shift);
+ binop_adjust(binop, i->key->key, shift);
break;
default:
BUG("unknown expression type %s\n", expr_name(i->key));
@@ -1847,22 +2421,24 @@ static void __binop_adjust(const struct expr *binop, struct expr *right,
}
}
-static void binop_adjust(struct expr *expr, unsigned int shift)
+static void __binop_postprocess(struct rule_pp_ctx *ctx,
+ struct expr *expr,
+ struct expr *left,
+ struct expr *mask,
+ struct expr **expr_binop)
{
- __binop_adjust(expr->left, expr->right, shift);
-}
-
-static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr)
-{
- struct expr *binop = expr->left;
- struct expr *left = binop->left;
- struct expr *mask = binop->right;
+ struct dl_proto_ctx *dl = dl_proto_ctx(ctx);
+ struct expr *binop = *expr_binop;
unsigned int shift;
+ assert(binop->etype == EXPR_BINOP);
+
if ((left->etype == EXPR_PAYLOAD &&
- payload_expr_trim(left, mask, &ctx->pctx, &shift)) ||
+ payload_expr_trim(left, mask, &dl->pctx, &shift)) ||
(left->etype == EXPR_EXTHDR &&
exthdr_find_template(left, mask, &shift))) {
+ struct expr *right = NULL;
+
/* mask is implicit, binop needs to be removed.
*
* Fix all values of the expression according to the mask
@@ -1872,59 +2448,106 @@ static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr)
* Finally, convert the expression to 1) by replacing
* the binop with the binop payload/exthdr expression.
*/
- binop_adjust(expr, shift);
+ switch (expr->etype) {
+ case EXPR_BINOP:
+ case EXPR_RELATIONAL:
+ right = expr->right;
+ binop_adjust(binop, right, shift);
+ break;
+ case EXPR_MAP:
+ right = expr->mappings;
+ binop_adjust(binop, right, shift);
+ break;
+ default:
+ break;
+ }
- assert(expr->left->etype == EXPR_BINOP);
assert(binop->left == left);
- expr->left = expr_get(left);
- expr_free(binop);
+ *expr_binop = expr_get(left);
+
if (left->etype == EXPR_PAYLOAD)
payload_match_postprocess(ctx, expr, left);
- else if (left->etype == EXPR_EXTHDR)
- expr_set_type(expr->right, left->dtype, left->byteorder);
+ else if (left->etype == EXPR_EXTHDR && right)
+ expr_set_type(right, left->dtype, left->byteorder);
+
+ expr_free(binop);
}
}
+static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr,
+ struct expr **expr_binop)
+{
+ struct expr *binop = *expr_binop;
+ struct expr *left = binop->left;
+ struct expr *mask = binop->right;
+
+ __binop_postprocess(ctx, expr, left, mask, expr_binop);
+}
+
static void map_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr)
{
- struct expr *binop = expr->left;
+ struct expr *binop = expr->map;
if (binop->op != OP_AND)
return;
if (binop->left->etype == EXPR_PAYLOAD &&
binop->right->etype == EXPR_VALUE)
- binop_postprocess(ctx, expr);
+ binop_postprocess(ctx, expr, &expr->map);
+}
+
+static bool is_shift_by_zero(const struct expr *binop)
+{
+ struct expr *rhs;
+
+ if (binop->op != OP_RSHIFT && binop->op != OP_LSHIFT)
+ return false;
+
+ rhs = binop->right;
+ if (rhs->etype != EXPR_VALUE || rhs->len > 64)
+ return false;
+
+ return mpz_get_uint64(rhs->value) == 0;
}
-static void relational_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr)
+static void relational_binop_postprocess(struct rule_pp_ctx *ctx,
+ struct expr **exprp)
{
- struct expr *binop = expr->left, *value = expr->right;
+ struct expr *expr = *exprp, *binop = expr->left, *right = expr->right;
- if (binop->op == OP_AND && expr->op == OP_NEQ &&
- value->dtype->basetype &&
- value->dtype->basetype->type == TYPE_BITMASK &&
- !mpz_cmp_ui(value->value, 0)) {
+ if (binop->op == OP_AND && (expr->op == OP_NEQ || expr->op == OP_EQ) &&
+ right->dtype->basetype &&
+ right->dtype->basetype->type == TYPE_BITMASK &&
+ right->etype == EXPR_VALUE &&
+ !mpz_cmp_ui(right->value, 0)) {
/* Flag comparison: data & flags != 0
*
* Split the flags into a list of flag values and convert the
* op to OP_EQ.
*/
- expr_free(value);
+ expr_free(right);
expr->left = expr_get(binop->left);
expr->right = binop_tree_to_list(NULL, binop->right);
- expr->op = OP_IMPLICIT;
-
+ switch (expr->op) {
+ case OP_NEQ:
+ expr->op = OP_IMPLICIT;
+ break;
+ case OP_EQ:
+ expr->op = OP_NEG;
+ break;
+ default:
+ BUG("unknown operation type %d\n", expr->op);
+ }
expr_free(binop);
} else if (binop->left->dtype->flags & DTYPE_F_PREFIX &&
- binop->op == OP_AND &&
+ binop->op == OP_AND && expr->right->etype == EXPR_VALUE &&
expr_mask_is_prefix(binop->right)) {
expr->left = expr_get(binop->left);
expr->right = prefix_expr_alloc(&expr->location,
- expr_get(value),
+ expr_get(right),
expr_mask_to_prefix(binop->right));
- expr_free(value);
+ expr_free(right);
expr_free(binop);
} else if (binop->op == OP_AND &&
binop->right->etype == EXPR_VALUE) {
@@ -1951,10 +2574,60 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx, struct expr *e
* payload_expr_trim will figure out if the mask is needed to match
* templates.
*/
- binop_postprocess(ctx, expr);
+ binop_postprocess(ctx, expr, &expr->left);
+ } else if (binop->op == OP_RSHIFT && binop->left->op == OP_AND &&
+ binop->right->etype == EXPR_VALUE && binop->left->right->etype == EXPR_VALUE) {
+ /* Handle 'ip version @s4' and similar, i.e. set lookups where the lhs needs
+ * fixups to mask out unwanted bits AND a shift.
+ */
+
+ binop_postprocess(ctx, binop, &binop->left);
+ if (is_shift_by_zero(binop)) {
+ struct expr *lhs = binop->left;
+
+ expr_get(lhs);
+ expr_free(binop);
+ expr->left = lhs;
+ }
}
}
+static bool payload_binop_postprocess(struct rule_pp_ctx *ctx,
+ struct expr **exprp)
+{
+ struct expr *expr = *exprp;
+
+ if (expr->op != OP_RSHIFT)
+ return false;
+
+ if (expr->left->etype == EXPR_UNARY) {
+ /*
+ * If the payload value was originally in a different byte-order
+ * from the payload expression, there will be a byte-order
+ * conversion to remove.
+ */
+ struct expr *left = expr_get(expr->left->arg);
+ expr_free(expr->left);
+ expr->left = left;
+ }
+
+ if (expr->left->etype != EXPR_BINOP || expr->left->op != OP_AND)
+ return false;
+
+ if (expr->left->left->etype != EXPR_PAYLOAD)
+ return false;
+
+ expr_set_type(expr->right, &integer_type,
+ BYTEORDER_HOST_ENDIAN);
+ expr_postprocess(ctx, &expr->right);
+
+ binop_postprocess(ctx, expr, &expr->left);
+ *exprp = expr_get(expr->left);
+ expr_free(expr);
+
+ return true;
+}
+
static struct expr *string_wildcard_expr_alloc(struct location *loc,
const struct expr *mask,
const struct expr *expr)
@@ -1972,61 +2645,38 @@ static struct expr *string_wildcard_expr_alloc(struct location *loc,
expr->len + BITS_PER_BYTE, data);
}
-static void escaped_string_wildcard_expr_alloc(struct expr **exprp,
- unsigned int len)
-{
- struct expr *expr = *exprp, *tmp;
- char data[len + 3];
- int pos;
-
- mpz_export_data(data, expr->value, BYTEORDER_HOST_ENDIAN, len);
- pos = div_round_up(len, BITS_PER_BYTE);
- data[pos - 1] = '\\';
- data[pos] = '*';
-
- tmp = constant_expr_alloc(&expr->location, expr->dtype,
- BYTEORDER_HOST_ENDIAN,
- expr->len + BITS_PER_BYTE, data);
- expr_free(expr);
- *exprp = tmp;
-}
-
/* This calculates the string length and checks if it is nul-terminated, this
* function is quite a hack :)
*/
static bool __expr_postprocess_string(struct expr **exprp)
{
struct expr *expr = *exprp;
- unsigned int len = expr->len;
- bool nulterminated = false;
- mpz_t tmp;
-
- mpz_init(tmp);
- while (len >= BITS_PER_BYTE) {
- mpz_bitmask(tmp, BITS_PER_BYTE);
- mpz_lshift_ui(tmp, len - BITS_PER_BYTE);
- mpz_and(tmp, tmp, expr->value);
- if (mpz_cmp_ui(tmp, 0))
- break;
- else
- nulterminated = true;
- len -= BITS_PER_BYTE;
- }
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ char data[len + 1];
- mpz_rshift_ui(tmp, len - BITS_PER_BYTE);
+ mpz_export_data(data, expr->value, BYTEORDER_HOST_ENDIAN, len);
- if (nulterminated &&
- mpz_cmp_ui(tmp, '*') == 0)
- escaped_string_wildcard_expr_alloc(exprp, len);
+ if (data[len - 1] != '\0')
+ return false;
- mpz_clear(tmp);
+ len = strlen(data);
+ if (len && data[len - 1] == '*') {
+ data[len - 1] = '\\';
+ data[len] = '*';
+ data[len + 1] = '\0';
+ expr = constant_expr_alloc(&expr->location, expr->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ (len + 2) * BITS_PER_BYTE, data);
+ expr_free(*exprp);
+ *exprp = expr;
+ }
- return nulterminated;
+ return true;
}
static struct expr *expr_postprocess_string(struct expr *expr)
{
- struct expr *mask;
+ struct expr *mask, *out;
assert(expr_basetype(expr)->type == TYPE_STRING);
if (__expr_postprocess_string(&expr))
@@ -2035,16 +2685,64 @@ static struct expr *expr_postprocess_string(struct expr *expr)
mask = constant_expr_alloc(&expr->location, &integer_type,
BYTEORDER_HOST_ENDIAN,
expr->len + BITS_PER_BYTE, NULL);
+ mpz_clear(mask->value);
mpz_init_bitmask(mask->value, expr->len);
- return string_wildcard_expr_alloc(&expr->location, mask, expr);
+ out = string_wildcard_expr_alloc(&expr->location, mask, expr);
+ expr_free(expr);
+ expr_free(mask);
+ return out;
+}
+
+static void expr_postprocess_value(struct rule_pp_ctx *ctx, struct expr **exprp)
+{
+ bool interval = (ctx->set && ctx->set->flags & NFT_SET_INTERVAL);
+ struct expr *expr = *exprp;
+
+ // FIXME
+ if (expr->byteorder == BYTEORDER_HOST_ENDIAN && !interval)
+ mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
+
+ if (expr_basetype(expr)->type == TYPE_STRING)
+ *exprp = expr_postprocess_string(expr);
+
+ expr = *exprp;
+ if (expr->dtype->basetype != NULL &&
+ expr->dtype->basetype->type == TYPE_BITMASK)
+ *exprp = bitmask_expr_to_binops(expr);
+}
+
+static void expr_postprocess_concat(struct rule_pp_ctx *ctx, struct expr **exprp)
+{
+ struct expr *i, *n, *expr = *exprp;
+ unsigned int type = expr->dtype->type, ntype = 0;
+ int off = expr->dtype->subtypes;
+ const struct datatype *dtype;
+ LIST_HEAD(tmp);
+
+ assert(expr->etype == EXPR_CONCAT);
+
+ ctx->flags |= RULE_PP_IN_CONCATENATION;
+ list_for_each_entry_safe(i, n, &expr->expressions, list) {
+ if (type) {
+ dtype = concat_subtype_lookup(type, --off);
+ expr_set_type(i, dtype, dtype->byteorder);
+ }
+ list_del(&i->list);
+ expr_postprocess(ctx, &i);
+ list_add_tail(&i->list, &tmp);
+
+ ntype = concat_subtype_add(ntype, i->dtype->type);
+ }
+ ctx->flags &= ~RULE_PP_IN_CONCATENATION;
+ list_splice(&tmp, &expr->expressions);
+ __datatype_set(expr, concat_type_alloc(ntype));
}
static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
{
+ struct dl_proto_ctx *dl = dl_proto_ctx(ctx);
struct expr *expr = *exprp, *i;
- //pr_debug("%s len %u\n", expr->ops->name, expr->len);
-
switch (expr->etype) {
case EXPR_MAP:
switch (expr->map->etype) {
@@ -2066,41 +2764,107 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
list_for_each_entry(i, &expr->expressions, list)
expr_postprocess(ctx, &i);
break;
- case EXPR_CONCAT: {
- unsigned int type = expr->dtype->type, ntype = 0;
- int off = expr->dtype->subtypes;
- const struct datatype *dtype;
-
- list_for_each_entry(i, &expr->expressions, list) {
- if (type) {
- dtype = concat_subtype_lookup(type, --off);
- expr_set_type(i, dtype, dtype->byteorder);
- }
- expr_postprocess(ctx, &i);
-
- ntype = concat_subtype_add(ntype, i->dtype->type);
- }
- datatype_set(expr, concat_type_alloc(ntype));
+ case EXPR_CONCAT:
+ expr_postprocess_concat(ctx, exprp);
break;
- }
case EXPR_UNARY:
expr_postprocess(ctx, &expr->arg);
expr_set_type(expr, expr->arg->dtype, !expr->arg->byteorder);
break;
case EXPR_BINOP:
+ if (payload_binop_postprocess(ctx, exprp))
+ break;
+
expr_postprocess(ctx, &expr->left);
- expr_set_type(expr->right, expr->left->dtype,
- expr->left->byteorder);
+ switch (expr->op) {
+ case OP_LSHIFT:
+ case OP_RSHIFT:
+ expr_set_type(expr->right, &integer_type,
+ BYTEORDER_HOST_ENDIAN);
+ break;
+ case OP_AND:
+ if (expr->right->len > expr->left->len) {
+ expr_set_type(expr->right, expr->left->dtype,
+ BYTEORDER_HOST_ENDIAN);
+ } else {
+ expr_set_type(expr->right, expr->left->dtype,
+ expr->left->byteorder);
+ }
+
+ /* Do not process OP_AND in ordinary rule context.
+ *
+ * Removal needs to be performed as part of the relational
+ * operation because the RHS constant might need to be adjusted
+ * (shifted).
+ *
+ * This is different in set element context or concatenations:
+ * There is no relational operation (eq, neq and so on), thus
+ * it needs to be processed right away.
+ */
+ if ((ctx->flags & RULE_PP_REMOVE_OP_AND) &&
+ expr->left->etype == EXPR_PAYLOAD &&
+ expr->right->etype == EXPR_VALUE) {
+ __binop_postprocess(ctx, expr, expr->left, expr->right, exprp);
+ return;
+ }
+ break;
+ default:
+ if (expr->right->len > expr->left->len) {
+ expr_set_type(expr->right, expr->left->dtype,
+ BYTEORDER_HOST_ENDIAN);
+ } else {
+ expr_set_type(expr->right, expr->left->dtype,
+ expr->left->byteorder);
+ }
+ }
expr_postprocess(ctx, &expr->right);
- expr_set_type(expr, expr->left->dtype,
- expr->left->byteorder);
+ switch (expr->op) {
+ case OP_LSHIFT:
+ case OP_RSHIFT:
+ expr_set_type(expr, &xinteger_type,
+ BYTEORDER_HOST_ENDIAN);
+ break;
+ default:
+ expr_set_type(expr, expr->left->dtype,
+ expr->left->byteorder);
+ }
+
break;
case EXPR_RELATIONAL:
switch (expr->left->etype) {
case EXPR_PAYLOAD:
payload_match_postprocess(ctx, expr, expr->left);
return;
+ case EXPR_CONCAT:
+ if (expr->right->etype == EXPR_SET_REF) {
+ assert(expr->left->dtype == &invalid_type);
+ assert(expr->right->dtype != &invalid_type);
+
+ datatype_set(expr->left, expr->right->dtype);
+ }
+ ctx->set = expr->right->set;
+ expr_postprocess(ctx, &expr->left);
+ ctx->set = NULL;
+ break;
+ case EXPR_UNARY:
+ if (lhs_is_meta_hour(expr->left->arg) &&
+ expr->right->etype == EXPR_RANGE) {
+ struct expr *range = expr->right;
+
+ /* Cross-day range needs to be reversed.
+ * Kernel handles time in UTC. Therefore,
+ * 03:00-14:00 AEDT (Sidney, Australia) time
+ * is a cross-day range.
+ */
+ if (mpz_cmp(range->left->value,
+ range->right->value) <= 0 &&
+ expr->op == OP_NEQ) {
+ range_expr_swap_values(range);
+ expr->op = OP_IMPLICIT;
+ }
+ }
+ /* fallthrough */
default:
expr_postprocess(ctx, &expr->left);
break;
@@ -2117,39 +2881,40 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
meta_match_postprocess(ctx, expr);
break;
case EXPR_BINOP:
- relational_binop_postprocess(ctx, expr);
+ relational_binop_postprocess(ctx, exprp);
break;
default:
break;
}
break;
case EXPR_PAYLOAD:
- payload_expr_complete(expr, &ctx->pctx);
- payload_dependency_kill(&ctx->pdctx, expr, ctx->pctx.family);
+ payload_expr_complete(expr, &dl->pctx);
+ if (expr->payload.inner_desc) {
+ if (meta_outer_may_dependency_kill(ctx, expr)) {
+ struct dl_proto_ctx *dl_outer = dl_proto_ctx_outer(ctx);
+
+ payload_dependency_release(&dl_outer->pdctx, expr->payload.inner_desc->base);
+ }
+ }
+ payload_dependency_kill(&dl->pdctx, expr, dl->pctx.family);
break;
case EXPR_VALUE:
- // FIXME
- if (expr->byteorder == BYTEORDER_HOST_ENDIAN)
- mpz_switch_byteorder(expr->value, expr->len / BITS_PER_BYTE);
-
- if (expr_basetype(expr)->type == TYPE_STRING)
- *exprp = expr_postprocess_string(expr);
-
- expr = *exprp;
- if (expr->dtype->basetype != NULL &&
- expr->dtype->basetype->type == TYPE_BITMASK)
- *exprp = bitmask_expr_to_binops(expr);
-
+ expr_postprocess_value(ctx, exprp);
break;
case EXPR_RANGE:
expr_postprocess(ctx, &expr->left);
expr_postprocess(ctx, &expr->right);
break;
+ case EXPR_PREFIX:
+ expr_postprocess(ctx, &expr->prefix);
+ break;
case EXPR_SET_ELEM:
+ ctx->flags |= RULE_PP_IN_SET_ELEM;
expr_postprocess(ctx, &expr->key);
+ ctx->flags &= ~RULE_PP_IN_SET_ELEM;
break;
case EXPR_EXTHDR:
- exthdr_dependency_kill(&ctx->pdctx, expr, ctx->pctx.family);
+ exthdr_dependency_kill(&dl->pdctx, expr, dl->pctx.family);
break;
case EXPR_SET_REF:
case EXPR_META:
@@ -2166,7 +2931,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
expr_postprocess(ctx, &expr->hash.expr);
break;
case EXPR_CT:
- ct_expr_update_type(&ctx->pctx, expr);
+ ct_expr_update_type(&dl->pctx, expr);
break;
default:
BUG("unknown expression type %s\n", expr_name(expr));
@@ -2175,48 +2940,35 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
static void stmt_reject_postprocess(struct rule_pp_ctx *rctx)
{
+ struct dl_proto_ctx *dl = dl_proto_ctx(rctx);
const struct proto_desc *desc, *base;
struct stmt *stmt = rctx->stmt;
int protocol;
- switch (rctx->pctx.family) {
+ switch (dl->pctx.family) {
case NFPROTO_IPV4:
- stmt->reject.family = rctx->pctx.family;
- datatype_set(stmt->reject.expr, &icmp_code_type);
+ stmt->reject.family = dl->pctx.family;
+ datatype_set(stmt->reject.expr, &reject_icmp_code_type);
if (stmt->reject.type == NFT_REJECT_TCP_RST &&
- payload_dependency_exists(&rctx->pdctx,
+ payload_dependency_exists(&dl->pdctx,
PROTO_BASE_TRANSPORT_HDR))
- payload_dependency_release(&rctx->pdctx);
+ payload_dependency_release(&dl->pdctx,
+ PROTO_BASE_TRANSPORT_HDR);
break;
case NFPROTO_IPV6:
- stmt->reject.family = rctx->pctx.family;
- datatype_set(stmt->reject.expr, &icmpv6_code_type);
+ stmt->reject.family = dl->pctx.family;
+ datatype_set(stmt->reject.expr, &reject_icmpv6_code_type);
if (stmt->reject.type == NFT_REJECT_TCP_RST &&
- payload_dependency_exists(&rctx->pdctx,
+ payload_dependency_exists(&dl->pdctx,
PROTO_BASE_TRANSPORT_HDR))
- payload_dependency_release(&rctx->pdctx);
+ payload_dependency_release(&dl->pdctx,
+ PROTO_BASE_TRANSPORT_HDR);
break;
case NFPROTO_INET:
- if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH) {
- datatype_set(stmt->reject.expr, &icmpx_code_type);
- break;
- }
- base = rctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
- desc = rctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
- protocol = proto_find_num(base, desc);
- switch (protocol) {
- case NFPROTO_IPV4:
- datatype_set(stmt->reject.expr, &icmp_code_type);
- break;
- case NFPROTO_IPV6:
- datatype_set(stmt->reject.expr, &icmpv6_code_type);
- break;
- }
- stmt->reject.family = protocol;
- break;
case NFPROTO_BRIDGE:
+ case NFPROTO_NETDEV:
if (stmt->reject.type == NFT_REJECT_ICMPX_UNREACH) {
- datatype_set(stmt->reject.expr, &icmpx_code_type);
+ datatype_set(stmt->reject.expr, &reject_icmpx_code_type);
break;
}
@@ -2225,25 +2977,27 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx)
*/
stmt->reject.verbose_print = 1;
- base = rctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
- desc = rctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ base = dl->pctx.protocol[PROTO_BASE_LL_HDR].desc;
+ desc = dl->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
protocol = proto_find_num(base, desc);
switch (protocol) {
- case __constant_htons(ETH_P_IP):
+ case NFPROTO_IPV4: /* INET */
+ case __constant_htons(ETH_P_IP): /* BRIDGE, NETDEV */
stmt->reject.family = NFPROTO_IPV4;
- datatype_set(stmt->reject.expr, &icmp_code_type);
+ datatype_set(stmt->reject.expr, &reject_icmp_code_type);
break;
- case __constant_htons(ETH_P_IPV6):
+ case NFPROTO_IPV6: /* INET */
+ case __constant_htons(ETH_P_IPV6): /* BRIDGE, NETDEV */
stmt->reject.family = NFPROTO_IPV6;
- datatype_set(stmt->reject.expr, &icmpv6_code_type);
+ datatype_set(stmt->reject.expr, &reject_icmpv6_code_type);
break;
default:
break;
}
- if (payload_dependency_exists(&rctx->pdctx, PROTO_BASE_NETWORK_HDR))
- payload_dependency_release(&rctx->pdctx);
-
+ if (payload_dependency_exists(&dl->pdctx, PROTO_BASE_NETWORK_HDR))
+ payload_dependency_release(&dl->pdctx,
+ PROTO_BASE_NETWORK_HDR);
break;
default:
break;
@@ -2286,23 +3040,24 @@ static bool expr_may_merge_range(struct expr *expr, struct expr *prev,
static void expr_postprocess_range(struct rule_pp_ctx *ctx, enum ops op)
{
+ struct dl_proto_ctx *dl = dl_proto_ctx(ctx);
struct stmt *nstmt, *stmt = ctx->stmt;
struct expr *nexpr, *rel;
- nexpr = range_expr_alloc(&ctx->pdctx.prev->location,
- expr_clone(ctx->pdctx.prev->expr->right),
+ nexpr = range_expr_alloc(&dl->pdctx.prev->location,
+ expr_clone(dl->pdctx.prev->expr->right),
expr_clone(stmt->expr->right));
expr_set_type(nexpr, stmt->expr->right->dtype,
stmt->expr->right->byteorder);
- rel = relational_expr_alloc(&ctx->pdctx.prev->location, op,
+ rel = relational_expr_alloc(&dl->pdctx.prev->location, op,
expr_clone(stmt->expr->left), nexpr);
nstmt = expr_stmt_alloc(&stmt->location, rel);
list_add_tail(&nstmt->list, &stmt->list);
- list_del(&ctx->pdctx.prev->list);
- stmt_free(ctx->pdctx.prev);
+ list_del(&dl->pdctx.prev->list);
+ stmt_free(dl->pdctx.prev);
list_del(&stmt->list);
stmt_free(stmt);
@@ -2311,26 +3066,28 @@ static void expr_postprocess_range(struct rule_pp_ctx *ctx, enum ops op)
static void stmt_expr_postprocess(struct rule_pp_ctx *ctx)
{
+ struct dl_proto_ctx *dl = dl_proto_ctx(ctx);
enum ops op;
expr_postprocess(ctx, &ctx->stmt->expr);
- if (ctx->pdctx.prev && ctx->stmt &&
- ctx->stmt->ops->type == ctx->pdctx.prev->ops->type &&
- expr_may_merge_range(ctx->stmt->expr, ctx->pdctx.prev->expr, &op))
+ if (dl->pdctx.prev && ctx->stmt &&
+ ctx->stmt->ops->type == dl->pdctx.prev->ops->type &&
+ expr_may_merge_range(ctx->stmt->expr, dl->pdctx.prev->expr, &op))
expr_postprocess_range(ctx, op);
}
static void stmt_payload_binop_pp(struct rule_pp_ctx *ctx, struct expr *binop)
{
+ struct dl_proto_ctx *dl = dl_proto_ctx(ctx);
struct expr *payload = binop->left;
struct expr *mask = binop->right;
unsigned int shift;
assert(payload->etype == EXPR_PAYLOAD);
- if (payload_expr_trim(payload, mask, &ctx->pctx, &shift)) {
- __binop_adjust(binop, mask, shift);
- payload_expr_complete(payload, &ctx->pctx);
+ if (payload_expr_trim(payload, mask, &dl->pctx, &shift)) {
+ binop_adjust(binop, mask, shift);
+ payload_expr_complete(payload, &dl->pctx);
expr_set_type(mask, payload->dtype,
payload->byteorder);
}
@@ -2348,7 +3105,7 @@ static void stmt_payload_binop_pp(struct rule_pp_ctx *ctx, struct expr *binop)
* the original payload expression because it has an odd size or
* a non-byte divisible offset/length.
*
- * Of that was the case, the 'value' expression is not a value but
+ * If that was the case, the 'value' expression is not a value but
* a binop expression with a munged payload expression on the left
* and a mask to clear the real payload offset/length.
*
@@ -2424,7 +3181,7 @@ static void stmt_payload_binop_postprocess(struct rule_pp_ctx *ctx)
mpz_set(mask->value, bitmask);
mpz_clear(bitmask);
- binop_postprocess(ctx, expr);
+ binop_postprocess(ctx, expr, &expr->left);
if (!payload_is_known(payload)) {
mpz_set(mask->value, tmp);
mpz_clear(tmp);
@@ -2449,6 +3206,7 @@ static void stmt_payload_binop_postprocess(struct rule_pp_ctx *ctx)
mpz_init_bitmask(bitmask, payload->len);
mpz_xor(bitmask, bitmask, value->value);
mpz_set(value->value, bitmask);
+ mpz_clear(bitmask);
break;
case OP_OR: /* IIb */
break;
@@ -2484,20 +3242,34 @@ static void stmt_payload_binop_postprocess(struct rule_pp_ctx *ctx)
static void stmt_payload_postprocess(struct rule_pp_ctx *ctx)
{
+ struct dl_proto_ctx *dl = dl_proto_ctx(ctx);
struct stmt *stmt = ctx->stmt;
+ payload_expr_complete(stmt->payload.expr, &dl->pctx);
+ if (!payload_is_known(stmt->payload.expr))
+ stmt_payload_binop_postprocess(ctx);
+
expr_postprocess(ctx, &stmt->payload.expr);
expr_set_type(stmt->payload.val,
stmt->payload.expr->dtype,
stmt->payload.expr->byteorder);
- if (!payload_is_known(stmt->payload.expr))
- stmt_payload_binop_postprocess(ctx);
-
expr_postprocess(ctx, &stmt->payload.val);
}
+static void stmt_queue_postprocess(struct rule_pp_ctx *ctx)
+{
+ struct stmt *stmt = ctx->stmt;
+ struct expr *e = stmt->queue.queue;
+
+ if (e == NULL || e->etype == EXPR_VALUE ||
+ e->etype == EXPR_RANGE)
+ return;
+
+ expr_postprocess(ctx, &stmt->queue.queue);
+}
+
/*
* We can only remove payload dependencies if they occur without
* a statement with side effects in between.
@@ -2519,18 +3291,75 @@ rule_maybe_reset_payload_deps(struct payload_dep_ctx *pdctx, enum stmt_types t)
payload_dependency_reset(pdctx);
}
+static bool has_inner_desc(const struct expr *expr)
+{
+ struct expr *i;
+
+ switch (expr->etype) {
+ case EXPR_BINOP:
+ return has_inner_desc(expr->left);
+ case EXPR_CONCAT:
+ list_for_each_entry(i, &expr->expressions, list) {
+ if (has_inner_desc(i))
+ return true;
+ }
+ break;
+ case EXPR_META:
+ return expr->meta.inner_desc;
+ case EXPR_PAYLOAD:
+ return expr->payload.inner_desc;
+ case EXPR_SET_ELEM:
+ return has_inner_desc(expr->key);
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static struct dl_proto_ctx *rule_update_dl_proto_ctx(struct rule_pp_ctx *rctx)
+{
+ const struct stmt *stmt = rctx->stmt;
+ bool inner = false;
+
+ switch (stmt->ops->type) {
+ case STMT_EXPRESSION:
+ if (has_inner_desc(stmt->expr->left))
+ inner = true;
+ break;
+ case STMT_SET:
+ if (has_inner_desc(stmt->set.key))
+ inner = true;
+ break;
+ default:
+ break;
+ }
+
+ if (inner)
+ rctx->dl = &rctx->_dl[1];
+ else
+ rctx->dl = &rctx->_dl[0];
+
+ return rctx->dl;
+}
+
static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *rule)
{
- struct rule_pp_ctx rctx;
struct stmt *stmt, *next;
+ struct dl_proto_ctx *dl;
+ struct rule_pp_ctx rctx;
+ struct expr *expr;
memset(&rctx, 0, sizeof(rctx));
- proto_ctx_init(&rctx.pctx, rule->handle.family, ctx->debug_mask);
+ proto_ctx_init(&rctx._dl[0].pctx, rule->handle.family, ctx->debug_mask, false);
+ /* use NFPROTO_BRIDGE to set up proto_eth as base protocol. */
+ proto_ctx_init(&rctx._dl[1].pctx, NFPROTO_BRIDGE, ctx->debug_mask, true);
list_for_each_entry_safe(stmt, next, &rule->stmts, list) {
enum stmt_types type = stmt->ops->type;
rctx.stmt = stmt;
+ dl = rule_update_dl_proto_ctx(&rctx);
switch (type) {
case STMT_EXPRESSION:
@@ -2551,24 +3380,24 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
expr_postprocess(&rctx, &stmt->ct.expr);
if (stmt->ct.expr->etype == EXPR_BINOP &&
- stmt->ct.key == NFT_CT_EVENTMASK)
- stmt->ct.expr = binop_tree_to_list(NULL,
- stmt->ct.expr);
+ stmt->ct.key == NFT_CT_EVENTMASK) {
+ expr = binop_tree_to_list(NULL, stmt->ct.expr);
+ expr_free(stmt->ct.expr);
+ stmt->ct.expr = expr;
+ }
}
break;
case STMT_NAT:
if (stmt->nat.addr != NULL)
expr_postprocess(&rctx, &stmt->nat.addr);
- if (stmt->nat.proto != NULL) {
- payload_dependency_reset(&rctx.pdctx);
+ if (stmt->nat.proto != NULL)
expr_postprocess(&rctx, &stmt->nat.proto);
- }
break;
case STMT_TPROXY:
if (stmt->tproxy.addr)
expr_postprocess(&rctx, &stmt->tproxy.addr);
if (stmt->tproxy.port) {
- payload_dependency_reset(&rctx.pdctx);
+ payload_dependency_reset(&dl->pdctx);
expr_postprocess(&rctx, &stmt->tproxy.port);
}
break;
@@ -2599,13 +3428,16 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
case STMT_OBJREF:
expr_postprocess(&rctx, &stmt->objref.expr);
break;
+ case STMT_QUEUE:
+ stmt_queue_postprocess(&rctx);
+ break;
default:
break;
}
- rctx.pdctx.prev = rctx.stmt;
+ dl->pdctx.prev = rctx.stmt;
- rule_maybe_reset_payload_deps(&rctx.pdctx, type);
+ rule_maybe_reset_payload_deps(&dl->pdctx, type);
}
}
@@ -2657,6 +3489,7 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
memset(&_ctx, 0, sizeof(_ctx));
_ctx.msgs = ctx->msgs;
_ctx.debug_mask = ctx->nft->debug_mask;
+ _ctx.nlctx = ctx;
memset(&h, 0, sizeof(h));
h.family = nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY);
@@ -2668,8 +3501,12 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
h.position.id = nftnl_rule_get_u64(nlr, NFTNL_RULE_POSITION);
pctx->rule = rule_alloc(&netlink_location, &h);
- pctx->table = table_lookup(&h, &ctx->nft->cache);
- assert(pctx->table != NULL);
+ pctx->table = table_cache_find(&ctx->nft->cache.table_cache,
+ h.table.name, h.family);
+ if (!pctx->table) {
+ errno = ENOENT;
+ return NULL;
+ }
pctx->rule->comment = nftnl_rule_get_comment(nlr);
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 498326d0..6204d8fd 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -9,9 +9,11 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <linux/netfilter/nf_tables.h>
+#include <linux/netfilter/nf_log.h>
-#include <string.h>
#include <rule.h>
#include <statement.h>
#include <expression.h>
@@ -23,11 +25,34 @@
#include <linux/netfilter.h>
#include <libnftnl/udata.h>
+struct nft_expr_loc *nft_expr_loc_find(const struct nftnl_expr *nle,
+ struct netlink_linearize_ctx *ctx)
+{
+ struct nft_expr_loc *eloc;
+ uint32_t hash;
+
+ hash = (uint64_t)nle % NFT_EXPR_LOC_HSIZE;
+ list_for_each_entry(eloc, &ctx->expr_loc_htable[hash], hlist) {
+ if (eloc->nle == nle)
+ return eloc;
+ }
-struct netlink_linearize_ctx {
- struct nftnl_rule *nlr;
- unsigned int reg_low;
-};
+ return NULL;
+}
+
+static void nft_expr_loc_add(const struct nftnl_expr *nle,
+ const struct location *loc,
+ struct netlink_linearize_ctx *ctx)
+{
+ struct nft_expr_loc *eloc;
+ uint32_t hash;
+
+ eloc = xmalloc(sizeof(*eloc));
+ eloc->nle = nle;
+ eloc->loc = loc;
+ hash = (uint64_t)nle % NFT_EXPR_LOC_HSIZE;
+ list_add_tail(&eloc->hlist, &ctx->expr_loc_htable[hash]);
+}
static void netlink_put_register(struct nftnl_expr *nle,
uint32_t attr, uint32_t reg)
@@ -104,6 +129,14 @@ static void netlink_gen_concat(struct netlink_linearize_ctx *ctx,
}
}
+static void nft_rule_add_expr(struct netlink_linearize_ctx *ctx,
+ struct nftnl_expr *nle,
+ const struct location *loc)
+{
+ nft_expr_loc_add(nle, loc, ctx);
+ nftnl_rule_add_expr(ctx->nlr, nle);
+}
+
static void netlink_gen_fib(struct netlink_linearize_ctx *ctx,
const struct expr *expr,
enum nft_registers dreg)
@@ -115,7 +148,7 @@ static void netlink_gen_fib(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_FIB_RESULT, expr->fib.result);
nftnl_expr_set_u32(nle, NFTNL_EXPR_FIB_FLAGS, expr->fib.flags);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_hash(struct netlink_linearize_ctx *ctx,
@@ -143,12 +176,11 @@ static void netlink_gen_hash(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_SEED, expr->hash.seed);
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_OFFSET, expr->hash.offset);
nftnl_expr_set_u32(nle, NFTNL_EXPR_HASH_TYPE, expr->hash.type);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
-static void netlink_gen_payload(struct netlink_linearize_ctx *ctx,
- const struct expr *expr,
- enum nft_registers dreg)
+static struct nftnl_expr *
+__netlink_gen_payload(const struct expr *expr, enum nft_registers dreg)
{
struct nftnl_expr *nle;
@@ -161,26 +193,92 @@ static void netlink_gen_payload(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_LEN,
div_round_up(expr->len, BITS_PER_BYTE));
- nftnl_rule_add_expr(ctx->nlr, nle);
+ return nle;
+}
+
+static struct nftnl_expr *
+__netlink_gen_meta(const struct expr *expr, enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("meta");
+ netlink_put_register(nle, NFTNL_EXPR_META_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, expr->meta.key);
+
+ return nle;
+}
+
+static struct nftnl_expr *netlink_gen_inner_expr(const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct expr *_expr = (struct expr *)expr;
+ struct nftnl_expr *nle;
+
+ switch (expr->etype) {
+ case EXPR_PAYLOAD:
+ if (expr->payload.base == NFT_PAYLOAD_INNER_HEADER + 1)
+ _expr->payload.base = NFT_PAYLOAD_TUN_HEADER + 1;
+
+ nle = __netlink_gen_payload(expr, dreg);
+ break;
+ case EXPR_META:
+ nle = __netlink_gen_meta(expr, dreg);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ return nle;
+}
+
+static void netlink_gen_inner(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg,
+ const struct proto_desc *desc)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("inner");
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_INNER_HDRSIZE, desc->inner.hdrsize);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_INNER_FLAGS, desc->inner.flags);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_INNER_TYPE, desc->inner.type);
+ nftnl_expr_set(nle, NFTNL_EXPR_INNER_EXPR, netlink_gen_inner_expr(expr, dreg), 0);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_payload(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct nftnl_expr *nle;
+
+ if (expr->payload.inner_desc) {
+ netlink_gen_inner(ctx, expr, dreg, expr->payload.inner_desc);
+ return;
+ }
+
+ nle = __netlink_gen_payload(expr, dreg);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_exthdr(struct netlink_linearize_ctx *ctx,
const struct expr *expr,
enum nft_registers dreg)
{
- unsigned int offset = expr->exthdr.tmpl->offset + expr->exthdr.offset;
+ unsigned int offset = expr->exthdr.offset;
struct nftnl_expr *nle;
nle = alloc_nft_expr("exthdr");
netlink_put_register(nle, NFTNL_EXPR_EXTHDR_DREG, dreg);
nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
- expr->exthdr.desc->type);
+ expr->exthdr.raw_type);
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE);
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN,
div_round_up(expr->len, BITS_PER_BYTE));
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_FLAGS, expr->exthdr.flags);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_meta(struct netlink_linearize_ctx *ctx,
@@ -189,10 +287,13 @@ static void netlink_gen_meta(struct netlink_linearize_ctx *ctx,
{
struct nftnl_expr *nle;
- nle = alloc_nft_expr("meta");
- netlink_put_register(nle, NFTNL_EXPR_META_DREG, dreg);
- nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, expr->meta.key);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ if (expr->meta.inner_desc) {
+ netlink_gen_inner(ctx, expr, dreg, expr->meta.inner_desc);
+ return;
+ }
+
+ nle = __netlink_gen_meta(expr, dreg);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_rt(struct netlink_linearize_ctx *ctx,
@@ -204,7 +305,7 @@ static void netlink_gen_rt(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("rt");
netlink_put_register(nle, NFTNL_EXPR_RT_DREG, dreg);
nftnl_expr_set_u32(nle, NFTNL_EXPR_RT_KEY, expr->rt.key);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_socket(struct netlink_linearize_ctx *ctx,
@@ -216,7 +317,8 @@ static void netlink_gen_socket(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("socket");
netlink_put_register(nle, NFTNL_EXPR_SOCKET_DREG, dreg);
nftnl_expr_set_u32(nle, NFTNL_EXPR_SOCKET_KEY, expr->socket.key);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_SOCKET_LEVEL, expr->socket.level);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_osf(struct netlink_linearize_ctx *ctx,
@@ -229,7 +331,7 @@ static void netlink_gen_osf(struct netlink_linearize_ctx *ctx,
netlink_put_register(nle, NFTNL_EXPR_OSF_DREG, dreg);
nftnl_expr_set_u8(nle, NFTNL_EXPR_OSF_TTL, expr->osf.ttl);
nftnl_expr_set_u32(nle, NFTNL_EXPR_OSF_FLAGS, expr->osf.flags);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_numgen(struct netlink_linearize_ctx *ctx,
@@ -243,7 +345,7 @@ static void netlink_gen_numgen(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_TYPE, expr->numgen.type);
nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_MODULUS, expr->numgen.mod);
nftnl_expr_set_u32(nle, NFTNL_EXPR_NG_OFFSET, expr->numgen.offset);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_ct(struct netlink_linearize_ctx *ctx,
@@ -259,7 +361,7 @@ static void netlink_gen_ct(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u8(nle, NFTNL_EXPR_CT_DIR,
expr->ct.direction);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
@@ -297,7 +399,7 @@ static void netlink_gen_map(struct netlink_linearize_ctx *ctx,
if (dreg == NFT_REG_VERDICT)
release_register(ctx, expr->map);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
@@ -323,7 +425,7 @@ static void netlink_gen_lookup(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_LOOKUP_FLAGS, NFT_LOOKUP_F_INV);
release_register(ctx, expr->left);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static enum nft_cmp_ops netlink_gen_cmp_op(enum ops op)
@@ -358,7 +460,8 @@ static struct expr *netlink_gen_prefix(struct netlink_linearize_ctx *ctx,
mpz_init(mask);
mpz_prefixmask(mask, expr->right->len, expr->right->prefix_len);
netlink_gen_raw_data(mask, expr->right->byteorder,
- expr->right->len / BITS_PER_BYTE, &nld);
+ div_round_up(expr->right->len, BITS_PER_BYTE),
+ &nld);
mpz_clear(mask);
zero.len = nld.len;
@@ -369,7 +472,7 @@ static struct expr *netlink_gen_prefix(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, nld.len);
nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, &nld.value, nld.len);
nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, &zero.value, zero.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
return expr->right->prefix;
}
@@ -399,7 +502,7 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
netlink_gen_data(range->right, &nld);
nftnl_expr_set(nle, NFTNL_EXPR_RANGE_TO_DATA,
nld.value, nld.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
break;
case OP_EQ:
case OP_IMPLICIT:
@@ -409,7 +512,7 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
netlink_gen_cmp_op(OP_GTE));
netlink_gen_data(range->left, &nld);
nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
nle = alloc_nft_expr("cmp");
netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
@@ -417,7 +520,7 @@ static void netlink_gen_range(struct netlink_linearize_ctx *ctx,
netlink_gen_cmp_op(OP_LTE));
netlink_gen_data(range->right, &nld);
nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
break;
default:
BUG("invalid range operation %u\n", expr->op);
@@ -448,19 +551,31 @@ static void netlink_gen_flagcmp(struct netlink_linearize_ctx *ctx,
netlink_gen_raw_data(zero, expr->right->byteorder, len, &nld);
netlink_gen_data(expr->right, &nld2);
- nle = alloc_nft_expr("bitwise");
- netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, sreg);
- netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, sreg);
- nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
- nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, &nld2.value, nld2.len);
- nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, &nld.value, nld.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ if (expr->left->etype == EXPR_BINOP) {
+ nle = alloc_nft_expr("cmp");
+ netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_EQ);
+ nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld2.value, nld2.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+ } else {
+ nle = alloc_nft_expr("bitwise");
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, sreg);
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, sreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
+ nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_MASK, &nld2.value, nld2.len);
+ nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_XOR, &nld.value, nld.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
- nle = alloc_nft_expr("cmp");
- netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
- nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_NEQ);
- nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nle = alloc_nft_expr("cmp");
+ netlink_put_register(nle, NFTNL_EXPR_CMP_SREG, sreg);
+ if (expr->op == OP_NEG)
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_EQ);
+ else
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_CMP_OP, NFT_CMP_NEQ);
+
+ nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, nld.len);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+ }
mpz_clear(zero);
release_register(ctx, expr->left);
@@ -486,6 +601,7 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
case OP_GT:
case OP_LTE:
case OP_GTE:
+ case OP_NEG:
break;
default:
BUG("invalid relational operation %u\n", expr->op);
@@ -501,7 +617,10 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
return netlink_gen_flagcmp(ctx, expr, dreg);
case EXPR_PREFIX:
sreg = get_register(ctx, expr->left);
- if (expr_basetype(expr->left)->type != TYPE_STRING) {
+ if (expr_basetype(expr->left)->type != TYPE_STRING &&
+ (expr->right->byteorder != BYTEORDER_BIG_ENDIAN ||
+ !expr->right->prefix_len ||
+ expr->right->prefix_len % BITS_PER_BYTE)) {
len = div_round_up(expr->right->len, BITS_PER_BYTE);
netlink_gen_expr(ctx, expr->left, sreg);
right = netlink_gen_prefix(ctx, expr, sreg);
@@ -513,7 +632,7 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
}
break;
default:
- if (expr->op == OP_IMPLICIT &&
+ if ((expr->op == OP_IMPLICIT || expr->op == OP_NEG) &&
expr->right->dtype->basetype != NULL &&
expr->right->dtype->basetype->type == TYPE_BITMASK)
return netlink_gen_flagcmp(ctx, expr, dreg);
@@ -533,7 +652,7 @@ static void netlink_gen_relational(struct netlink_linearize_ctx *ctx,
nftnl_expr_set(nle, NFTNL_EXPR_CMP_DATA, nld.value, len);
release_register(ctx, expr->left);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void combine_binop(mpz_t mask, mpz_t xor, const mpz_t m, const mpz_t x)
@@ -545,14 +664,41 @@ static void combine_binop(mpz_t mask, mpz_t xor, const mpz_t m, const mpz_t x)
mpz_and(mask, mask, m);
}
-static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
+static void netlink_gen_shift(struct netlink_linearize_ctx *ctx,
const struct expr *expr,
enum nft_registers dreg)
{
+ enum nft_bitwise_ops op = expr->op == OP_LSHIFT ?
+ NFT_BITWISE_LSHIFT : NFT_BITWISE_RSHIFT;
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ struct nft_data_linearize nld;
+ struct nftnl_expr *nle;
+
+ netlink_gen_expr(ctx, expr->left, dreg);
+
+ nle = alloc_nft_expr("bitwise");
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, dreg);
+ netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_OP, op);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
+
+ netlink_gen_raw_data(expr->right->value, expr->right->byteorder,
+ sizeof(uint32_t), &nld);
+
+ nftnl_expr_set(nle, NFTNL_EXPR_BITWISE_DATA, nld.value,
+ nld.len);
+
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ struct expr *binops[NFT_MAX_EXPR_RECURSION];
struct nftnl_expr *nle;
struct nft_data_linearize nld;
struct expr *left, *i;
- struct expr *binops[16];
mpz_t mask, xor, val, tmp;
unsigned int len;
int n = 0;
@@ -562,17 +708,20 @@ static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
mpz_init(val);
mpz_init(tmp);
- binops[n++] = left = (void *)expr;
- while (left->etype == EXPR_BINOP && left->left != NULL)
+ binops[n++] = left = (struct expr *) expr;
+ while (left->etype == EXPR_BINOP && left->left != NULL &&
+ (left->op == OP_AND || left->op == OP_OR || left->op == OP_XOR)) {
+ if (n == array_size(binops))
+ BUG("NFT_MAX_EXPR_RECURSION limit reached");
binops[n++] = left = left->left;
- n--;
+ }
- netlink_gen_expr(ctx, binops[n--], dreg);
+ netlink_gen_expr(ctx, binops[--n], dreg);
mpz_bitmask(mask, expr->len);
mpz_set_ui(xor, 0);
- for (; n >= 0; n--) {
- i = binops[n];
+ while (n > 0) {
+ i = binops[--n];
mpz_set(val, i->right->value);
switch (i->op) {
@@ -598,6 +747,7 @@ static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("bitwise");
netlink_put_register(nle, NFTNL_EXPR_BITWISE_SREG, dreg);
netlink_put_register(nle, NFTNL_EXPR_BITWISE_DREG, dreg);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_OP, NFT_BITWISE_BOOL);
nftnl_expr_set_u32(nle, NFTNL_EXPR_BITWISE_LEN, len);
netlink_gen_raw_data(mask, expr->byteorder, len, &nld);
@@ -610,7 +760,22 @@ static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
mpz_clear(xor);
mpz_clear(mask);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
+}
+
+static void netlink_gen_binop(struct netlink_linearize_ctx *ctx,
+ const struct expr *expr,
+ enum nft_registers dreg)
+{
+ switch(expr->op) {
+ case OP_LSHIFT:
+ case OP_RSHIFT:
+ netlink_gen_shift(ctx, expr, dreg);
+ break;
+ default:
+ netlink_gen_bitwise(ctx, expr, dreg);
+ break;
+ }
}
static enum nft_byteorder_ops netlink_gen_unary_op(enum ops op)
@@ -632,6 +797,8 @@ static void netlink_gen_unary(struct netlink_linearize_ctx *ctx,
struct nftnl_expr *nle;
int byte_size;
+ assert(div_round_up(expr->arg->len, BITS_PER_BYTE) != 1);
+
if ((expr->arg->len % 64) == 0)
byte_size = 8;
else if ((expr->arg->len % 32) == 0)
@@ -645,20 +812,21 @@ static void netlink_gen_unary(struct netlink_linearize_ctx *ctx,
netlink_put_register(nle, NFTNL_EXPR_BYTEORDER_SREG, dreg);
netlink_put_register(nle, NFTNL_EXPR_BYTEORDER_DREG, dreg);
nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_LEN,
- expr->len / BITS_PER_BYTE);
+ div_round_up(expr->len, BITS_PER_BYTE));
nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_SIZE,
byte_size);
nftnl_expr_set_u32(nle, NFTNL_EXPR_BYTEORDER_OP,
netlink_gen_unary_op(expr->op));
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_immediate(struct netlink_linearize_ctx *ctx,
const struct expr *expr,
enum nft_registers dreg)
{
- struct nftnl_expr *nle;
+ const struct location *loc = &expr->location;
struct nft_data_linearize nld;
+ struct nftnl_expr *nle;
nle = alloc_nft_expr("immediate");
netlink_put_register(nle, NFTNL_EXPR_IMM_DREG, dreg);
@@ -668,17 +836,20 @@ static void netlink_gen_immediate(struct netlink_linearize_ctx *ctx,
nftnl_expr_set(nle, NFTNL_EXPR_IMM_DATA, nld.value, nld.len);
break;
case EXPR_VERDICT:
- if ((expr->chain != NULL) &&
- !nftnl_expr_is_set(nle, NFTNL_EXPR_IMM_CHAIN)) {
+ if (expr->chain) {
nftnl_expr_set_str(nle, NFTNL_EXPR_IMM_CHAIN,
nld.chain);
+ loc = &expr->chain->location;
+ } else if (expr->chain_id) {
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_IMM_CHAIN_ID,
+ nld.chain_id);
}
nftnl_expr_set_u32(nle, NFTNL_EXPR_IMM_VERDICT, nld.verdict);
break;
default:
break;
}
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, loc);
}
static void netlink_gen_xfrm(struct netlink_linearize_ctx *ctx,
@@ -692,7 +863,7 @@ static void netlink_gen_xfrm(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_XFRM_KEY, expr->xfrm.key);
nftnl_expr_set_u8(nle, NFTNL_EXPR_XFRM_DIR, expr->xfrm.direction);
nftnl_expr_set_u32(nle, NFTNL_EXPR_XFRM_SPNUM, expr->xfrm.spnum);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_expr(struct netlink_linearize_ctx *ctx,
@@ -775,12 +946,10 @@ static void netlink_gen_objref_stmt(struct netlink_linearize_ctx *ctx,
default:
BUG("unsupported expression %u\n", expr->etype);
}
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
-static struct nftnl_expr *
-netlink_gen_connlimit_stmt(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
+static struct nftnl_expr *netlink_gen_connlimit_stmt(const struct stmt *stmt)
{
struct nftnl_expr *nle;
@@ -793,9 +962,7 @@ netlink_gen_connlimit_stmt(struct netlink_linearize_ctx *ctx,
return nle;
}
-static struct nftnl_expr *
-netlink_gen_counter_stmt(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
+static struct nftnl_expr *netlink_gen_counter_stmt(const struct stmt *stmt)
{
struct nftnl_expr *nle;
@@ -812,9 +979,7 @@ netlink_gen_counter_stmt(struct netlink_linearize_ctx *ctx,
return nle;
}
-static struct nftnl_expr *
-netlink_gen_limit_stmt(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
+static struct nftnl_expr *netlink_gen_limit_stmt(const struct stmt *stmt)
{
struct nftnl_expr *nle;
@@ -830,9 +995,7 @@ netlink_gen_limit_stmt(struct netlink_linearize_ctx *ctx,
return nle;
}
-static struct nftnl_expr *
-netlink_gen_quota_stmt(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
+static struct nftnl_expr *netlink_gen_quota_stmt(const struct stmt *stmt)
{
struct nftnl_expr *nle;
@@ -844,19 +1007,30 @@ netlink_gen_quota_stmt(struct netlink_linearize_ctx *ctx,
return nle;
}
-static struct nftnl_expr *
-netlink_gen_stmt_stateful(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
+static struct nftnl_expr *netlink_gen_last_stmt(const struct stmt *stmt)
+{
+ struct nftnl_expr *nle;
+
+ nle = alloc_nft_expr("last");
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_LAST_SET, stmt->last.set);
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_LAST_MSECS, stmt->last.used);
+
+ return nle;
+}
+
+struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt)
{
switch (stmt->ops->type) {
case STMT_CONNLIMIT:
- return netlink_gen_connlimit_stmt(ctx, stmt);
+ return netlink_gen_connlimit_stmt(stmt);
case STMT_COUNTER:
- return netlink_gen_counter_stmt(ctx, stmt);
+ return netlink_gen_counter_stmt(stmt);
case STMT_LIMIT:
- return netlink_gen_limit_stmt(ctx, stmt);
+ return netlink_gen_limit_stmt(stmt);
case STMT_QUOTA:
- return netlink_gen_quota_stmt(ctx, stmt);
+ return netlink_gen_quota_stmt(stmt);
+ case STMT_LAST:
+ return netlink_gen_last_stmt(stmt);
default:
BUG("unknown stateful statement type %s\n", stmt->ops->name);
}
@@ -894,17 +1068,17 @@ static void netlink_gen_exthdr_stmt(struct netlink_linearize_ctx *ctx,
expr = stmt->exthdr.expr;
- offset = expr->exthdr.tmpl->offset + expr->exthdr.offset;
+ offset = expr->exthdr.offset;
nle = alloc_nft_expr("exthdr");
netlink_put_register(nle, NFTNL_EXPR_EXTHDR_SREG, sreg);
nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
- expr->exthdr.desc->type);
+ expr->exthdr.raw_type);
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OFFSET, offset / BITS_PER_BYTE);
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_LEN,
div_round_up(expr->len, BITS_PER_BYTE));
nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_payload_stmt(struct netlink_linearize_ctx *ctx,
@@ -937,16 +1111,17 @@ static void netlink_gen_payload_stmt(struct netlink_linearize_ctx *ctx,
expr->len / BITS_PER_BYTE);
if (csum_off) {
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_CSUM_TYPE,
- NFT_PAYLOAD_CSUM_INET);
+ desc->checksum_type);
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_CSUM_OFFSET,
csum_off / BITS_PER_BYTE);
}
- if (expr->payload.base == PROTO_BASE_NETWORK_HDR &&
- payload_needs_l4csum_update_pseudohdr(expr, desc))
+ if ((expr->payload.base == PROTO_BASE_NETWORK_HDR && desc &&
+ payload_needs_l4csum_update_pseudohdr(expr, desc)) ||
+ expr->payload.base == PROTO_BASE_INNER_HDR)
nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_FLAGS,
NFT_PAYLOAD_L4CSUM_PSEUDOHDR);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_meta_stmt(struct netlink_linearize_ctx *ctx,
@@ -962,7 +1137,7 @@ static void netlink_gen_meta_stmt(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("meta");
netlink_put_register(nle, NFTNL_EXPR_META_SREG, sreg);
nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, stmt->meta.key);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_log_stmt(struct netlink_linearize_ctx *ctx,
@@ -972,8 +1147,10 @@ static void netlink_gen_log_stmt(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("log");
if (stmt->log.prefix != NULL) {
- nftnl_expr_set_str(nle, NFTNL_EXPR_LOG_PREFIX,
- stmt->log.prefix);
+ char prefix[NF_LOG_PREFIXLEN] = {};
+
+ expr_to_string(stmt->log.prefix, prefix);
+ nftnl_expr_set_str(nle, NFTNL_EXPR_LOG_PREFIX, prefix);
}
if (stmt->log.flags & STMT_LOG_GROUP) {
nftnl_expr_set_u16(nle, NFTNL_EXPR_LOG_GROUP, stmt->log.group);
@@ -991,7 +1168,7 @@ static void netlink_gen_log_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_LOG_FLAGS,
stmt->log.logflags);
}
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_reject_stmt(struct netlink_linearize_ctx *ctx,
@@ -1005,7 +1182,18 @@ static void netlink_gen_reject_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u8(nle, NFTNL_EXPR_REJECT_CODE,
stmt->reject.icmp_code);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static unsigned int nat_addrlen(uint8_t family)
+{
+ switch (family) {
+ case NFPROTO_IPV4: return 32;
+ case NFPROTO_IPV6: return 128;
+ }
+
+ BUG("invalid nat family %u\n", family);
+ return 0;
}
static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
@@ -1014,8 +1202,8 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
struct nftnl_expr *nle;
enum nft_registers amin_reg, amax_reg;
enum nft_registers pmin_reg, pmax_reg;
+ uint8_t family = 0;
int registers = 0;
- int family;
int nftnl_flag_attr;
int nftnl_reg_pmin, nftnl_reg_pmax;
@@ -1072,8 +1260,46 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
netlink_gen_expr(ctx, stmt->nat.addr, amin_reg);
netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MIN,
amin_reg);
+ if (stmt->nat.addr->etype == EXPR_MAP &&
+ stmt->nat.addr->mappings->set->data->flags & EXPR_F_INTERVAL) {
+ amin_reg += netlink_register_space(nat_addrlen(family));
+ if (stmt->nat.type_flags & STMT_NAT_F_CONCAT) {
+ netlink_put_register(nle, nftnl_reg_pmin,
+ amin_reg);
+ } else {
+ netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX,
+ amin_reg);
+ }
+ }
}
+ if (stmt->nat.type_flags & STMT_NAT_F_CONCAT) {
+ /* nat_stmt evaluation step doesn't allow
+ * STMT_NAT_F_CONCAT && stmt->nat.proto.
+ */
+ assert(stmt->nat.proto == NULL);
+
+ pmin_reg = amin_reg;
+
+ if (stmt->nat.type_flags & STMT_NAT_F_INTERVAL) {
+ pmin_reg += netlink_register_space(nat_addrlen(family));
+ netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX,
+ pmin_reg);
+ }
+
+ /* if STMT_NAT_F_CONCAT is set, the mapped type is a
+ * concatenation of 'addr . inet_service'.
+ * The map lookup will then return the
+ * concatenated value, so we need to skip
+ * the address and use the register that
+ * will hold the inet_service part.
+ */
+ pmin_reg += netlink_register_space(nat_addrlen(family));
+ if (stmt->nat.type_flags & STMT_NAT_F_INTERVAL)
+ netlink_put_register(nle, nftnl_reg_pmax, pmin_reg);
+ else
+ netlink_put_register(nle, nftnl_reg_pmin, pmin_reg);
+ }
}
if (stmt->nat.proto) {
@@ -1099,7 +1325,7 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
registers--;
}
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_tproxy_stmt(struct netlink_linearize_ctx *ctx,
@@ -1138,7 +1364,7 @@ static void netlink_gen_tproxy_stmt(struct netlink_linearize_ctx *ctx,
registers--;
}
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_synproxy_stmt(struct netlink_linearize_ctx *ctx,
@@ -1153,7 +1379,7 @@ static void netlink_gen_synproxy_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_SYNPROXY_FLAGS,
stmt->synproxy.flags);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_dup_stmt(struct netlink_linearize_ctx *ctx,
@@ -1184,7 +1410,7 @@ static void netlink_gen_dup_stmt(struct netlink_linearize_ctx *ctx,
if (stmt->dup.to != NULL)
release_register(ctx, stmt->dup.to);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_fwd_stmt(struct netlink_linearize_ctx *ctx,
@@ -1211,39 +1437,69 @@ static void netlink_gen_fwd_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_FWD_NFPROTO,
stmt->fwd.family);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_optstrip_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct nftnl_expr *nle = alloc_nft_expr("exthdr");
+ struct expr *expr = stmt->optstrip.expr;
+
+ nftnl_expr_set_u8(nle, NFTNL_EXPR_EXTHDR_TYPE,
+ expr->exthdr.raw_type);
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_EXTHDR_OP, expr->exthdr.op);
+ nft_rule_add_expr(ctx, nle, &expr->location);
}
static void netlink_gen_queue_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
+ enum nft_registers sreg = 0;
struct nftnl_expr *nle;
uint16_t total_queues;
+ struct expr *expr;
mpz_t low, high;
mpz_init2(low, 16);
mpz_init2(high, 16);
- if (stmt->queue.queue != NULL) {
- range_expr_value_low(low, stmt->queue.queue);
- range_expr_value_high(high, stmt->queue.queue);
+
+ expr = stmt->queue.queue;
+
+ if (expr) {
+ if (expr->etype == EXPR_RANGE || expr->etype == EXPR_VALUE) {
+ range_expr_value_low(low, stmt->queue.queue);
+ range_expr_value_high(high, stmt->queue.queue);
+ } else {
+ sreg = get_register(ctx, expr);
+ netlink_gen_expr(ctx, expr, sreg);
+ release_register(ctx, expr);
+ }
}
+
total_queues = mpz_get_uint16(high) - mpz_get_uint16(low) + 1;
nle = alloc_nft_expr("queue");
- nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_NUM, mpz_get_uint16(low));
- nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_TOTAL, total_queues);
+
+ if (sreg) {
+ netlink_put_register(nle, NFTNL_EXPR_QUEUE_SREG_QNUM, sreg);
+ } else {
+ nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_NUM, mpz_get_uint16(low));
+ nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_TOTAL, total_queues);
+ }
+
if (stmt->queue.flags)
nftnl_expr_set_u16(nle, NFTNL_EXPR_QUEUE_FLAGS,
stmt->queue.flags);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
mpz_clear(low);
mpz_clear(high);
}
static void netlink_gen_ct_stmt(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
+ const struct stmt *stmt)
{
struct nftnl_expr *nle;
enum nft_registers sreg;
@@ -1259,7 +1515,7 @@ static void netlink_gen_ct_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u8(nle, NFTNL_EXPR_CT_DIR,
stmt->ct.direction);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_notrack_stmt(struct netlink_linearize_ctx *ctx,
@@ -1268,7 +1524,7 @@ static void netlink_gen_notrack_stmt(struct netlink_linearize_ctx *ctx,
struct nftnl_expr *nle;
nle = alloc_nft_expr("notrack");
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_flow_offload_stmt(struct netlink_linearize_ctx *ctx,
@@ -1279,15 +1535,17 @@ static void netlink_gen_flow_offload_stmt(struct netlink_linearize_ctx *ctx,
nle = alloc_nft_expr("flow_offload");
nftnl_expr_set_str(nle, NFTNL_EXPR_FLOW_TABLE_NAME,
stmt->flow.table_name);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
}
static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
struct set *set = stmt->meter.set->set;
- struct nftnl_expr *nle;
enum nft_registers sreg_key;
+ struct nftnl_expr *nle;
+ int num_stmts = 0;
+ struct stmt *this;
sreg_key = get_register(ctx, stmt->set.key->key);
netlink_gen_expr(ctx, stmt->set.key->key, sreg_key);
@@ -1301,11 +1559,24 @@ static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_OP, stmt->set.op);
nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, set->handle.set.name);
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
- if (stmt->set.stmt)
- nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
- netlink_gen_stmt_stateful(ctx, stmt->set.stmt), 0);
+ list_for_each_entry(this, &stmt->set.stmt_list, list)
+ num_stmts++;
+
+ if (num_stmts == 1) {
+ list_for_each_entry(this, &stmt->set.stmt_list, list) {
+ nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
+ netlink_gen_stmt_stateful(this), 0);
+ }
+ } else if (num_stmts > 1) {
+ list_for_each_entry(this, &stmt->set.stmt_list, list) {
+ nftnl_expr_add_expr(nle, NFTNL_EXPR_DYNSET_EXPRESSIONS,
+ netlink_gen_stmt_stateful(this));
+ }
+ nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_FLAGS,
+ NFT_DYNSET_F_EXPR);
+ }
}
static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
@@ -1315,14 +1586,16 @@ static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
enum nft_registers sreg_data;
enum nft_registers sreg_key;
struct nftnl_expr *nle;
+ int num_stmts = 0;
+ struct stmt *this;
- sreg_key = get_register(ctx, stmt->map.key);
- netlink_gen_expr(ctx, stmt->map.key, sreg_key);
+ sreg_key = get_register(ctx, stmt->map.key->key);
+ netlink_gen_expr(ctx, stmt->map.key->key, sreg_key);
sreg_data = get_register(ctx, stmt->map.data);
netlink_gen_expr(ctx, stmt->map.data, sreg_data);
- release_register(ctx, stmt->map.key);
+ release_register(ctx, stmt->map.key->key);
release_register(ctx, stmt->map.data);
nle = alloc_nft_expr("dynset");
@@ -1332,12 +1605,26 @@ static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_OP, stmt->map.op);
nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, set->handle.set.name);
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+
+ if (stmt->map.key->timeout > 0)
+ nftnl_expr_set_u64(nle, NFTNL_EXPR_DYNSET_TIMEOUT,
+ stmt->map.key->timeout);
- if (stmt->map.stmt)
- nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
- netlink_gen_stmt_stateful(ctx, stmt->map.stmt), 0);
+ list_for_each_entry(this, &stmt->map.stmt_list, list)
+ num_stmts++;
- nftnl_rule_add_expr(ctx->nlr, nle);
+ if (num_stmts == 1) {
+ list_for_each_entry(this, &stmt->map.stmt_list, list) {
+ nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
+ netlink_gen_stmt_stateful(this), 0);
+ }
+ } else if (num_stmts > 1) {
+ list_for_each_entry(this, &stmt->map.stmt_list, list) {
+ nftnl_expr_add_expr(nle, NFTNL_EXPR_DYNSET_EXPRESSIONS,
+ netlink_gen_stmt_stateful(this));
+ }
+ }
}
static void netlink_gen_meter_stmt(struct netlink_linearize_ctx *ctx,
@@ -1367,8 +1654,14 @@ static void netlink_gen_meter_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, set->handle.set.name);
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
- netlink_gen_stmt_stateful(ctx, stmt->meter.stmt), 0);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ netlink_gen_stmt_stateful(stmt->meter.stmt), 0);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
+}
+
+static void netlink_gen_chain_stmt(struct netlink_linearize_ctx *ctx,
+ const struct stmt *stmt)
+{
+ return netlink_gen_expr(ctx, stmt->chain.expr, NFT_REG_VERDICT);
}
static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
@@ -1413,8 +1706,9 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
case STMT_COUNTER:
case STMT_LIMIT:
case STMT_QUOTA:
- nle = netlink_gen_stmt_stateful(ctx, stmt);
- nftnl_rule_add_expr(ctx->nlr, nle);
+ case STMT_LAST:
+ nle = netlink_gen_stmt_stateful(stmt);
+ nft_rule_add_expr(ctx, nle, &stmt->location);
break;
case STMT_NOTRACK:
return netlink_gen_notrack_stmt(ctx, stmt);
@@ -1424,23 +1718,49 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
return netlink_gen_objref_stmt(ctx, stmt);
case STMT_MAP:
return netlink_gen_map_stmt(ctx, stmt);
+ case STMT_CHAIN:
+ return netlink_gen_chain_stmt(ctx, stmt);
+ case STMT_OPTSTRIP:
+ return netlink_gen_optstrip_stmt(ctx, stmt);
default:
BUG("unknown statement type %s\n", stmt->ops->name);
}
}
-void netlink_linearize_rule(struct netlink_ctx *ctx, struct nftnl_rule *nlr,
- const struct rule *rule)
+void netlink_linearize_init(struct netlink_linearize_ctx *lctx,
+ struct nftnl_rule *nlr)
{
- struct netlink_linearize_ctx lctx;
- const struct stmt *stmt;
+ int i;
- memset(&lctx, 0, sizeof(lctx));
- lctx.reg_low = NFT_REG_1;
- lctx.nlr = nlr;
+ memset(lctx, 0, sizeof(*lctx));
+ lctx->reg_low = NFT_REG_1;
+ lctx->nlr = nlr;
+ lctx->expr_loc_htable =
+ xmalloc(sizeof(struct list_head) * NFT_EXPR_LOC_HSIZE);
+ for (i = 0; i < NFT_EXPR_LOC_HSIZE; i++)
+ init_list_head(&lctx->expr_loc_htable[i]);
+}
+
+void netlink_linearize_fini(struct netlink_linearize_ctx *lctx)
+{
+ struct nft_expr_loc *eloc, *next;
+ int i;
+
+ for (i = 0; i < NFT_EXPR_LOC_HSIZE; i++) {
+ list_for_each_entry_safe(eloc, next, &lctx->expr_loc_htable[i], hlist)
+ free(eloc);
+ }
+ free(lctx->expr_loc_htable);
+}
+
+void netlink_linearize_rule(struct netlink_ctx *ctx,
+ const struct rule *rule,
+ struct netlink_linearize_ctx *lctx)
+{
+ const struct stmt *stmt;
list_for_each_entry(stmt, &rule->stmts, list)
- netlink_gen_stmt(&lctx, stmt);
+ netlink_gen_stmt(lctx, stmt);
if (rule->comment) {
struct nftnl_udata_buf *udata;
@@ -1452,12 +1772,23 @@ void netlink_linearize_rule(struct netlink_ctx *ctx, struct nftnl_rule *nlr,
if (!nftnl_udata_put_strz(udata, NFTNL_UDATA_RULE_COMMENT,
rule->comment))
memory_allocation_error();
- nftnl_rule_set_data(nlr, NFTNL_RULE_USERDATA,
+ nftnl_rule_set_data(lctx->nlr, NFTNL_RULE_USERDATA,
nftnl_udata_buf_data(udata),
nftnl_udata_buf_len(udata));
nftnl_udata_buf_free(udata);
}
- netlink_dump_rule(nlr, ctx);
+ if (ctx->nft->debug_mask & NFT_DEBUG_NETLINK) {
+ nftnl_rule_set_str(lctx->nlr, NFTNL_RULE_TABLE,
+ rule->handle.table.name);
+ if (rule->handle.chain.name)
+ nftnl_rule_set_str(lctx->nlr, NFTNL_RULE_CHAIN,
+ rule->handle.chain.name);
+
+ netlink_dump_rule(lctx->nlr, ctx);
+
+ nftnl_rule_unset(lctx->nlr, NFTNL_RULE_CHAIN);
+ nftnl_rule_unset(lctx->nlr, NFTNL_RULE_TABLE);
+ }
}
diff --git a/src/nfnl_osf.c b/src/nfnl_osf.c
index 08e978de..20a1bfe7 100644
--- a/src/nfnl_osf.c
+++ b/src/nfnl_osf.c
@@ -19,12 +19,12 @@
* Based on iptables/utils/nfnl_osf.c.
*/
+#include <nft.h>
+
#include <sys/time.h>
#include <ctype.h>
#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
#include <time.h>
#include <netinet/ip.h>
diff --git a/src/nftutils.c b/src/nftutils.c
new file mode 100644
index 00000000..ca178aa0
--- /dev/null
+++ b/src/nftutils.c
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <nft.h>
+
+#include "nftutils.h"
+
+#include <netdb.h>
+
+/* Buffer size used for getprotobynumber_r() and similar. The manual comments
+ * that a buffer of 1024 should be sufficient "for most applications"(??), so
+ * let's double it. It still fits reasonably on the stack, so no need to
+ * choose a smaller one. */
+#define NETDB_BUFSIZE 2048
+
+bool nft_getprotobynumber(int proto, char *out_name, size_t name_len)
+{
+ const struct protoent *result;
+
+#if HAVE_DECL_GETPROTOBYNUMBER_R
+ struct protoent result_buf;
+ char buf[NETDB_BUFSIZE];
+ int r;
+
+ r = getprotobynumber_r(proto,
+ &result_buf,
+ buf,
+ sizeof(buf),
+ (struct protoent **) &result);
+ if (r != 0 || result != &result_buf)
+ result = NULL;
+#else
+ result = getprotobynumber(proto);
+#endif
+
+ if (!result)
+ return false;
+
+ if (strlen(result->p_name) >= name_len)
+ return false;
+ strcpy(out_name, result->p_name);
+ return true;
+}
+
+int nft_getprotobyname(const char *name)
+{
+ const struct protoent *result;
+
+#if HAVE_DECL_GETPROTOBYNAME_R
+ struct protoent result_buf;
+ char buf[NETDB_BUFSIZE];
+ int r;
+
+ r = getprotobyname_r(name,
+ &result_buf,
+ buf,
+ sizeof(buf),
+ (struct protoent **) &result);
+ if (r != 0 || result != &result_buf)
+ result = NULL;
+#else
+ result = getprotobyname(name);
+#endif
+
+ if (!result)
+ return -1;
+
+ if (result->p_proto < 0 || result->p_proto > UINT8_MAX)
+ return -1;
+ return (uint8_t) result->p_proto;
+}
+
+bool nft_getservbyport(int port, const char *proto, char *out_name, size_t name_len)
+{
+ const struct servent *result;
+
+#if HAVE_DECL_GETSERVBYPORT_R
+ struct servent result_buf;
+ char buf[NETDB_BUFSIZE];
+ int r;
+
+ r = getservbyport_r(port,
+ proto,
+ &result_buf,
+ buf,
+ sizeof(buf),
+ (struct servent**) &result);
+ if (r != 0 || result != &result_buf)
+ result = NULL;
+#else
+ result = getservbyport(port, proto);
+#endif
+
+ if (!result)
+ return false;
+
+ if (strlen(result->s_name) >= name_len)
+ return false;
+ strcpy(out_name, result->s_name);
+ return true;
+}
diff --git a/src/nftutils.h b/src/nftutils.h
new file mode 100644
index 00000000..7db56f42
--- /dev/null
+++ b/src/nftutils.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+#ifndef NFTUTILS_H
+#define NFTUTILS_H
+
+#include <stddef.h>
+
+/* The maximum buffer size for (struct protoent).p_name. It is excessively large,
+ * while still reasonably fitting on the stack. Arbitrarily chosen. */
+#define NFT_PROTONAME_MAXSIZE 1024
+
+bool nft_getprotobynumber(int number, char *out_name, size_t name_len);
+int nft_getprotobyname(const char *name);
+
+/* The maximum buffer size for (struct servent).s_name. It is excessively large,
+ * while still reasonably fitting on the stack. Arbitrarily chosen. */
+#define NFT_SERVNAME_MAXSIZE 1024
+
+bool nft_getservbyport(int port, const char *proto, char *out_name, size_t name_len);
+
+#endif /* NFTUTILS_H */
diff --git a/src/numgen.c b/src/numgen.c
index 8318d0a2..3029fa58 100644
--- a/src/numgen.c
+++ b/src/numgen.c
@@ -4,10 +4,12 @@
* Copyright (c) 2016 Pablo Neira Ayuso <pablo@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
*/
+#include <nft.h>
+
#include <nftables.h>
#include <expression.h>
#include <datatype.h>
@@ -51,6 +53,66 @@ static void numgen_expr_clone(struct expr *new, const struct expr *expr)
new->numgen.offset = expr->numgen.offset;
}
+#define NFTNL_UDATA_NUMGEN_TYPE 0
+#define NFTNL_UDATA_NUMGEN_MOD 1
+#define NFTNL_UDATA_NUMGEN_OFFSET 2
+#define NFTNL_UDATA_NUMGEN_MAX 3
+
+static int numgen_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_NUMGEN_TYPE, expr->numgen.type);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_NUMGEN_MOD, expr->numgen.mod);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_NUMGEN_OFFSET, expr->numgen.offset);
+
+ return 0;
+}
+
+static int numgen_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_NUMGEN_TYPE:
+ case NFTNL_UDATA_NUMGEN_MOD:
+ case NFTNL_UDATA_NUMGEN_OFFSET:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *numgen_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_NUMGEN_MAX + 1] = {};
+ enum nft_ng_types type;
+ uint32_t mod, offset;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ numgen_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_NUMGEN_TYPE] ||
+ !ud[NFTNL_UDATA_NUMGEN_MOD] ||
+ !ud[NFTNL_UDATA_NUMGEN_OFFSET])
+ return NULL;
+
+ type = nftnl_udata_get_u32(ud[NFTNL_UDATA_NUMGEN_TYPE]);
+ mod = nftnl_udata_get_u32(ud[NFTNL_UDATA_NUMGEN_MOD]);
+ offset = nftnl_udata_get_u32(ud[NFTNL_UDATA_NUMGEN_OFFSET]);
+
+ return numgen_expr_alloc(&internal_location, type, mod, offset);
+}
+
const struct expr_ops numgen_expr_ops = {
.type = EXPR_NUMGEN,
.name = "numgen",
@@ -58,6 +120,8 @@ const struct expr_ops numgen_expr_ops = {
.json = numgen_expr_json,
.cmp = numgen_expr_cmp,
.clone = numgen_expr_clone,
+ .parse_udata = numgen_expr_parse_udata,
+ .build_udata = numgen_expr_build_udata,
};
struct expr *numgen_expr_alloc(const struct location *loc,
diff --git a/src/optimize.c b/src/optimize.c
new file mode 100644
index 00000000..b90dd995
--- /dev/null
+++ b/src/optimize.c
@@ -0,0 +1,1406 @@
+/*
+ * Copyright (c) 2021 Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+/* Funded through the NGI0 PET Fund established by NLnet (https://nlnet.nl)
+ * with support from the European Commission's Next Generation Internet
+ * programme.
+ */
+
+#include <nft.h>
+
+#include <errno.h>
+#include <inttypes.h>
+#include <nftables.h>
+#include <parser.h>
+#include <expression.h>
+#include <statement.h>
+#include <utils.h>
+#include <erec.h>
+#include <linux/netfilter.h>
+
+#define MAX_STMTS 32
+
+struct optimize_ctx {
+ struct stmt *stmt[MAX_STMTS];
+ uint32_t num_stmts;
+
+ struct stmt ***stmt_matrix;
+ struct rule **rule;
+ uint32_t num_rules;
+};
+
+static bool __expr_cmp(const struct expr *expr_a, const struct expr *expr_b)
+{
+ if (expr_a->etype != expr_b->etype)
+ return false;
+
+ switch (expr_a->etype) {
+ case EXPR_PAYLOAD:
+ if (expr_a->payload.base != expr_b->payload.base)
+ return false;
+ if (expr_a->payload.offset != expr_b->payload.offset)
+ return false;
+ if (expr_a->payload.desc != expr_b->payload.desc)
+ return false;
+ if (expr_a->payload.inner_desc != expr_b->payload.inner_desc)
+ return false;
+ if (expr_a->payload.tmpl != expr_b->payload.tmpl)
+ return false;
+ break;
+ case EXPR_EXTHDR:
+ if (expr_a->exthdr.desc != expr_b->exthdr.desc)
+ return false;
+ if (expr_a->exthdr.tmpl != expr_b->exthdr.tmpl)
+ return false;
+ break;
+ case EXPR_META:
+ if (expr_a->meta.key != expr_b->meta.key)
+ return false;
+ if (expr_a->meta.base != expr_b->meta.base)
+ return false;
+ break;
+ case EXPR_CT:
+ if (expr_a->ct.key != expr_b->ct.key)
+ return false;
+ if (expr_a->ct.base != expr_b->ct.base)
+ return false;
+ if (expr_a->ct.direction != expr_b->ct.direction)
+ return false;
+ if (expr_a->ct.nfproto != expr_b->ct.nfproto)
+ return false;
+ break;
+ case EXPR_RT:
+ if (expr_a->rt.key != expr_b->rt.key)
+ return false;
+ break;
+ case EXPR_SOCKET:
+ if (expr_a->socket.key != expr_b->socket.key)
+ return false;
+ if (expr_a->socket.level != expr_b->socket.level)
+ return false;
+ break;
+ case EXPR_OSF:
+ if (expr_a->osf.ttl != expr_b->osf.ttl)
+ return false;
+ if (expr_a->osf.flags != expr_b->osf.flags)
+ return false;
+ break;
+ case EXPR_XFRM:
+ if (expr_a->xfrm.key != expr_b->xfrm.key)
+ return false;
+ if (expr_a->xfrm.direction != expr_b->xfrm.direction)
+ return false;
+ break;
+ case EXPR_FIB:
+ if (expr_a->fib.flags != expr_b->fib.flags)
+ return false;
+ if (expr_a->fib.result != expr_b->fib.result)
+ return false;
+ break;
+ case EXPR_NUMGEN:
+ if (expr_a->numgen.type != expr_b->numgen.type)
+ return false;
+ if (expr_a->numgen.mod != expr_b->numgen.mod)
+ return false;
+ if (expr_a->numgen.offset != expr_b->numgen.offset)
+ return false;
+ break;
+ case EXPR_HASH:
+ if (expr_a->hash.mod != expr_b->hash.mod)
+ return false;
+ if (expr_a->hash.seed_set != expr_b->hash.seed_set)
+ return false;
+ if (expr_a->hash.seed != expr_b->hash.seed)
+ return false;
+ if (expr_a->hash.offset != expr_b->hash.offset)
+ return false;
+ if (expr_a->hash.type != expr_b->hash.type)
+ return false;
+ break;
+ case EXPR_BINOP:
+ return __expr_cmp(expr_a->left, expr_b->left);
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+static bool stmt_expr_supported(const struct expr *expr)
+{
+ switch (expr->right->etype) {
+ case EXPR_SYMBOL:
+ case EXPR_RANGE:
+ case EXPR_PREFIX:
+ case EXPR_SET:
+ case EXPR_LIST:
+ case EXPR_VALUE:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool expr_symbol_set(const struct expr *expr)
+{
+ return expr->right->etype == EXPR_SYMBOL &&
+ expr->right->symtype == SYMBOL_SET;
+}
+
+static bool __stmt_type_eq(const struct stmt *stmt_a, const struct stmt *stmt_b,
+ bool fully_compare)
+{
+ struct expr *expr_a, *expr_b;
+
+ if (stmt_a->ops->type != stmt_b->ops->type)
+ return false;
+
+ switch (stmt_a->ops->type) {
+ case STMT_EXPRESSION:
+ expr_a = stmt_a->expr;
+ expr_b = stmt_b->expr;
+
+ if (expr_a->op != expr_b->op)
+ return false;
+ if (expr_a->op != OP_IMPLICIT && expr_a->op != OP_EQ)
+ return false;
+
+ if (fully_compare) {
+ if (!stmt_expr_supported(expr_a) ||
+ !stmt_expr_supported(expr_b))
+ return false;
+
+ if (expr_symbol_set(expr_a) ||
+ expr_symbol_set(expr_b))
+ return false;
+ }
+
+ return __expr_cmp(expr_a->left, expr_b->left);
+ case STMT_COUNTER:
+ case STMT_NOTRACK:
+ break;
+ case STMT_VERDICT:
+ if (!fully_compare)
+ break;
+
+ expr_a = stmt_a->expr;
+ expr_b = stmt_b->expr;
+
+ if (expr_a->etype != expr_b->etype)
+ return false;
+
+ if (expr_a->etype == EXPR_MAP &&
+ expr_b->etype == EXPR_MAP)
+ return __expr_cmp(expr_a->map, expr_b->map);
+ break;
+ case STMT_LOG:
+ if (stmt_a->log.snaplen != stmt_b->log.snaplen ||
+ stmt_a->log.group != stmt_b->log.group ||
+ stmt_a->log.qthreshold != stmt_b->log.qthreshold ||
+ stmt_a->log.level != stmt_b->log.level ||
+ stmt_a->log.logflags != stmt_b->log.logflags ||
+ stmt_a->log.flags != stmt_b->log.flags)
+ return false;
+
+ if (!!stmt_a->log.prefix ^ !!stmt_b->log.prefix)
+ return false;
+
+ if (!stmt_a->log.prefix)
+ return true;
+
+ if (stmt_a->log.prefix->etype != EXPR_VALUE ||
+ stmt_b->log.prefix->etype != EXPR_VALUE ||
+ mpz_cmp(stmt_a->log.prefix->value, stmt_b->log.prefix->value))
+ return false;
+ break;
+ case STMT_REJECT:
+ if (stmt_a->reject.family != stmt_b->reject.family ||
+ stmt_a->reject.type != stmt_b->reject.type ||
+ stmt_a->reject.icmp_code != stmt_b->reject.icmp_code)
+ return false;
+
+ if (!!stmt_a->reject.expr ^ !!stmt_b->reject.expr)
+ return false;
+
+ if (!stmt_a->reject.expr)
+ return true;
+
+ if (__expr_cmp(stmt_a->reject.expr, stmt_b->reject.expr))
+ return false;
+ break;
+ case STMT_NAT:
+ if (stmt_a->nat.type != stmt_b->nat.type ||
+ stmt_a->nat.flags != stmt_b->nat.flags ||
+ stmt_a->nat.family != stmt_b->nat.family ||
+ stmt_a->nat.type_flags != stmt_b->nat.type_flags)
+ return false;
+
+ switch (stmt_a->nat.type) {
+ case NFT_NAT_SNAT:
+ case NFT_NAT_DNAT:
+ if ((stmt_a->nat.addr &&
+ stmt_a->nat.addr->etype != EXPR_SYMBOL &&
+ stmt_a->nat.addr->etype != EXPR_RANGE) ||
+ (stmt_b->nat.addr &&
+ stmt_b->nat.addr->etype != EXPR_SYMBOL &&
+ stmt_b->nat.addr->etype != EXPR_RANGE) ||
+ (stmt_a->nat.proto &&
+ stmt_a->nat.proto->etype != EXPR_SYMBOL &&
+ stmt_a->nat.proto->etype != EXPR_RANGE) ||
+ (stmt_b->nat.proto &&
+ stmt_b->nat.proto->etype != EXPR_SYMBOL &&
+ stmt_b->nat.proto->etype != EXPR_RANGE))
+ return false;
+ break;
+ case NFT_NAT_MASQ:
+ break;
+ case NFT_NAT_REDIR:
+ if ((stmt_a->nat.proto &&
+ stmt_a->nat.proto->etype != EXPR_SYMBOL &&
+ stmt_a->nat.proto->etype != EXPR_RANGE) ||
+ (stmt_b->nat.proto &&
+ stmt_b->nat.proto->etype != EXPR_SYMBOL &&
+ stmt_b->nat.proto->etype != EXPR_RANGE))
+ return false;
+
+ /* it should be possible to infer implicit redirections
+ * such as:
+ *
+ * tcp dport 1234 redirect
+ * tcp dport 3456 redirect to :7890
+ * merge:
+ * redirect to tcp dport map { 1234 : 1234, 3456 : 7890 }
+ *
+ * currently not implemented.
+ */
+ if (fully_compare &&
+ stmt_a->nat.type == NFT_NAT_REDIR &&
+ stmt_b->nat.type == NFT_NAT_REDIR &&
+ (!!stmt_a->nat.proto ^ !!stmt_b->nat.proto))
+ return false;
+
+ break;
+ default:
+ assert(0);
+ }
+
+ return true;
+ default:
+ /* ... Merging anything else is yet unsupported. */
+ return false;
+ }
+
+ return true;
+}
+
+static bool expr_verdict_eq(const struct expr *expr_a, const struct expr *expr_b)
+{
+ if (expr_a->verdict != expr_b->verdict)
+ return false;
+ if (expr_a->chain && expr_b->chain) {
+ if (expr_a->chain->etype != expr_b->chain->etype)
+ return false;
+ if (expr_a->chain->etype == EXPR_VALUE &&
+ strcmp(expr_a->chain->identifier, expr_b->chain->identifier))
+ return false;
+ } else if (expr_a->chain || expr_b->chain) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool stmt_verdict_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
+{
+ struct expr *expr_a, *expr_b;
+
+ assert (stmt_a->ops->type == STMT_VERDICT);
+
+ expr_a = stmt_a->expr;
+ expr_b = stmt_b->expr;
+ if (expr_a->etype == EXPR_VERDICT &&
+ expr_b->etype == EXPR_VERDICT)
+ return expr_verdict_eq(expr_a, expr_b);
+
+ if (expr_a->etype == EXPR_MAP &&
+ expr_b->etype == EXPR_MAP)
+ return __expr_cmp(expr_a->map, expr_b->map);
+
+ return false;
+}
+
+static bool stmt_type_find(struct optimize_ctx *ctx, const struct stmt *stmt)
+{
+ bool unsupported_exists = false;
+ uint32_t i;
+
+ for (i = 0; i < ctx->num_stmts; i++) {
+ if (ctx->stmt[i]->ops->type == STMT_INVALID)
+ unsupported_exists = true;
+
+ if (__stmt_type_eq(stmt, ctx->stmt[i], false))
+ return true;
+ }
+
+ switch (stmt->ops->type) {
+ case STMT_EXPRESSION:
+ case STMT_VERDICT:
+ case STMT_COUNTER:
+ case STMT_NOTRACK:
+ case STMT_LOG:
+ case STMT_NAT:
+ case STMT_REJECT:
+ break;
+ default:
+ /* add unsupported statement only once to statement matrix. */
+ if (unsupported_exists)
+ return true;
+ break;
+ }
+
+ return false;
+}
+
+static struct stmt_ops unsupported_stmt_ops = {
+ .type = STMT_INVALID,
+ .name = "unsupported",
+};
+
+static int rule_collect_stmts(struct optimize_ctx *ctx, struct rule *rule)
+{
+ struct stmt *stmt, *clone;
+
+ list_for_each_entry(stmt, &rule->stmts, list) {
+ if (stmt_type_find(ctx, stmt))
+ continue;
+
+ /* No refcounter available in statement objects, clone it to
+ * to store in the array of selectors.
+ */
+ clone = stmt_alloc(&internal_location, stmt->ops);
+ switch (stmt->ops->type) {
+ case STMT_EXPRESSION:
+ if (stmt->expr->op != OP_IMPLICIT &&
+ stmt->expr->op != OP_EQ) {
+ clone->ops = &unsupported_stmt_ops;
+ break;
+ }
+ if (stmt->expr->left->etype == EXPR_CONCAT) {
+ clone->ops = &unsupported_stmt_ops;
+ break;
+ }
+ /* fall-through */
+ case STMT_VERDICT:
+ clone->expr = expr_get(stmt->expr);
+ break;
+ case STMT_COUNTER:
+ case STMT_NOTRACK:
+ break;
+ case STMT_LOG:
+ memcpy(&clone->log, &stmt->log, sizeof(clone->log));
+ if (stmt->log.prefix)
+ clone->log.prefix = expr_get(stmt->log.prefix);
+ break;
+ case STMT_NAT:
+ if ((stmt->nat.addr &&
+ stmt->nat.addr->etype == EXPR_MAP) ||
+ (stmt->nat.proto &&
+ stmt->nat.proto->etype == EXPR_MAP)) {
+ clone->ops = &unsupported_stmt_ops;
+ break;
+ }
+ clone->nat.type = stmt->nat.type;
+ clone->nat.family = stmt->nat.family;
+ if (stmt->nat.addr)
+ clone->nat.addr = expr_clone(stmt->nat.addr);
+ if (stmt->nat.proto)
+ clone->nat.proto = expr_clone(stmt->nat.proto);
+ clone->nat.flags = stmt->nat.flags;
+ clone->nat.type_flags = stmt->nat.type_flags;
+ break;
+ case STMT_REJECT:
+ if (stmt->reject.expr)
+ clone->reject.expr = expr_get(stmt->reject.expr);
+ clone->reject.type = stmt->reject.type;
+ clone->reject.icmp_code = stmt->reject.icmp_code;
+ clone->reject.family = stmt->reject.family;
+ break;
+ default:
+ clone->ops = &unsupported_stmt_ops;
+ break;
+ }
+
+ ctx->stmt[ctx->num_stmts++] = clone;
+ if (ctx->num_stmts >= MAX_STMTS)
+ return -1;
+ }
+
+ return 0;
+}
+
+static int unsupported_in_stmt_matrix(const struct optimize_ctx *ctx)
+{
+ uint32_t i;
+
+ for (i = 0; i < ctx->num_stmts; i++) {
+ if (ctx->stmt[i]->ops->type == STMT_INVALID)
+ return i;
+ }
+ /* this should not happen. */
+ return -1;
+}
+
+static int cmd_stmt_find_in_stmt_matrix(struct optimize_ctx *ctx, struct stmt *stmt)
+{
+ uint32_t i;
+
+ for (i = 0; i < ctx->num_stmts; i++) {
+ if (__stmt_type_eq(stmt, ctx->stmt[i], false))
+ return i;
+ }
+
+ return -1;
+}
+
+static struct stmt unsupported_stmt = {
+ .ops = &unsupported_stmt_ops,
+};
+
+static void rule_build_stmt_matrix_stmts(struct optimize_ctx *ctx,
+ struct rule *rule, uint32_t *i)
+{
+ struct stmt *stmt;
+ int k;
+
+ list_for_each_entry(stmt, &rule->stmts, list) {
+ k = cmd_stmt_find_in_stmt_matrix(ctx, stmt);
+ if (k < 0) {
+ k = unsupported_in_stmt_matrix(ctx);
+ assert(k >= 0);
+ ctx->stmt_matrix[*i][k] = &unsupported_stmt;
+ continue;
+ }
+ ctx->stmt_matrix[*i][k] = stmt;
+ }
+ ctx->rule[(*i)++] = rule;
+}
+
+static int stmt_verdict_find(const struct optimize_ctx *ctx)
+{
+ uint32_t i;
+
+ for (i = 0; i < ctx->num_stmts; i++) {
+ if (ctx->stmt[i]->ops->type != STMT_VERDICT)
+ continue;
+
+ return i;
+ }
+
+ return -1;
+}
+
+struct merge {
+ /* interval of rules to be merged */
+ uint32_t rule_from;
+ uint32_t num_rules;
+ /* statements to be merged (index relative to statement matrix) */
+ uint32_t stmt[MAX_STMTS];
+ uint32_t num_stmts;
+};
+
+static void merge_expr_stmts(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge,
+ struct stmt *stmt_a)
+{
+ struct expr *expr_a, *expr_b, *set, *elem;
+ struct stmt *stmt_b;
+ uint32_t i;
+
+ set = set_expr_alloc(&internal_location, NULL);
+ set->set_flags |= NFT_SET_ANONYMOUS;
+
+ expr_a = stmt_a->expr->right;
+ elem = set_elem_expr_alloc(&internal_location, expr_get(expr_a));
+ compound_expr_add(set, elem);
+
+ for (i = from + 1; i <= to; i++) {
+ stmt_b = ctx->stmt_matrix[i][merge->stmt[0]];
+ expr_b = stmt_b->expr->right;
+ elem = set_elem_expr_alloc(&internal_location, expr_get(expr_b));
+ compound_expr_add(set, elem);
+ }
+
+ expr_free(stmt_a->expr->right);
+ stmt_a->expr->right = set;
+}
+
+static void merge_vmap(const struct optimize_ctx *ctx,
+ struct stmt *stmt_a, const struct stmt *stmt_b)
+{
+ struct expr *mappings, *mapping, *expr;
+
+ mappings = stmt_b->expr->mappings;
+ list_for_each_entry(expr, &mappings->expressions, list) {
+ mapping = expr_clone(expr);
+ compound_expr_add(stmt_a->expr->mappings, mapping);
+ }
+}
+
+static void merge_verdict_stmts(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge,
+ struct stmt *stmt_a)
+{
+ struct stmt *stmt_b;
+ uint32_t i;
+
+ for (i = from + 1; i <= to; i++) {
+ stmt_b = ctx->stmt_matrix[i][merge->stmt[0]];
+ switch (stmt_b->ops->type) {
+ case STMT_VERDICT:
+ switch (stmt_b->expr->etype) {
+ case EXPR_MAP:
+ merge_vmap(ctx, stmt_a, stmt_b);
+ break;
+ default:
+ assert(0);
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+}
+
+static void merge_stmts(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to, const struct merge *merge)
+{
+ struct stmt *stmt_a = ctx->stmt_matrix[from][merge->stmt[0]];
+
+ switch (stmt_a->ops->type) {
+ case STMT_EXPRESSION:
+ merge_expr_stmts(ctx, from, to, merge, stmt_a);
+ break;
+ case STMT_VERDICT:
+ merge_verdict_stmts(ctx, from, to, merge, stmt_a);
+ break;
+ default:
+ assert(0);
+ }
+}
+
+static void __merge_concat(const struct optimize_ctx *ctx, uint32_t i,
+ const struct merge *merge, struct list_head *concat_list)
+{
+ struct expr *concat, *next, *expr, *concat_clone, *clone;
+ LIST_HEAD(pending_list);
+ struct stmt *stmt_a;
+ uint32_t k;
+
+ concat = concat_expr_alloc(&internal_location);
+ list_add(&concat->list, concat_list);
+
+ for (k = 0; k < merge->num_stmts; k++) {
+ list_for_each_entry_safe(concat, next, concat_list, list) {
+ stmt_a = ctx->stmt_matrix[i][merge->stmt[k]];
+ switch (stmt_a->expr->right->etype) {
+ case EXPR_SET:
+ list_for_each_entry(expr, &stmt_a->expr->right->expressions, list) {
+ concat_clone = expr_clone(concat);
+ clone = expr_clone(expr->key);
+ compound_expr_add(concat_clone, clone);
+ list_add_tail(&concat_clone->list, &pending_list);
+ }
+ list_del(&concat->list);
+ expr_free(concat);
+ break;
+ case EXPR_SYMBOL:
+ case EXPR_VALUE:
+ case EXPR_PREFIX:
+ case EXPR_RANGE:
+ clone = expr_clone(stmt_a->expr->right);
+ compound_expr_add(concat, clone);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ }
+ list_splice_init(&pending_list, concat_list);
+ }
+}
+
+static void __merge_concat_stmts(const struct optimize_ctx *ctx, uint32_t i,
+ const struct merge *merge, struct expr *set)
+{
+ struct expr *concat, *next, *elem;
+ LIST_HEAD(concat_list);
+
+ __merge_concat(ctx, i, merge, &concat_list);
+
+ list_for_each_entry_safe(concat, next, &concat_list, list) {
+ list_del(&concat->list);
+ elem = set_elem_expr_alloc(&internal_location, concat);
+ compound_expr_add(set, elem);
+ }
+}
+
+static void merge_concat_stmts(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge)
+{
+ struct stmt *stmt, *stmt_a;
+ struct expr *concat, *set;
+ uint32_t i, k;
+
+ stmt = ctx->stmt_matrix[from][merge->stmt[0]];
+ /* build concatenation of selectors, eg. ifname . ip daddr . tcp dport */
+ concat = concat_expr_alloc(&internal_location);
+
+ for (k = 0; k < merge->num_stmts; k++) {
+ stmt_a = ctx->stmt_matrix[from][merge->stmt[k]];
+ compound_expr_add(concat, expr_get(stmt_a->expr->left));
+ }
+ expr_free(stmt->expr->left);
+ stmt->expr->left = concat;
+
+ /* build set data contenation, eg. { eth0 . 1.1.1.1 . 22 } */
+ set = set_expr_alloc(&internal_location, NULL);
+ set->set_flags |= NFT_SET_ANONYMOUS;
+
+ for (i = from; i <= to; i++)
+ __merge_concat_stmts(ctx, i, merge, set);
+
+ expr_free(stmt->expr->right);
+ stmt->expr->right = set;
+
+ for (k = 1; k < merge->num_stmts; k++) {
+ stmt_a = ctx->stmt_matrix[from][merge->stmt[k]];
+ list_del(&stmt_a->list);
+ stmt_free(stmt_a);
+ }
+}
+
+static void build_verdict_map(struct expr *expr, struct stmt *verdict,
+ struct expr *set, struct stmt *counter)
+{
+ struct expr *item, *elem, *mapping;
+
+ switch (expr->etype) {
+ case EXPR_LIST:
+ list_for_each_entry(item, &expr->expressions, list) {
+ elem = set_elem_expr_alloc(&internal_location, expr_get(item));
+ if (counter)
+ list_add_tail(&counter->list, &elem->stmt_list);
+
+ mapping = mapping_expr_alloc(&internal_location, elem,
+ expr_get(verdict->expr));
+ compound_expr_add(set, mapping);
+ }
+ break;
+ case EXPR_SET:
+ list_for_each_entry(item, &expr->expressions, list) {
+ elem = set_elem_expr_alloc(&internal_location, expr_get(item->key));
+ if (counter)
+ list_add_tail(&counter->list, &elem->stmt_list);
+
+ mapping = mapping_expr_alloc(&internal_location, elem,
+ expr_get(verdict->expr));
+ compound_expr_add(set, mapping);
+ }
+ break;
+ case EXPR_PREFIX:
+ case EXPR_RANGE:
+ case EXPR_VALUE:
+ case EXPR_SYMBOL:
+ case EXPR_CONCAT:
+ elem = set_elem_expr_alloc(&internal_location, expr_get(expr));
+ if (counter)
+ list_add_tail(&counter->list, &elem->stmt_list);
+
+ mapping = mapping_expr_alloc(&internal_location, elem,
+ expr_get(verdict->expr));
+ compound_expr_add(set, mapping);
+ break;
+ default:
+ assert(0);
+ break;
+ }
+}
+
+static void remove_counter(const struct optimize_ctx *ctx, uint32_t from)
+{
+ struct stmt *stmt;
+ uint32_t i;
+
+ /* remove counter statement */
+ for (i = 0; i < ctx->num_stmts; i++) {
+ stmt = ctx->stmt_matrix[from][i];
+ if (!stmt)
+ continue;
+
+ if (stmt->ops->type == STMT_COUNTER) {
+ list_del(&stmt->list);
+ stmt_free(stmt);
+ }
+ }
+}
+
+static struct stmt *zap_counter(const struct optimize_ctx *ctx, uint32_t from)
+{
+ struct stmt *stmt;
+ uint32_t i;
+
+ /* remove counter statement */
+ for (i = 0; i < ctx->num_stmts; i++) {
+ stmt = ctx->stmt_matrix[from][i];
+ if (!stmt)
+ continue;
+
+ if (stmt->ops->type == STMT_COUNTER) {
+ list_del(&stmt->list);
+ return stmt;
+ }
+ }
+
+ return NULL;
+}
+
+static void merge_stmts_vmap(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge)
+{
+ struct stmt *stmt_a = ctx->stmt_matrix[from][merge->stmt[0]];
+ struct stmt *stmt_b, *verdict_a, *verdict_b, *stmt;
+ struct expr *expr_a, *expr_b, *expr, *left, *set;
+ struct stmt *counter;
+ uint32_t i;
+ int k;
+
+ k = stmt_verdict_find(ctx);
+ assert(k >= 0);
+
+ set = set_expr_alloc(&internal_location, NULL);
+ set->set_flags |= NFT_SET_ANONYMOUS;
+
+ expr_a = stmt_a->expr->right;
+ verdict_a = ctx->stmt_matrix[from][k];
+ counter = zap_counter(ctx, from);
+ build_verdict_map(expr_a, verdict_a, set, counter);
+
+ for (i = from + 1; i <= to; i++) {
+ stmt_b = ctx->stmt_matrix[i][merge->stmt[0]];
+ expr_b = stmt_b->expr->right;
+ verdict_b = ctx->stmt_matrix[i][k];
+ counter = zap_counter(ctx, i);
+ build_verdict_map(expr_b, verdict_b, set, counter);
+ }
+
+ left = expr_get(stmt_a->expr->left);
+ expr = map_expr_alloc(&internal_location, left, set);
+ stmt = verdict_stmt_alloc(&internal_location, expr);
+
+ list_add(&stmt->list, &stmt_a->list);
+ list_del(&stmt_a->list);
+ stmt_free(stmt_a);
+ list_del(&verdict_a->list);
+ stmt_free(verdict_a);
+}
+
+static void __merge_concat_stmts_vmap(const struct optimize_ctx *ctx,
+ uint32_t i, const struct merge *merge,
+ struct expr *set, struct stmt *verdict)
+{
+ struct expr *concat, *next, *elem, *mapping;
+ LIST_HEAD(concat_list);
+ struct stmt *counter;
+
+ counter = zap_counter(ctx, i);
+ __merge_concat(ctx, i, merge, &concat_list);
+
+ list_for_each_entry_safe(concat, next, &concat_list, list) {
+ list_del(&concat->list);
+ elem = set_elem_expr_alloc(&internal_location, concat);
+ if (counter)
+ list_add_tail(&counter->list, &elem->stmt_list);
+
+ mapping = mapping_expr_alloc(&internal_location, elem,
+ expr_get(verdict->expr));
+ compound_expr_add(set, mapping);
+ }
+}
+
+static void merge_concat_stmts_vmap(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge)
+{
+ struct stmt *orig_stmt = ctx->stmt_matrix[from][merge->stmt[0]];
+ struct stmt *stmt, *stmt_a, *verdict;
+ struct expr *concat_a, *expr, *set;
+ uint32_t i;
+ int k;
+
+ k = stmt_verdict_find(ctx);
+ assert(k >= 0);
+
+ /* build concatenation of selectors, eg. ifname . ip daddr . tcp dport */
+ concat_a = concat_expr_alloc(&internal_location);
+ for (i = 0; i < merge->num_stmts; i++) {
+ stmt_a = ctx->stmt_matrix[from][merge->stmt[i]];
+ compound_expr_add(concat_a, expr_get(stmt_a->expr->left));
+ }
+
+ /* build set data contenation, eg. { eth0 . 1.1.1.1 . 22 : accept } */
+ set = set_expr_alloc(&internal_location, NULL);
+ set->set_flags |= NFT_SET_ANONYMOUS;
+
+ for (i = from; i <= to; i++) {
+ verdict = ctx->stmt_matrix[i][k];
+ __merge_concat_stmts_vmap(ctx, i, merge, set, verdict);
+ }
+
+ expr = map_expr_alloc(&internal_location, concat_a, set);
+ stmt = verdict_stmt_alloc(&internal_location, expr);
+
+ list_add(&stmt->list, &orig_stmt->list);
+ list_del(&orig_stmt->list);
+ stmt_free(orig_stmt);
+
+ for (i = 1; i < merge->num_stmts; i++) {
+ stmt_a = ctx->stmt_matrix[from][merge->stmt[i]];
+ list_del(&stmt_a->list);
+ stmt_free(stmt_a);
+ }
+
+ verdict = ctx->stmt_matrix[from][k];
+ list_del(&verdict->list);
+ stmt_free(verdict);
+}
+
+static bool stmt_verdict_cmp(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to)
+{
+ struct stmt *stmt_a, *stmt_b;
+ uint32_t i;
+ int k;
+
+ k = stmt_verdict_find(ctx);
+ if (k < 0)
+ return true;
+
+ for (i = from; i + 1 <= to; i++) {
+ stmt_a = ctx->stmt_matrix[i][k];
+ stmt_b = ctx->stmt_matrix[i + 1][k];
+ if (!stmt_a && !stmt_b)
+ continue;
+ if (!stmt_a || !stmt_b)
+ return false;
+ if (!stmt_verdict_eq(stmt_a, stmt_b))
+ return false;
+ }
+
+ return true;
+}
+
+static int stmt_nat_type(const struct optimize_ctx *ctx, int from,
+ enum nft_nat_etypes *nat_type)
+{
+ uint32_t j;
+
+ for (j = 0; j < ctx->num_stmts; j++) {
+ if (!ctx->stmt_matrix[from][j])
+ continue;
+
+ if (ctx->stmt_matrix[from][j]->ops->type == STMT_NAT) {
+ *nat_type = ctx->stmt_matrix[from][j]->nat.type;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+static int stmt_nat_find(const struct optimize_ctx *ctx, int from)
+{
+ enum nft_nat_etypes nat_type;
+ uint32_t i;
+
+ if (stmt_nat_type(ctx, from, &nat_type) < 0)
+ return -1;
+
+ for (i = 0; i < ctx->num_stmts; i++) {
+ if (ctx->stmt[i]->ops->type != STMT_NAT ||
+ ctx->stmt[i]->nat.type != nat_type)
+ continue;
+
+ return i;
+ }
+
+ return -1;
+}
+
+static struct expr *stmt_nat_expr(struct stmt *nat_stmt)
+{
+ struct expr *nat_expr;
+
+ assert(nat_stmt->ops->type == STMT_NAT);
+
+ if (nat_stmt->nat.proto) {
+ if (nat_stmt->nat.addr) {
+ nat_expr = concat_expr_alloc(&internal_location);
+ compound_expr_add(nat_expr, expr_get(nat_stmt->nat.addr));
+ compound_expr_add(nat_expr, expr_get(nat_stmt->nat.proto));
+ } else {
+ nat_expr = expr_get(nat_stmt->nat.proto);
+ }
+ expr_free(nat_stmt->nat.proto);
+ nat_stmt->nat.proto = NULL;
+ } else {
+ nat_expr = expr_get(nat_stmt->nat.addr);
+ }
+
+ assert(nat_expr);
+
+ return nat_expr;
+}
+
+static void merge_nat(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge)
+{
+ struct expr *expr, *set, *elem, *nat_expr, *mapping, *left;
+ int k, family = NFPROTO_UNSPEC;
+ struct stmt *stmt, *nat_stmt;
+ uint32_t i;
+
+ k = stmt_nat_find(ctx, from);
+ assert(k >= 0);
+
+ set = set_expr_alloc(&internal_location, NULL);
+ set->set_flags |= NFT_SET_ANONYMOUS;
+
+ for (i = from; i <= to; i++) {
+ stmt = ctx->stmt_matrix[i][merge->stmt[0]];
+ expr = stmt->expr->right;
+
+ nat_stmt = ctx->stmt_matrix[i][k];
+ nat_expr = stmt_nat_expr(nat_stmt);
+
+ elem = set_elem_expr_alloc(&internal_location, expr_get(expr));
+ mapping = mapping_expr_alloc(&internal_location, elem, nat_expr);
+ compound_expr_add(set, mapping);
+ }
+
+ stmt = ctx->stmt_matrix[from][merge->stmt[0]];
+ left = expr_get(stmt->expr->left);
+ if (left->etype == EXPR_PAYLOAD) {
+ if (left->payload.desc == &proto_ip)
+ family = NFPROTO_IPV4;
+ else if (left->payload.desc == &proto_ip6)
+ family = NFPROTO_IPV6;
+ }
+ expr = map_expr_alloc(&internal_location, left, set);
+
+ nat_stmt = ctx->stmt_matrix[from][k];
+ if (nat_stmt->nat.family == NFPROTO_UNSPEC)
+ nat_stmt->nat.family = family;
+
+ expr_free(nat_stmt->nat.addr);
+ if (nat_stmt->nat.type == NFT_NAT_REDIR)
+ nat_stmt->nat.proto = expr;
+ else
+ nat_stmt->nat.addr = expr;
+
+ remove_counter(ctx, from);
+ list_del(&stmt->list);
+ stmt_free(stmt);
+}
+
+static void merge_concat_nat(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge)
+{
+ struct expr *expr, *set, *elem, *nat_expr, *mapping, *left, *concat;
+ int k, family = NFPROTO_UNSPEC;
+ struct stmt *stmt, *nat_stmt;
+ uint32_t i, j;
+
+ k = stmt_nat_find(ctx, from);
+ assert(k >= 0);
+
+ set = set_expr_alloc(&internal_location, NULL);
+ set->set_flags |= NFT_SET_ANONYMOUS;
+
+ for (i = from; i <= to; i++) {
+
+ concat = concat_expr_alloc(&internal_location);
+ for (j = 0; j < merge->num_stmts; j++) {
+ stmt = ctx->stmt_matrix[i][merge->stmt[j]];
+ expr = stmt->expr->right;
+ compound_expr_add(concat, expr_get(expr));
+ }
+
+ nat_stmt = ctx->stmt_matrix[i][k];
+ nat_expr = stmt_nat_expr(nat_stmt);
+
+ elem = set_elem_expr_alloc(&internal_location, concat);
+ mapping = mapping_expr_alloc(&internal_location, elem, nat_expr);
+ compound_expr_add(set, mapping);
+ }
+
+ concat = concat_expr_alloc(&internal_location);
+ for (j = 0; j < merge->num_stmts; j++) {
+ stmt = ctx->stmt_matrix[from][merge->stmt[j]];
+ left = stmt->expr->left;
+ if (left->etype == EXPR_PAYLOAD) {
+ if (left->payload.desc == &proto_ip)
+ family = NFPROTO_IPV4;
+ else if (left->payload.desc == &proto_ip6)
+ family = NFPROTO_IPV6;
+ }
+ compound_expr_add(concat, expr_get(left));
+ }
+ expr = map_expr_alloc(&internal_location, concat, set);
+
+ nat_stmt = ctx->stmt_matrix[from][k];
+ if (nat_stmt->nat.family == NFPROTO_UNSPEC)
+ nat_stmt->nat.family = family;
+
+ expr_free(nat_stmt->nat.addr);
+ nat_stmt->nat.addr = expr;
+
+ remove_counter(ctx, from);
+ for (j = 0; j < merge->num_stmts; j++) {
+ stmt = ctx->stmt_matrix[from][merge->stmt[j]];
+ list_del(&stmt->list);
+ stmt_free(stmt);
+ }
+}
+
+static void rule_optimize_print(struct output_ctx *octx,
+ const struct rule *rule)
+{
+ const struct location *loc = &rule->location;
+ const struct input_descriptor *indesc = loc->indesc;
+ const char *line = "";
+ char buf[1024];
+
+ switch (indesc->type) {
+ case INDESC_BUFFER:
+ case INDESC_CLI:
+ line = indesc->data;
+ *strchrnul(line, '\n') = '\0';
+ break;
+ case INDESC_STDIN:
+ line = indesc->data;
+ line += loc->line_offset;
+ *strchrnul(line, '\n') = '\0';
+ break;
+ case INDESC_FILE:
+ line = line_location(indesc, loc, buf, sizeof(buf));
+ break;
+ case INDESC_INTERNAL:
+ case INDESC_NETLINK:
+ break;
+ default:
+ BUG("invalid input descriptor type %u\n", indesc->type);
+ }
+
+ print_location(octx->error_fp, indesc, loc);
+ fprintf(octx->error_fp, "%s\n", line);
+}
+
+enum {
+ MERGE_BY_VERDICT,
+ MERGE_BY_NAT_MAP,
+ MERGE_BY_NAT,
+};
+
+static uint32_t merge_stmt_type(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to)
+{
+ const struct stmt *stmt;
+ uint32_t i, j;
+
+ for (i = from; i <= to; i++) {
+ for (j = 0; j < ctx->num_stmts; j++) {
+ stmt = ctx->stmt_matrix[i][j];
+ if (!stmt)
+ continue;
+ if (stmt->ops->type == STMT_NAT) {
+ if ((stmt->nat.type == NFT_NAT_REDIR &&
+ !stmt->nat.proto) ||
+ stmt->nat.type == NFT_NAT_MASQ)
+ return MERGE_BY_NAT;
+
+ return MERGE_BY_NAT_MAP;
+ }
+ }
+ }
+
+ /* merge by verdict, even if no verdict is specified. */
+ return MERGE_BY_VERDICT;
+}
+
+static void merge_rules(const struct optimize_ctx *ctx,
+ uint32_t from, uint32_t to,
+ const struct merge *merge,
+ struct output_ctx *octx)
+{
+ uint32_t merge_type;
+ bool same_verdict;
+ uint32_t i;
+
+ merge_type = merge_stmt_type(ctx, from, to);
+
+ switch (merge_type) {
+ case MERGE_BY_VERDICT:
+ same_verdict = stmt_verdict_cmp(ctx, from, to);
+ if (merge->num_stmts > 1) {
+ if (same_verdict)
+ merge_concat_stmts(ctx, from, to, merge);
+ else
+ merge_concat_stmts_vmap(ctx, from, to, merge);
+ } else {
+ if (same_verdict)
+ merge_stmts(ctx, from, to, merge);
+ else
+ merge_stmts_vmap(ctx, from, to, merge);
+ }
+ break;
+ case MERGE_BY_NAT_MAP:
+ if (merge->num_stmts > 1)
+ merge_concat_nat(ctx, from, to, merge);
+ else
+ merge_nat(ctx, from, to, merge);
+ break;
+ case MERGE_BY_NAT:
+ if (merge->num_stmts > 1)
+ merge_concat_stmts(ctx, from, to, merge);
+ else
+ merge_stmts(ctx, from, to, merge);
+ break;
+ default:
+ assert(0);
+ }
+
+ if (ctx->rule[from]->comment) {
+ free_const(ctx->rule[from]->comment);
+ ctx->rule[from]->comment = NULL;
+ }
+
+ octx->flags |= NFT_CTX_OUTPUT_STATELESS;
+
+ fprintf(octx->error_fp, "Merging:\n");
+ rule_optimize_print(octx, ctx->rule[from]);
+
+ for (i = from + 1; i <= to; i++) {
+ rule_optimize_print(octx, ctx->rule[i]);
+ list_del(&ctx->rule[i]->list);
+ rule_free(ctx->rule[i]);
+ }
+
+ fprintf(octx->error_fp, "into:\n\t");
+ rule_print(ctx->rule[from], octx);
+ fprintf(octx->error_fp, "\n");
+
+ octx->flags &= ~NFT_CTX_OUTPUT_STATELESS;
+}
+
+static bool stmt_type_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
+{
+ if (!stmt_a && !stmt_b)
+ return true;
+ else if (!stmt_a)
+ return false;
+ else if (!stmt_b)
+ return false;
+
+ return __stmt_type_eq(stmt_a, stmt_b, true);
+}
+
+static bool stmt_is_mergeable(const struct stmt *stmt)
+{
+ if (!stmt)
+ return false;
+
+ switch (stmt->ops->type) {
+ case STMT_VERDICT:
+ if (stmt->expr->etype == EXPR_MAP)
+ return true;
+ break;
+ case STMT_EXPRESSION:
+ case STMT_NAT:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
+
+static bool rules_eq(const struct optimize_ctx *ctx, int i, int j)
+{
+ uint32_t k, mergeable = 0;
+
+ for (k = 0; k < ctx->num_stmts; k++) {
+ if (stmt_is_mergeable(ctx->stmt_matrix[i][k]))
+ mergeable++;
+
+ if (!stmt_type_eq(ctx->stmt_matrix[i][k], ctx->stmt_matrix[j][k]))
+ return false;
+ }
+
+ if (mergeable == 0)
+ return false;
+
+ return true;
+}
+
+static int chain_optimize(struct nft_ctx *nft, struct list_head *rules)
+{
+ struct optimize_ctx *ctx;
+ uint32_t num_merges = 0;
+ struct merge *merge;
+ uint32_t i, j, m, k;
+ struct rule *rule;
+ int ret;
+
+ ctx = xzalloc(sizeof(*ctx));
+
+ /* Step 1: collect statements in rules */
+ list_for_each_entry(rule, rules, list) {
+ ret = rule_collect_stmts(ctx, rule);
+ if (ret < 0)
+ goto err;
+
+ ctx->num_rules++;
+ }
+
+ ctx->rule = xzalloc(sizeof(*ctx->rule) * ctx->num_rules);
+ ctx->stmt_matrix = xzalloc(sizeof(*ctx->stmt_matrix) * ctx->num_rules);
+ for (i = 0; i < ctx->num_rules; i++)
+ ctx->stmt_matrix[i] = xzalloc_array(MAX_STMTS,
+ sizeof(**ctx->stmt_matrix));
+
+ merge = xzalloc(sizeof(*merge) * ctx->num_rules);
+
+ /* Step 2: Build matrix of statements */
+ i = 0;
+ list_for_each_entry(rule, rules, list)
+ rule_build_stmt_matrix_stmts(ctx, rule, &i);
+
+ /* Step 3: Look for common selectors for possible rule mergers */
+ for (i = 0; i < ctx->num_rules; i++) {
+ for (j = i + 1; j < ctx->num_rules; j++) {
+ if (!rules_eq(ctx, i, j)) {
+ if (merge[num_merges].num_rules > 0)
+ num_merges++;
+
+ i = j - 1;
+ break;
+ }
+ if (merge[num_merges].num_rules > 0) {
+ merge[num_merges].num_rules++;
+ } else {
+ merge[num_merges].rule_from = i;
+ merge[num_merges].num_rules = 2;
+ }
+ }
+ if (j == ctx->num_rules && merge[num_merges].num_rules > 0) {
+ num_merges++;
+ break;
+ }
+ }
+
+ /* Step 4: Infer how to merge the candidate rules */
+ for (k = 0; k < num_merges; k++) {
+ i = merge[k].rule_from;
+
+ for (m = 0; m < ctx->num_stmts; m++) {
+ if (!ctx->stmt_matrix[i][m])
+ continue;
+ switch (ctx->stmt_matrix[i][m]->ops->type) {
+ case STMT_EXPRESSION:
+ merge[k].stmt[merge[k].num_stmts++] = m;
+ break;
+ case STMT_VERDICT:
+ if (ctx->stmt_matrix[i][m]->expr->etype == EXPR_MAP)
+ merge[k].stmt[merge[k].num_stmts++] = m;
+ break;
+ default:
+ break;
+ }
+ }
+
+ j = merge[k].num_rules - 1;
+ merge_rules(ctx, i, i + j, &merge[k], &nft->output);
+ }
+ ret = 0;
+ for (i = 0; i < ctx->num_rules; i++)
+ free(ctx->stmt_matrix[i]);
+
+ free(ctx->stmt_matrix);
+ free(merge);
+err:
+ for (i = 0; i < ctx->num_stmts; i++)
+ stmt_free(ctx->stmt[i]);
+
+ free(ctx->rule);
+ free(ctx);
+
+ return ret;
+}
+
+static int cmd_optimize(struct nft_ctx *nft, struct cmd *cmd)
+{
+ struct table *table;
+ struct chain *chain;
+ int ret = 0;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ table = cmd->table;
+ if (!table)
+ break;
+
+ list_for_each_entry(chain, &table->chains, list) {
+ if (chain->flags & CHAIN_F_HW_OFFLOAD)
+ continue;
+
+ chain_optimize(nft, &chain->rules);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+int nft_optimize(struct nft_ctx *nft, struct list_head *cmds)
+{
+ struct cmd *cmd;
+ int ret = 0;
+
+ list_for_each_entry(cmd, cmds, list) {
+ switch (cmd->op) {
+ case CMD_ADD:
+ ret = cmd_optimize(nft, cmd);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return ret;
+}
diff --git a/src/osf.c b/src/osf.c
index f0c22393..a8f80b2b 100644
--- a/src/osf.c
+++ b/src/osf.c
@@ -1,7 +1,16 @@
+/*
+ * Copyright (c) 2018 Fernando Fernandez Mancera <ffmancera@riseup.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
#include <nftables.h>
#include <expression.h>
#include <utils.h>
-#include <string.h>
#include <osf.h>
#include <json.h>
@@ -37,6 +46,17 @@ static bool osf_expr_cmp(const struct expr *e1, const struct expr *e2)
(e1->osf.flags == e2->osf.flags);
}
+static int osf_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ return 0;
+}
+
+static struct expr *osf_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ return osf_expr_alloc(&internal_location, 0, 0);
+}
+
const struct expr_ops osf_expr_ops = {
.type = EXPR_OSF,
.name = "osf",
@@ -44,6 +64,8 @@ const struct expr_ops osf_expr_ops = {
.clone = osf_expr_clone,
.cmp = osf_expr_cmp,
.json = osf_expr_json,
+ .parse_udata = osf_expr_parse_udata,
+ .build_udata = osf_expr_build_udata,
};
struct expr *osf_expr_alloc(const struct location *loc, const uint8_t ttl,
diff --git a/src/owner.c b/src/owner.c
new file mode 100644
index 00000000..65eaad3e
--- /dev/null
+++ b/src/owner.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2021 Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <inttypes.h>
+#include <dirent.h>
+
+#include <netlink.h>
+#include <owner.h>
+
+static char *pid2name(pid_t pid)
+{
+ char procname[256], *prog;
+ FILE *fp;
+ int ret;
+
+ ret = snprintf(procname, sizeof(procname), "/proc/%lu/stat", (unsigned long)pid);
+ if (ret < 0 || ret > (int)sizeof(procname))
+ return NULL;
+
+ fp = fopen(procname, "r");
+ if (!fp)
+ return NULL;
+
+ ret = fscanf(fp, "%*u (%m[^)]", &prog);
+
+ fclose(fp);
+
+ if (ret == 1)
+ return prog;
+
+ return NULL;
+}
+
+static char *portid2name(pid_t pid, uint32_t portid, unsigned long inode)
+{
+ const struct dirent *ent;
+ char procname[256];
+ DIR *dir;
+ int ret;
+
+ ret = snprintf(procname, sizeof(procname), "/proc/%lu/fd/", (unsigned long)pid);
+ if (ret < 0 || ret >= (int)sizeof(procname))
+ return NULL;
+
+ dir = opendir(procname);
+ if (!dir)
+ return NULL;
+
+ for (;;) {
+ unsigned long ino;
+ char tmp[128];
+ ssize_t rl;
+
+ ent = readdir(dir);
+ if (!ent)
+ break;
+
+ if (ent->d_type != DT_LNK)
+ continue;
+
+ ret = snprintf(procname, sizeof(procname), "/proc/%d/fd/%s",
+ pid, ent->d_name);
+ if (ret < 0 || ret >= (int)sizeof(procname))
+ continue;
+
+ rl = readlink(procname, tmp, sizeof(tmp));
+ if (rl <= 0 || rl >= (ssize_t)sizeof(tmp))
+ continue;
+
+ tmp[rl] = 0;
+
+ ret = sscanf(tmp, "socket:[%lu]", &ino);
+ if (ret == 1 && ino == inode) {
+ closedir(dir);
+ return pid2name(pid);
+ }
+ }
+
+ closedir(dir);
+ return NULL;
+}
+
+static char *name_by_portid(uint32_t portid, unsigned long inode)
+{
+ const struct dirent *ent;
+ char *prog;
+ DIR *dir;
+
+ /* Many netlink users use their process ID to allocate the first port id. */
+ prog = portid2name(portid, portid, inode);
+ if (prog)
+ return prog;
+
+ /* no luck, search harder. */
+ dir = opendir("/proc");
+ if (!dir)
+ return NULL;
+
+ for (;;) {
+ unsigned long pid;
+ char *end;
+
+ ent = readdir(dir);
+ if (!ent)
+ break;
+
+ if (ent->d_type != DT_DIR)
+ continue;
+
+ pid = strtoul(ent->d_name, &end, 10);
+ if (pid <= 1 || *end)
+ continue;
+
+ if (pid == portid) /* already tried */
+ continue;
+
+ prog = portid2name(pid, portid, inode);
+ if (prog)
+ break;
+ }
+
+ closedir(dir);
+ return prog;
+}
+
+char *get_progname(uint32_t portid)
+{
+ FILE *fp = fopen("/proc/net/netlink", "r");
+ uint32_t portid_check;
+ unsigned long inode;
+ int ret, prot;
+
+ if (!fp)
+ return NULL;
+
+ for (;;) {
+ char line[256];
+
+ if (!fgets(line, sizeof(line), fp))
+ break;
+
+ ret = sscanf(line, "%*x %d %u %*x %*d %*d %*x %*d %*u %lu\n",
+ &prot, &portid_check, &inode);
+
+ if (ret == EOF)
+ break;
+
+ if (ret == 3 && portid_check == portid && prot == NETLINK_NETFILTER) {
+ static uint32_t last_portid;
+ static uint32_t last_inode;
+ static char *last_program;
+ char *prog;
+
+ fclose(fp);
+
+ if (last_portid == portid && last_inode == inode)
+ return last_program;
+
+ prog = name_by_portid(portid, inode);
+
+ free(last_program);
+ last_program = prog;
+ last_portid = portid;
+ last_inode = inode;
+ return prog;
+ }
+ }
+
+ fclose(fp);
+ return NULL;
+}
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 1e2b3001..61bed761 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -9,11 +9,14 @@
*/
%{
+#include <nft.h>
+#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <inttypes.h>
#include <syslog.h>
+#include <net/if.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/if_ether.h>
@@ -38,17 +41,18 @@
#include <utils.h>
#include <parser.h>
#include <erec.h>
+#include <sctp_chunk.h>
#include "parser_bison.h"
void parser_init(struct nft_ctx *nft, struct parser_state *state,
- struct list_head *msgs, struct list_head *cmds)
+ struct list_head *msgs, struct list_head *cmds,
+ struct scope *top_scope)
{
memset(state, 0, sizeof(*state));
- init_list_head(&state->top_scope.symbols);
state->msgs = msgs;
state->cmds = cmds;
- state->scopes[0] = scope_init(&state->top_scope, NULL);
+ state->scopes[0] = scope_init(top_scope, NULL);
init_list_head(&state->indesc_list);
}
@@ -63,16 +67,26 @@ static struct scope *current_scope(const struct parser_state *state)
return state->scopes[state->scope];
}
-static void open_scope(struct parser_state *state, struct scope *scope)
+static int open_scope(struct parser_state *state, struct scope *scope)
{
- assert(state->scope < array_size(state->scopes) - 1);
+ if (state->scope >= array_size(state->scopes) - 1) {
+ state->scope_err = true;
+ return -1;
+ }
+
scope_init(scope, current_scope(state));
state->scopes[++state->scope] = scope;
+
+ return 0;
}
static void close_scope(struct parser_state *state)
{
- assert(state->scope > 0);
+ if (state->scope_err || state->scope == 0) {
+ state->scope_err = false;
+ return;
+ }
+
state->scope--;
}
@@ -102,6 +116,81 @@ static void location_update(struct location *loc, struct location *rhs, int n)
}
}
+static struct expr *handle_concat_expr(const struct location *loc,
+ struct expr *expr,
+ struct expr *expr_l, struct expr *expr_r,
+ struct location loc_rhs[3])
+{
+ if (expr->etype != EXPR_CONCAT) {
+ expr = concat_expr_alloc(loc);
+ compound_expr_add(expr, expr_l);
+ } else {
+ location_update(&expr_r->location, loc_rhs, 2);
+
+ expr = expr_l;
+ expr->location = *loc;
+ }
+
+ compound_expr_add(expr, expr_r);
+ return expr;
+}
+
+static bool already_set(const void *attr, const struct location *loc,
+ struct parser_state *state)
+{
+ if (!attr)
+ return false;
+
+ erec_queue(error(loc, "You can only specify this once. This statement is duplicated."),
+ state->msgs);
+ return true;
+}
+
+static struct expr *ifname_expr_alloc(const struct location *location,
+ struct list_head *queue,
+ const char *name)
+{
+ size_t length = strlen(name);
+ struct expr *expr;
+
+ if (length == 0) {
+ free_const(name);
+ erec_queue(error(location, "empty interface name"), queue);
+ return NULL;
+ }
+
+ if (length >= IFNAMSIZ) {
+ free_const(name);
+ erec_queue(error(location, "interface name too long"), queue);
+ return NULL;
+ }
+
+ expr = constant_expr_alloc(location, &ifname_type, BYTEORDER_HOST_ENDIAN,
+ length * BITS_PER_BYTE, name);
+
+ free_const(name);
+
+ return expr;
+}
+
+static void timeout_state_free(struct timeout_state *s)
+{
+ free_const(s->timeout_str);
+ free(s);
+}
+
+static void timeout_states_free(struct list_head *list)
+{
+ struct timeout_state *ts, *next;
+
+ list_for_each_entry_safe(ts, next, list, head) {
+ list_del(&ts->head);
+ timeout_state_free(ts);
+ }
+
+ free(list);
+}
+
#define YYLLOC_DEFAULT(Current, Rhs, N) location_update(&Current, Rhs, N)
#define symbol_value(loc, str) \
@@ -154,7 +243,12 @@ int nft_lex(void *, void *, void *);
struct handle_spec handle_spec;
struct position_spec position_spec;
struct prio_spec prio_spec;
- const struct exthdr_desc *exthdr_desc;
+ struct limit_rate limit_rate;
+ struct tcp_kind_field {
+ uint16_t kind; /* must allow > 255 for SACK1, 2.. hack */
+ uint8_t field;
+ } tcp_kind_field;
+ struct timeout_state *timeout_state;
}
%token TOKEN_EOF 0 "end of file"
@@ -194,6 +288,8 @@ int nft_lex(void *, void *, void *);
%token SOCKET "socket"
%token TRANSPARENT "transparent"
+%token WILDCARD "wildcard"
+%token CGROUPV2 "cgroupv2"
%token TPROXY "tproxy"
@@ -202,9 +298,11 @@ int nft_lex(void *, void *, void *);
%token SYNPROXY "synproxy"
%token MSS "mss"
%token WSCALE "wscale"
-%token SACKPERM "sack-perm"
+
+%token TYPEOF "typeof"
%token HOOK "hook"
+%token HOOKS "hooks"
%token DEVICE "device"
%token DEVICES "devices"
%token TABLE "table"
@@ -240,6 +338,8 @@ int nft_lex(void *, void *, void *);
%token DESCRIBE "describe"
%token IMPORT "import"
%token EXPORT "export"
+%token DESTROY "destroy"
+
%token MONITOR "monitor"
%token ALL "all"
@@ -277,7 +377,7 @@ int nft_lex(void *, void *, void *);
%token <string> STRING "string"
%token <string> QUOTED_STRING "quoted string"
%token <string> ASTERISK_STRING "string with a trailing asterisk"
-%destructor { xfree($$); } STRING QUOTED_STRING ASTERISK_STRING
+%destructor { free_const($$); } STRING QUOTED_STRING ASTERISK_STRING
%token LL_HDR "ll"
%token NETWORK_HDR "nh"
@@ -293,6 +393,7 @@ int nft_lex(void *, void *, void *);
%token VLAN "vlan"
%token ID "id"
%token CFI "cfi"
+%token DEI "dei"
%token PCP "pcp"
%token ARP "arp"
@@ -341,6 +442,7 @@ int nft_lex(void *, void *, void *);
%token ICMP6 "icmpv6"
%token PPTR "param-problem"
%token MAXDELAY "max-delay"
+%token TADDR "taddr"
%token AH "ah"
%token RESERVED "reserved"
@@ -352,6 +454,7 @@ int nft_lex(void *, void *, void *);
%token FLAGS "flags"
%token CPI "cpi"
+%token PORT "port"
%token UDP "udp"
%token SPORT "sport"
%token DPORT "dport"
@@ -366,25 +469,69 @@ int nft_lex(void *, void *, void *);
%token OPTION "option"
%token ECHO "echo"
%token EOL "eol"
-%token MAXSEG "maxseg"
-%token NOOP "noop"
+%token MPTCP "mptcp"
+%token NOP "nop"
%token SACK "sack"
%token SACK0 "sack0"
%token SACK1 "sack1"
%token SACK2 "sack2"
%token SACK3 "sack3"
-%token SACK_PERMITTED "sack-permitted"
+%token SACK_PERM "sack-permitted"
+%token FASTOPEN "fastopen"
+%token MD5SIG "md5sig"
%token TIMESTAMP "timestamp"
-%token KIND "kind"
%token COUNT "count"
%token LEFT "left"
%token RIGHT "right"
%token TSVAL "tsval"
%token TSECR "tsecr"
+%token SUBTYPE "subtype"
%token DCCP "dccp"
+%token VXLAN "vxlan"
+%token VNI "vni"
+
+%token GRE "gre"
+%token GRETAP "gretap"
+
+%token GENEVE "geneve"
+
%token SCTP "sctp"
+%token CHUNK "chunk"
+%token DATA "data"
+%token INIT "init"
+%token INIT_ACK "init-ack"
+%token HEARTBEAT "heartbeat"
+%token HEARTBEAT_ACK "heartbeat-ack"
+%token ABORT "abort"
+%token SHUTDOWN "shutdown"
+%token SHUTDOWN_ACK "shutdown-ack"
+%token ERROR "error"
+%token COOKIE_ECHO "cookie-echo"
+%token COOKIE_ACK "cookie-ack"
+%token ECNE "ecne"
+%token CWR "cwr"
+%token SHUTDOWN_COMPLETE "shutdown-complete"
+%token ASCONF_ACK "asconf-ack"
+%token FORWARD_TSN "forward-tsn"
+%token ASCONF "asconf"
+%token TSN "tsn"
+%token STREAM "stream"
+%token SSN "ssn"
+%token PPID "ppid"
+%token INIT_TAG "init-tag"
+%token A_RWND "a-rwnd"
+%token NUM_OSTREAMS "num-outbound-streams"
+%token NUM_ISTREAMS "num-inbound-streams"
+%token INIT_TSN "initial-tsn"
+%token CUM_TSN_ACK "cum-tsn-ack"
+%token NUM_GACK_BLOCKS "num-gap-ack-blocks"
+%token NUM_DUP_TSNS "num-dup-tsns"
+%token LOWEST_TSN "lowest-tsn"
+%token SEQNO "seqno"
+%token NEW_CUM_TSN "new-cum-tsn"
+
%token VTAG "vtag"
%token RT "rt"
@@ -455,6 +602,9 @@ int nft_lex(void *, void *, void *);
%token BYTES "bytes"
%token AVGPKT "avgpkt"
+%token LAST "last"
+%token NEVER "never"
+
%token COUNTERS "counters"
%token QUOTAS "quotas"
%token LIMITS "limits"
@@ -480,9 +630,6 @@ int nft_lex(void *, void *, void *);
%token SECMARK "secmark"
%token SECMARKS "secmarks"
-%token NANOSECOND "nanosecond"
-%token MICROSECOND "microsecond"
-%token MILLISECOND "millisecond"
%token SECOND "second"
%token MINUTE "minute"
%token HOUR "hour"
@@ -534,19 +681,21 @@ int nft_lex(void *, void *, void *);
%token EXTHDR "exthdr"
%token IPSEC "ipsec"
-%token MODE "mode"
%token REQID "reqid"
%token SPNUM "spnum"
-%token TRANSPORT "transport"
-%token TUNNEL "tunnel"
%token IN "in"
%token OUT "out"
+%token XT "xt"
+
+%type <limit_rate> limit_rate_pkts
+%type <limit_rate> limit_rate_bytes
+
%type <string> identifier type_identifier string comment_spec
-%destructor { xfree($$); } identifier type_identifier string comment_spec
+%destructor { free_const($$); } identifier type_identifier string comment_spec
-%type <val> time_spec quota_used
+%type <val> time_spec time_spec_or_num_s quota_used
%type <expr> data_type_expr data_type_atom_expr
%destructor { expr_free($$); } data_type_expr data_type_atom_expr
@@ -554,25 +703,41 @@ int nft_lex(void *, void *, void *);
%type <cmd> line
%destructor { cmd_free($$); } line
-%type <cmd> base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd get_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd
-%destructor { cmd_free($$); } base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd get_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd
+%type <cmd> base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd get_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd destroy_cmd
+%destructor { cmd_free($$); } base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd get_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd destroy_cmd
+
+%type <handle> table_spec tableid_spec table_or_id_spec
+%destructor { handle_free(&$$); } table_spec tableid_spec table_or_id_spec
+%type <handle> chain_spec chainid_spec chain_or_id_spec
+%destructor { handle_free(&$$); } chain_spec chainid_spec chain_or_id_spec
+
+%type <handle> flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec
+%destructor { handle_free(&$$); } flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec
+%type <handle> set_spec setid_spec set_or_id_spec
+%destructor { handle_free(&$$); } set_spec setid_spec set_or_id_spec
+%type <handle> obj_spec objid_spec obj_or_id_spec
+%destructor { handle_free(&$$); } obj_spec objid_spec obj_or_id_spec
+
+%type <handle> set_identifier flowtableid_spec flowtable_identifier obj_identifier
+%destructor { handle_free(&$$); } set_identifier flowtableid_spec obj_identifier
+
+%type <handle> basehook_spec
+%destructor { handle_free(&$$); } basehook_spec
-%type <handle> table_spec tableid_spec chain_spec chainid_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec
-%destructor { handle_free(&$$); } table_spec tableid_spec chain_spec chainid_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec index_spec
-%type <handle> set_spec setid_spec set_identifier flowtable_identifier obj_spec objid_spec obj_identifier
-%destructor { handle_free(&$$); } set_spec setid_spec set_identifier obj_spec objid_spec obj_identifier
%type <val> family_spec family_spec_explicit
%type <val32> int_num chain_policy
%type <prio_spec> extended_prio_spec prio_spec
-%type <string> extended_prio_name
-%destructor { xfree($$); } extended_prio_name
+%destructor { expr_free($$.expr); } extended_prio_spec prio_spec
-%type <string> dev_spec quota_unit
-%destructor { xfree($$); } dev_spec quota_unit
+%type <string> extended_prio_name quota_unit basehook_device_name
+%destructor { free_const($$); } extended_prio_name quota_unit basehook_device_name
+
+%type <expr> dev_spec
+%destructor { free($$); } dev_spec
%type <table> table_block_alloc table_block
%destructor { close_scope(state); table_free($$); } table_block_alloc
-%type <chain> chain_block_alloc chain_block
+%type <chain> chain_block_alloc chain_block subchain_block
%destructor { close_scope(state); chain_free($$); } chain_block_alloc
%type <rule> rule rule_alloc
%destructor { rule_free($$); } rule
@@ -586,6 +751,7 @@ int nft_lex(void *, void *, void *);
%type <set> map_block_alloc map_block
%destructor { set_free($$); } map_block_alloc
+%type <val> map_block_obj_type map_block_obj_typeof map_block_data_interval
%type <flowtable> flowtable_block_alloc flowtable_block
%destructor { flowtable_free($$); } flowtable_block_alloc
@@ -593,12 +759,15 @@ int nft_lex(void *, void *, void *);
%type <obj> obj_block_alloc counter_block quota_block ct_helper_block ct_timeout_block ct_expect_block limit_block secmark_block synproxy_block
%destructor { obj_free($$); } obj_block_alloc
-%type <list> stmt_list
-%destructor { stmt_list_free($$); xfree($$); } stmt_list
-%type <stmt> stmt match_stmt verdict_stmt
-%destructor { stmt_free($$); } stmt match_stmt verdict_stmt
-%type <stmt> counter_stmt counter_stmt_alloc stateful_stmt
-%destructor { stmt_free($$); } counter_stmt counter_stmt_alloc stateful_stmt
+%type <list> stmt_list stateful_stmt_list set_elem_stmt_list
+%destructor { stmt_list_free($$); free($$); } stmt_list stateful_stmt_list set_elem_stmt_list
+%type <stmt> stmt match_stmt verdict_stmt set_elem_stmt
+%destructor { stmt_free($$); } stmt match_stmt verdict_stmt set_elem_stmt
+%type <stmt> counter_stmt counter_stmt_alloc stateful_stmt last_stmt
+%destructor { stmt_free($$); } counter_stmt counter_stmt_alloc stateful_stmt last_stmt
+%type <stmt> objref_stmt objref_stmt_counter objref_stmt_limit objref_stmt_quota objref_stmt_ct objref_stmt_synproxy
+%destructor { stmt_free($$); } objref_stmt objref_stmt_counter objref_stmt_limit objref_stmt_quota objref_stmt_ct objref_stmt_synproxy
+
%type <stmt> payload_stmt
%destructor { stmt_free($$); } payload_stmt
%type <stmt> ct_stmt
@@ -610,7 +779,7 @@ int nft_lex(void *, void *, void *);
%type <val> level_type log_flags log_flags_tcp log_flag_tcp
%type <stmt> limit_stmt quota_stmt connlimit_stmt
%destructor { stmt_free($$); } limit_stmt quota_stmt connlimit_stmt
-%type <val> limit_burst_pkts limit_burst_bytes limit_mode time_unit quota_mode
+%type <val> limit_burst_pkts limit_burst_bytes limit_mode limit_bytes time_unit quota_mode
%type <stmt> reject_stmt reject_stmt_alloc
%destructor { stmt_free($$); } reject_stmt reject_stmt_alloc
%type <stmt> nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
@@ -620,10 +789,14 @@ int nft_lex(void *, void *, void *);
%destructor { stmt_free($$); } tproxy_stmt
%type <stmt> synproxy_stmt synproxy_stmt_alloc
%destructor { stmt_free($$); } synproxy_stmt synproxy_stmt_alloc
-
-
-%type <stmt> queue_stmt queue_stmt_alloc
-%destructor { stmt_free($$); } queue_stmt queue_stmt_alloc
+%type <stmt> chain_stmt
+%destructor { stmt_free($$); } chain_stmt
+%type <val> chain_stmt_type
+
+%type <stmt> queue_stmt queue_stmt_alloc queue_stmt_compat
+%destructor { stmt_free($$); } queue_stmt queue_stmt_alloc queue_stmt_compat
+%type <expr> queue_stmt_expr_simple queue_stmt_expr queue_expr reject_with_expr
+%destructor { expr_free($$); } queue_stmt_expr_simple queue_stmt_expr queue_expr reject_with_expr
%type <val> queue_stmt_flags queue_stmt_flag
%type <stmt> dup_stmt
%destructor { stmt_free($$); } dup_stmt
@@ -639,12 +812,14 @@ int nft_lex(void *, void *, void *);
%type <expr> symbol_expr verdict_expr integer_expr variable_expr chain_expr policy_expr
%destructor { expr_free($$); } symbol_expr verdict_expr integer_expr variable_expr chain_expr policy_expr
-%type <expr> primary_expr shift_expr and_expr
-%destructor { expr_free($$); } primary_expr shift_expr and_expr
+%type <expr> primary_expr shift_expr and_expr typeof_expr typeof_data_expr typeof_key_expr typeof_verdict_expr
+%destructor { expr_free($$); } primary_expr shift_expr and_expr typeof_expr typeof_data_expr typeof_key_expr typeof_verdict_expr
%type <expr> exclusive_or_expr inclusive_or_expr
%destructor { expr_free($$); } exclusive_or_expr inclusive_or_expr
%type <expr> basic_expr
%destructor { expr_free($$); } basic_expr
+%type <expr> set_ref_expr set_ref_symbol_expr
+%destructor { expr_free($$); } set_ref_expr set_ref_symbol_expr
%type <expr> multiton_rhs_expr
%destructor { expr_free($$); } multiton_rhs_expr
@@ -656,8 +831,8 @@ int nft_lex(void *, void *, void *);
%type <expr> multiton_stmt_expr
%destructor { expr_free($$); } multiton_stmt_expr
-%type <expr> prefix_stmt_expr range_stmt_expr wildcard_expr
-%destructor { expr_free($$); } prefix_stmt_expr range_stmt_expr wildcard_expr
+%type <expr> prefix_stmt_expr range_stmt_expr
+%destructor { expr_free($$); } prefix_stmt_expr range_stmt_expr
%type <expr> primary_stmt_expr basic_stmt_expr
%destructor { expr_free($$); } primary_stmt_expr basic_stmt_expr
@@ -708,6 +883,8 @@ int nft_lex(void *, void *, void *);
%type <expr> payload_expr payload_raw_expr
%destructor { expr_free($$); } payload_expr payload_raw_expr
%type <val> payload_base_spec
+%type <val> payload_raw_len
+
%type <expr> eth_hdr_expr vlan_hdr_expr
%destructor { expr_free($$); } eth_hdr_expr vlan_hdr_expr
%type <val> eth_hdr_field vlan_hdr_field
@@ -727,9 +904,12 @@ int nft_lex(void *, void *, void *);
%type <expr> udp_hdr_expr udplite_hdr_expr
%destructor { expr_free($$); } udp_hdr_expr udplite_hdr_expr
%type <val> udp_hdr_field udplite_hdr_field
-%type <expr> dccp_hdr_expr sctp_hdr_expr
-%destructor { expr_free($$); } dccp_hdr_expr sctp_hdr_expr
+%type <expr> dccp_hdr_expr sctp_hdr_expr sctp_chunk_alloc
+%destructor { expr_free($$); } dccp_hdr_expr sctp_hdr_expr sctp_chunk_alloc
%type <val> dccp_hdr_field sctp_hdr_field
+%type <val> sctp_chunk_type sctp_chunk_common_field
+%type <val> sctp_chunk_data_field sctp_chunk_init_field
+%type <val> sctp_chunk_sack_field
%type <expr> th_hdr_expr
%destructor { expr_free($$); } th_hdr_expr
%type <val> th_hdr_field
@@ -774,7 +954,7 @@ int nft_lex(void *, void *, void *);
%type <val> markup_format
%type <string> monitor_event
-%destructor { xfree($$); } monitor_event
+%destructor { free_const($$); } monitor_event
%type <val> monitor_object monitor_format
%type <val> synproxy_ts synproxy_sack
@@ -782,7 +962,23 @@ int nft_lex(void *, void *, void *);
%type <expr> tcp_hdr_expr
%destructor { expr_free($$); } tcp_hdr_expr
%type <val> tcp_hdr_field
-%type <val> tcp_hdr_option_type tcp_hdr_option_field
+%type <val> tcp_hdr_option_type
+%type <val> tcp_hdr_option_sack
+%type <val> tcpopt_field_maxseg tcpopt_field_mptcp tcpopt_field_sack tcpopt_field_tsopt tcpopt_field_window
+%type <tcp_kind_field> tcp_hdr_option_kind_and_field
+
+%type <expr> inner_eth_expr inner_inet_expr inner_expr
+%destructor { expr_free($$); } inner_eth_expr inner_inet_expr inner_expr
+
+%type <expr> vxlan_hdr_expr geneve_hdr_expr gre_hdr_expr gretap_hdr_expr
+%destructor { expr_free($$); } vxlan_hdr_expr geneve_hdr_expr gre_hdr_expr gretap_hdr_expr
+%type <val> vxlan_hdr_field geneve_hdr_field gre_hdr_field
+
+%type <stmt> optstrip_stmt
+%destructor { stmt_free($$); } optstrip_stmt
+
+%type <stmt> xt_stmt
+%destructor { stmt_free($$); } xt_stmt
%type <expr> boolean_expr
%destructor { expr_free($$); } boolean_expr
@@ -792,15 +988,21 @@ int nft_lex(void *, void *, void *);
%destructor { expr_free($$); } exthdr_exists_expr
%type <val> exthdr_key
-%type <val> ct_l4protoname ct_obj_type
+%type <val> ct_l4protoname ct_obj_type ct_cmd_type ct_obj_type_map
+
+%type <timeout_state> timeout_state
+%destructor { timeout_state_free($$); } timeout_state
-%type <list> timeout_states timeout_state
-%destructor { xfree($$); } timeout_states timeout_state
+%type <list> timeout_states
+%destructor { timeout_states_free($$); } timeout_states
%type <val> xfrm_state_key xfrm_state_proto_key xfrm_dir xfrm_spnum
%type <expr> xfrm_expr
%destructor { expr_free($$); } xfrm_expr
+%type <expr> set_elem_key_expr
+%destructor { expr_free($$); } set_elem_key_expr
+
%%
input : /* empty */
@@ -821,13 +1023,69 @@ opt_newline : NEWLINE
| /* empty */
;
+close_scope_ah : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_AH); };
+close_scope_arp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_ARP); };
+close_scope_at : { scanner_pop_start_cond(nft->scanner, PARSER_SC_AT); };
+close_scope_comp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_COMP); };
+close_scope_ct : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CT); };
+close_scope_counter : { scanner_pop_start_cond(nft->scanner, PARSER_SC_COUNTER); };
+close_scope_last : { scanner_pop_start_cond(nft->scanner, PARSER_SC_LAST); };
+close_scope_dccp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_DCCP); };
+close_scope_destroy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_DESTROY); };
+close_scope_dst : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_DST); };
+close_scope_dup : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_DUP); };
+close_scope_esp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_ESP); };
+close_scope_eth : { scanner_pop_start_cond(nft->scanner, PARSER_SC_ETH); };
+close_scope_export : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_EXPORT); };
+close_scope_fib : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_FIB); };
+close_scope_frag : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_FRAG); };
+close_scope_fwd : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_FWD); };
+close_scope_gre : { scanner_pop_start_cond(nft->scanner, PARSER_SC_GRE); };
+close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); };
+close_scope_hbh : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HBH); };
+close_scope_ip : { scanner_pop_start_cond(nft->scanner, PARSER_SC_IP); };
+close_scope_ip6 : { scanner_pop_start_cond(nft->scanner, PARSER_SC_IP6); };
+close_scope_vlan : { scanner_pop_start_cond(nft->scanner, PARSER_SC_VLAN); };
+close_scope_icmp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_ICMP); };
+close_scope_igmp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_IGMP); };
+close_scope_import : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_IMPORT); };
+close_scope_ipsec : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_IPSEC); };
+close_scope_list : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_LIST); };
+close_scope_limit : { scanner_pop_start_cond(nft->scanner, PARSER_SC_LIMIT); };
+close_scope_meta : { scanner_pop_start_cond(nft->scanner, PARSER_SC_META); };
+close_scope_mh : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_MH); };
+close_scope_monitor : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_MONITOR); };
+close_scope_nat : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_NAT); };
+close_scope_numgen : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_NUMGEN); };
+close_scope_osf : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_OSF); };
+close_scope_policy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_POLICY); };
+close_scope_quota : { scanner_pop_start_cond(nft->scanner, PARSER_SC_QUOTA); };
+close_scope_queue : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_QUEUE); };
+close_scope_reject : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_REJECT); };
+close_scope_reset : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_RESET); };
+close_scope_rt : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_RT); };
+close_scope_sctp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_SCTP); };
+close_scope_sctp_chunk : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_SCTP_CHUNK); };
+close_scope_secmark : { scanner_pop_start_cond(nft->scanner, PARSER_SC_SECMARK); };
+close_scope_socket : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_SOCKET); }
+close_scope_tcp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_TCP); };
+close_scope_tproxy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_TPROXY); };
+close_scope_type : { scanner_pop_start_cond(nft->scanner, PARSER_SC_TYPE); };
+close_scope_th : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_TH); };
+close_scope_udp : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_UDP); };
+close_scope_udplite : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_UDPLITE); };
+
+close_scope_log : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_LOG); }
+close_scope_synproxy : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_SYNPROXY); }
+close_scope_xt : { scanner_pop_start_cond(nft->scanner, PARSER_SC_XT); }
+
common_block : INCLUDE QUOTED_STRING stmt_separator
{
if (scanner_include_file(nft, scanner, $2, &@$) < 0) {
- xfree($2);
+ free_const($2);
YYERROR;
}
- xfree($2);
+ free_const($2);
}
| DEFINE identifier '=' initializer_expr stmt_separator
{
@@ -836,19 +1094,20 @@ common_block : INCLUDE QUOTED_STRING stmt_separator
if (symbol_lookup(scope, $2) != NULL) {
erec_queue(error(&@2, "redefinition of symbol '%s'", $2),
state->msgs);
- xfree($2);
+ expr_free($4);
+ free_const($2);
YYERROR;
}
symbol_bind(scope, $2, $4);
- xfree($2);
+ free_const($2);
}
| REDEFINE identifier '=' initializer_expr stmt_separator
{
struct scope *scope = current_scope(state);
symbol_bind(scope, $2, $4);
- xfree($2);
+ free_const($2);
}
| UNDEFINE identifier stmt_separator
{
@@ -857,9 +1116,10 @@ common_block : INCLUDE QUOTED_STRING stmt_separator
if (symbol_unbind(scope, $2) < 0) {
erec_queue(error(&@2, "undefined symbol '%s'", $2),
state->msgs);
+ free_const($2);
YYERROR;
}
- xfree($2);
+ free_const($2);
}
| error stmt_separator
{
@@ -899,14 +1159,15 @@ base_cmd : /* empty */ add_cmd { $$ = $1; }
| INSERT insert_cmd { $$ = $2; }
| DELETE delete_cmd { $$ = $2; }
| GET get_cmd { $$ = $2; }
- | LIST list_cmd { $$ = $2; }
- | RESET reset_cmd { $$ = $2; }
+ | LIST list_cmd close_scope_list { $$ = $2; }
+ | RESET reset_cmd close_scope_reset { $$ = $2; }
| FLUSH flush_cmd { $$ = $2; }
| RENAME rename_cmd { $$ = $2; }
- | IMPORT import_cmd { $$ = $2; }
- | EXPORT export_cmd { $$ = $2; }
- | MONITOR monitor_cmd { $$ = $2; }
+ | IMPORT import_cmd close_scope_import { $$ = $2; }
+ | EXPORT export_cmd close_scope_export { $$ = $2; }
+ | MONITOR monitor_cmd close_scope_monitor { $$ = $2; }
| DESCRIBE describe_cmd { $$ = $2; }
+ | DESTROY destroy_cmd close_scope_destroy { $$ = $2; }
;
add_cmd : TABLE table_spec
@@ -956,7 +1217,7 @@ add_cmd : TABLE table_spec
}
| ELEMENT set_spec set_block_expr
{
- $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SETELEM, &$2, &@$, $3);
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
}
| FLOWTABLE flowtable_spec flowtable_block_alloc
'{' flowtable_block '}'
@@ -965,7 +1226,7 @@ add_cmd : TABLE table_spec
handle_merge(&$3->handle, &$2);
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_FLOWTABLE, &$2, &@$, $5);
}
- | COUNTER obj_spec
+ | COUNTER obj_spec close_scope_counter
{
struct obj *obj;
@@ -974,35 +1235,55 @@ add_cmd : TABLE table_spec
handle_merge(&obj->handle, &$2);
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, obj);
}
- | COUNTER obj_spec counter_obj counter_config
+ | COUNTER obj_spec counter_obj counter_config close_scope_counter
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, $3);
+ }
+ | COUNTER obj_spec counter_obj '{' counter_block '}' close_scope_counter
{
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_COUNTER, &$2, &@$, $3);
}
- | QUOTA obj_spec quota_obj quota_config
+ | QUOTA obj_spec quota_obj quota_config close_scope_quota
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_QUOTA, &$2, &@$, $3);
+ }
+ | QUOTA obj_spec quota_obj '{' quota_block '}' close_scope_quota
{
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_QUOTA, &$2, &@$, $3);
}
- | CT HELPER obj_spec ct_obj_alloc '{' ct_helper_block '}'
+ | CT HELPER obj_spec ct_obj_alloc '{' ct_helper_block '}' close_scope_ct
{
$$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_HELPER, &$3, &@$, $4);
}
- | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}'
+ | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}' close_scope_ct
{
$$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4);
}
- | CT EXPECTATION obj_spec ct_obj_alloc '{' ct_expect_block '}'
+ | CT EXPECTATION obj_spec ct_obj_alloc '{' ct_expect_block '}' close_scope_ct
{
$$ = cmd_alloc_obj_ct(CMD_ADD, NFT_OBJECT_CT_EXPECT, &$3, &@$, $4);
}
- | LIMIT obj_spec limit_obj limit_config
+ | LIMIT obj_spec limit_obj limit_config close_scope_limit
{
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &$2, &@$, $3);
}
- | SECMARK obj_spec secmark_obj secmark_config
+ | LIMIT obj_spec limit_obj '{' limit_block '}' close_scope_limit
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_LIMIT, &$2, &@$, $3);
+ }
+ | SECMARK obj_spec secmark_obj secmark_config close_scope_secmark
{
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_SECMARK, &$2, &@$, $3);
}
- | SYNPROXY obj_spec synproxy_obj synproxy_config
+ | SECMARK obj_spec secmark_obj '{' secmark_block '}' close_scope_secmark
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SECMARK, &$2, &@$, $3);
+ }
+ | SYNPROXY obj_spec synproxy_obj synproxy_config close_scope_synproxy
+ {
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SYNPROXY, &$2, &@$, $3);
+ }
+ | SYNPROXY obj_spec synproxy_obj '{' synproxy_block '}' close_scope_synproxy
{
$$ = cmd_alloc(CMD_ADD, CMD_OBJ_SYNPROXY, &$2, &@$, $3);
}
@@ -1053,7 +1334,7 @@ create_cmd : TABLE table_spec
}
| ELEMENT set_spec set_block_expr
{
- $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SETELEM, &$2, &@$, $3);
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
}
| FLOWTABLE flowtable_spec flowtable_block_alloc
'{' flowtable_block '}'
@@ -1062,7 +1343,7 @@ create_cmd : TABLE table_spec
handle_merge(&$3->handle, &$2);
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_FLOWTABLE, &$2, &@$, $5);
}
- | COUNTER obj_spec
+ | COUNTER obj_spec close_scope_counter
{
struct obj *obj;
@@ -1071,35 +1352,35 @@ create_cmd : TABLE table_spec
handle_merge(&obj->handle, &$2);
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, obj);
}
- | COUNTER obj_spec counter_obj counter_config
+ | COUNTER obj_spec counter_obj counter_config close_scope_counter
{
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_COUNTER, &$2, &@$, $3);
}
- | QUOTA obj_spec quota_obj quota_config
+ | QUOTA obj_spec quota_obj quota_config close_scope_quota
{
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_QUOTA, &$2, &@$, $3);
}
- | CT HELPER obj_spec ct_obj_alloc '{' ct_helper_block '}'
+ | CT HELPER obj_spec ct_obj_alloc '{' ct_helper_block '}' close_scope_ct
{
$$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_HELPER, &$3, &@$, $4);
}
- | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}'
+ | CT TIMEOUT obj_spec ct_obj_alloc '{' ct_timeout_block '}' close_scope_ct
{
$$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_TIMEOUT, &$3, &@$, $4);
}
- | CT EXPECTATION obj_spec ct_obj_alloc '{' ct_expect_block '}'
+ | CT EXPECTATION obj_spec ct_obj_alloc '{' ct_expect_block '}' close_scope_ct
{
$$ = cmd_alloc_obj_ct(CMD_CREATE, NFT_OBJECT_CT_EXPECT, &$3, &@$, $4);
}
- | LIMIT obj_spec limit_obj limit_config
+ | LIMIT obj_spec limit_obj limit_config close_scope_limit
{
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_LIMIT, &$2, &@$, $3);
}
- | SECMARK obj_spec secmark_obj secmark_config
+ | SECMARK obj_spec secmark_obj secmark_config close_scope_secmark
{
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SECMARK, &$2, &@$, $3);
}
- | SYNPROXY obj_spec synproxy_obj synproxy_config
+ | SYNPROXY obj_spec synproxy_obj synproxy_config close_scope_synproxy
{
$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SYNPROXY, &$2, &@$, $3);
}
@@ -1111,31 +1392,43 @@ insert_cmd : RULE rule_position rule
}
;
-delete_cmd : TABLE table_spec
- {
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_TABLE, &$2, &@$, NULL);
- }
- | TABLE tableid_spec
+table_or_id_spec : table_spec
+ | tableid_spec
+ ;
+
+chain_or_id_spec : chain_spec
+ | chainid_spec
+ ;
+
+set_or_id_spec : set_spec
+ | setid_spec
+ ;
+
+obj_or_id_spec : obj_spec
+ | objid_spec
+ ;
+
+delete_cmd : TABLE table_or_id_spec
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_TABLE, &$2, &@$, NULL);
}
- | CHAIN chain_spec
+ | CHAIN chain_or_id_spec
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &$2, &@$, NULL);
}
- | CHAIN chainid_spec
+ | CHAIN chain_spec chain_block_alloc
+ '{' chain_block '}'
{
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &$2, &@$, NULL);
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ close_scope(state);
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &$2, &@$, $5);
}
| RULE ruleid_spec
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_RULE, &$2, &@$, NULL);
}
- | SET set_spec
- {
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SET, &$2, &@$, NULL);
- }
- | SET setid_spec
+ | SET set_or_id_spec
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SET, &$2, &@$, NULL);
}
@@ -1145,61 +1438,122 @@ delete_cmd : TABLE table_spec
}
| ELEMENT set_spec set_block_expr
{
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SETELEM, &$2, &@$, $3);
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
}
| FLOWTABLE flowtable_spec
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL);
}
- | COUNTER obj_spec
+ | FLOWTABLE flowtableid_spec
{
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL);
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL);
}
- | COUNTER objid_spec
+ | FLOWTABLE flowtable_spec flowtable_block_alloc
+ '{' flowtable_block '}'
{
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL);
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &$2, &@$, $5);
}
- | QUOTA obj_spec
+ | COUNTER obj_or_id_spec close_scope_counter
{
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_QUOTA, &$2, &@$, NULL);
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL);
}
- | QUOTA objid_spec
+ | QUOTA obj_or_id_spec close_scope_quota
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_QUOTA, &$2, &@$, NULL);
}
- | CT ct_obj_type obj_spec ct_obj_alloc
+ | CT ct_obj_type obj_spec ct_obj_alloc close_scope_ct
{
$$ = cmd_alloc_obj_ct(CMD_DELETE, $2, &$3, &@$, $4);
+ if ($2 == NFT_OBJECT_CT_TIMEOUT)
+ init_list_head(&$4->ct_timeout.timeout_list);
}
- | LIMIT obj_spec
+ | LIMIT obj_or_id_spec close_scope_limit
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_LIMIT, &$2, &@$, NULL);
}
- | LIMIT objid_spec
+ | SECMARK obj_or_id_spec close_scope_secmark
{
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_LIMIT, &$2, &@$, NULL);
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SECMARK, &$2, &@$, NULL);
}
- | SECMARK obj_spec
+ | SYNPROXY obj_or_id_spec close_scope_synproxy
{
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SECMARK, &$2, &@$, NULL);
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SYNPROXY, &$2, &@$, NULL);
}
- | SECMARK objid_spec
+ ;
+
+destroy_cmd : TABLE table_or_id_spec
{
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SECMARK, &$2, &@$, NULL);
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_TABLE, &$2, &@$, NULL);
}
- | SYNPROXY obj_spec
+ | CHAIN chain_or_id_spec
{
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SYNPROXY, &$2, &@$, NULL);
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_CHAIN, &$2, &@$, NULL);
}
- | SYNPROXY objid_spec
+ | RULE ruleid_spec
{
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SYNPROXY, &$2, &@$, NULL);
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_RULE, &$2, &@$, NULL);
+ }
+ | SET set_or_id_spec
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_SET, &$2, &@$, NULL);
+ }
+ | MAP set_spec
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_SET, &$2, &@$, NULL);
+ }
+ | ELEMENT set_spec set_block_expr
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
+ }
+ | FLOWTABLE flowtable_spec
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL);
+ }
+ | FLOWTABLE flowtableid_spec
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL);
+ }
+ | FLOWTABLE flowtable_spec flowtable_block_alloc
+ '{' flowtable_block '}'
+ {
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_FLOWTABLE, &$2, &@$, $5);
+ }
+ | COUNTER obj_or_id_spec close_scope_counter
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_COUNTER, &$2, &@$, NULL);
+ }
+ | QUOTA obj_or_id_spec close_scope_quota
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_QUOTA, &$2, &@$, NULL);
+ }
+ | CT ct_obj_type obj_spec ct_obj_alloc close_scope_ct
+ {
+ $$ = cmd_alloc_obj_ct(CMD_DESTROY, $2, &$3, &@$, $4);
+ if ($2 == NFT_OBJECT_CT_TIMEOUT)
+ init_list_head(&$4->ct_timeout.timeout_list);
+ }
+ | LIMIT obj_or_id_spec close_scope_limit
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_LIMIT, &$2, &@$, NULL);
+ }
+ | SECMARK obj_or_id_spec close_scope_secmark
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_SECMARK, &$2, &@$, NULL);
+ }
+ | SYNPROXY obj_or_id_spec close_scope_synproxy
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_SYNPROXY, &$2, &@$, NULL);
}
;
+
get_cmd : ELEMENT set_spec set_block_expr
{
- $$ = cmd_alloc(CMD_GET, CMD_OBJ_SETELEM, &$2, &@$, $3);
+ $$ = cmd_alloc(CMD_GET, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
}
;
@@ -1239,7 +1593,7 @@ list_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTERS, &$3, &@$, NULL);
}
- | COUNTER obj_spec
+ | COUNTER obj_spec close_scope_counter
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_COUNTER, &$2, &@$, NULL);
}
@@ -1251,7 +1605,7 @@ list_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTAS, &$3, &@$, NULL);
}
- | QUOTA obj_spec
+ | QUOTA obj_spec close_scope_quota
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_QUOTA, &$2, &@$, NULL);
}
@@ -1263,7 +1617,7 @@ list_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_LIMITS, &$3, &@$, NULL);
}
- | LIMIT obj_spec
+ | LIMIT obj_spec close_scope_limit
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_LIMIT, &$2, &@$, NULL);
}
@@ -1275,7 +1629,7 @@ list_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARKS, &$3, &@$, NULL);
}
- | SECMARK obj_spec
+ | SECMARK obj_spec close_scope_secmark
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_SECMARK, &$2, &@$, NULL);
}
@@ -1287,7 +1641,7 @@ list_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXYS, &$3, &@$, NULL);
}
- | SYNPROXY obj_spec
+ | SYNPROXY obj_spec close_scope_synproxy
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_SYNPROXY, &$2, &@$, NULL);
}
@@ -1315,6 +1669,10 @@ list_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_FLOWTABLES, &$2, &@$, NULL);
}
+ | FLOWTABLE flowtable_spec
+ {
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL);
+ }
| MAPS ruleset_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_MAPS, &$2, &@$, NULL);
@@ -1323,21 +1681,37 @@ list_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_MAP, &$2, &@$, NULL);
}
- | CT ct_obj_type obj_spec
+ | CT ct_obj_type obj_spec close_scope_ct
{
$$ = cmd_alloc_obj_ct(CMD_LIST, $2, &$3, &@$, NULL);
}
- | CT HELPERS TABLE table_spec
+ | CT ct_cmd_type TABLE table_spec close_scope_ct
{
- $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_HELPERS, &$4, &@$, NULL);
+ $$ = cmd_alloc(CMD_LIST, $2, &$4, &@$, NULL);
}
- | CT TIMEOUT TABLE table_spec
+ | HOOKS basehook_spec
{
- $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_TIMEOUT, &$4, &@$, NULL);
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_HOOKS, &$2, &@$, NULL);
}
- | CT EXPECTATION TABLE table_spec
+ ;
+
+basehook_device_name : DEVICE STRING
{
- $$ = cmd_alloc(CMD_LIST, CMD_OBJ_CT_EXPECT, &$4, &@$, NULL);
+ $$ = $2;
+ }
+ ;
+
+basehook_spec : ruleset_spec
+ {
+ $$ = $1;
+ }
+ | ruleset_spec basehook_device_name
+ {
+ if ($2) {
+ $1.obj.name = $2;
+ $1.obj.location = @2;
+ }
+ $$ = $1;
}
;
@@ -1345,11 +1719,16 @@ reset_cmd : COUNTERS ruleset_spec
{
$$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &$2, &@$, NULL);
}
+ | COUNTERS table_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &$2, &@$, NULL);
+ }
| COUNTERS TABLE table_spec
{
+ /* alias of previous rule. */
$$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTERS, &$3, &@$, NULL);
}
- | COUNTER obj_spec
+ | COUNTER obj_spec close_scope_counter
{
$$ = cmd_alloc(CMD_RESET, CMD_OBJ_COUNTER, &$2,&@$, NULL);
}
@@ -1361,10 +1740,53 @@ reset_cmd : COUNTERS ruleset_spec
{
$$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &$3, &@$, NULL);
}
- | QUOTA obj_spec
+ | QUOTAS table_spec
+ {
+ /* alias of previous rule. */
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &$2, &@$, NULL);
+ }
+ | QUOTA obj_spec close_scope_quota
{
$$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTA, &$2, &@$, NULL);
}
+ | RULES ruleset_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &$2, &@$, NULL);
+ }
+ | RULES table_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &$2, &@$, NULL);
+ }
+ | RULES TABLE table_spec
+ {
+ /* alias of previous rule. */
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &$3, &@$, NULL);
+ }
+ | RULES chain_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &$2, &@$, NULL);
+ }
+ | RULES CHAIN chain_spec
+ {
+ /* alias of previous rule. */
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_RULES, &$3, &@$, NULL);
+ }
+ | RULE ruleid_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_RULE, &$2, &@$, NULL);
+ }
+ | ELEMENT set_spec set_block_expr
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
+ }
+ | SET set_or_id_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_SET, &$2, &@$, NULL);
+ }
+ | MAP set_or_id_spec
+ {
+ $$ = cmd_alloc(CMD_RESET, CMD_OBJ_MAP, &$2, &@$, NULL);
+ }
;
flush_cmd : TABLE table_spec
@@ -1475,21 +1897,36 @@ describe_cmd : primary_expr
table_block_alloc : /* empty */
{
$$ = table_alloc();
- open_scope(state, &$$->scope);
+ if (open_scope(state, &$$->scope) < 0) {
+ erec_queue(error(&@$, "too many levels of nesting"),
+ state->msgs);
+ state->nerrs++;
+ }
}
;
table_options : FLAGS STRING
{
if (strcmp($2, "dormant") == 0) {
- $<table>0->flags = TABLE_F_DORMANT;
- xfree($2);
+ $<table>0->flags |= TABLE_F_DORMANT;
+ free_const($2);
+ } else if (strcmp($2, "owner") == 0) {
+ $<table>0->flags |= TABLE_F_OWNER;
+ free_const($2);
} else {
erec_queue(error(&@2, "unknown table option %s", $2),
state->msgs);
- xfree($2);
+ free_const($2);
+ YYERROR;
+ }
+ }
+ | comment_spec
+ {
+ if (already_set($<table>0->comment, &@$, state)) {
+ free_const($1);
YYERROR;
}
+ $<table>0->comment = $1;
}
;
@@ -1541,7 +1978,7 @@ table_block : /* empty */ { $$ = $<table>-1; }
}
| table_block COUNTER obj_identifier
obj_block_alloc '{' counter_block '}'
- stmt_separator
+ stmt_separator close_scope_counter
{
$4->location = @3;
$4->type = NFT_OBJECT_COUNTER;
@@ -1552,7 +1989,7 @@ table_block : /* empty */ { $$ = $<table>-1; }
}
| table_block QUOTA obj_identifier
obj_block_alloc '{' quota_block '}'
- stmt_separator
+ stmt_separator close_scope_quota
{
$4->location = @3;
$4->type = NFT_OBJECT_QUOTA;
@@ -1561,7 +1998,7 @@ table_block : /* empty */ { $$ = $<table>-1; }
list_add_tail(&$4->list, &$1->objs);
$$ = $1;
}
- | table_block CT HELPER obj_identifier obj_block_alloc '{' ct_helper_block '}' stmt_separator
+ | table_block CT HELPER obj_identifier obj_block_alloc '{' ct_helper_block '}' stmt_separator close_scope_ct
{
$5->location = @4;
$5->type = NFT_OBJECT_CT_HELPER;
@@ -1570,7 +2007,7 @@ table_block : /* empty */ { $$ = $<table>-1; }
list_add_tail(&$5->list, &$1->objs);
$$ = $1;
}
- | table_block CT TIMEOUT obj_identifier obj_block_alloc '{' ct_timeout_block '}' stmt_separator
+ | table_block CT TIMEOUT obj_identifier obj_block_alloc '{' ct_timeout_block '}' stmt_separator close_scope_ct
{
$5->location = @4;
$5->type = NFT_OBJECT_CT_TIMEOUT;
@@ -1579,7 +2016,7 @@ table_block : /* empty */ { $$ = $<table>-1; }
list_add_tail(&$5->list, &$1->objs);
$$ = $1;
}
- | table_block CT EXPECTATION obj_identifier obj_block_alloc '{' ct_expect_block '}' stmt_separator
+ | table_block CT EXPECTATION obj_identifier obj_block_alloc '{' ct_expect_block '}' stmt_separator close_scope_ct
{
$5->location = @4;
$5->type = NFT_OBJECT_CT_EXPECT;
@@ -1590,7 +2027,7 @@ table_block : /* empty */ { $$ = $<table>-1; }
}
| table_block LIMIT obj_identifier
obj_block_alloc '{' limit_block '}'
- stmt_separator
+ stmt_separator close_scope_limit
{
$4->location = @3;
$4->type = NFT_OBJECT_LIMIT;
@@ -1601,7 +2038,7 @@ table_block : /* empty */ { $$ = $<table>-1; }
}
| table_block SECMARK obj_identifier
obj_block_alloc '{' secmark_block '}'
- stmt_separator
+ stmt_separator close_scope_secmark
{
$4->location = @3;
$4->type = NFT_OBJECT_SECMARK;
@@ -1612,7 +2049,7 @@ table_block : /* empty */ { $$ = $<table>-1; }
}
| table_block SYNPROXY obj_identifier
obj_block_alloc '{' synproxy_block '}'
- stmt_separator
+ stmt_separator close_scope_synproxy
{
$4->location = @3;
$4->type = NFT_OBJECT_SYNPROXY;
@@ -1625,8 +2062,12 @@ table_block : /* empty */ { $$ = $<table>-1; }
chain_block_alloc : /* empty */
{
- $$ = chain_alloc(NULL);
- open_scope(state, &$$->scope);
+ $$ = chain_alloc();
+ if (open_scope(state, &$$->scope) < 0) {
+ erec_queue(error(&@$, "too many levels of nesting"),
+ state->msgs);
+ state->nerrs++;
+ }
}
;
@@ -1635,25 +2076,127 @@ chain_block : /* empty */ { $$ = $<chain>-1; }
| chain_block stmt_separator
| chain_block hook_spec stmt_separator
| chain_block policy_spec stmt_separator
+ | chain_block flags_spec stmt_separator
| chain_block rule stmt_separator
{
list_add_tail(&$2->list, &$1->rules);
$$ = $1;
}
+ | chain_block DEVICES '=' flowtable_expr stmt_separator
+ {
+ if ($$->dev_expr) {
+ list_splice_init(&$4->expressions, &$$->dev_expr->expressions);
+ expr_free($4);
+ break;
+ }
+ $$->dev_expr = $4;
+ }
+ | chain_block comment_spec stmt_separator
+ {
+ if (already_set($1->comment, &@2, state)) {
+ free_const($2);
+ YYERROR;
+ }
+ $1->comment = $2;
+ }
+ ;
+
+subchain_block : /* empty */ { $$ = $<chain>-1; }
+ | subchain_block stmt_separator
+ | subchain_block rule stmt_separator
+ {
+ list_add_tail(&$2->list, &$1->rules);
+ $$ = $1;
+ }
;
+typeof_verdict_expr : primary_expr
+ {
+ struct expr *e = $1;
+
+ if (e->etype == EXPR_SYMBOL &&
+ strcmp("verdict", e->identifier) == 0) {
+ struct expr *v = verdict_expr_alloc(&@1, NF_ACCEPT, NULL);
+
+ expr_free(e);
+ v->flags &= ~EXPR_F_CONSTANT;
+ e = v;
+ }
+
+ if (expr_ops(e)->build_udata == NULL) {
+ erec_queue(error(&@1, "map data type '%s' lacks typeof serialization", expr_ops(e)->name),
+ state->msgs);
+ expr_free(e);
+ YYERROR;
+ }
+ $$ = e;
+ }
+ | typeof_expr DOT primary_expr
+ {
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
+ }
+ ;
+
+typeof_data_expr : INTERVAL typeof_expr
+ {
+ $2->flags |= EXPR_F_INTERVAL;
+ $$ = $2;
+ }
+ | typeof_verdict_expr
+ {
+ $$ = $1;
+ }
+ ;
+
+typeof_expr : primary_expr
+ {
+ if (expr_ops($1)->build_udata == NULL) {
+ erec_queue(error(&@1, "primary expression type '%s' lacks typeof serialization", expr_ops($1)->name),
+ state->msgs);
+ expr_free($1);
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ | typeof_expr DOT primary_expr
+ {
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
+ }
+ ;
+
+
set_block_alloc : /* empty */
{
- $$ = set_alloc(NULL);
+ $$ = set_alloc(&internal_location);
}
;
+typeof_key_expr : TYPEOF typeof_expr { $$ = $2; }
+ | TYPE data_type_expr close_scope_type { $$ = $2; }
+ ;
+
set_block : /* empty */ { $$ = $<set>-1; }
| set_block common_block
| set_block stmt_separator
- | set_block TYPE data_type_expr stmt_separator
+ | set_block typeof_key_expr stmt_separator
{
- $1->key = $3;
+ if (already_set($1->key, &@2, state)) {
+ expr_free($2);
+ YYERROR;
+ }
+
+ $1->key = $2;
$$ = $1;
}
| set_block FLAGS set_flag_list stmt_separator
@@ -1671,8 +2214,18 @@ set_block : /* empty */ { $$ = $<set>-1; }
$1->gc_int = $3;
$$ = $1;
}
+ | set_block stateful_stmt_list stmt_separator
+ {
+ list_splice_tail($2, &$1->stmt_list);
+ $$ = $1;
+ free($2);
+ }
| set_block ELEMENTS '=' set_block_expr
{
+ if (already_set($1->init, &@2, state)) {
+ expr_free($4);
+ YYERROR;
+ }
$1->init = $4;
$$ = $1;
}
@@ -1682,6 +2235,15 @@ set_block : /* empty */ { $$ = $<set>-1; }
$$ = $1;
}
| set_block set_mechanism stmt_separator
+ | set_block comment_spec stmt_separator
+ {
+ if (already_set($1->comment, &@2, state)) {
+ free_const($2);
+ YYERROR;
+ }
+ $1->comment = $2;
+ $$ = $1;
+ }
;
set_block_expr : set_expr
@@ -1703,10 +2265,29 @@ set_flag : CONSTANT { $$ = NFT_SET_CONSTANT; }
map_block_alloc : /* empty */
{
- $$ = set_alloc(NULL);
+ $$ = set_alloc(&internal_location);
}
;
+ct_obj_type_map : TIMEOUT { $$ = NFT_OBJECT_CT_TIMEOUT; }
+ | EXPECTATION { $$ = NFT_OBJECT_CT_EXPECT; }
+ ;
+
+map_block_obj_type : COUNTER close_scope_counter { $$ = NFT_OBJECT_COUNTER; }
+ | QUOTA close_scope_quota { $$ = NFT_OBJECT_QUOTA; }
+ | LIMIT close_scope_limit { $$ = NFT_OBJECT_LIMIT; }
+ | SECMARK close_scope_secmark { $$ = NFT_OBJECT_SECMARK; }
+ | SYNPROXY close_scope_synproxy { $$ = NFT_OBJECT_SYNPROXY; }
+ ;
+
+map_block_obj_typeof : map_block_obj_type
+ | CT ct_obj_type_map close_scope_ct { $$ = $2; }
+ ;
+
+map_block_data_interval : INTERVAL { $$ = EXPR_F_INTERVAL; }
+ | { $$ = 0; }
+ ;
+
map_block : /* empty */ { $$ = $<set>-1; }
| map_block common_block
| map_block stmt_separator
@@ -1715,50 +2296,71 @@ map_block : /* empty */ { $$ = $<set>-1; }
$1->timeout = $3;
$$ = $1;
}
- | map_block TYPE
- data_type_expr COLON data_type_expr
- stmt_separator
+ | map_block GC_INTERVAL time_spec stmt_separator
{
- $1->key = $3;
- $1->datatype = $5->dtype;
-
- expr_free($5);
- $1->flags |= NFT_SET_MAP;
+ $1->gc_int = $3;
$$ = $1;
}
| map_block TYPE
- data_type_expr COLON COUNTER
- stmt_separator
+ data_type_expr COLON map_block_data_interval data_type_expr
+ stmt_separator close_scope_type
{
+ if (already_set($1->key, &@2, state)) {
+ expr_free($3);
+ expr_free($6);
+ YYERROR;
+ }
+
$1->key = $3;
- $1->objtype = NFT_OBJECT_COUNTER;
- $1->flags |= NFT_SET_OBJECT;
+ $1->data = $6;
+ $1->data->flags |= $5;
+
+ $1->flags |= NFT_SET_MAP;
$$ = $1;
}
- | map_block TYPE
- data_type_expr COLON QUOTA
+ | map_block TYPEOF
+ typeof_expr COLON typeof_data_expr
stmt_separator
{
+ if (already_set($1->key, &@2, state)) {
+ expr_free($3);
+ expr_free($5);
+ YYERROR;
+ }
+
$1->key = $3;
- $1->objtype = NFT_OBJECT_QUOTA;
- $1->flags |= NFT_SET_OBJECT;
+
+ if ($5->etype == EXPR_CT && $5->ct.key == NFT_CT_HELPER) {
+ $1->objtype = NFT_OBJECT_CT_HELPER;
+ $1->flags |= NFT_SET_OBJECT;
+ expr_free($5);
+ } else {
+ $1->data = $5;
+ $1->flags |= NFT_SET_MAP;
+ }
+
$$ = $1;
}
| map_block TYPE
- data_type_expr COLON LIMIT
- stmt_separator
+ data_type_expr COLON map_block_obj_type
+ stmt_separator close_scope_type
{
+ if (already_set($1->key, &@2, state)) {
+ expr_free($3);
+ YYERROR;
+ }
+
$1->key = $3;
- $1->objtype = NFT_OBJECT_LIMIT;
+ $1->objtype = $5;
$1->flags |= NFT_SET_OBJECT;
$$ = $1;
}
- | map_block TYPE
- data_type_expr COLON SECMARK
+ | map_block TYPEOF
+ typeof_expr COLON map_block_obj_typeof
stmt_separator
{
$1->key = $3;
- $1->objtype = NFT_OBJECT_SECMARK;
+ $1->objtype = $5;
$1->flags |= NFT_SET_OBJECT;
$$ = $1;
}
@@ -1767,15 +2369,30 @@ map_block : /* empty */ { $$ = $<set>-1; }
$1->flags |= $3;
$$ = $1;
}
+ | map_block stateful_stmt_list stmt_separator
+ {
+ list_splice_tail($2, &$1->stmt_list);
+ $$ = $1;
+ free($2);
+ }
| map_block ELEMENTS '=' set_block_expr
{
$1->init = $4;
$$ = $1;
}
+ | map_block comment_spec stmt_separator
+ {
+ if (already_set($1->comment, &@2, state)) {
+ free_const($2);
+ YYERROR;
+ }
+ $1->comment = $2;
+ $$ = $1;
+ }
| map_block set_mechanism stmt_separator
;
-set_mechanism : POLICY set_policy_spec
+set_mechanism : POLICY set_policy_spec close_scope_policy
{
$<set>0->policy = $2;
}
@@ -1791,7 +2408,7 @@ set_policy_spec : PERFORMANCE { $$ = NFT_SET_POL_PERFORMANCE; }
flowtable_block_alloc : /* empty */
{
- $$ = flowtable_alloc(NULL);
+ $$ = flowtable_alloc(&internal_location);
}
;
@@ -1800,14 +2417,15 @@ flowtable_block : /* empty */ { $$ = $<flowtable>-1; }
| flowtable_block stmt_separator
| flowtable_block HOOK STRING prio_spec stmt_separator
{
- $$->hookstr = chain_hookname_lookup($3);
- if ($$->hookstr == NULL) {
- erec_queue(error(&@3, "unknown chain hook %s", $3),
+ $$->hook.loc = @3;
+ $$->hook.name = chain_hookname_lookup($3);
+ if ($$->hook.name == NULL) {
+ erec_queue(error(&@3, "unknown chain hook"),
state->msgs);
- xfree($3);
+ free_const($3);
YYERROR;
}
- xfree($3);
+ free_const($3);
$$->priority = $4;
}
@@ -1815,6 +2433,14 @@ flowtable_block : /* empty */ { $$ = $<flowtable>-1; }
{
$$->dev_expr = $4;
}
+ | flowtable_block COUNTER close_scope_counter
+ {
+ $$->flags |= NFT_FLOWTABLE_COUNTER;
+ }
+ | flowtable_block FLAGS OFFLOAD stmt_separator
+ {
+ $$->flags |= FLOWTABLE_F_HW_OFFLOAD;
+ }
;
flowtable_expr : '{' flowtable_list_expr '}'
@@ -1822,11 +2448,16 @@ flowtable_expr : '{' flowtable_list_expr '}'
$2->location = @$;
$$ = $2;
}
+ | variable_expr
+ {
+ $1->location = @$;
+ $$ = $1;
+ }
;
flowtable_list_expr : flowtable_expr_member
{
- $$ = compound_expr_alloc(&@$, EXPR_INVALID);
+ $$ = compound_expr_alloc(&@$, EXPR_LIST);
compound_expr_add($$, $1);
}
| flowtable_list_expr COMMA flowtable_expr_member
@@ -1837,11 +2468,28 @@ flowtable_list_expr : flowtable_expr_member
| flowtable_list_expr COMMA opt_newline
;
-flowtable_expr_member : STRING
+flowtable_expr_member : QUOTED_STRING
{
- $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
- current_scope(state),
- $1);
+ struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $1);
+
+ if (!expr)
+ YYERROR;
+
+ $$ = expr;
+ }
+ | STRING
+ {
+ struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $1);
+
+ if (!expr)
+ YYERROR;
+
+ $$ = expr;
+ }
+ | variable_expr
+ {
+ datatype_set($1->sym->expr, &ifname_type);
+ $$ = $1;
}
;
@@ -1851,11 +2499,12 @@ data_type_atom_expr : type_identifier
if (dtype == NULL) {
erec_queue(error(&@1, "unknown datatype %s", $1),
state->msgs);
+ free_const($1);
YYERROR;
}
$$ = constant_expr_alloc(&@1, dtype, dtype->byteorder,
dtype->size, NULL);
- xfree($1);
+ free_const($1);
}
| TIME
{
@@ -1867,26 +2516,18 @@ data_type_atom_expr : type_identifier
data_type_expr : data_type_atom_expr
| data_type_expr DOT data_type_atom_expr
{
- if ($1->etype != EXPR_CONCAT) {
- $$ = concat_expr_alloc(&@$);
- compound_expr_add($$, $1);
- } else {
- struct location rhs[] = {
- [1] = @2,
- [2] = @3,
- };
- location_update(&$3->location, rhs, 2);
-
- $$ = $1;
- $$->location = @$;
- }
- compound_expr_add($$, $3);
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
}
;
obj_block_alloc : /* empty */
{
- $$ = obj_alloc(NULL);
+ $$ = obj_alloc(&internal_location);
}
;
@@ -1897,6 +2538,14 @@ counter_block : /* empty */ { $$ = $<obj>-1; }
{
$$ = $1;
}
+ | counter_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ free_const($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
;
quota_block : /* empty */ { $$ = $<obj>-1; }
@@ -1906,6 +2555,14 @@ quota_block : /* empty */ { $$ = $<obj>-1; }
{
$$ = $1;
}
+ | quota_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ free_const($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
;
ct_helper_block : /* empty */ { $$ = $<obj>-1; }
@@ -1915,15 +2572,36 @@ ct_helper_block : /* empty */ { $$ = $<obj>-1; }
{
$$ = $1;
}
+ | ct_helper_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ free_const($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
;
-ct_timeout_block : /*empty */ { $$ = $<obj>-1; }
+ct_timeout_block : /*empty */
+ {
+ $$ = $<obj>-1;
+ init_list_head(&$$->ct_timeout.timeout_list);
+ $$->type = NFT_OBJECT_CT_TIMEOUT;
+ }
| ct_timeout_block common_block
| ct_timeout_block stmt_separator
| ct_timeout_block ct_timeout_config
{
$$ = $1;
}
+ | ct_timeout_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ free_const($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
;
ct_expect_block : /*empty */ { $$ = $<obj>-1; }
@@ -1933,6 +2611,14 @@ ct_expect_block : /*empty */ { $$ = $<obj>-1; }
{
$$ = $1;
}
+ | ct_expect_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ free_const($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
;
limit_block : /* empty */ { $$ = $<obj>-1; }
@@ -1942,6 +2628,14 @@ limit_block : /* empty */ { $$ = $<obj>-1; }
{
$$ = $1;
}
+ | limit_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ free_const($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
;
secmark_block : /* empty */ { $$ = $<obj>-1; }
@@ -1951,6 +2645,14 @@ secmark_block : /* empty */ { $$ = $<obj>-1; }
{
$$ = $1;
}
+ | secmark_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ free_const($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
;
synproxy_block : /* empty */ { $$ = $<obj>-1; }
@@ -1960,6 +2662,14 @@ synproxy_block : /* empty */ { $$ = $<obj>-1; }
{
$$ = $1;
}
+ | synproxy_block comment_spec
+ {
+ if (already_set($<obj>1->comment, &@2, state)) {
+ free_const($2);
+ YYERROR;
+ }
+ $<obj>1->comment = $2;
+ }
;
type_identifier : STRING { $$ = $1; }
@@ -1969,30 +2679,38 @@ type_identifier : STRING { $$ = $1; }
| CLASSID { $$ = xstrdup("classid"); }
;
-hook_spec : TYPE STRING HOOK STRING dev_spec prio_spec
+hook_spec : TYPE close_scope_type STRING HOOK STRING dev_spec prio_spec
{
- const char *chain_type = chain_type_name_lookup($2);
+ const char *chain_type = chain_type_name_lookup($3);
if (chain_type == NULL) {
- erec_queue(error(&@2, "unknown chain type %s", $2),
+ erec_queue(error(&@3, "unknown chain type"),
state->msgs);
- xfree($2);
+ free_const($3);
+ free_const($5);
+ expr_free($6);
+ expr_free($7.expr);
YYERROR;
}
- $<chain>0->type = xstrdup(chain_type);
- xfree($2);
-
- $<chain>0->hookstr = chain_hookname_lookup($4);
- if ($<chain>0->hookstr == NULL) {
- erec_queue(error(&@4, "unknown chain hook %s", $4),
+ $<chain>0->type.loc = @3;
+ $<chain>0->type.str = xstrdup(chain_type);
+ free_const($3);
+
+ $<chain>0->loc = @$;
+ $<chain>0->hook.loc = @5;
+ $<chain>0->hook.name = chain_hookname_lookup($5);
+ if ($<chain>0->hook.name == NULL) {
+ erec_queue(error(&@5, "unknown chain hook"),
state->msgs);
- xfree($4);
+ free_const($5);
+ expr_free($6);
+ expr_free($7.expr);
YYERROR;
}
- xfree($4);
+ free_const($5);
- $<chain>0->dev = $5;
- $<chain>0->priority = $6;
+ $<chain>0->dev_expr = $6;
+ $<chain>0->priority = $7;
$<chain>0->flags |= CHAIN_F_BASECHAIN;
}
;
@@ -2025,7 +2743,6 @@ extended_prio_spec : int_num
{
struct prio_spec spec = {0};
- datatype_set($1->sym->expr, &priority_type);
spec.expr = $1;
$$ = spec;
}
@@ -2037,7 +2754,7 @@ extended_prio_spec : int_num
BYTEORDER_HOST_ENDIAN,
strlen($1) * BITS_PER_BYTE,
$1);
- xfree($1);
+ free_const($1);
$$ = spec;
}
| extended_prio_name PLUS NUM
@@ -2050,7 +2767,7 @@ extended_prio_spec : int_num
BYTEORDER_HOST_ENDIAN,
strlen(str) * BITS_PER_BYTE,
str);
- xfree($1);
+ free_const($1);
$$ = spec;
}
| extended_prio_name DASH NUM
@@ -2063,6 +2780,7 @@ extended_prio_spec : int_num
BYTEORDER_HOST_ENDIAN,
strlen(str) * BITS_PER_BYTE,
str);
+ free_const($1);
$$ = spec;
}
;
@@ -2071,11 +2789,37 @@ int_num : NUM { $$ = $1; }
| DASH NUM { $$ = -$2; }
;
-dev_spec : DEVICE string { $$ = $2; }
+dev_spec : DEVICE string
+ {
+ struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $2);
+
+ if (!expr)
+ YYERROR;
+
+ $$ = compound_expr_alloc(&@$, EXPR_LIST);
+ compound_expr_add($$, expr);
+
+ }
+ | DEVICE variable_expr
+ {
+ datatype_set($2->sym->expr, &ifname_type);
+ $$ = compound_expr_alloc(&@$, EXPR_LIST);
+ compound_expr_add($$, $2);
+ }
+ | DEVICES '=' flowtable_expr
+ {
+ $$ = $3;
+ }
| /* empty */ { $$ = NULL; }
;
-policy_spec : POLICY policy_expr
+flags_spec : FLAGS OFFLOAD
+ {
+ $<chain>0->flags |= CHAIN_F_HW_OFFLOAD;
+ }
+ ;
+
+policy_spec : POLICY policy_expr close_scope_policy
{
if ($<chain>0->policy) {
erec_queue(error(&@$, "you cannot set chain policy twice"),
@@ -2083,7 +2827,8 @@ policy_spec : POLICY policy_expr
expr_free($2);
YYERROR;
}
- $<chain>0->policy = $2;
+ $<chain>0->policy = $2;
+ $<chain>0->policy->location = @$;
}
;
@@ -2106,6 +2851,7 @@ chain_policy : ACCEPT { $$ = NF_ACCEPT; }
;
identifier : STRING
+ | LAST { $$ = xstrdup("last"); }
;
string : STRING
@@ -2119,7 +2865,7 @@ time_spec : STRING
uint64_t res;
erec = time_parse(&@1, $1, &res);
- xfree($1);
+ free_const($1);
if (erec != NULL) {
erec_queue(erec, state->msgs);
YYERROR;
@@ -2128,16 +2874,21 @@ time_spec : STRING
}
;
+/* compatibility kludge to allow either 60, 60s, 1m, ... */
+time_spec_or_num_s : NUM
+ | time_spec { $$ = $1 / 1000u; }
+ ;
+
family_spec : /* empty */ { $$ = NFPROTO_IPV4; }
| family_spec_explicit
;
-family_spec_explicit : IP { $$ = NFPROTO_IPV4; }
- | IP6 { $$ = NFPROTO_IPV6; }
- | INET { $$ = NFPROTO_INET; }
- | ARP { $$ = NFPROTO_ARP; }
- | BRIDGE { $$ = NFPROTO_BRIDGE; }
- | NETDEV { $$ = NFPROTO_NETDEV; }
+family_spec_explicit : IP close_scope_ip { $$ = NFPROTO_IPV4; }
+ | IP6 close_scope_ip6 { $$ = NFPROTO_IPV6; }
+ | INET { $$ = NFPROTO_INET; }
+ | ARP close_scope_arp { $$ = NFPROTO_ARP; }
+ | BRIDGE { $$ = NFPROTO_BRIDGE; }
+ | NETDEV { $$ = NFPROTO_NETDEV; }
;
table_spec : family_spec identifier
@@ -2154,7 +2905,7 @@ tableid_spec : family_spec HANDLE NUM
memset(&$$, 0, sizeof($$));
$$.family = $1;
$$.handle.id = $3;
- $$.handle.location = @$;
+ $$.handle.location = @3;
}
;
@@ -2169,7 +2920,7 @@ chain_spec : table_spec identifier
chainid_spec : table_spec HANDLE NUM
{
$$ = $1;
- $$.handle.location = @$;
+ $$.handle.location = @3;
$$.handle.id = $3;
}
;
@@ -2193,7 +2944,7 @@ set_spec : table_spec identifier
setid_spec : table_spec HANDLE NUM
{
$$ = $1;
- $$.handle.location = @$;
+ $$.handle.location = @3;
$$.handle.id = $3;
}
;
@@ -2206,18 +2957,27 @@ set_identifier : identifier
}
;
-
flowtable_spec : table_spec identifier
{
- $$ = $1;
- $$.flowtable = $2;
+ $$ = $1;
+ $$.flowtable.name = $2;
+ $$.flowtable.location = @2;
+ }
+ ;
+
+flowtableid_spec : table_spec HANDLE NUM
+ {
+ $$ = $1;
+ $$.handle.location = @3;
+ $$.handle.id = $3;
}
;
flowtable_identifier : identifier
{
memset(&$$, 0, sizeof($$));
- $$.flowtable = $1;
+ $$.flowtable.name = $1;
+ $$.flowtable.location = @1;
}
;
@@ -2232,7 +2992,7 @@ obj_spec : table_spec identifier
objid_spec : table_spec HANDLE NUM
{
$$ = $1;
- $$.handle.location = @$;
+ $$.handle.location = @3;
$$.handle.id = $3;
}
;
@@ -2248,7 +3008,7 @@ obj_identifier : identifier
handle_spec : HANDLE NUM
{
memset(&$$, 0, sizeof($$));
- $$.handle.location = @$;
+ $$.handle.location = @2;
$$.handle.id = $2;
}
;
@@ -2306,6 +3066,7 @@ comment_spec : COMMENT string
erec_queue(error(&@2, "comment too long, %d characters maximum allowed",
NFTNL_UDATA_COMMENT_MAXLEN),
state->msgs);
+ free_const($2);
YYERROR;
}
$$ = $2;
@@ -2342,7 +3103,7 @@ rule_alloc : stmt_list
list_for_each_entry(i, $1, list)
$$->num_stmts++;
list_splice_tail($1, &$$->stmts);
- xfree($1);
+ free($1);
}
;
@@ -2359,10 +3120,78 @@ stmt_list : stmt
}
;
-stateful_stmt : counter_stmt
+stateful_stmt_list : stateful_stmt
+ {
+ $$ = xmalloc(sizeof(*$$));
+ init_list_head($$);
+ list_add_tail(&$1->list, $$);
+ }
+ | stateful_stmt_list stateful_stmt
+ {
+ $$ = $1;
+ list_add_tail(&$2->list, $1);
+ }
+ ;
+
+objref_stmt_counter : COUNTER NAME stmt_expr close_scope_counter
+ {
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_COUNTER;
+ $$->objref.expr = $3;
+ }
+ ;
+
+objref_stmt_limit : LIMIT NAME stmt_expr close_scope_limit
+ {
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_LIMIT;
+ $$->objref.expr = $3;
+ }
+ ;
+
+objref_stmt_quota : QUOTA NAME stmt_expr close_scope_quota
+ {
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_QUOTA;
+ $$->objref.expr = $3;
+ }
+ ;
+
+objref_stmt_synproxy : SYNPROXY NAME stmt_expr close_scope_synproxy
+ {
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_SYNPROXY;
+ $$->objref.expr = $3;
+ }
+ ;
+
+objref_stmt_ct : CT TIMEOUT SET stmt_expr close_scope_ct
+ {
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_CT_TIMEOUT;
+ $$->objref.expr = $4;
+
+ }
+ | CT EXPECTATION SET stmt_expr close_scope_ct
+ {
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_CT_EXPECT;
+ $$->objref.expr = $4;
+ }
+ ;
+
+objref_stmt : objref_stmt_counter
+ | objref_stmt_limit
+ | objref_stmt_quota
+ | objref_stmt_synproxy
+ | objref_stmt_ct
+ ;
+
+stateful_stmt : counter_stmt close_scope_counter
| limit_stmt
| quota_stmt
| connlimit_stmt
+ | last_stmt close_scope_last
;
stmt : verdict_stmt
@@ -2371,19 +3200,47 @@ stmt : verdict_stmt
| payload_stmt
| stateful_stmt
| meta_stmt
- | log_stmt
- | reject_stmt
- | nat_stmt
- | tproxy_stmt
+ | log_stmt close_scope_log
+ | reject_stmt close_scope_reject
+ | nat_stmt close_scope_nat
+ | tproxy_stmt close_scope_tproxy
| queue_stmt
| ct_stmt
- | masq_stmt
- | redir_stmt
- | dup_stmt
- | fwd_stmt
+ | masq_stmt close_scope_nat
+ | redir_stmt close_scope_nat
+ | dup_stmt close_scope_dup
+ | fwd_stmt close_scope_fwd
| set_stmt
| map_stmt
- | synproxy_stmt
+ | synproxy_stmt close_scope_synproxy
+ | chain_stmt
+ | optstrip_stmt
+ | xt_stmt close_scope_xt
+ | objref_stmt
+ ;
+
+xt_stmt : XT STRING string
+ {
+ $$ = NULL;
+ free_const($2);
+ free_const($3);
+ erec_queue(error(&@$, "unsupported xtables compat expression, use iptables-nft with this ruleset"),
+ state->msgs);
+ YYERROR;
+ }
+ ;
+
+chain_stmt_type : JUMP { $$ = NFT_JUMP; }
+ | GOTO { $$ = NFT_GOTO; }
+ ;
+
+chain_stmt : chain_stmt_type chain_block_alloc '{' subchain_block '}'
+ {
+ $2->location = @2;
+ close_scope(state);
+ $4->location = @4;
+ $$ = chain_stmt_alloc(&@$, $4, $1);
+ }
;
verdict_stmt : verdict_expr
@@ -2407,13 +3264,7 @@ verdict_map_expr : '{' verdict_map_list_expr '}'
$2->location = @$;
$$ = $2;
}
- | AT identifier
- {
- $$ = symbol_expr_alloc(&@$, SYMBOL_SET,
- current_scope(state),
- $2);
- xfree($2);
- }
+ | set_ref_expr
;
verdict_map_list_expr : verdict_map_list_member_expr
@@ -2431,16 +3282,16 @@ verdict_map_list_expr : verdict_map_list_member_expr
verdict_map_list_member_expr: opt_newline set_elem_expr COLON verdict_expr opt_newline
{
- $$ = mapping_expr_alloc(&@$, $2, $4);
+ $$ = mapping_expr_alloc(&@2, $2, $4);
}
;
-connlimit_stmt : CT COUNT NUM
+connlimit_stmt : CT COUNT NUM close_scope_ct
{
$$ = connlimit_stmt_alloc(&@$);
$$->connlimit.count = $3;
}
- | CT COUNT OVER NUM
+ | CT COUNT OVER NUM close_scope_ct
{
$$ = connlimit_stmt_alloc(&@$);
$$->connlimit.count = $4;
@@ -2455,12 +3306,6 @@ counter_stmt_alloc : COUNTER
{
$$ = counter_stmt_alloc(&@$);
}
- | COUNTER NAME stmt_expr
- {
- $$ = objref_stmt_alloc(&@$);
- $$->objref.type = NFT_OBJECT_COUNTER;
- $$->objref.expr = $3;
- }
;
counter_args : counter_arg
@@ -2472,14 +3317,32 @@ counter_args : counter_arg
counter_arg : PACKETS NUM
{
+ assert($<stmt>0->ops->type == STMT_COUNTER);
$<stmt>0->counter.packets = $2;
}
| BYTES NUM
{
+ assert($<stmt>0->ops->type == STMT_COUNTER);
$<stmt>0->counter.bytes = $2;
}
;
+last_stmt : LAST
+ {
+ $$ = last_stmt_alloc(&@$);
+ }
+ | LAST USED NEVER
+ {
+ $$ = last_stmt_alloc(&@$);
+ }
+ | LAST USED time_spec
+ {
+ $$ = last_stmt_alloc(&@$);
+ $$->last.used = $3;
+ $$->last.set = true;
+ }
+ ;
+
log_stmt : log_stmt_alloc
| log_stmt_alloc log_args
;
@@ -2499,7 +3362,127 @@ log_args : log_arg
log_arg : PREFIX string
{
- $<stmt>0->log.prefix = $2;
+ struct scope *scope = current_scope(state);
+ bool done = false, another_var = false;
+ char *start, *end, scratch = '\0';
+ struct expr *expr, *item;
+ struct symbol *sym;
+ enum {
+ PARSE_TEXT,
+ PARSE_VAR,
+ } prefix_state;
+
+ /* No variables in log prefix, skip. */
+ if (!strchr($2, '$')) {
+ expr = constant_expr_alloc(&@$, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ (strlen($2) + 1) * BITS_PER_BYTE, $2);
+ free_const($2);
+ $<stmt>0->log.prefix = expr;
+ $<stmt>0->log.flags |= STMT_LOG_PREFIX;
+ break;
+ }
+
+ /* Parse variables in log prefix string using a
+ * state machine parser with two states. This
+ * parser creates list of expressions composed
+ * of constant and variable expressions.
+ */
+ expr = compound_expr_alloc(&@$, EXPR_LIST);
+
+ start = (char *)$2;
+
+ if (*start != '$') {
+ prefix_state = PARSE_TEXT;
+ } else {
+ prefix_state = PARSE_VAR;
+ start++;
+ }
+ end = start;
+
+ /* Not nice, but works. */
+ while (!done) {
+ switch (prefix_state) {
+ case PARSE_TEXT:
+ while (*end != '\0' && *end != '$')
+ end++;
+
+ if (*end == '\0')
+ done = true;
+
+ *end = '\0';
+ item = constant_expr_alloc(&@$, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ (strlen(start) + 1) * BITS_PER_BYTE,
+ start);
+ compound_expr_add(expr, item);
+
+ if (done)
+ break;
+
+ start = end + 1;
+ end = start;
+
+ /* fall through */
+ case PARSE_VAR:
+ while (isalnum(*end) || *end == '_')
+ end++;
+
+ if (*end == '\0')
+ done = true;
+ else if (*end == '$')
+ another_var = true;
+ else
+ scratch = *end;
+
+ *end = '\0';
+
+ sym = symbol_get(scope, start);
+ if (!sym) {
+ sym = symbol_lookup_fuzzy(scope, start);
+ if (sym) {
+ erec_queue(error(&@2, "unknown identifier '%s'; "
+ "did you mean identifier ‘%s’?",
+ start, sym->identifier),
+ state->msgs);
+ } else {
+ erec_queue(error(&@2, "unknown identifier '%s'",
+ start),
+ state->msgs);
+ }
+ expr_free(expr);
+ free_const($2);
+ YYERROR;
+ }
+ item = variable_expr_alloc(&@$, scope, sym);
+ compound_expr_add(expr, item);
+
+ if (done)
+ break;
+
+ /* Restore original byte after
+ * symbol lookup.
+ */
+ if (scratch) {
+ *end = scratch;
+ scratch = '\0';
+ }
+
+ start = end;
+ if (another_var) {
+ another_var = false;
+ start++;
+ prefix_state = PARSE_VAR;
+ } else {
+ prefix_state = PARSE_TEXT;
+ }
+ end = start;
+ break;
+ }
+ }
+
+ free_const($2);
+ $<stmt>0->log.prefix = expr;
$<stmt>0->log.flags |= STMT_LOG_PREFIX;
}
| GROUP NUM
@@ -2551,18 +3534,18 @@ level_type : string
else {
erec_queue(error(&@1, "invalid log level"),
state->msgs);
- xfree($1);
+ free_const($1);
YYERROR;
}
- xfree($1);
+ free_const($1);
}
;
-log_flags : TCP log_flags_tcp
+log_flags : TCP log_flags_tcp close_scope_tcp
{
$$ = $2;
}
- | IP OPTIONS
+ | IP OPTIONS close_scope_ip
{
$$ = NF_LOG_IPOPT;
}
@@ -2570,7 +3553,7 @@ log_flags : TCP log_flags_tcp
{
$$ = NF_LOG_UID;
}
- | ETHER
+ | ETHER close_scope_eth
{
$$ = NF_LOG_MACDECODE;
}
@@ -2597,40 +3580,29 @@ log_flag_tcp : SEQUENCE
}
;
-limit_stmt : LIMIT RATE limit_mode NUM SLASH time_unit limit_burst_pkts
+limit_stmt : LIMIT RATE limit_mode limit_rate_pkts limit_burst_pkts close_scope_limit
{
+ if ($5 == 0) {
+ erec_queue(error(&@5, "packet limit burst must be > 0"),
+ state->msgs);
+ YYERROR;
+ }
$$ = limit_stmt_alloc(&@$);
- $$->limit.rate = $4;
- $$->limit.unit = $6;
- $$->limit.burst = $7;
+ $$->limit.rate = $4.rate;
+ $$->limit.unit = $4.unit;
+ $$->limit.burst = $5;
$$->limit.type = NFT_LIMIT_PKTS;
$$->limit.flags = $3;
}
- | LIMIT RATE limit_mode NUM STRING limit_burst_bytes
+ | LIMIT RATE limit_mode limit_rate_bytes limit_burst_bytes close_scope_limit
{
- struct error_record *erec;
- uint64_t rate, unit;
-
- erec = rate_parse(&@$, $5, &rate, &unit);
- xfree($5);
- if (erec != NULL) {
- erec_queue(erec, state->msgs);
- YYERROR;
- }
-
$$ = limit_stmt_alloc(&@$);
- $$->limit.rate = rate * $4;
- $$->limit.unit = unit;
- $$->limit.burst = $6;
+ $$->limit.rate = $4.rate;
+ $$->limit.unit = $4.unit;
+ $$->limit.burst = $5;
$$->limit.type = NFT_LIMIT_PKT_BYTES;
$$->limit.flags = $3;
}
- | LIMIT NAME stmt_expr
- {
- $$ = objref_stmt_alloc(&@$);
- $$->objref.type = NFT_OBJECT_LIMIT;
- $$->objref.expr = $3;
- }
;
quota_mode : OVER { $$ = NFT_QUOTA_F_INV; }
@@ -2649,7 +3621,7 @@ quota_used : /* empty */ { $$ = 0; }
uint64_t rate;
erec = data_unit_parse(&@$, $3, &rate);
- xfree($3);
+ free_const($3);
if (erec != NULL) {
erec_queue(erec, state->msgs);
YYERROR;
@@ -2658,13 +3630,13 @@ quota_used : /* empty */ { $$ = 0; }
}
;
-quota_stmt : QUOTA quota_mode NUM quota_unit quota_used
+quota_stmt : QUOTA quota_mode NUM quota_unit quota_used close_scope_quota
{
struct error_record *erec;
uint64_t rate;
erec = data_unit_parse(&@$, $4, &rate);
- xfree($4);
+ free_const($4);
if (erec != NULL) {
erec_queue(erec, state->msgs);
YYERROR;
@@ -2674,12 +3646,6 @@ quota_stmt : QUOTA quota_mode NUM quota_unit quota_used
$$->quota.used = $5;
$$->quota.flags = $2;
}
- | QUOTA NAME stmt_expr
- {
- $$ = objref_stmt_alloc(&@$);
- $$->objref.type = NFT_OBJECT_QUOTA;
- $$->objref.expr = $3;
- }
;
limit_mode : OVER { $$ = NFT_LIMIT_F_INV; }
@@ -2687,24 +3653,55 @@ limit_mode : OVER { $$ = NFT_LIMIT_F_INV; }
| /* empty */ { $$ = 0; }
;
-limit_burst_pkts : /* empty */ { $$ = 0; }
+limit_burst_pkts : /* empty */ { $$ = 5; }
| BURST NUM PACKETS { $$ = $2; }
;
+limit_rate_pkts : NUM SLASH time_unit
+ {
+ $$.rate = $1;
+ $$.unit = $3;
+ }
+ ;
+
limit_burst_bytes : /* empty */ { $$ = 0; }
- | BURST NUM BYTES { $$ = $2; }
- | BURST NUM STRING
+ | BURST limit_bytes { $$ = $2; }
+ ;
+
+limit_rate_bytes : NUM STRING
+ {
+ struct error_record *erec;
+ uint64_t rate, unit;
+
+ erec = rate_parse(&@$, $2, &rate, &unit);
+ free_const($2);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ $$.rate = rate * $1;
+ $$.unit = unit;
+ }
+ | limit_bytes SLASH time_unit
+ {
+ $$.rate = $1;
+ $$.unit = $3;
+ }
+ ;
+
+limit_bytes : NUM BYTES { $$ = $1; }
+ | NUM STRING
{
struct error_record *erec;
uint64_t rate;
- erec = data_unit_parse(&@$, $3, &rate);
- xfree($3);
+ erec = data_unit_parse(&@$, $2, &rate);
+ free_const($2);
if (erec != NULL) {
erec_queue(erec, state->msgs);
YYERROR;
}
- $$ = $2 * rate;
+ $$ = $1 * rate;
}
;
@@ -2724,44 +3721,61 @@ reject_stmt_alloc : _REJECT
}
;
+reject_with_expr : STRING
+ {
+ $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
+ current_scope(state), $1);
+ free_const($1);
+ }
+ | integer_expr { $$ = $1; }
+ ;
+
reject_opts : /* empty */
{
$<stmt>0->reject.type = -1;
$<stmt>0->reject.icmp_code = -1;
}
- | WITH ICMP TYPE STRING
+ | WITH ICMP TYPE reject_with_expr close_scope_type close_scope_icmp
{
$<stmt>0->reject.family = NFPROTO_IPV4;
$<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH;
- $<stmt>0->reject.expr =
- symbol_expr_alloc(&@$, SYMBOL_VALUE,
- current_scope(state),
- $4);
- datatype_set($<stmt>0->reject.expr, &icmp_code_type);
- xfree($4);
+ $<stmt>0->reject.expr = $4;
+ datatype_set($<stmt>0->reject.expr, &reject_icmp_code_type);
}
- | WITH ICMP6 TYPE STRING
+ | WITH ICMP reject_with_expr
+ {
+ $<stmt>0->reject.family = NFPROTO_IPV4;
+ $<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH;
+ $<stmt>0->reject.expr = $3;
+ datatype_set($<stmt>0->reject.expr, &reject_icmp_code_type);
+ }
+ | WITH ICMP6 TYPE reject_with_expr close_scope_type close_scope_icmp
{
$<stmt>0->reject.family = NFPROTO_IPV6;
$<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH;
- $<stmt>0->reject.expr =
- symbol_expr_alloc(&@$, SYMBOL_VALUE,
- current_scope(state),
- $4);
- datatype_set($<stmt>0->reject.expr, &icmpv6_code_type);
- xfree($4);
+ $<stmt>0->reject.expr = $4;
+ datatype_set($<stmt>0->reject.expr, &reject_icmpv6_code_type);
+ }
+ | WITH ICMP6 reject_with_expr
+ {
+ $<stmt>0->reject.family = NFPROTO_IPV6;
+ $<stmt>0->reject.type = NFT_REJECT_ICMP_UNREACH;
+ $<stmt>0->reject.expr = $3;
+ datatype_set($<stmt>0->reject.expr, &reject_icmpv6_code_type);
+ }
+ | WITH ICMPX TYPE reject_with_expr close_scope_type
+ {
+ $<stmt>0->reject.type = NFT_REJECT_ICMPX_UNREACH;
+ $<stmt>0->reject.expr = $4;
+ datatype_set($<stmt>0->reject.expr, &reject_icmpx_code_type);
}
- | WITH ICMPX TYPE STRING
+ | WITH ICMPX reject_with_expr
{
$<stmt>0->reject.type = NFT_REJECT_ICMPX_UNREACH;
- $<stmt>0->reject.expr =
- symbol_expr_alloc(&@$, SYMBOL_VALUE,
- current_scope(state),
- $4);
- datatype_set($<stmt>0->reject.expr, &icmpx_code_type);
- xfree($4);
+ $<stmt>0->reject.expr = $3;
+ datatype_set($<stmt>0->reject.expr, &reject_icmpx_code_type);
}
- | WITH TCP RESET
+ | WITH TCP close_scope_tcp RESET close_scope_reset
{
$<stmt>0->reject.type = NFT_REJECT_TCP_RST;
}
@@ -2770,8 +3784,8 @@ reject_opts : /* empty */
nat_stmt : nat_stmt_alloc nat_stmt_args
;
-nat_stmt_alloc : SNAT { $$ = nat_stmt_alloc(&@$, NFT_NAT_SNAT); }
- | DNAT { $$ = nat_stmt_alloc(&@$, NFT_NAT_DNAT); }
+nat_stmt_alloc : SNAT { $$ = nat_stmt_alloc(&@$, __NFT_NAT_SNAT); }
+ | DNAT { $$ = nat_stmt_alloc(&@$, __NFT_NAT_DNAT); }
;
tproxy_stmt : TPROXY TO stmt_expr
@@ -2822,12 +3836,6 @@ synproxy_stmt_alloc : SYNPROXY
{
$$ = synproxy_stmt_alloc(&@$);
}
- | SYNPROXY NAME stmt_expr
- {
- $$ = objref_stmt_alloc(&@$);
- $$->objref.type = NFT_OBJECT_SYNPROXY;
- $$->objref.expr = $3;
- }
;
synproxy_args : synproxy_arg
@@ -2851,7 +3859,7 @@ synproxy_arg : MSS NUM
{
$<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_TIMESTAMP;
}
- | SACKPERM
+ | SACK_PERM
{
$<stmt>0->synproxy.flags |= NF_SYNPROXY_OPT_SACK_PERM;
}
@@ -2906,24 +3914,25 @@ synproxy_ts : /* empty */ { $$ = 0; }
;
synproxy_sack : /* empty */ { $$ = 0; }
- | SACKPERM
+ | SACK_PERM
{
$$ = NF_SYNPROXY_OPT_SACK_PERM;
}
;
-primary_stmt_expr : symbol_expr { $$ = $1; }
- | integer_expr { $$ = $1; }
- | boolean_expr { $$ = $1; }
- | meta_expr { $$ = $1; }
- | rt_expr { $$ = $1; }
- | ct_expr { $$ = $1; }
- | numgen_expr { $$ = $1; }
- | hash_expr { $$ = $1; }
- | payload_expr { $$ = $1; }
- | keyword_expr { $$ = $1; }
- | socket_expr { $$ = $1; }
- | osf_expr { $$ = $1; }
+primary_stmt_expr : symbol_expr { $$ = $1; }
+ | integer_expr { $$ = $1; }
+ | boolean_expr { $$ = $1; }
+ | meta_expr { $$ = $1; }
+ | rt_expr { $$ = $1; }
+ | ct_expr { $$ = $1; }
+ | numgen_expr { $$ = $1; }
+ | hash_expr { $$ = $1; }
+ | payload_expr { $$ = $1; }
+ | keyword_expr { $$ = $1; }
+ | socket_expr { $$ = $1; }
+ | osf_expr { $$ = $1; }
+ | '(' basic_stmt_expr ')' { $$ = $2; }
;
shift_stmt_expr : primary_stmt_expr
@@ -2931,7 +3940,7 @@ shift_stmt_expr : primary_stmt_expr
{
$$ = binop_expr_alloc(&@$, OP_LSHIFT, $1, $3);
}
- | shift_stmt_expr RSHIFT primary_rhs_expr
+ | shift_stmt_expr RSHIFT primary_stmt_expr
{
$$ = binop_expr_alloc(&@$, OP_RSHIFT, $1, $3);
}
@@ -2964,25 +3973,17 @@ basic_stmt_expr : inclusive_or_stmt_expr
concat_stmt_expr : basic_stmt_expr
| concat_stmt_expr DOT primary_stmt_expr
{
- if ($$->etype != EXPR_CONCAT) {
- $$ = concat_expr_alloc(&@$);
- compound_expr_add($$, $1);
- } else {
- struct location rhs[] = {
- [1] = @2,
- [2] = @3,
- };
- location_update(&$3->location, rhs, 2);
-
- $$ = $1;
- $$->location = @$;
- }
- compound_expr_add($$, $3);
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
}
;
map_stmt_expr_set : set_expr
- | symbol_expr
+ | set_ref_expr
;
map_stmt_expr : concat_stmt_expr MAP map_stmt_expr_set
@@ -3004,20 +4005,8 @@ range_stmt_expr : basic_stmt_expr DASH basic_stmt_expr
}
;
-wildcard_expr : ASTERISK
- {
- struct expr *expr;
-
- expr = constant_expr_alloc(&@$, &integer_type,
- BYTEORDER_HOST_ENDIAN,
- 0, NULL);
- $$ = prefix_expr_alloc(&@$, expr, 0);
- }
- ;
-
multiton_stmt_expr : prefix_stmt_expr
| range_stmt_expr
- | wildcard_expr
;
stmt_expr : map_stmt_expr
@@ -3066,6 +4055,36 @@ nat_stmt_args : stmt_expr
{
$<stmt>0->nat.flags = $2;
}
+ | nf_key_proto ADDR DOT PORT TO stmt_expr
+ {
+ $<stmt>0->nat.family = $1;
+ $<stmt>0->nat.addr = $6;
+ $<stmt>0->nat.type_flags = STMT_NAT_F_CONCAT;
+ }
+ | nf_key_proto INTERVAL TO stmt_expr
+ {
+ $<stmt>0->nat.family = $1;
+ $<stmt>0->nat.addr = $4;
+ }
+ | INTERVAL TO stmt_expr
+ {
+ $<stmt>0->nat.addr = $3;
+ }
+ | nf_key_proto PREFIX TO stmt_expr
+ {
+ $<stmt>0->nat.family = $1;
+ $<stmt>0->nat.addr = $4;
+ $<stmt>0->nat.type_flags =
+ STMT_NAT_F_PREFIX;
+ $<stmt>0->nat.flags |= NF_NAT_RANGE_NETMAP;
+ }
+ | PREFIX TO stmt_expr
+ {
+ $<stmt>0->nat.addr = $3;
+ $<stmt>0->nat.type_flags =
+ STMT_NAT_F_PREFIX;
+ $<stmt>0->nat.flags |= NF_NAT_RANGE_NETMAP;
+ }
;
masq_stmt : masq_stmt_alloc masq_stmt_args
@@ -3160,13 +4179,28 @@ nf_nat_flag : RANDOM { $$ = NF_NAT_RANGE_PROTO_RANDOM; }
| PERSISTENT { $$ = NF_NAT_RANGE_PERSISTENT; }
;
-queue_stmt : queue_stmt_alloc
+queue_stmt : queue_stmt_compat close_scope_queue
+ | QUEUE TO queue_stmt_expr close_scope_queue
+ {
+ $$ = queue_stmt_alloc(&@$, $3, 0);
+ }
+ | QUEUE FLAGS queue_stmt_flags TO queue_stmt_expr close_scope_queue
+ {
+ $$ = queue_stmt_alloc(&@$, $5, $3);
+ }
+ | QUEUE FLAGS queue_stmt_flags QUEUENUM queue_stmt_expr_simple close_scope_queue
+ {
+ $$ = queue_stmt_alloc(&@$, $5, $3);
+ }
+ ;
+
+queue_stmt_compat : queue_stmt_alloc
| queue_stmt_alloc queue_stmt_args
;
queue_stmt_alloc : QUEUE
{
- $$ = queue_stmt_alloc(&@$);
+ $$ = queue_stmt_alloc(&@$, NULL, 0);
}
;
@@ -3177,7 +4211,7 @@ queue_stmt_args : queue_stmt_arg
| queue_stmt_args queue_stmt_arg
;
-queue_stmt_arg : QUEUENUM stmt_expr
+queue_stmt_arg : QUEUENUM queue_stmt_expr_simple
{
$<stmt>0->queue.queue = $2;
$<stmt>0->queue.queue->location = @$;
@@ -3188,6 +4222,24 @@ queue_stmt_arg : QUEUENUM stmt_expr
}
;
+queue_expr : variable_expr
+ | integer_expr
+ ;
+
+queue_stmt_expr_simple : integer_expr
+ | variable_expr
+ | queue_expr DASH queue_expr
+ {
+ $$ = range_expr_alloc(&@$, $1, $3);
+ }
+ ;
+
+queue_stmt_expr : numgen_expr
+ | hash_expr
+ | map_expr
+ | queue_stmt_expr_simple
+ ;
+
queue_stmt_flags : queue_stmt_flag
| queue_stmt_flags COMMA queue_stmt_flag
{
@@ -3209,27 +4261,28 @@ set_elem_expr_stmt_alloc: concat_expr
}
;
-set_stmt : SET set_stmt_op set_elem_expr_stmt symbol_expr
+set_stmt : SET set_stmt_op set_elem_expr_stmt set_ref_expr
{
$$ = set_stmt_alloc(&@$);
$$->set.op = $2;
$$->set.key = $3;
$$->set.set = $4;
}
- | set_stmt_op symbol_expr '{' set_elem_expr_stmt '}'
+ | set_stmt_op set_ref_expr '{' set_elem_expr_stmt '}'
{
$$ = set_stmt_alloc(&@$);
$$->set.op = $1;
$$->set.key = $4;
$$->set.set = $2;
}
- | set_stmt_op symbol_expr '{' set_elem_expr_stmt stateful_stmt '}'
+ | set_stmt_op set_ref_expr '{' set_elem_expr_stmt stateful_stmt_list '}'
{
$$ = set_stmt_alloc(&@$);
$$->set.op = $1;
$$->set.key = $4;
$$->set.set = $2;
- $$->set.stmt = $5;
+ list_splice_tail($5, &$$->set.stmt_list);
+ free($5);
}
;
@@ -3238,7 +4291,7 @@ set_stmt_op : ADD { $$ = NFT_DYNSET_OP_ADD; }
| DELETE { $$ = NFT_DYNSET_OP_DELETE; }
;
-map_stmt : set_stmt_op symbol_expr '{' set_elem_expr_stmt COLON set_elem_expr_stmt '}'
+map_stmt : set_stmt_op set_ref_expr '{' set_elem_expr_stmt COLON set_elem_expr_stmt '}'
{
$$ = map_stmt_alloc(&@$);
$$->map.op = $1;
@@ -3246,14 +4299,15 @@ map_stmt : set_stmt_op symbol_expr '{' set_elem_expr_stmt COLON set_elem_expr_s
$$->map.data = $6;
$$->map.set = $2;
}
- | set_stmt_op symbol_expr '{' set_elem_expr_stmt stateful_stmt COLON set_elem_expr_stmt '}'
+ | set_stmt_op set_ref_expr '{' set_elem_expr_stmt stateful_stmt_list COLON set_elem_expr_stmt '}'
{
$$ = map_stmt_alloc(&@$);
$$->map.op = $1;
$$->map.key = $4;
$$->map.data = $7;
- $$->map.stmt = $5;
$$->map.set = $2;
+ list_splice_tail($5, &$$->map.stmt_list);
+ free($5);
}
;
@@ -3329,12 +4383,12 @@ variable_expr : '$' identifier
erec_queue(error(&@2, "unknown identifier '%s'", $2),
state->msgs);
}
- xfree($2);
+ free_const($2);
YYERROR;
}
$$ = variable_expr_alloc(&@$, scope, sym);
- xfree($2);
+ free_const($2);
}
;
@@ -3344,14 +4398,20 @@ symbol_expr : variable_expr
$$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
current_scope(state),
$1);
- xfree($1);
+ free_const($1);
}
- | AT identifier
+ ;
+
+set_ref_expr : set_ref_symbol_expr
+ | variable_expr
+ ;
+
+set_ref_symbol_expr : AT identifier close_scope_at
{
$$ = symbol_expr_alloc(&@$, SYMBOL_SET,
current_scope(state),
$2);
- xfree($2);
+ free_const($2);
}
;
@@ -3383,7 +4443,7 @@ primary_expr : symbol_expr { $$ = $1; }
| '(' basic_expr ')' { $$ = $2; }
;
-fib_expr : FIB fib_tuple fib_result
+fib_expr : FIB fib_tuple fib_result close_scope_fib
{
if (($2 & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) == 0) {
erec_queue(error(&@2, "fib: need either saddr or daddr"), state->msgs);
@@ -3408,7 +4468,7 @@ fib_expr : FIB fib_tuple fib_result
fib_result : OIF { $$ =NFT_FIB_RESULT_OIF; }
| OIFNAME { $$ =NFT_FIB_RESULT_OIFNAME; }
- | TYPE { $$ =NFT_FIB_RESULT_ADDRTYPE; }
+ | TYPE close_scope_type { $$ =NFT_FIB_RESULT_ADDRTYPE; }
;
fib_flag : SADDR { $$ = NFTA_FIB_F_SADDR; }
@@ -3425,11 +4485,11 @@ fib_tuple : fib_flag DOT fib_tuple
| fib_flag
;
-osf_expr : OSF osf_ttl HDRVERSION
+osf_expr : OSF osf_ttl HDRVERSION close_scope_osf
{
$$ = osf_expr_alloc(&@$, $2, NFT_OSF_F_VERSION);
}
- | OSF osf_ttl NAME
+ | OSF osf_ttl NAME close_scope_osf
{
$$ = osf_expr_alloc(&@$, $2, 0);
}
@@ -3448,8 +4508,10 @@ osf_ttl : /* empty */
else {
erec_queue(error(&@2, "invalid ttl option"),
state->msgs);
+ free_const($2);
YYERROR;
}
+ free_const($2);
}
;
@@ -3491,20 +4553,12 @@ basic_expr : inclusive_or_expr
concat_expr : basic_expr
| concat_expr DOT basic_expr
{
- if ($$->etype != EXPR_CONCAT) {
- $$ = concat_expr_alloc(&@$);
- compound_expr_add($$, $1);
- } else {
- struct location rhs[] = {
- [1] = @2,
- [2] = @3,
- };
- location_update(&$3->location, rhs, 2);
-
- $$ = $1;
- $$->location = @$;
- }
- compound_expr_add($$, $3);
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
}
;
@@ -3522,7 +4576,6 @@ range_rhs_expr : basic_rhs_expr DASH basic_rhs_expr
multiton_rhs_expr : prefix_rhs_expr
| range_rhs_expr
- | wildcard_expr
;
map_expr : concat_expr MAP rhs_expr
@@ -3566,7 +4619,7 @@ set_list_member_expr : opt_newline set_expr opt_newline
}
| opt_newline set_elem_expr COLON set_rhs_expr opt_newline
{
- $$ = mapping_expr_alloc(&@$, $2, $4);
+ $$ = mapping_expr_alloc(&@2, $2, $4);
}
;
@@ -3585,10 +4638,26 @@ meter_key_expr_alloc : concat_expr
;
set_elem_expr : set_elem_expr_alloc
- | set_elem_expr_alloc set_elem_options
+ | set_elem_expr_alloc set_elem_expr_options
+ | set_elem_expr_alloc set_elem_expr_options set_elem_stmt_list
+ {
+ $$ = $1;
+ list_splice_tail($3, &$$->stmt_list);
+ free($3);
+ }
+ ;
+
+set_elem_key_expr : set_lhs_expr { $$ = $1; }
+ | ASTERISK { $$ = set_elem_catchall_expr_alloc(&@1); }
;
-set_elem_expr_alloc : set_lhs_expr
+set_elem_expr_alloc : set_elem_key_expr set_elem_stmt_list
+ {
+ $$ = set_elem_expr_alloc(&@1, $1);
+ list_splice_tail($2, &$$->stmt_list);
+ free($2);
+ }
+ | set_elem_key_expr
{
$$ = set_elem_expr_alloc(&@1, $1);
}
@@ -3611,12 +4680,130 @@ set_elem_option : TIMEOUT time_spec
}
| comment_spec
{
+ if (already_set($<expr>0->comment, &@1, state)) {
+ free_const($1);
+ YYERROR;
+ }
+ $<expr>0->comment = $1;
+ }
+ ;
+
+set_elem_expr_options : set_elem_expr_option
+ {
+ $<expr>$ = $<expr>0;
+ }
+ | set_elem_expr_options set_elem_expr_option
+ ;
+
+set_elem_stmt_list : set_elem_stmt
+ {
+ $$ = xmalloc(sizeof(*$$));
+ init_list_head($$);
+ list_add_tail(&$1->list, $$);
+ }
+ | set_elem_stmt_list set_elem_stmt
+ {
+ $$ = $1;
+ list_add_tail(&$2->list, $1);
+ }
+ ;
+
+set_elem_stmt : COUNTER close_scope_counter
+ {
+ $$ = counter_stmt_alloc(&@$);
+ }
+ | COUNTER PACKETS NUM BYTES NUM close_scope_counter
+ {
+ $$ = counter_stmt_alloc(&@$);
+ $$->counter.packets = $3;
+ $$->counter.bytes = $5;
+ }
+ | LIMIT RATE limit_mode limit_rate_pkts limit_burst_pkts close_scope_limit
+ {
+ if ($5 == 0) {
+ erec_queue(error(&@5, "limit burst must be > 0"),
+ state->msgs);
+ YYERROR;
+ }
+ $$ = limit_stmt_alloc(&@$);
+ $$->limit.rate = $4.rate;
+ $$->limit.unit = $4.unit;
+ $$->limit.burst = $5;
+ $$->limit.type = NFT_LIMIT_PKTS;
+ $$->limit.flags = $3;
+ }
+ | LIMIT RATE limit_mode limit_rate_bytes limit_burst_bytes close_scope_limit
+ {
+ if ($5 == 0) {
+ erec_queue(error(&@6, "limit burst must be > 0"),
+ state->msgs);
+ YYERROR;
+ }
+ $$ = limit_stmt_alloc(&@$);
+ $$->limit.rate = $4.rate;
+ $$->limit.unit = $4.unit;
+ $$->limit.burst = $5;
+ $$->limit.type = NFT_LIMIT_PKT_BYTES;
+ $$->limit.flags = $3;
+ }
+ | CT COUNT NUM close_scope_ct
+ {
+ $$ = connlimit_stmt_alloc(&@$);
+ $$->connlimit.count = $3;
+ }
+ | CT COUNT OVER NUM close_scope_ct
+ {
+ $$ = connlimit_stmt_alloc(&@$);
+ $$->connlimit.count = $4;
+ $$->connlimit.flags = NFT_CONNLIMIT_F_INV;
+ }
+ | QUOTA quota_mode NUM quota_unit quota_used close_scope_quota
+ {
+ struct error_record *erec;
+ uint64_t rate;
+
+ erec = data_unit_parse(&@$, $4, &rate);
+ free_const($4);
+ if (erec != NULL) {
+ erec_queue(erec, state->msgs);
+ YYERROR;
+ }
+ $$ = quota_stmt_alloc(&@$);
+ $$->quota.bytes = $3 * rate;
+ $$->quota.used = $5;
+ $$->quota.flags = $2;
+ }
+ | LAST USED NEVER close_scope_last
+ {
+ $$ = last_stmt_alloc(&@$);
+ }
+ | LAST USED time_spec close_scope_last
+ {
+ $$ = last_stmt_alloc(&@$);
+ $$->last.used = $3;
+ $$->last.set = true;
+ }
+ ;
+
+set_elem_expr_option : TIMEOUT time_spec
+ {
+ $<expr>0->timeout = $2;
+ }
+ | EXPIRES time_spec
+ {
+ $<expr>0->expiration = $2;
+ }
+ | comment_spec
+ {
+ if (already_set($<expr>0->comment, &@1, state)) {
+ free_const($1);
+ YYERROR;
+ }
$<expr>0->comment = $1;
}
;
set_lhs_expr : concat_rhs_expr
- | multiton_rhs_expr
;
set_rhs_expr : concat_rhs_expr
@@ -3625,6 +4812,16 @@ set_rhs_expr : concat_rhs_expr
initializer_expr : rhs_expr
| list_rhs_expr
+ | '{' '}' { $$ = compound_expr_alloc(&@$, EXPR_SET); }
+ | DASH NUM
+ {
+ int32_t num = -$2;
+
+ $$ = constant_expr_alloc(&@$, &integer_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(num) * BITS_PER_BYTE,
+ &num);
+ }
;
counter_config : PACKETS NUM BYTES NUM
@@ -3651,7 +4848,7 @@ quota_config : quota_mode NUM quota_unit quota_used
uint64_t rate;
erec = data_unit_parse(&@$, $3, &rate);
- xfree($3);
+ free_const($3);
if (erec != NULL) {
erec_queue(erec, state->msgs);
YYERROR;
@@ -3680,10 +4877,10 @@ secmark_config : string
ret = snprintf(secmark->ctx, sizeof(secmark->ctx), "%s", $1);
if (ret <= 0 || ret >= (int)sizeof(secmark->ctx)) {
erec_queue(error(&@1, "invalid context '%s', max length is %u\n", $1, (int)sizeof(secmark->ctx)), state->msgs);
- xfree($1);
+ free_const($1);
YYERROR;
}
- xfree($1);
+ free_const($1);
}
;
@@ -3699,22 +4896,35 @@ ct_obj_type : HELPER { $$ = NFT_OBJECT_CT_HELPER; }
| EXPECTATION { $$ = NFT_OBJECT_CT_EXPECT; }
;
-ct_l4protoname : TCP { $$ = IPPROTO_TCP; }
- | UDP { $$ = IPPROTO_UDP; }
+ct_cmd_type : HELPERS { $$ = CMD_OBJ_CT_HELPERS; }
+ | TIMEOUT { $$ = CMD_OBJ_CT_TIMEOUTS; }
+ | EXPECTATION { $$ = CMD_OBJ_CT_EXPECTATIONS; }
+ ;
+
+ct_l4protoname : TCP close_scope_tcp { $$ = IPPROTO_TCP; }
+ | UDP close_scope_udp { $$ = IPPROTO_UDP; }
;
-ct_helper_config : TYPE QUOTED_STRING PROTOCOL ct_l4protoname stmt_separator
+ct_helper_config : TYPE QUOTED_STRING PROTOCOL ct_l4protoname stmt_separator close_scope_type
{
struct ct_helper *ct;
int ret;
ct = &$<obj>0->ct_helper;
+ if (ct->l4proto) {
+ erec_queue(error(&@2, "You can only specify this once. This statement is already set for %s.", ct->name), state->msgs);
+ free_const($2);
+ YYERROR;
+ }
+
ret = snprintf(ct->name, sizeof(ct->name), "%s", $2);
if (ret <= 0 || ret >= (int)sizeof(ct->name)) {
erec_queue(error(&@2, "invalid name '%s', max length is %u\n", $2, (int)sizeof(ct->name)), state->msgs);
+ free_const($2);
YYERROR;
}
+ free_const($2);
ct->l4proto = $4;
}
@@ -3728,17 +4938,16 @@ timeout_states : timeout_state
{
$$ = xmalloc(sizeof(*$$));
init_list_head($$);
- list_add_tail($1, $$);
+ list_add_tail(&$1->head, $$);
}
| timeout_states COMMA timeout_state
{
- list_add_tail($3, $1);
+ list_add_tail(&$3->head, $1);
$$ = $1;
}
;
-timeout_state : STRING COLON NUM
-
+timeout_state : STRING COLON time_spec_or_num_s
{
struct timeout_state *ts;
@@ -3747,7 +4956,7 @@ timeout_state : STRING COLON NUM
ts->timeout_value = $3;
ts->location = @1;
init_list_head(&ts->head);
- $$ = &ts->head;
+ $$ = ts;
}
;
@@ -3759,13 +4968,13 @@ ct_timeout_config : PROTOCOL ct_l4protoname stmt_separator
ct = &$<obj>0->ct_timeout;
ct->l4proto = l4proto;
}
- | POLICY '=' '{' timeout_states '}' stmt_separator
+ | POLICY '=' '{' timeout_states '}' stmt_separator close_scope_policy
{
struct ct_timeout *ct;
ct = &$<obj>0->ct_timeout;
- init_list_head(&ct->timeout_list);
list_splice_tail($4, &ct->timeout_list);
+ free($4);
}
| L3PROTOCOL family_spec_explicit stmt_separator
{
@@ -3801,33 +5010,25 @@ ct_obj_alloc : /* empty */
}
;
-limit_config : RATE limit_mode NUM SLASH time_unit limit_burst_pkts
+limit_config : RATE limit_mode limit_rate_pkts limit_burst_pkts
{
struct limit *limit;
limit = &$<obj>0->limit;
- limit->rate = $3;
- limit->unit = $5;
- limit->burst = $6;
+ limit->rate = $3.rate;
+ limit->unit = $3.unit;
+ limit->burst = $4;
limit->type = NFT_LIMIT_PKTS;
limit->flags = $2;
}
- | RATE limit_mode NUM STRING limit_burst_bytes
+ | RATE limit_mode limit_rate_bytes limit_burst_bytes
{
struct limit *limit;
- struct error_record *erec;
- uint64_t rate, unit;
-
- erec = rate_parse(&@$, $4, &rate, &unit);
- if (erec != NULL) {
- erec_queue(erec, state->msgs);
- YYERROR;
- }
limit = &$<obj>0->limit;
- limit->rate = rate * $3;
- limit->unit = unit;
- limit->burst = $5;
+ limit->rate = $3.rate;
+ limit->unit = $3.unit;
+ limit->burst = $4;
limit->type = NFT_LIMIT_PKT_BYTES;
limit->flags = $2;
}
@@ -3848,10 +5049,30 @@ relational_expr : expr /* implicit */ rhs_expr
{
$$ = relational_expr_alloc(&@$, OP_IMPLICIT, $1, $2);
}
+ | expr /* implicit */ basic_rhs_expr SLASH list_rhs_expr
+ {
+ $$ = flagcmp_expr_alloc(&@$, OP_EQ, $1, $4, $2);
+ }
+ | expr /* implicit */ list_rhs_expr SLASH list_rhs_expr
+ {
+ $$ = flagcmp_expr_alloc(&@$, OP_EQ, $1, $4, $2);
+ }
+ | expr relational_op basic_rhs_expr SLASH list_rhs_expr
+ {
+ $$ = flagcmp_expr_alloc(&@$, $2, $1, $5, $3);
+ }
+ | expr relational_op list_rhs_expr SLASH list_rhs_expr
+ {
+ $$ = flagcmp_expr_alloc(&@$, $2, $1, $5, $3);
+ }
| expr relational_op rhs_expr
{
$$ = relational_expr_alloc(&@2, $2, $1, $3);
}
+ | expr relational_op list_rhs_expr
+ {
+ $$ = relational_expr_alloc(&@2, $2, $1, $3);
+ }
;
list_rhs_expr : basic_rhs_expr COMMA basic_rhs_expr
@@ -3869,8 +5090,8 @@ list_rhs_expr : basic_rhs_expr COMMA basic_rhs_expr
;
rhs_expr : concat_rhs_expr { $$ = $1; }
- | multiton_rhs_expr { $$ = $1; }
| set_expr { $$ = $1; }
+ | set_ref_symbol_expr { $$ = $1; }
;
shift_rhs_expr : primary_rhs_expr
@@ -3909,22 +5130,24 @@ basic_rhs_expr : inclusive_or_rhs_expr
;
concat_rhs_expr : basic_rhs_expr
- | concat_rhs_expr DOT basic_rhs_expr
+ | multiton_rhs_expr
+ | concat_rhs_expr DOT multiton_rhs_expr
{
- if ($$->etype != EXPR_CONCAT) {
- $$ = concat_expr_alloc(&@$);
- compound_expr_add($$, $1);
- } else {
- struct location rhs[] = {
- [1] = @2,
- [2] = @3,
- };
- location_update(&$3->location, rhs, 2);
-
- $$ = $1;
- $$->location = @$;
- }
- compound_expr_add($$, $3);
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
+ }
+ | concat_rhs_expr DOT basic_rhs_expr
+ {
+ struct location rhs[] = {
+ [1] = @2,
+ [2] = @3,
+ };
+
+ $$ = handle_concat_expr(&@$, $$, $1, $3, rhs);
}
;
@@ -3940,60 +5163,62 @@ boolean_expr : boolean_keys
}
;
-keyword_expr : ETHER { $$ = symbol_value(&@$, "ether"); }
- | IP { $$ = symbol_value(&@$, "ip"); }
- | IP6 { $$ = symbol_value(&@$, "ip6"); }
- | VLAN { $$ = symbol_value(&@$, "vlan"); }
- | ARP { $$ = symbol_value(&@$, "arp"); }
- | DNAT { $$ = symbol_value(&@$, "dnat"); }
- | SNAT { $$ = symbol_value(&@$, "snat"); }
+keyword_expr : ETHER close_scope_eth { $$ = symbol_value(&@$, "ether"); }
+ | IP close_scope_ip { $$ = symbol_value(&@$, "ip"); }
+ | IP6 close_scope_ip6 { $$ = symbol_value(&@$, "ip6"); }
+ | VLAN close_scope_vlan { $$ = symbol_value(&@$, "vlan"); }
+ | ARP close_scope_arp { $$ = symbol_value(&@$, "arp"); }
+ | DNAT close_scope_nat { $$ = symbol_value(&@$, "dnat"); }
+ | SNAT close_scope_nat { $$ = symbol_value(&@$, "snat"); }
| ECN { $$ = symbol_value(&@$, "ecn"); }
- | RESET { $$ = symbol_value(&@$, "reset"); }
+ | RESET close_scope_reset { $$ = symbol_value(&@$, "reset"); }
+ | DESTROY close_scope_destroy { $$ = symbol_value(&@$, "destroy"); }
| ORIGINAL { $$ = symbol_value(&@$, "original"); }
| REPLY { $$ = symbol_value(&@$, "reply"); }
| LABEL { $$ = symbol_value(&@$, "label"); }
+ | LAST close_scope_last { $$ = symbol_value(&@$, "last"); }
;
primary_rhs_expr : symbol_expr { $$ = $1; }
| integer_expr { $$ = $1; }
| boolean_expr { $$ = $1; }
| keyword_expr { $$ = $1; }
- | TCP
+ | TCP close_scope_tcp
{
uint8_t data = IPPROTO_TCP;
$$ = constant_expr_alloc(&@$, &inet_protocol_type,
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
- | UDP
+ | UDP close_scope_udp
{
uint8_t data = IPPROTO_UDP;
$$ = constant_expr_alloc(&@$, &inet_protocol_type,
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
- | UDPLITE
+ | UDPLITE close_scope_udplite
{
uint8_t data = IPPROTO_UDPLITE;
$$ = constant_expr_alloc(&@$, &inet_protocol_type,
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
- | ESP
+ | ESP close_scope_esp
{
uint8_t data = IPPROTO_ESP;
$$ = constant_expr_alloc(&@$, &inet_protocol_type,
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
- | AH
+ | AH close_scope_ah
{
uint8_t data = IPPROTO_AH;
$$ = constant_expr_alloc(&@$, &inet_protocol_type,
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
- | ICMP
+ | ICMP close_scope_icmp
{
uint8_t data = IPPROTO_ICMP;
$$ = constant_expr_alloc(&@$, &inet_protocol_type,
@@ -4007,35 +5232,42 @@ primary_rhs_expr : symbol_expr { $$ = $1; }
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
- | ICMP6
+ | ICMP6 close_scope_icmp
{
uint8_t data = IPPROTO_ICMPV6;
$$ = constant_expr_alloc(&@$, &inet_protocol_type,
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
- | COMP
+ | GRE close_scope_gre
+ {
+ uint8_t data = IPPROTO_GRE;
+ $$ = constant_expr_alloc(&@$, &inet_protocol_type,
+ BYTEORDER_HOST_ENDIAN,
+ sizeof(data) * BITS_PER_BYTE, &data);
+ }
+ | COMP close_scope_comp
{
uint8_t data = IPPROTO_COMP;
$$ = constant_expr_alloc(&@$, &inet_protocol_type,
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
- | DCCP
+ | DCCP close_scope_dccp
{
uint8_t data = IPPROTO_DCCP;
$$ = constant_expr_alloc(&@$, &inet_protocol_type,
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
- | SCTP
+ | SCTP close_scope_sctp
{
uint8_t data = IPPROTO_SCTP;
$$ = constant_expr_alloc(&@$, &inet_protocol_type,
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
- | REDIRECT
+ | REDIRECT close_scope_nat
{
uint8_t data = ICMP_REDIRECT;
$$ = constant_expr_alloc(&@$, &icmp_type_type,
@@ -4051,6 +5283,7 @@ relational_op : EQ { $$ = OP_EQ; }
| GT { $$ = OP_GT; }
| GTE { $$ = OP_GTE; }
| LTE { $$ = OP_LTE; }
+ | NOT { $$ = OP_NEG; }
;
verdict_expr : ACCEPT
@@ -4086,11 +5319,11 @@ chain_expr : variable_expr
BYTEORDER_HOST_ENDIAN,
strlen($1) * BITS_PER_BYTE,
$1);
- xfree($1);
+ free_const($1);
}
;
-meta_expr : META meta_key
+meta_expr : META meta_key close_scope_meta
{
$$ = meta_expr_alloc(&@$, $2);
}
@@ -4098,13 +5331,13 @@ meta_expr : META meta_key
{
$$ = meta_expr_alloc(&@$, $1);
}
- | META STRING
+ | META STRING close_scope_meta
{
struct error_record *erec;
unsigned int key;
erec = meta_key_parse(&@$, $2, &key);
- xfree($2);
+ free_const($2);
if (erec != NULL) {
erec_queue(erec, state->msgs);
YYERROR;
@@ -4122,7 +5355,7 @@ meta_key_qualified : LENGTH { $$ = NFT_META_LEN; }
| PROTOCOL { $$ = NFT_META_PROTOCOL; }
| PRIORITY { $$ = NFT_META_PRIORITY; }
| RANDOM { $$ = NFT_META_PRANDOM; }
- | SECMARK { $$ = NFT_META_SECMARK; }
+ | SECMARK close_scope_secmark { $$ = NFT_META_SECMARK; }
;
meta_key_unqualified : MARK { $$ = NFT_META_MARK; }
@@ -4145,19 +5378,26 @@ meta_key_unqualified : MARK { $$ = NFT_META_MARK; }
| IIFGROUP { $$ = NFT_META_IIFGROUP; }
| OIFGROUP { $$ = NFT_META_OIFGROUP; }
| CGROUP { $$ = NFT_META_CGROUP; }
- | IPSEC { $$ = NFT_META_SECPATH; }
+ | IPSEC close_scope_ipsec { $$ = NFT_META_SECPATH; }
| TIME { $$ = NFT_META_TIME_NS; }
| DAY { $$ = NFT_META_TIME_DAY; }
| HOUR { $$ = NFT_META_TIME_HOUR; }
;
-meta_stmt : META meta_key SET stmt_expr
+meta_stmt : META meta_key SET stmt_expr close_scope_meta
{
switch ($2) {
case NFT_META_SECMARK:
- $$ = objref_stmt_alloc(&@$);
- $$->objref.type = NFT_OBJECT_SECMARK;
- $$->objref.expr = $4;
+ switch ($4->etype) {
+ case EXPR_CT:
+ $$ = meta_stmt_alloc(&@$, $2, $4);
+ break;
+ default:
+ $$ = objref_stmt_alloc(&@$);
+ $$->objref.type = NFT_OBJECT_SECMARK;
+ $$->objref.expr = $4;
+ break;
+ }
break;
default:
$$ = meta_stmt_alloc(&@$, $2, $4);
@@ -4168,15 +5408,16 @@ meta_stmt : META meta_key SET stmt_expr
{
$$ = meta_stmt_alloc(&@$, $1, $3);
}
- | META STRING SET stmt_expr
+ | META STRING SET stmt_expr close_scope_meta
{
struct error_record *erec;
unsigned int key;
erec = meta_key_parse(&@$, $2, &key);
- xfree($2);
+ free_const($2);
if (erec != NULL) {
erec_queue(erec, state->msgs);
+ expr_free($4);
YYERROR;
}
@@ -4186,24 +5427,29 @@ meta_stmt : META meta_key SET stmt_expr
{
$$ = notrack_stmt_alloc(&@$);
}
- | FLOW OFFLOAD AT string
+ | FLOW OFFLOAD AT string close_scope_at
{
$$ = flow_offload_stmt_alloc(&@$, $4);
}
- | FLOW ADD AT string
+ | FLOW ADD AT string close_scope_at
{
$$ = flow_offload_stmt_alloc(&@$, $4);
}
;
-socket_expr : SOCKET socket_key
+socket_expr : SOCKET socket_key close_scope_socket
+ {
+ $$ = socket_expr_alloc(&@$, $2, 0);
+ }
+ | SOCKET CGROUPV2 LEVEL NUM close_scope_socket
{
- $$ = socket_expr_alloc(&@$, $2);
+ $$ = socket_expr_alloc(&@$, NFT_SOCKET_CGROUPV2, $4);
}
;
socket_key : TRANSPARENT { $$ = NFT_SOCKET_TRANSPARENT; }
| MARK { $$ = NFT_SOCKET_MARK; }
+ | WILDCARD { $$ = NFT_SOCKET_WILDCARD; }
;
offset_opt : /* empty */ { $$ = 0; }
@@ -4214,7 +5460,7 @@ numgen_type : INC { $$ = NFT_NG_INCREMENTAL; }
| RANDOM { $$ = NFT_NG_RANDOM; }
;
-numgen_expr : NUMGEN numgen_type MOD NUM offset_opt
+numgen_expr : NUMGEN numgen_type MOD NUM offset_opt close_scope_numgen
{
$$ = numgen_expr_alloc(&@$, $2, $4, $5);
}
@@ -4236,7 +5482,7 @@ xfrm_state_proto_key : DADDR { $$ = NFT_XFRM_KEY_DADDR_IP4; }
| SADDR { $$ = NFT_XFRM_KEY_SADDR_IP4; }
;
-xfrm_expr : IPSEC xfrm_dir xfrm_spnum xfrm_state_key
+xfrm_expr : IPSEC xfrm_dir xfrm_spnum xfrm_state_key close_scope_ipsec
{
if ($3 > 255) {
erec_queue(error(&@3, "value too large"), state->msgs);
@@ -4244,7 +5490,7 @@ xfrm_expr : IPSEC xfrm_dir xfrm_spnum xfrm_state_key
}
$$ = xfrm_expr_alloc(&@$, $2, $3, $4);
}
- | IPSEC xfrm_dir xfrm_spnum nf_key_proto xfrm_state_proto_key
+ | IPSEC xfrm_dir xfrm_spnum nf_key_proto xfrm_state_proto_key close_scope_ipsec
{
enum nft_xfrm_keys xfrmk = $5;
@@ -4271,31 +5517,31 @@ xfrm_expr : IPSEC xfrm_dir xfrm_spnum xfrm_state_key
}
;
-hash_expr : JHASH expr MOD NUM SEED NUM offset_opt
+hash_expr : JHASH expr MOD NUM SEED NUM offset_opt close_scope_hash
{
$$ = hash_expr_alloc(&@$, $4, true, $6, $7, NFT_HASH_JENKINS);
$$->hash.expr = $2;
}
- | JHASH expr MOD NUM offset_opt
+ | JHASH expr MOD NUM offset_opt close_scope_hash
{
$$ = hash_expr_alloc(&@$, $4, false, 0, $5, NFT_HASH_JENKINS);
$$->hash.expr = $2;
}
- | SYMHASH MOD NUM offset_opt
+ | SYMHASH MOD NUM offset_opt close_scope_hash
{
$$ = hash_expr_alloc(&@$, $3, false, 0, $4, NFT_HASH_SYM);
}
;
-nf_key_proto : IP { $$ = NFPROTO_IPV4; }
- | IP6 { $$ = NFPROTO_IPV6; }
+nf_key_proto : IP close_scope_ip { $$ = NFPROTO_IPV4; }
+ | IP6 close_scope_ip6 { $$ = NFPROTO_IPV6; }
;
-rt_expr : RT rt_key
+rt_expr : RT rt_key close_scope_rt
{
$$ = rt_expr_alloc(&@$, $2, true);
}
- | RT nf_key_proto rt_key
+ | RT nf_key_proto rt_key close_scope_rt
{
enum nft_rt_keys rtk = $3;
@@ -4318,18 +5564,18 @@ rt_expr : RT rt_key
rt_key : CLASSID { $$ = NFT_RT_CLASSID; }
| NEXTHOP { $$ = NFT_RT_NEXTHOP4; }
| MTU { $$ = NFT_RT_TCPMSS; }
- | IPSEC { $$ = NFT_RT_XFRM; }
+ | IPSEC close_scope_ipsec { $$ = NFT_RT_XFRM; }
;
-ct_expr : CT ct_key
+ct_expr : CT ct_key close_scope_ct
{
$$ = ct_expr_alloc(&@$, $2, -1);
}
- | CT ct_dir ct_key_dir
+ | CT ct_dir ct_key_dir close_scope_ct
{
$$ = ct_expr_alloc(&@$, $3, $2);
}
- | CT ct_dir ct_key_proto_field
+ | CT ct_dir ct_key_proto_field close_scope_ct
{
$$ = ct_expr_alloc(&@$, $3, $2);
}
@@ -4353,6 +5599,8 @@ ct_key : L3PROTOCOL { $$ = NFT_CT_L3PROTOCOL; }
| PROTO_DST { $$ = NFT_CT_PROTO_DST; }
| LABEL { $$ = NFT_CT_LABELS; }
| EVENT { $$ = NFT_CT_EVENTMASK; }
+ | SECMARK close_scope_secmark { $$ = NFT_CT_SECMARK; }
+ | ID { $$ = NFT_CT_ID; }
| ct_key_dir_optional
;
@@ -4365,10 +5613,10 @@ ct_key_dir : SADDR { $$ = NFT_CT_SRC; }
| ct_key_dir_optional
;
-ct_key_proto_field : IP SADDR { $$ = NFT_CT_SRC_IP; }
- | IP DADDR { $$ = NFT_CT_DST_IP; }
- | IP6 SADDR { $$ = NFT_CT_SRC_IP6; }
- | IP6 DADDR { $$ = NFT_CT_DST_IP6; }
+ct_key_proto_field : IP SADDR close_scope_ip { $$ = NFT_CT_SRC_IP; }
+ | IP DADDR close_scope_ip { $$ = NFT_CT_DST_IP; }
+ | IP6 SADDR close_scope_ip6 { $$ = NFT_CT_SRC_IP6; }
+ | IP6 DADDR close_scope_ip6 { $$ = NFT_CT_DST_IP6; }
;
ct_key_dir_optional : BYTES { $$ = NFT_CT_BYTES; }
@@ -4395,7 +5643,7 @@ list_stmt_expr : symbol_stmt_expr COMMA symbol_stmt_expr
}
;
-ct_stmt : CT ct_key SET stmt_expr
+ct_stmt : CT ct_key SET stmt_expr close_scope_ct
{
switch ($2) {
case NFT_CT_HELPER:
@@ -4408,20 +5656,7 @@ ct_stmt : CT ct_key SET stmt_expr
break;
}
}
- | CT TIMEOUT SET stmt_expr
- {
- $$ = objref_stmt_alloc(&@$);
- $$->objref.type = NFT_OBJECT_CT_TIMEOUT;
- $$->objref.expr = $4;
-
- }
- | CT EXPECTATION SET stmt_expr
- {
- $$ = objref_stmt_alloc(&@$);
- $$->objref.type = NFT_OBJECT_CT_EXPECT;
- $$->objref.expr = $4;
- }
- | CT ct_dir ct_key_dir_optional SET stmt_expr
+ | CT ct_dir ct_key_dir_optional SET stmt_expr close_scope_ct
{
$$ = ct_stmt_alloc(&@$, $3, $2, $5);
}
@@ -4450,13 +5685,35 @@ payload_expr : payload_raw_expr
| comp_hdr_expr
| udp_hdr_expr
| udplite_hdr_expr
- | tcp_hdr_expr
+ | tcp_hdr_expr close_scope_tcp
| dccp_hdr_expr
| sctp_hdr_expr
| th_hdr_expr
+ | vxlan_hdr_expr
+ | geneve_hdr_expr
+ | gre_hdr_expr
+ | gretap_hdr_expr
;
-payload_raw_expr : AT payload_base_spec COMMA NUM COMMA NUM
+payload_raw_len : NUM
+ {
+ if ($1 > NFT_MAX_EXPR_LEN_BITS) {
+ erec_queue(error(&@1, "raw payload length %u exceeds upper limit of %u",
+ $1, NFT_MAX_EXPR_LEN_BITS),
+ state->msgs);
+ YYERROR;
+ }
+
+ if ($1 == 0) {
+ erec_queue(error(&@1, "raw payload length cannot be 0"), state->msgs);
+ YYERROR;
+ }
+
+ $$ = $1;
+ }
+ ;
+
+payload_raw_expr : AT payload_base_spec COMMA NUM COMMA payload_raw_len close_scope_at
{
$$ = payload_expr_alloc(&@$, NULL, 0);
payload_init_raw($$, $2, $4, $6);
@@ -4467,10 +5724,21 @@ payload_raw_expr : AT payload_base_spec COMMA NUM COMMA NUM
payload_base_spec : LL_HDR { $$ = PROTO_BASE_LL_HDR; }
| NETWORK_HDR { $$ = PROTO_BASE_NETWORK_HDR; }
- | TRANSPORT_HDR { $$ = PROTO_BASE_TRANSPORT_HDR; }
+ | TRANSPORT_HDR close_scope_th { $$ = PROTO_BASE_TRANSPORT_HDR; }
+ | STRING
+ {
+ if (!strcmp($1, "ih")) {
+ $$ = PROTO_BASE_INNER_HDR;
+ } else {
+ erec_queue(error(&@1, "unknown raw payload base"), state->msgs);
+ free_const($1);
+ YYERROR;
+ }
+ free_const($1);
+ }
;
-eth_hdr_expr : ETHER eth_hdr_field
+eth_hdr_expr : ETHER eth_hdr_field close_scope_eth
{
$$ = payload_expr_alloc(&@$, &proto_eth, $2);
}
@@ -4478,10 +5746,10 @@ eth_hdr_expr : ETHER eth_hdr_field
eth_hdr_field : SADDR { $$ = ETHHDR_SADDR; }
| DADDR { $$ = ETHHDR_DADDR; }
- | TYPE { $$ = ETHHDR_TYPE; }
+ | TYPE close_scope_type { $$ = ETHHDR_TYPE; }
;
-vlan_hdr_expr : VLAN vlan_hdr_field
+vlan_hdr_expr : VLAN vlan_hdr_field close_scope_vlan
{
$$ = payload_expr_alloc(&@$, &proto_vlan, $2);
}
@@ -4489,11 +5757,12 @@ vlan_hdr_expr : VLAN vlan_hdr_field
vlan_hdr_field : ID { $$ = VLANHDR_VID; }
| CFI { $$ = VLANHDR_CFI; }
+ | DEI { $$ = VLANHDR_DEI; }
| PCP { $$ = VLANHDR_PCP; }
- | TYPE { $$ = VLANHDR_TYPE; }
+ | TYPE close_scope_type { $$ = VLANHDR_TYPE; }
;
-arp_hdr_expr : ARP arp_hdr_field
+arp_hdr_expr : ARP arp_hdr_field close_scope_arp
{
$$ = payload_expr_alloc(&@$, &proto_arp, $2);
}
@@ -4504,23 +5773,27 @@ arp_hdr_field : HTYPE { $$ = ARPHDR_HRD; }
| HLEN { $$ = ARPHDR_HLN; }
| PLEN { $$ = ARPHDR_PLN; }
| OPERATION { $$ = ARPHDR_OP; }
- | SADDR ETHER { $$ = ARPHDR_SADDR_ETHER; }
- | DADDR ETHER { $$ = ARPHDR_DADDR_ETHER; }
- | SADDR IP { $$ = ARPHDR_SADDR_IP; }
- | DADDR IP { $$ = ARPHDR_DADDR_IP; }
+ | SADDR ETHER close_scope_eth { $$ = ARPHDR_SADDR_ETHER; }
+ | DADDR ETHER close_scope_eth { $$ = ARPHDR_DADDR_ETHER; }
+ | SADDR IP close_scope_ip { $$ = ARPHDR_SADDR_IP; }
+ | DADDR IP close_scope_ip { $$ = ARPHDR_DADDR_IP; }
;
-ip_hdr_expr : IP ip_hdr_field
+ip_hdr_expr : IP ip_hdr_field close_scope_ip
{
$$ = payload_expr_alloc(&@$, &proto_ip, $2);
}
- | IP OPTION ip_option_type ip_option_field
+ | IP OPTION ip_option_type ip_option_field close_scope_ip
{
- $$ = ipopt_expr_alloc(&@$, $3, $4, 0);
+ $$ = ipopt_expr_alloc(&@$, $3, $4);
+ if (!$$) {
+ erec_queue(error(&@1, "unknown ip option type/field"), state->msgs);
+ YYERROR;
+ }
}
- | IP OPTION ip_option_type
+ | IP OPTION ip_option_type close_scope_ip
{
- $$ = ipopt_expr_alloc(&@$, $3, IPOPT_FIELD_TYPE, 0);
+ $$ = ipopt_expr_alloc(&@$, $3, IPOPT_FIELD_TYPE);
$$->exthdr.flags = NFT_EXTHDR_F_PRESENT;
}
;
@@ -4545,20 +5818,20 @@ ip_option_type : LSRR { $$ = IPOPT_LSRR; }
| RA { $$ = IPOPT_RA; }
;
-ip_option_field : TYPE { $$ = IPOPT_FIELD_TYPE; }
+ip_option_field : TYPE close_scope_type { $$ = IPOPT_FIELD_TYPE; }
| LENGTH { $$ = IPOPT_FIELD_LENGTH; }
| VALUE { $$ = IPOPT_FIELD_VALUE; }
| PTR { $$ = IPOPT_FIELD_PTR; }
| ADDR { $$ = IPOPT_FIELD_ADDR_0; }
;
-icmp_hdr_expr : ICMP icmp_hdr_field
+icmp_hdr_expr : ICMP icmp_hdr_field close_scope_icmp
{
$$ = payload_expr_alloc(&@$, &proto_icmp, $2);
}
;
-icmp_hdr_field : TYPE { $$ = ICMPHDR_TYPE; }
+icmp_hdr_field : TYPE close_scope_type { $$ = ICMPHDR_TYPE; }
| CODE { $$ = ICMPHDR_CODE; }
| CHECKSUM { $$ = ICMPHDR_CHECKSUM; }
| ID { $$ = ICMPHDR_ID; }
@@ -4567,19 +5840,19 @@ icmp_hdr_field : TYPE { $$ = ICMPHDR_TYPE; }
| MTU { $$ = ICMPHDR_MTU; }
;
-igmp_hdr_expr : IGMP igmp_hdr_field
+igmp_hdr_expr : IGMP igmp_hdr_field close_scope_igmp
{
$$ = payload_expr_alloc(&@$, &proto_igmp, $2);
}
;
-igmp_hdr_field : TYPE { $$ = IGMPHDR_TYPE; }
+igmp_hdr_field : TYPE close_scope_type { $$ = IGMPHDR_TYPE; }
| CHECKSUM { $$ = IGMPHDR_CHECKSUM; }
| MRT { $$ = IGMPHDR_MRT; }
| GROUP { $$ = IGMPHDR_GROUP; }
;
-ip6_hdr_expr : IP6 ip6_hdr_field
+ip6_hdr_expr : IP6 ip6_hdr_field close_scope_ip6
{
$$ = payload_expr_alloc(&@$, &proto_ip6, $2);
}
@@ -4595,13 +5868,13 @@ ip6_hdr_field : HDRVERSION { $$ = IP6HDR_VERSION; }
| SADDR { $$ = IP6HDR_SADDR; }
| DADDR { $$ = IP6HDR_DADDR; }
;
-icmp6_hdr_expr : ICMP6 icmp6_hdr_field
+icmp6_hdr_expr : ICMP6 icmp6_hdr_field close_scope_icmp
{
$$ = payload_expr_alloc(&@$, &proto_icmp6, $2);
}
;
-icmp6_hdr_field : TYPE { $$ = ICMP6HDR_TYPE; }
+icmp6_hdr_field : TYPE close_scope_type { $$ = ICMP6HDR_TYPE; }
| CODE { $$ = ICMP6HDR_CODE; }
| CHECKSUM { $$ = ICMP6HDR_CHECKSUM; }
| PPTR { $$ = ICMP6HDR_PPTR; }
@@ -4609,9 +5882,11 @@ icmp6_hdr_field : TYPE { $$ = ICMP6HDR_TYPE; }
| ID { $$ = ICMP6HDR_ID; }
| SEQUENCE { $$ = ICMP6HDR_SEQ; }
| MAXDELAY { $$ = ICMP6HDR_MAXDELAY; }
+ | TADDR { $$ = ICMP6HDR_TADDR; }
+ | DADDR { $$ = ICMP6HDR_DADDR; }
;
-auth_hdr_expr : AH auth_hdr_field
+auth_hdr_expr : AH auth_hdr_field close_scope_ah
{
$$ = payload_expr_alloc(&@$, &proto_ah, $2);
}
@@ -4624,7 +5899,7 @@ auth_hdr_field : NEXTHDR { $$ = AHHDR_NEXTHDR; }
| SEQUENCE { $$ = AHHDR_SEQUENCE; }
;
-esp_hdr_expr : ESP esp_hdr_field
+esp_hdr_expr : ESP esp_hdr_field close_scope_esp
{
$$ = payload_expr_alloc(&@$, &proto_esp, $2);
}
@@ -4634,7 +5909,7 @@ esp_hdr_field : SPI { $$ = ESPHDR_SPI; }
| SEQUENCE { $$ = ESPHDR_SEQUENCE; }
;
-comp_hdr_expr : COMP comp_hdr_field
+comp_hdr_expr : COMP comp_hdr_field close_scope_comp
{
$$ = payload_expr_alloc(&@$, &proto_comp, $2);
}
@@ -4645,7 +5920,7 @@ comp_hdr_field : NEXTHDR { $$ = COMPHDR_NEXTHDR; }
| CPI { $$ = COMPHDR_CPI; }
;
-udp_hdr_expr : UDP udp_hdr_field
+udp_hdr_expr : UDP udp_hdr_field close_scope_udp
{
$$ = payload_expr_alloc(&@$, &proto_udp, $2);
}
@@ -4657,7 +5932,7 @@ udp_hdr_field : SPORT { $$ = UDPHDR_SPORT; }
| CHECKSUM { $$ = UDPHDR_CHECKSUM; }
;
-udplite_hdr_expr : UDPLITE udplite_hdr_field
+udplite_hdr_expr : UDPLITE udplite_hdr_field close_scope_udplite
{
$$ = payload_expr_alloc(&@$, &proto_udplite, $2);
}
@@ -4673,15 +5948,119 @@ tcp_hdr_expr : TCP tcp_hdr_field
{
$$ = payload_expr_alloc(&@$, &proto_tcp, $2);
}
- | TCP OPTION tcp_hdr_option_type tcp_hdr_option_field
- {
- $$ = tcpopt_expr_alloc(&@$, $3, $4);
- }
| TCP OPTION tcp_hdr_option_type
{
- $$ = tcpopt_expr_alloc(&@$, $3, TCPOPTHDR_FIELD_KIND);
+ $$ = tcpopt_expr_alloc(&@$, $3, TCPOPT_COMMON_KIND);
$$->exthdr.flags = NFT_EXTHDR_F_PRESENT;
}
+ | TCP OPTION tcp_hdr_option_kind_and_field
+ {
+ $$ = tcpopt_expr_alloc(&@$, $3.kind, $3.field);
+ if ($$ == NULL) {
+ erec_queue(error(&@1, "Could not find a tcp option template"), state->msgs);
+ YYERROR;
+ }
+ }
+ | TCP OPTION AT close_scope_at tcp_hdr_option_type COMMA NUM COMMA payload_raw_len
+ {
+ $$ = tcpopt_expr_alloc(&@$, $5, 0);
+ tcpopt_init_raw($$, $5, $7, $9, 0);
+ }
+ ;
+
+inner_inet_expr : ip_hdr_expr
+ | icmp_hdr_expr
+ | igmp_hdr_expr
+ | ip6_hdr_expr
+ | icmp6_hdr_expr
+ | auth_hdr_expr
+ | esp_hdr_expr
+ | comp_hdr_expr
+ | udp_hdr_expr
+ | udplite_hdr_expr
+ | tcp_hdr_expr close_scope_tcp
+ | dccp_hdr_expr
+ | sctp_hdr_expr
+ | th_hdr_expr
+ ;
+
+inner_eth_expr : eth_hdr_expr
+ | vlan_hdr_expr
+ | arp_hdr_expr
+ ;
+
+inner_expr : inner_eth_expr
+ | inner_inet_expr
+ ;
+
+vxlan_hdr_expr : VXLAN vxlan_hdr_field
+ {
+ struct expr *expr;
+
+ expr = payload_expr_alloc(&@$, &proto_vxlan, $2);
+ expr->payload.inner_desc = &proto_vxlan;
+ $$ = expr;
+ }
+ | VXLAN inner_expr
+ {
+ $$ = $2;
+ $$->location = @$;
+ $$->payload.inner_desc = &proto_vxlan;
+ }
+ ;
+
+vxlan_hdr_field : VNI { $$ = VXLANHDR_VNI; }
+ | FLAGS { $$ = VXLANHDR_FLAGS; }
+ ;
+
+geneve_hdr_expr : GENEVE geneve_hdr_field
+ {
+ struct expr *expr;
+
+ expr = payload_expr_alloc(&@$, &proto_geneve, $2);
+ expr->payload.inner_desc = &proto_geneve;
+ $$ = expr;
+ }
+ | GENEVE inner_expr
+ {
+ $$ = $2;
+ $$->location = @$;
+ $$->payload.inner_desc = &proto_geneve;
+ }
+ ;
+
+geneve_hdr_field : VNI { $$ = GNVHDR_VNI; }
+ | TYPE { $$ = GNVHDR_TYPE; }
+ ;
+
+gre_hdr_expr : GRE gre_hdr_field close_scope_gre
+ {
+ $$ = payload_expr_alloc(&@$, &proto_gre, $2);
+ }
+ | GRE close_scope_gre inner_inet_expr
+ {
+ $$ = $3;
+ $$->payload.inner_desc = &proto_gre;
+ }
+ ;
+
+gre_hdr_field : HDRVERSION { $$ = GREHDR_VERSION; }
+ | FLAGS { $$ = GREHDR_FLAGS; }
+ | PROTOCOL { $$ = GREHDR_PROTOCOL; }
+ ;
+
+gretap_hdr_expr : GRETAP close_scope_gre inner_expr
+ {
+ $$ = $3;
+ $$->payload.inner_desc = &proto_gretap;
+ }
+ ;
+
+optstrip_stmt : RESET TCP OPTION tcp_hdr_option_type close_scope_tcp
+ {
+ $$ = optstrip_stmt_alloc(&@$, tcpopt_expr_alloc(&@$,
+ $4, TCPOPT_COMMON_KIND));
+ }
;
tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; }
@@ -4696,45 +6075,211 @@ tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; }
| URGPTR { $$ = TCPHDR_URGPTR; }
;
-tcp_hdr_option_type : EOL { $$ = TCPOPTHDR_EOL; }
- | NOOP { $$ = TCPOPTHDR_NOOP; }
- | MAXSEG { $$ = TCPOPTHDR_MAXSEG; }
- | WINDOW { $$ = TCPOPTHDR_WINDOW; }
- | SACK_PERMITTED { $$ = TCPOPTHDR_SACK_PERMITTED; }
- | SACK { $$ = TCPOPTHDR_SACK0; }
- | SACK0 { $$ = TCPOPTHDR_SACK0; }
- | SACK1 { $$ = TCPOPTHDR_SACK1; }
- | SACK2 { $$ = TCPOPTHDR_SACK2; }
- | SACK3 { $$ = TCPOPTHDR_SACK3; }
- | ECHO { $$ = TCPOPTHDR_ECHO; }
- | TIMESTAMP { $$ = TCPOPTHDR_TIMESTAMP; }
+tcp_hdr_option_kind_and_field : MSS tcpopt_field_maxseg
+ {
+ struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_MAXSEG, .field = $2 };
+ $$ = kind_field;
+ }
+ | tcp_hdr_option_sack tcpopt_field_sack
+ {
+ struct tcp_kind_field kind_field = { .kind = $1, .field = $2 };
+ $$ = kind_field;
+ }
+ | WINDOW tcpopt_field_window
+ {
+ struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_WINDOW, .field = $2 };
+ $$ = kind_field;
+ }
+ | TIMESTAMP tcpopt_field_tsopt
+ {
+ struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_TIMESTAMP, .field = $2 };
+ $$ = kind_field;
+ }
+ | tcp_hdr_option_type LENGTH
+ {
+ struct tcp_kind_field kind_field = { .kind = $1, .field = TCPOPT_COMMON_LENGTH };
+ $$ = kind_field;
+ }
+ | MPTCP tcpopt_field_mptcp
+ {
+ struct tcp_kind_field kind_field = { .kind = TCPOPT_KIND_MPTCP, .field = $2 };
+ $$ = kind_field;
+ }
+ ;
+
+tcp_hdr_option_sack : SACK { $$ = TCPOPT_KIND_SACK; }
+ | SACK0 { $$ = TCPOPT_KIND_SACK; }
+ | SACK1 { $$ = TCPOPT_KIND_SACK1; }
+ | SACK2 { $$ = TCPOPT_KIND_SACK2; }
+ | SACK3 { $$ = TCPOPT_KIND_SACK3; }
+ ;
+
+tcp_hdr_option_type : ECHO { $$ = TCPOPT_KIND_ECHO; }
+ | EOL { $$ = TCPOPT_KIND_EOL; }
+ | FASTOPEN { $$ = TCPOPT_KIND_FASTOPEN; }
+ | MD5SIG { $$ = TCPOPT_KIND_MD5SIG; }
+ | MPTCP { $$ = TCPOPT_KIND_MPTCP; }
+ | MSS { $$ = TCPOPT_KIND_MAXSEG; }
+ | NOP { $$ = TCPOPT_KIND_NOP; }
+ | SACK_PERM { $$ = TCPOPT_KIND_SACK_PERMITTED; }
+ | TIMESTAMP { $$ = TCPOPT_KIND_TIMESTAMP; }
+ | WINDOW { $$ = TCPOPT_KIND_WINDOW; }
+ | tcp_hdr_option_sack { $$ = $1; }
+ | NUM {
+ if ($1 > 255) {
+ erec_queue(error(&@1, "value too large"), state->msgs);
+ YYERROR;
+ }
+ $$ = $1;
+ }
+ ;
+
+tcpopt_field_sack : LEFT { $$ = TCPOPT_SACK_LEFT; }
+ | RIGHT { $$ = TCPOPT_SACK_RIGHT; }
;
-tcp_hdr_option_field : KIND { $$ = TCPOPTHDR_FIELD_KIND; }
- | LENGTH { $$ = TCPOPTHDR_FIELD_LENGTH; }
- | SIZE { $$ = TCPOPTHDR_FIELD_SIZE; }
- | COUNT { $$ = TCPOPTHDR_FIELD_COUNT; }
- | LEFT { $$ = TCPOPTHDR_FIELD_LEFT; }
- | RIGHT { $$ = TCPOPTHDR_FIELD_RIGHT; }
- | TSVAL { $$ = TCPOPTHDR_FIELD_TSVAL; }
- | TSECR { $$ = TCPOPTHDR_FIELD_TSECR; }
+tcpopt_field_window : COUNT { $$ = TCPOPT_WINDOW_COUNT; }
;
-dccp_hdr_expr : DCCP dccp_hdr_field
+tcpopt_field_tsopt : TSVAL { $$ = TCPOPT_TS_TSVAL; }
+ | TSECR { $$ = TCPOPT_TS_TSECR; }
+ ;
+
+tcpopt_field_maxseg : SIZE { $$ = TCPOPT_MAXSEG_SIZE; }
+ ;
+
+tcpopt_field_mptcp : SUBTYPE { $$ = TCPOPT_MPTCP_SUBTYPE; }
+ ;
+
+dccp_hdr_expr : DCCP dccp_hdr_field close_scope_dccp
{
$$ = payload_expr_alloc(&@$, &proto_dccp, $2);
}
+ | DCCP OPTION NUM close_scope_dccp
+ {
+ if ($3 > DCCPOPT_TYPE_MAX) {
+ erec_queue(error(&@1, "value too large"),
+ state->msgs);
+ YYERROR;
+ }
+ $$ = dccpopt_expr_alloc(&@$, $3);
+ }
;
dccp_hdr_field : SPORT { $$ = DCCPHDR_SPORT; }
| DPORT { $$ = DCCPHDR_DPORT; }
- | TYPE { $$ = DCCPHDR_TYPE; }
+ | TYPE close_scope_type { $$ = DCCPHDR_TYPE; }
+ ;
+
+sctp_chunk_type : DATA { $$ = SCTP_CHUNK_TYPE_DATA; }
+ | INIT { $$ = SCTP_CHUNK_TYPE_INIT; }
+ | INIT_ACK { $$ = SCTP_CHUNK_TYPE_INIT_ACK; }
+ | SACK { $$ = SCTP_CHUNK_TYPE_SACK; }
+ | HEARTBEAT { $$ = SCTP_CHUNK_TYPE_HEARTBEAT; }
+ | HEARTBEAT_ACK { $$ = SCTP_CHUNK_TYPE_HEARTBEAT_ACK; }
+ | ABORT { $$ = SCTP_CHUNK_TYPE_ABORT; }
+ | SHUTDOWN { $$ = SCTP_CHUNK_TYPE_SHUTDOWN; }
+ | SHUTDOWN_ACK { $$ = SCTP_CHUNK_TYPE_SHUTDOWN_ACK; }
+ | ERROR { $$ = SCTP_CHUNK_TYPE_ERROR; }
+ | COOKIE_ECHO { $$ = SCTP_CHUNK_TYPE_COOKIE_ECHO; }
+ | COOKIE_ACK { $$ = SCTP_CHUNK_TYPE_COOKIE_ACK; }
+ | ECNE { $$ = SCTP_CHUNK_TYPE_ECNE; }
+ | CWR { $$ = SCTP_CHUNK_TYPE_CWR; }
+ | SHUTDOWN_COMPLETE { $$ = SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE; }
+ | ASCONF_ACK { $$ = SCTP_CHUNK_TYPE_ASCONF_ACK; }
+ | FORWARD_TSN { $$ = SCTP_CHUNK_TYPE_FORWARD_TSN; }
+ | ASCONF { $$ = SCTP_CHUNK_TYPE_ASCONF; }
+ ;
+
+sctp_chunk_common_field : TYPE close_scope_type { $$ = SCTP_CHUNK_COMMON_TYPE; }
+ | FLAGS { $$ = SCTP_CHUNK_COMMON_FLAGS; }
+ | LENGTH { $$ = SCTP_CHUNK_COMMON_LENGTH; }
;
-sctp_hdr_expr : SCTP sctp_hdr_field
+sctp_chunk_data_field : TSN { $$ = SCTP_CHUNK_DATA_TSN; }
+ | STREAM { $$ = SCTP_CHUNK_DATA_STREAM; }
+ | SSN { $$ = SCTP_CHUNK_DATA_SSN; }
+ | PPID { $$ = SCTP_CHUNK_DATA_PPID; }
+ ;
+
+sctp_chunk_init_field : INIT_TAG { $$ = SCTP_CHUNK_INIT_TAG; }
+ | A_RWND { $$ = SCTP_CHUNK_INIT_RWND; }
+ | NUM_OSTREAMS { $$ = SCTP_CHUNK_INIT_OSTREAMS; }
+ | NUM_ISTREAMS { $$ = SCTP_CHUNK_INIT_ISTREAMS; }
+ | INIT_TSN { $$ = SCTP_CHUNK_INIT_TSN; }
+ ;
+
+sctp_chunk_sack_field : CUM_TSN_ACK { $$ = SCTP_CHUNK_SACK_CTSN_ACK; }
+ | A_RWND { $$ = SCTP_CHUNK_SACK_RWND; }
+ | NUM_GACK_BLOCKS { $$ = SCTP_CHUNK_SACK_GACK_BLOCKS; }
+ | NUM_DUP_TSNS { $$ = SCTP_CHUNK_SACK_DUP_TSNS; }
+ ;
+
+sctp_chunk_alloc : sctp_chunk_type
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, $1, SCTP_CHUNK_COMMON_TYPE);
+ $$->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ }
+ | sctp_chunk_type sctp_chunk_common_field
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, $1, $2);
+ }
+ | DATA sctp_chunk_data_field
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_DATA, $2);
+ }
+ | INIT sctp_chunk_init_field
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_INIT, $2);
+ }
+ | INIT_ACK sctp_chunk_init_field
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_INIT_ACK, $2);
+ }
+ | SACK sctp_chunk_sack_field
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_SACK, $2);
+ }
+ | SHUTDOWN CUM_TSN_ACK
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_SHUTDOWN,
+ SCTP_CHUNK_SHUTDOWN_CTSN_ACK);
+ }
+ | ECNE LOWEST_TSN
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ECNE,
+ SCTP_CHUNK_ECNE_CWR_MIN_TSN);
+ }
+ | CWR LOWEST_TSN
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_CWR,
+ SCTP_CHUNK_ECNE_CWR_MIN_TSN);
+ }
+ | ASCONF_ACK SEQNO
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ASCONF_ACK,
+ SCTP_CHUNK_ASCONF_SEQNO);
+ }
+ | FORWARD_TSN NEW_CUM_TSN
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_FORWARD_TSN,
+ SCTP_CHUNK_FORWARD_TSN_NCTSN);
+ }
+ | ASCONF SEQNO
+ {
+ $$ = sctp_chunk_expr_alloc(&@$, SCTP_CHUNK_TYPE_ASCONF,
+ SCTP_CHUNK_ASCONF_SEQNO);
+ }
+ ;
+
+sctp_hdr_expr : SCTP sctp_hdr_field close_scope_sctp
{
$$ = payload_expr_alloc(&@$, &proto_sctp, $2);
}
+ | SCTP CHUNK sctp_chunk_alloc close_scope_sctp_chunk close_scope_sctp
+ {
+ $$ = $3;
+ }
;
sctp_hdr_field : SPORT { $$ = SCTPHDR_SPORT; }
@@ -4743,7 +6288,7 @@ sctp_hdr_field : SPORT { $$ = SCTPHDR_SPORT; }
| CHECKSUM { $$ = SCTPHDR_CHECKSUM; }
;
-th_hdr_expr : TRANSPORT_HDR th_hdr_field
+th_hdr_expr : TRANSPORT_HDR th_hdr_field close_scope_th
{
$$ = payload_expr_alloc(&@$, &proto_th, $2);
if ($$)
@@ -4765,7 +6310,7 @@ exthdr_expr : hbh_hdr_expr
| mh_hdr_expr
;
-hbh_hdr_expr : HBH hbh_hdr_field
+hbh_hdr_expr : HBH hbh_hdr_field close_scope_hbh
{
$$ = exthdr_expr_alloc(&@$, &exthdr_hbh, $2);
}
@@ -4775,7 +6320,7 @@ hbh_hdr_field : NEXTHDR { $$ = HBHHDR_NEXTHDR; }
| HDRLENGTH { $$ = HBHHDR_HDRLENGTH; }
;
-rt_hdr_expr : RT rt_hdr_field
+rt_hdr_expr : RT rt_hdr_field close_scope_rt
{
$$ = exthdr_expr_alloc(&@$, &exthdr_rt, $2);
}
@@ -4783,11 +6328,11 @@ rt_hdr_expr : RT rt_hdr_field
rt_hdr_field : NEXTHDR { $$ = RTHDR_NEXTHDR; }
| HDRLENGTH { $$ = RTHDR_HDRLENGTH; }
- | TYPE { $$ = RTHDR_TYPE; }
+ | TYPE close_scope_type { $$ = RTHDR_TYPE; }
| SEG_LEFT { $$ = RTHDR_SEG_LEFT; }
;
-rt0_hdr_expr : RT0 rt0_hdr_field
+rt0_hdr_expr : RT0 rt0_hdr_field close_scope_rt
{
$$ = exthdr_expr_alloc(&@$, &exthdr_rt0, $2);
}
@@ -4799,7 +6344,7 @@ rt0_hdr_field : ADDR '[' NUM ']'
}
;
-rt2_hdr_expr : RT2 rt2_hdr_field
+rt2_hdr_expr : RT2 rt2_hdr_field close_scope_rt
{
$$ = exthdr_expr_alloc(&@$, &exthdr_rt2, $2);
}
@@ -4808,7 +6353,7 @@ rt2_hdr_expr : RT2 rt2_hdr_field
rt2_hdr_field : ADDR { $$ = RT2HDR_ADDR; }
;
-rt4_hdr_expr : RT4 rt4_hdr_field
+rt4_hdr_expr : RT4 rt4_hdr_field close_scope_rt
{
$$ = exthdr_expr_alloc(&@$, &exthdr_rt4, $2);
}
@@ -4823,7 +6368,7 @@ rt4_hdr_field : LAST_ENT { $$ = RT4HDR_LASTENT; }
}
;
-frag_hdr_expr : FRAG frag_hdr_field
+frag_hdr_expr : FRAG frag_hdr_field close_scope_frag
{
$$ = exthdr_expr_alloc(&@$, &exthdr_frag, $2);
}
@@ -4837,7 +6382,7 @@ frag_hdr_field : NEXTHDR { $$ = FRAGHDR_NEXTHDR; }
| ID { $$ = FRAGHDR_ID; }
;
-dst_hdr_expr : DST dst_hdr_field
+dst_hdr_expr : DST dst_hdr_field close_scope_dst
{
$$ = exthdr_expr_alloc(&@$, &exthdr_dst, $2);
}
@@ -4847,7 +6392,7 @@ dst_hdr_field : NEXTHDR { $$ = DSTHDR_NEXTHDR; }
| HDRLENGTH { $$ = DSTHDR_HDRLENGTH; }
;
-mh_hdr_expr : MH mh_hdr_field
+mh_hdr_expr : MH mh_hdr_field close_scope_mh
{
$$ = exthdr_expr_alloc(&@$, &exthdr_mh, $2);
}
@@ -4855,7 +6400,7 @@ mh_hdr_expr : MH mh_hdr_field
mh_hdr_field : NEXTHDR { $$ = MHHDR_NEXTHDR; }
| HDRLENGTH { $$ = MHHDR_HDRLENGTH; }
- | TYPE { $$ = MHHDR_TYPE; }
+ | TYPE close_scope_type { $$ = MHHDR_TYPE; }
| RESERVED { $$ = MHHDR_RESERVED; }
| CHECKSUM { $$ = MHHDR_CHECKSUM; }
;
@@ -4867,18 +6412,18 @@ exthdr_exists_expr : EXTHDR exthdr_key
desc = exthdr_find_proto($2);
/* Assume that NEXTHDR template is always
- * the fist one in list of templates.
+ * the first one in list of templates.
*/
$$ = exthdr_expr_alloc(&@$, desc, 1);
$$->exthdr.flags = NFT_EXTHDR_F_PRESENT;
}
;
-exthdr_key : HBH { $$ = IPPROTO_HOPOPTS; }
- | RT { $$ = IPPROTO_ROUTING; }
- | FRAG { $$ = IPPROTO_FRAGMENT; }
- | DST { $$ = IPPROTO_DSTOPTS; }
- | MH { $$ = IPPROTO_MH; }
+exthdr_key : HBH close_scope_hbh { $$ = IPPROTO_HOPOPTS; }
+ | RT close_scope_rt { $$ = IPPROTO_ROUTING; }
+ | FRAG close_scope_frag { $$ = IPPROTO_FRAGMENT; }
+ | DST close_scope_dst { $$ = IPPROTO_DSTOPTS; }
+ | MH close_scope_mh { $$ = IPPROTO_MH; }
;
%%
diff --git a/src/parser_json.c b/src/parser_json.c
index bc29dedf..418d4ad7 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -1,7 +1,14 @@
-#define _GNU_SOURCE
+/*
+ * Copyright (c) Red Hat GmbH. Author: Phil Sutter <phil@nwl.cc>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
#include <errno.h>
-#include <stdint.h> /* needed by gmputil.h */
-#include <string.h>
#include <syslog.h>
#include <erec.h>
@@ -11,12 +18,14 @@
#include <netlink.h>
#include <parser.h>
#include <rule.h>
+#include <sctp_chunk.h>
#include <socket.h>
#include <netdb.h>
#include <netinet/icmp6.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
+#include <net/if.h>
#include <linux/xfrm.h>
#include <linux/netfilter.h>
@@ -39,9 +48,9 @@
#define CTX_F_MANGLE (1 << 5)
#define CTX_F_SES (1 << 6) /* set_elem_expr_stmt */
#define CTX_F_MAP (1 << 7) /* LHS of map_expr */
+#define CTX_F_CONCAT (1 << 8) /* inside concat_expr */
struct json_ctx {
- struct input_descriptor indesc;
struct nft_ctx *nft;
struct list_head *msgs;
struct list_head *cmds;
@@ -98,16 +107,18 @@ static struct expr *json_parse_primary_expr(struct json_ctx *ctx, json_t *root);
static struct expr *json_parse_set_rhs_expr(struct json_ctx *ctx, json_t *root);
static struct expr *json_parse_set_elem_expr_stmt(struct json_ctx *ctx, json_t *root);
static struct expr *json_parse_map_lhs_expr(struct json_ctx *ctx, json_t *root);
+static struct expr *json_parse_concat_elem_expr(struct json_ctx *ctx, json_t *root);
static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root);
/* parsing helpers */
const struct location *int_loc = &internal_location;
+static struct input_descriptor json_indesc;
static void json_lib_error(struct json_ctx *ctx, json_error_t *err)
{
struct location loc = {
- .indesc = &ctx->indesc,
+ .indesc = &json_indesc,
.line_offset = err->position - err->column,
.first_line = err->line,
.last_line = err->line,
@@ -311,15 +322,6 @@ static struct expr *json_parse_constant(struct json_ctx *ctx, const char *name)
return NULL;
}
-static struct expr *wildcard_expr_alloc(void)
-{
- struct expr *expr;
-
- expr = constant_expr_alloc(int_loc, &integer_type,
- BYTEORDER_HOST_ENDIAN, 0, NULL);
- return prefix_expr_alloc(int_loc, expr, 0);
-}
-
/* this is a combination of symbol_expr, integer_expr, boolean_expr ... */
static struct expr *json_parse_immediate(struct json_ctx *ctx, json_t *root)
{
@@ -334,7 +336,7 @@ static struct expr *json_parse_immediate(struct json_ctx *ctx, json_t *root)
symtype = SYMBOL_SET;
str++;
} else if (str[0] == '*' && str[1] == '\0') {
- return wildcard_expr_alloc();
+ return set_elem_catchall_expr_alloc(int_loc);
} else if (is_keyword(str)) {
return symbol_expr_alloc(int_loc,
SYMBOL_VALUE, NULL, str);
@@ -424,13 +426,15 @@ static struct expr *json_parse_socket_expr(struct json_ctx *ctx,
keyval = NFT_SOCKET_TRANSPARENT;
else if (!strcmp(key, "mark"))
keyval = NFT_SOCKET_MARK;
+ else if (!strcmp(key, "wildcard"))
+ keyval = NFT_SOCKET_WILDCARD;
if (keyval == -1) {
json_error(ctx, "Invalid socket key value.");
return NULL;
}
- return socket_expr_alloc(int_loc, keyval);
+ return socket_expr_alloc(int_loc, keyval, 0);
}
static int json_parse_payload_field(const struct proto_desc *desc,
@@ -453,9 +457,9 @@ static int json_parse_tcp_option_type(const char *name, int *val)
{
unsigned int i;
- for (i = 0; i < array_size(tcpopthdr_protocols); i++) {
- if (tcpopthdr_protocols[i] &&
- !strcmp(tcpopthdr_protocols[i]->name, name)) {
+ for (i = 0; i < array_size(tcpopt_protocols); i++) {
+ if (tcpopt_protocols[i] &&
+ !strcmp(tcpopt_protocols[i]->name, name)) {
if (val)
*val = i;
return 0;
@@ -463,8 +467,10 @@ static int json_parse_tcp_option_type(const char *name, int *val)
}
/* special case for sack0 - sack3 */
if (sscanf(name, "sack%u", &i) == 1 && i < 4) {
- if (val)
- *val = TCPOPTHDR_SACK0 + i;
+ if (val && i == 0)
+ *val = TCPOPT_KIND_SACK;
+ else if (val && i > 0)
+ *val = TCPOPT_KIND_SACK1 + i - 1;
return 0;
}
return 1;
@@ -472,12 +478,40 @@ static int json_parse_tcp_option_type(const char *name, int *val)
static int json_parse_tcp_option_field(int type, const char *name, int *val)
{
+ const struct exthdr_desc *desc;
+ unsigned int block = 0;
unsigned int i;
- const struct exthdr_desc *desc = tcpopthdr_protocols[type];
+
+ switch (type) {
+ case TCPOPT_KIND_SACK1:
+ type = TCPOPT_KIND_SACK;
+ block = 1;
+ break;
+ case TCPOPT_KIND_SACK2:
+ type = TCPOPT_KIND_SACK;
+ block = 2;
+ break;
+ case TCPOPT_KIND_SACK3:
+ type = TCPOPT_KIND_SACK;
+ block = 3;
+ break;
+ }
+
+ if (type < 0 || type >= (int)array_size(tcpopt_protocols))
+ return 1;
+
+ desc = tcpopt_protocols[type];
+ if (!desc)
+ return 1;
for (i = 0; i < array_size(desc->templates); i++) {
if (desc->templates[i].token &&
!strcmp(desc->templates[i].token, name)) {
+ if (block) {
+ block--;
+ continue;
+ }
+
if (val)
*val = i;
return 0;
@@ -506,6 +540,27 @@ static const struct proto_desc *proto_lookup_byname(const char *name)
&proto_dccp,
&proto_sctp,
&proto_th,
+ &proto_vxlan,
+ &proto_gre,
+ &proto_gretap,
+ &proto_geneve,
+ };
+ unsigned int i;
+
+ for (i = 0; i < array_size(proto_tbl); i++) {
+ if (!strcmp(proto_tbl[i]->name, name))
+ return proto_tbl[i];
+ }
+ return NULL;
+}
+
+static const struct proto_desc *inner_proto_lookup_byname(const char *name)
+{
+ const struct proto_desc *proto_tbl[] = {
+ &proto_geneve,
+ &proto_gre,
+ &proto_gretap,
+ &proto_vxlan,
};
unsigned int i;
@@ -519,7 +574,7 @@ static const struct proto_desc *proto_lookup_byname(const char *name)
static struct expr *json_parse_payload_expr(struct json_ctx *ctx,
const char *type, json_t *root)
{
- const char *protocol, *field, *base;
+ const char *tunnel, *protocol, *field, *base;
int offset, len, val;
struct expr *expr;
@@ -531,15 +586,51 @@ static struct expr *json_parse_payload_expr(struct json_ctx *ctx,
val = PROTO_BASE_NETWORK_HDR;
} else if (!strcmp(base, "th")) {
val = PROTO_BASE_TRANSPORT_HDR;
+ } else if (!strcmp(base, "ih")) {
+ val = PROTO_BASE_INNER_HDR;
} else {
json_error(ctx, "Invalid payload base '%s'.", base);
return NULL;
}
+
+ if (len <= 0 || len > (int)NFT_MAX_EXPR_LEN_BITS) {
+ json_error(ctx, "Payload length must be between 0 and %lu, got %d",
+ NFT_MAX_EXPR_LEN_BITS, len);
+ return NULL;
+ }
+
expr = payload_expr_alloc(int_loc, NULL, 0);
payload_init_raw(expr, val, offset, len);
expr->byteorder = BYTEORDER_BIG_ENDIAN;
expr->payload.is_raw = true;
return expr;
+ } else if (!json_unpack(root, "{s:s, s:s, s:s}",
+ "tunnel", &tunnel, "protocol", &protocol, "field", &field)) {
+ const struct proto_desc *proto = proto_lookup_byname(protocol);
+ const struct proto_desc *inner_proto = inner_proto_lookup_byname(tunnel);
+
+ if (!inner_proto) {
+ json_error(ctx, "Unknown payload tunnel protocol '%s'.",
+ tunnel);
+ return NULL;
+ }
+ if (!proto) {
+ json_error(ctx, "Unknown payload protocol '%s'.",
+ protocol);
+ return NULL;
+ }
+ if (json_parse_payload_field(proto, field, &val)) {
+ json_error(ctx, "Unknown %s field '%s'.",
+ protocol, field);
+ return NULL;
+ }
+ expr = payload_expr_alloc(int_loc, proto, val);
+ expr->payload.inner_desc = inner_proto;
+
+ if (proto == &proto_th)
+ expr->payload.is_raw = true;
+
+ return expr;
} else if (!json_unpack(root, "{s:s, s:s}",
"protocol", &protocol, "field", &field)) {
const struct proto_desc *proto = proto_lookup_byname(protocol);
@@ -568,30 +659,54 @@ static struct expr *json_parse_payload_expr(struct json_ctx *ctx,
static struct expr *json_parse_tcp_option_expr(struct json_ctx *ctx,
const char *type, json_t *root)
{
+ int fieldval, kind, offset, len;
const char *desc, *field;
- int descval, fieldval;
struct expr *expr;
- if (json_unpack_err(ctx, root, "{s:s}", "name", &desc))
- return NULL;
+ if (!json_unpack(root, "{s:i, s:i, s:i}",
+ "base", &kind, "offset", &offset, "len", &len)) {
+ uint32_t flag = 0;
- if (json_parse_tcp_option_type(desc, &descval)) {
- json_error(ctx, "Unknown tcp option name '%s'.", desc);
- return NULL;
- }
+ if (kind < 0 || kind > 255)
+ return NULL;
- if (json_unpack(root, "{s:s}", "field", &field)) {
- expr = tcpopt_expr_alloc(int_loc, descval,
- TCPOPTHDR_FIELD_KIND);
- expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ if (len < 0 || len > (int)NFT_MAX_EXPR_LEN_BITS) {
+ json_error(ctx, "option length must be between 0 and %lu, got %d",
+ NFT_MAX_EXPR_LEN_BITS, len);
+ return NULL;
+ }
+
+ expr = tcpopt_expr_alloc(int_loc, kind,
+ TCPOPT_COMMON_KIND);
+ if (offset == TCPOPT_COMMON_KIND && len == 8)
+ flag = NFT_EXTHDR_F_PRESENT;
+
+ tcpopt_init_raw(expr, kind, offset, len, flag);
return expr;
+ } else if (!json_unpack(root, "{s:s}", "name", &desc)) {
+ if (json_parse_tcp_option_type(desc, &kind)) {
+ json_error(ctx, "Unknown tcp option name '%s'.", desc);
+ return NULL;
+ }
+
+ if (json_unpack(root, "{s:s}", "field", &field)) {
+ expr = tcpopt_expr_alloc(int_loc, kind,
+ TCPOPT_COMMON_KIND);
+ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+ return expr;
+ }
+
+ if (json_parse_tcp_option_field(kind, field, &fieldval)) {
+ json_error(ctx, "Unknown tcp option field '%s'.", field);
+ return NULL;
+ }
+
+ return tcpopt_expr_alloc(int_loc, kind, fieldval);
}
- if (json_parse_tcp_option_field(descval, field, &fieldval)) {
- json_error(ctx, "Unknown tcp option field '%s'.", field);
- return NULL;
- }
- return tcpopt_expr_alloc(int_loc, descval, fieldval);
+
+ json_error(ctx, "Invalid tcp option expression properties.");
+ return NULL;
}
static int json_parse_ip_option_type(const char *name, int *val)
@@ -626,7 +741,7 @@ static int json_parse_ip_option_field(int type, const char *name, int *val)
}
static struct expr *json_parse_ip_option_expr(struct json_ctx *ctx,
- const char *type, json_t *root)
+ const char *type, json_t *root)
{
const char *desc, *field;
int descval, fieldval;
@@ -642,7 +757,7 @@ static struct expr *json_parse_ip_option_expr(struct json_ctx *ctx,
if (json_unpack(root, "{s:s}", "field", &field)) {
expr = ipopt_expr_alloc(int_loc, descval,
- IPOPT_FIELD_TYPE, 0);
+ IPOPT_FIELD_TYPE);
expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
return expr;
@@ -651,7 +766,70 @@ static struct expr *json_parse_ip_option_expr(struct json_ctx *ctx,
json_error(ctx, "Unknown ip option field '%s'.", field);
return NULL;
}
- return ipopt_expr_alloc(int_loc, descval, fieldval, 0);
+ return ipopt_expr_alloc(int_loc, descval, fieldval);
+}
+
+static int json_parse_sctp_chunk_field(const struct exthdr_desc *desc,
+ const char *name, int *val)
+{
+ unsigned int i;
+
+ for (i = 0; i < array_size(desc->templates); i++) {
+ if (desc->templates[i].token &&
+ !strcmp(desc->templates[i].token, name)) {
+ if (val)
+ *val = i;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static struct expr *json_parse_sctp_chunk_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ const struct exthdr_desc *desc;
+ const char *name, *field;
+ struct expr *expr;
+ int fieldval;
+
+ if (json_unpack_err(ctx, root, "{s:s}", "name", &name))
+ return NULL;
+
+ desc = sctp_chunk_protocol_find(name);
+ if (!desc) {
+ json_error(ctx, "Unknown sctp chunk name '%s'.", name);
+ return NULL;
+ }
+
+ if (json_unpack(root, "{s:s}", "field", &field)) {
+ expr = sctp_chunk_expr_alloc(int_loc, desc->type,
+ SCTP_CHUNK_COMMON_TYPE);
+ expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
+
+ return expr;
+ }
+ if (json_parse_sctp_chunk_field(desc, field, &fieldval)) {
+ json_error(ctx, "Unknown sctp chunk field '%s'.", field);
+ return NULL;
+ }
+ return sctp_chunk_expr_alloc(int_loc, desc->type, fieldval);
+}
+
+static struct expr *json_parse_dccp_option_expr(struct json_ctx *ctx,
+ const char *type, json_t *root)
+{
+ int opt_type;
+
+ if (json_unpack_err(ctx, root, "{s:i}", "type", &opt_type))
+ return NULL;
+
+ if (opt_type < DCCPOPT_TYPE_MIN || opt_type > DCCPOPT_TYPE_MAX) {
+ json_error(ctx, "Unknown dccp option type '%d'.", opt_type);
+ return NULL;
+ }
+
+ return dccpopt_expr_alloc(int_loc, opt_type);
}
static const struct exthdr_desc *exthdr_lookup_byname(const char *name)
@@ -982,13 +1160,13 @@ static struct expr *json_parse_fib_expr(struct json_ctx *ctx,
}
if ((flagval & (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) ==
- (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) {
+ (NFTA_FIB_F_SADDR|NFTA_FIB_F_DADDR)) {
json_error(ctx, "fib: saddr and daddr are mutually exclusive");
return NULL;
}
if ((flagval & (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) ==
- (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) {
+ (NFTA_FIB_F_IIF|NFTA_FIB_F_OIF)) {
json_error(ctx, "fib: iif and oif are mutually exclusive");
return NULL;
}
@@ -1026,6 +1204,18 @@ static struct expr *json_parse_binop_expr(struct json_ctx *ctx,
return NULL;
}
+ if (json_array_size(root) > 2) {
+ left = json_parse_primary_expr(ctx, json_array_get(root, 0));
+ right = json_parse_primary_expr(ctx, json_array_get(root, 1));
+ left = binop_expr_alloc(int_loc, thisop, left, right);
+ for (i = 2; i < json_array_size(root); i++) {
+ jright = json_array_get(root, i);
+ right = json_parse_primary_expr(ctx, jright);
+ left = binop_expr_alloc(int_loc, thisop, left, right);
+ }
+ return left;
+ }
+
if (json_unpack_err(ctx, root, "[o, o!]", &jleft, &jright))
return NULL;
@@ -1034,7 +1224,7 @@ static struct expr *json_parse_binop_expr(struct json_ctx *ctx,
json_error(ctx, "Failed to parse LHS of binop expression.");
return NULL;
}
- right = json_parse_primary_expr(ctx, jright);
+ right = json_parse_rhs_expr(ctx, jright);
if (!right) {
json_error(ctx, "Failed to parse RHS of binop expression.");
expr_free(left);
@@ -1057,7 +1247,7 @@ static struct expr *json_parse_concat_expr(struct json_ctx *ctx,
}
json_array_foreach(root, index, value) {
- tmp = json_parse_primary_expr(ctx, value);
+ tmp = json_parse_concat_elem_expr(ctx, value);
if (!tmp) {
json_error(ctx, "Parsing expr at index %zd failed.", index);
expr_free(expr);
@@ -1353,28 +1543,30 @@ static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root)
{ "set", json_parse_set_expr, CTX_F_RHS | CTX_F_STMT }, /* allow this as stmt expr because that allows set references */
{ "map", json_parse_map_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS },
/* below three are multiton_rhs_expr */
- { "prefix", json_parse_prefix_expr, CTX_F_RHS | CTX_F_STMT },
- { "range", json_parse_range_expr, CTX_F_RHS | CTX_F_STMT },
- { "payload", json_parse_payload_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP },
- { "exthdr", json_parse_exthdr_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "tcp option", json_parse_tcp_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES },
- { "ip option", json_parse_ip_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES },
- { "meta", json_parse_meta_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP },
- { "osf", json_parse_osf_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_MAP },
- { "ipsec", json_parse_xfrm_expr, CTX_F_PRIMARY | CTX_F_MAP },
- { "socket", json_parse_socket_expr, CTX_F_PRIMARY },
- { "rt", json_parse_rt_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "ct", json_parse_ct_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP },
- { "numgen", json_parse_numgen_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
+ { "prefix", json_parse_prefix_expr, CTX_F_RHS | CTX_F_SET_RHS | CTX_F_STMT | CTX_F_CONCAT },
+ { "range", json_parse_range_expr, CTX_F_RHS | CTX_F_SET_RHS | CTX_F_STMT | CTX_F_CONCAT },
+ { "payload", json_parse_payload_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "exthdr", json_parse_exthdr_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "tcp option", json_parse_tcp_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
+ { "ip option", json_parse_ip_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
+ { "sctp chunk", json_parse_sctp_chunk_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
+ { "dccp option", json_parse_dccp_option_expr, CTX_F_PRIMARY },
+ { "meta", json_parse_meta_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "osf", json_parse_osf_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT },
+ { "ipsec", json_parse_xfrm_expr, CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT },
+ { "socket", json_parse_socket_expr, CTX_F_PRIMARY | CTX_F_CONCAT },
+ { "rt", json_parse_rt_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "ct", json_parse_ct_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "numgen", json_parse_numgen_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
/* below two are hash expr */
- { "jhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "symhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "fib", json_parse_fib_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "|", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "^", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "&", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { ">>", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "<<", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
+ { "jhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "symhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "fib", json_parse_fib_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "|", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "^", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "&", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { ">>", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "<<", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
{ "accept", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
{ "drop", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
{ "continue", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
@@ -1499,6 +1691,11 @@ static struct expr *json_parse_map_lhs_expr(struct json_ctx *ctx, json_t *root)
return json_parse_flagged_expr(ctx, CTX_F_MAP, root);
}
+static struct expr *json_parse_concat_elem_expr(struct json_ctx *ctx, json_t *root)
+{
+ return json_parse_flagged_expr(ctx, CTX_F_CONCAT, root);
+}
+
static struct expr *json_parse_dtype_expr(struct json_ctx *ctx, json_t *root)
{
if (json_is_string(root)) {
@@ -1552,13 +1749,18 @@ static struct stmt *json_parse_match_stmt(struct json_ctx *ctx,
!strcmp(opstr, expr_op_symbols[op]))
break;
}
- if (op == __OP_MAX) {
+ switch (op) {
+ case OP_EQ ... OP_NEG:
+ break;
+ case __OP_MAX:
if (!strcmp(opstr, "in")) {
op = OP_IMPLICIT;
- } else {
- json_error(ctx, "Unknown relational op '%s'.", opstr);
- return NULL;
+ break;
}
+ /* fall through */
+ default:
+ json_error(ctx, "Invalid relational op '%s'.", opstr);
+ return NULL;
}
left = json_parse_expr(ctx, jleft);
@@ -1578,7 +1780,7 @@ static struct stmt *json_parse_match_stmt(struct json_ctx *ctx,
}
static struct stmt *json_parse_counter_stmt(struct json_ctx *ctx,
- const char *key, json_t *value)
+ const char *key, json_t *value)
{
uint64_t packets, bytes;
struct stmt *stmt;
@@ -1587,8 +1789,8 @@ static struct stmt *json_parse_counter_stmt(struct json_ctx *ctx,
return counter_stmt_alloc(int_loc);
if (!json_unpack(value, "{s:I, s:I}",
- "packets", &packets,
- "bytes", &bytes)) {
+ "packets", &packets,
+ "bytes", &bytes)) {
stmt = counter_stmt_alloc(int_loc);
stmt->counter.packets = packets;
stmt->counter.bytes = bytes;
@@ -1606,6 +1808,27 @@ static struct stmt *json_parse_counter_stmt(struct json_ctx *ctx,
return stmt;
}
+static struct stmt *json_parse_last_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct stmt *stmt;
+ int64_t used;
+
+ if (json_is_null(value))
+ return last_stmt_alloc(int_loc);
+
+ if (!json_unpack(value, "{s:I}", "used", &used)) {
+ stmt = last_stmt_alloc(int_loc);
+ if (used != -1) {
+ stmt->last.used = used;
+ stmt->last.set = 1;
+ }
+ return stmt;
+ }
+
+ return NULL;
+}
+
static struct stmt *json_parse_verdict_stmt(struct json_ctx *ctx,
const char *key, json_t *value)
{
@@ -1619,14 +1842,14 @@ static struct stmt *json_parse_verdict_stmt(struct json_ctx *ctx,
}
static struct stmt *json_parse_mangle_stmt(struct json_ctx *ctx,
- const char *type, json_t *root)
+ const char *type, json_t *root)
{
json_t *jkey, *jvalue;
struct expr *key, *value;
struct stmt *stmt;
if (json_unpack_err(ctx, root, "{s:o, s:o}",
- "key", &jkey, "value", &jvalue))
+ "key", &jkey, "value", &jvalue))
return NULL;
key = json_parse_mangle_lhs_expr(ctx, jkey);
@@ -1679,7 +1902,7 @@ static uint64_t rate_to_bytes(uint64_t val, const char *unit)
}
static struct stmt *json_parse_quota_stmt(struct json_ctx *ctx,
- const char *key, json_t *value)
+ const char *key, json_t *value)
{
struct stmt *stmt;
int inv = 0;
@@ -1740,6 +1963,9 @@ static struct stmt *json_parse_limit_stmt(struct json_ctx *ctx,
stmt = limit_stmt_alloc(int_loc);
if (!strcmp(rate_unit, "packets")) {
+ if (burst == 0)
+ burst = 5;
+
stmt->limit.type = NFT_LIMIT_PKTS;
stmt->limit.rate = rate;
stmt->limit.burst = burst;
@@ -1803,8 +2029,30 @@ out_err:
return NULL;
}
+static struct stmt *json_parse_flow_offload_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ const char *opstr, *flowtable;
+
+ if (json_unpack_err(ctx, value, "{s:s, s:s}",
+ "op", &opstr, "flowtable", &flowtable))
+ return NULL;
+
+ if (strcmp(opstr, "add")) {
+ json_error(ctx, "Unknown flow offload statement op '%s'.", opstr);
+ return NULL;
+ }
+
+ if (flowtable[0] != '@') {
+ json_error(ctx, "Illegal flowtable reference in flow offload statement.");
+ return NULL;
+ }
+
+ return flow_offload_stmt_alloc(int_loc, xstrdup(flowtable + 1));
+}
+
static struct stmt *json_parse_notrack_stmt(struct json_ctx *ctx,
- const char *key, json_t *value)
+ const char *key, json_t *value)
{
return notrack_stmt_alloc(int_loc);
}
@@ -1841,6 +2089,23 @@ static struct stmt *json_parse_dup_stmt(struct json_ctx *ctx,
return stmt;
}
+static struct stmt *json_parse_secmark_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct stmt *stmt;
+
+ stmt = objref_stmt_alloc(int_loc);
+ stmt->objref.type = NFT_OBJECT_SECMARK;
+ stmt->objref.expr = json_parse_stmt_expr(ctx, value);
+ if (!stmt->objref.expr) {
+ json_error(ctx, "Invalid secmark reference.");
+ stmt_free(stmt);
+ return NULL;
+ }
+
+ return stmt;
+}
+
static int json_parse_nat_flag(struct json_ctx *ctx,
json_t *root, int *flags)
{
@@ -1851,6 +2116,7 @@ static int json_parse_nat_flag(struct json_ctx *ctx,
{ "random", NF_NAT_RANGE_PROTO_RANDOM },
{ "fully-random", NF_NAT_RANGE_PROTO_RANDOM_FULLY },
{ "persistent", NF_NAT_RANGE_PERSISTENT },
+ { "netmap", NF_NAT_RANGE_NETMAP },
};
const char *flag;
unsigned int i;
@@ -1895,6 +2161,60 @@ static int json_parse_nat_flags(struct json_ctx *ctx, json_t *root)
return flags;
}
+static int json_parse_nat_type_flag(struct json_ctx *ctx,
+ json_t *root, int *flags)
+{
+ const struct {
+ const char *flag;
+ int val;
+ } flag_tbl[] = {
+ { "interval", STMT_NAT_F_INTERVAL },
+ { "prefix", STMT_NAT_F_PREFIX },
+ { "concat", STMT_NAT_F_CONCAT },
+ };
+ const char *flag;
+ unsigned int i;
+
+ assert(flags);
+
+ if (!json_is_string(root)) {
+ json_error(ctx, "Invalid nat type flag type %s, expected string.",
+ json_typename(root));
+ return 1;
+ }
+ flag = json_string_value(root);
+ for (i = 0; i < array_size(flag_tbl); i++) {
+ if (!strcmp(flag, flag_tbl[i].flag)) {
+ *flags |= flag_tbl[i].val;
+ return 0;
+ }
+ }
+ json_error(ctx, "Unknown nat type flag '%s'.", flag);
+ return 1;
+}
+
+static int json_parse_nat_type_flags(struct json_ctx *ctx, json_t *root)
+{
+ int flags = 0;
+ json_t *value;
+ size_t index;
+
+ if (json_is_string(root)) {
+ json_parse_nat_type_flag(ctx, root, &flags);
+ return flags;
+ } else if (!json_is_array(root)) {
+ json_error(ctx, "Invalid nat flags type %s.",
+ json_typename(root));
+ return -1;
+ }
+ json_array_foreach(root, index, value) {
+ if (json_parse_nat_type_flag(ctx, value, &flags))
+ json_error(ctx, "Parsing nat type flag at index %zu failed.",
+ index);
+ }
+ return flags;
+}
+
static int nat_type_parse(const char *type)
{
const char * const nat_etypes[] = {
@@ -1957,11 +2277,21 @@ static struct stmt *json_parse_nat_stmt(struct json_ctx *ctx,
}
stmt->nat.flags = flags;
}
+ if (!json_unpack(value, "{s:o}", "type_flags", &tmp)) {
+ int flags = json_parse_nat_type_flags(ctx, tmp);
+
+ if (flags < 0) {
+ stmt_free(stmt);
+ return NULL;
+ }
+ stmt->nat.type_flags = flags;
+ }
+
return stmt;
}
static struct stmt *json_parse_tproxy_stmt(struct json_ctx *ctx,
- const char *key, json_t *value)
+ const char *key, json_t *value)
{
json_t *jaddr, *tmp;
struct stmt *stmt;
@@ -1997,7 +2327,7 @@ out_free:
}
static struct stmt *json_parse_reject_stmt(struct json_ctx *ctx,
- const char *key, json_t *value)
+ const char *key, json_t *value)
{
struct stmt *stmt = reject_stmt_alloc(int_loc);
const struct datatype *dtype = NULL;
@@ -2013,17 +2343,17 @@ static struct stmt *json_parse_reject_stmt(struct json_ctx *ctx,
stmt->reject.icmp_code = 0;
} else if (!strcmp(type, "icmpx")) {
stmt->reject.type = NFT_REJECT_ICMPX_UNREACH;
- dtype = &icmpx_code_type;
+ dtype = &reject_icmpx_code_type;
stmt->reject.icmp_code = 0;
} else if (!strcmp(type, "icmp")) {
stmt->reject.type = NFT_REJECT_ICMP_UNREACH;
stmt->reject.family = NFPROTO_IPV4;
- dtype = &icmp_code_type;
+ dtype = &reject_icmp_code_type;
stmt->reject.icmp_code = 0;
} else if (!strcmp(type, "icmpv6")) {
stmt->reject.type = NFT_REJECT_ICMP_UNREACH;
stmt->reject.family = NFPROTO_IPV6;
- dtype = &icmpv6_code_type;
+ dtype = &reject_icmpv6_code_type;
stmt->reject.icmp_code = 0;
}
}
@@ -2039,13 +2369,36 @@ static struct stmt *json_parse_reject_stmt(struct json_ctx *ctx,
return stmt;
}
+static void json_parse_set_stmt_list(struct json_ctx *ctx,
+ struct list_head *stmt_list,
+ json_t *stmt_json)
+{
+ struct list_head *head;
+ struct stmt *tmp;
+ json_t *value;
+ size_t index;
+
+ if (!stmt_json)
+ return;
+
+ if (!json_is_array(stmt_json))
+ json_error(ctx, "Unexpected object type in stmt");
+
+ head = stmt_list;
+ json_array_foreach(stmt_json, index, value) {
+ tmp = json_parse_stmt(ctx, value);
+ list_add(&tmp->list, head);
+ head = &tmp->list;
+ }
+}
+
static struct stmt *json_parse_set_stmt(struct json_ctx *ctx,
- const char *key, json_t *value)
+ const char *key, json_t *value)
{
const char *opstr, *set;
struct expr *expr, *expr2;
+ json_t *elem, *stmt_json;
struct stmt *stmt;
- json_t *elem;
int op;
if (json_unpack_err(ctx, value, "{s:s, s:o, s:s}",
@@ -2080,6 +2433,67 @@ static struct stmt *json_parse_set_stmt(struct json_ctx *ctx,
stmt->set.op = op;
stmt->set.key = expr;
stmt->set.set = expr2;
+
+ if (!json_unpack(value, "{s:o}", "stmt", &stmt_json))
+ json_parse_set_stmt_list(ctx, &stmt->set.stmt_list, stmt_json);
+
+ return stmt;
+}
+
+static struct stmt *json_parse_map_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct expr *expr, *expr2, *expr_data;
+ json_t *elem, *data, *stmt_json;
+ const char *opstr, *set;
+ struct stmt *stmt;
+ int op;
+
+ if (json_unpack_err(ctx, value, "{s:s, s:o, s:o, s:s}",
+ "op", &opstr, "elem", &elem, "data", &data, "map", &set))
+ return NULL;
+
+ if (!strcmp(opstr, "add")) {
+ op = NFT_DYNSET_OP_ADD;
+ } else if (!strcmp(opstr, "update")) {
+ op = NFT_DYNSET_OP_UPDATE;
+ } else if (!strcmp(opstr, "delete")) {
+ op = NFT_DYNSET_OP_DELETE;
+ } else {
+ json_error(ctx, "Unknown map statement op '%s'.", opstr);
+ return NULL;
+ }
+
+ expr = json_parse_set_elem_expr_stmt(ctx, elem);
+ if (!expr) {
+ json_error(ctx, "Illegal map statement element.");
+ return NULL;
+ }
+
+ expr_data = json_parse_set_elem_expr_stmt(ctx, data);
+ if (!expr_data) {
+ json_error(ctx, "Illegal map expression data.");
+ expr_free(expr);
+ return NULL;
+ }
+
+ if (set[0] != '@') {
+ json_error(ctx, "Illegal map reference in map statement.");
+ expr_free(expr);
+ expr_free(expr_data);
+ return NULL;
+ }
+ expr2 = symbol_expr_alloc(int_loc, SYMBOL_SET, NULL, set + 1);
+
+ stmt = map_stmt_alloc(int_loc);
+ stmt->map.op = op;
+ stmt->map.key = expr;
+ stmt->map.data = expr_data;
+ stmt->map.set = expr2;
+
+ if (!json_unpack(value, "{s:o}", "stmt", &stmt_json))
+ json_parse_set_stmt_list(ctx, &stmt->set.stmt_list, stmt_json);
+
return stmt;
}
@@ -2151,7 +2565,9 @@ static struct stmt *json_parse_log_stmt(struct json_ctx *ctx,
stmt = log_stmt_alloc(int_loc);
if (!json_unpack(value, "{s:s}", "prefix", &tmpstr)) {
- stmt->log.prefix = xstrdup(tmpstr);
+ stmt->log.prefix = constant_expr_alloc(int_loc, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ (strlen(tmpstr) + 1) * BITS_PER_BYTE, tmpstr);
stmt->log.flags |= STMT_LOG_PREFIX;
}
if (!json_unpack(value, "{s:i}", "group", &tmp)) {
@@ -2317,7 +2733,7 @@ static struct stmt *json_parse_cthelper_stmt(struct json_ctx *ctx,
}
static struct stmt *json_parse_cttimeout_stmt(struct json_ctx *ctx,
- const char *key, json_t *value)
+ const char *key, json_t *value)
{
struct stmt *stmt = objref_stmt_alloc(int_loc);
@@ -2352,7 +2768,7 @@ static struct stmt *json_parse_meter_stmt(struct json_ctx *ctx,
json_t *jkey, *jstmt;
struct stmt *stmt;
const char *name;
- uint32_t size = 0xffff;
+ uint32_t size = 0;
if (json_unpack_err(ctx, value, "{s:s, s:o, s:o}",
"name", &name, "key", &jkey, "stmt", &jstmt))
@@ -2393,14 +2809,14 @@ static int queue_flag_parse(const char *name, uint16_t *flags)
static struct stmt *json_parse_queue_stmt(struct json_ctx *ctx,
const char *key, json_t *value)
{
- struct stmt *stmt = queue_stmt_alloc(int_loc);
+ struct expr *qexpr = NULL;
+ uint16_t flags = 0;
json_t *tmp;
if (!json_unpack(value, "{s:o}", "num", &tmp)) {
- stmt->queue.queue = json_parse_stmt_expr(ctx, tmp);
- if (!stmt->queue.queue) {
+ qexpr = json_parse_stmt_expr(ctx, tmp);
+ if (!qexpr) {
json_error(ctx, "Invalid queue num.");
- stmt_free(stmt);
return NULL;
}
}
@@ -2412,15 +2828,15 @@ static struct stmt *json_parse_queue_stmt(struct json_ctx *ctx,
if (json_is_string(tmp)) {
flag = json_string_value(tmp);
- if (queue_flag_parse(flag, &stmt->queue.flags)) {
+ if (queue_flag_parse(flag, &flags)) {
json_error(ctx, "Invalid queue flag '%s'.",
flag);
- stmt_free(stmt);
+ expr_free(qexpr);
return NULL;
}
} else if (!json_is_array(tmp)) {
json_error(ctx, "Unexpected object type in queue flags.");
- stmt_free(stmt);
+ expr_free(qexpr);
return NULL;
}
@@ -2428,20 +2844,20 @@ static struct stmt *json_parse_queue_stmt(struct json_ctx *ctx,
if (!json_is_string(val)) {
json_error(ctx, "Invalid object in queue flag array at index %zu.",
index);
- stmt_free(stmt);
+ expr_free(qexpr);
return NULL;
}
flag = json_string_value(val);
- if (queue_flag_parse(flag, &stmt->queue.flags)) {
+ if (queue_flag_parse(flag, &flags)) {
json_error(ctx, "Invalid queue flag '%s'.",
flag);
- stmt_free(stmt);
+ expr_free(qexpr);
return NULL;
}
}
}
- return stmt;
+ return queue_stmt_alloc(int_loc, qexpr, flags);
}
static struct stmt *json_parse_connlimit_stmt(struct json_ctx *ctx,
@@ -2462,6 +2878,21 @@ static struct stmt *json_parse_connlimit_stmt(struct json_ctx *ctx,
return stmt;
}
+static struct stmt *json_parse_optstrip_stmt(struct json_ctx *ctx,
+ const char *key, json_t *value)
+{
+ struct expr *expr = json_parse_expr(ctx, value);
+
+ if (!expr ||
+ expr->etype != EXPR_EXTHDR ||
+ expr->exthdr.op != NFT_EXTHDR_OP_TCPOPT) {
+ json_error(ctx, "Illegal TCP optstrip argument");
+ return NULL;
+ }
+
+ return optstrip_stmt_alloc(int_loc, expr);
+}
+
static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
{
struct {
@@ -2478,7 +2909,9 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
{ "counter", json_parse_counter_stmt },
{ "mangle", json_parse_mangle_stmt },
{ "quota", json_parse_quota_stmt },
+ { "last", json_parse_last_stmt },
{ "limit", json_parse_limit_stmt },
+ { "flow", json_parse_flow_offload_stmt },
{ "fwd", json_parse_fwd_stmt },
{ "notrack", json_parse_notrack_stmt },
{ "dup", json_parse_dup_stmt },
@@ -2488,6 +2921,7 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
{ "redirect", json_parse_nat_stmt },
{ "reject", json_parse_reject_stmt },
{ "set", json_parse_set_stmt },
+ { "map", json_parse_map_stmt },
{ "log", json_parse_log_stmt },
{ "ct helper", json_parse_cthelper_stmt },
{ "ct timeout", json_parse_cttimeout_stmt },
@@ -2497,6 +2931,8 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
{ "ct count", json_parse_connlimit_stmt },
{ "tproxy", json_parse_tproxy_stmt },
{ "synproxy", json_parse_synproxy_stmt },
+ { "reset", json_parse_optstrip_stmt },
+ { "secmark", json_parse_secmark_stmt },
};
const char *type;
unsigned int i;
@@ -2516,6 +2952,11 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
return verdict_stmt_alloc(int_loc, expr);
}
+ if (!strcmp(type, "xt")) {
+ json_error(ctx, "unsupported xtables compat expression, use iptables-nft with this ruleset");
+ return NULL;
+ }
+
for (i = 0; i < array_size(stmt_parser_tbl); i++) {
if (!strcmp(type, stmt_parser_tbl[i].key))
return stmt_parser_tbl[i].cb(ctx, stmt_parser_tbl[i].key, tmp);
@@ -2528,17 +2969,21 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root,
enum cmd_ops op, enum cmd_obj obj)
{
+ const char *family = "", *comment = NULL;
struct handle h = {
.table.location = *int_loc,
};
- const char *family = "";
+ struct table *table = NULL;
if (json_unpack_err(ctx, root, "{s:s}",
"family", &family))
return NULL;
- if (op != CMD_DELETE &&
- json_unpack_err(ctx, root, "{s:s}", "name", &h.table.name)) {
- return NULL;
+
+ if (op != CMD_DELETE) {
+ if (json_unpack_err(ctx, root, "{s:s}", "name", &h.table.name))
+ return NULL;
+
+ json_unpack(root, "{s:s}", "comment", &comment);
} else if (op == CMD_DELETE &&
json_unpack(root, "{s:s}", "name", &h.table.name) &&
json_unpack(root, "{s:I}", "handle", &h.handle.id)) {
@@ -2552,10 +2997,16 @@ static struct cmd *json_parse_cmd_add_table(struct json_ctx *ctx, json_t *root,
if (h.table.name)
h.table.name = xstrdup(h.table.name);
+ if (comment) {
+ table = table_alloc();
+ handle_merge(&table->handle, &h);
+ table->comment = xstrdup(comment);
+ }
+
if (op == CMD_ADD)
json_object_del(root, "handle");
- return cmd_alloc(op, obj, &h, int_loc, NULL);
+ return cmd_alloc(op, obj, &h, int_loc, table);
}
static struct expr *parse_policy(const char *policy)
@@ -2574,23 +3025,60 @@ static struct expr *parse_policy(const char *policy)
sizeof(int) * BITS_PER_BYTE, &policy_num);
}
+static struct expr *json_parse_devs(struct json_ctx *ctx, json_t *root)
+{
+ struct expr *tmp, *expr = compound_expr_alloc(int_loc, EXPR_LIST);
+ const char *dev;
+ json_t *value;
+ size_t index;
+
+ if (!json_unpack(root, "s", &dev)) {
+ tmp = constant_expr_alloc(int_loc, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen(dev) * BITS_PER_BYTE, dev);
+ compound_expr_add(expr, tmp);
+ return expr;
+ }
+ if (!json_is_array(root)) {
+ expr_free(expr);
+ return NULL;
+ }
+
+ json_array_foreach(root, index, value) {
+ if (json_unpack(value, "s", &dev)) {
+ json_error(ctx, "Invalid device at index %zu.",
+ index);
+ expr_free(expr);
+ return NULL;
+ }
+ tmp = constant_expr_alloc(int_loc, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen(dev) * BITS_PER_BYTE, dev);
+ compound_expr_add(expr, tmp);
+ }
+ return expr;
+}
+
static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
enum cmd_ops op, enum cmd_obj obj)
{
struct handle h = {
.table.location = *int_loc,
};
- const char *family = "", *policy = "", *type, *hookstr;
+ const char *family = "", *policy = "", *type, *hookstr, *comment = NULL;
+ struct chain *chain = NULL;
+ json_t *devs = NULL;
int prio;
- struct chain *chain;
if (json_unpack_err(ctx, root, "{s:s, s:s}",
"family", &family,
"table", &h.table.name))
return NULL;
- if (op != CMD_DELETE &&
- json_unpack_err(ctx, root, "{s:s}", "name", &h.chain.name)) {
- return NULL;
+ if (op != CMD_DELETE) {
+ if (json_unpack_err(ctx, root, "{s:s}", "name", &h.chain.name))
+ return NULL;
+
+ json_unpack(root, "{s:s}", "comment", &comment);
} else if (op == CMD_DELETE &&
json_unpack(root, "{s:s}", "name", &h.chain.name) &&
json_unpack(root, "{s:I}", "handle", &h.handle.id)) {
@@ -2605,32 +3093,49 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
if (h.chain.name)
h.chain.name = xstrdup(h.chain.name);
+ if (comment) {
+ chain = chain_alloc();
+ handle_merge(&chain->handle, &h);
+ chain->comment = xstrdup(comment);
+ }
+
if (op == CMD_DELETE ||
op == CMD_LIST ||
op == CMD_FLUSH ||
json_unpack(root, "{s:s, s:s, s:i}",
"type", &type, "hook", &hookstr, "prio", &prio))
- return cmd_alloc(op, obj, &h, int_loc, NULL);
+ return cmd_alloc(op, obj, &h, int_loc, chain);
+
+ if (!chain)
+ chain = chain_alloc();
- chain = chain_alloc(NULL);
chain->flags |= CHAIN_F_BASECHAIN;
- chain->type = xstrdup(type);
+ chain->type.str = xstrdup(type);
chain->priority.expr = constant_expr_alloc(int_loc, &integer_type,
BYTEORDER_HOST_ENDIAN,
sizeof(int) * BITS_PER_BYTE,
&prio);
- chain->hookstr = chain_hookname_lookup(hookstr);
- if (!chain->hookstr) {
+ chain->hook.name = chain_hookname_lookup(hookstr);
+ if (!chain->hook.name) {
json_error(ctx, "Invalid chain hook '%s'.", hookstr);
chain_free(chain);
return NULL;
}
- if (!json_unpack(root, "{s:s}", "dev", &chain->dev))
- chain->dev = xstrdup(chain->dev);
+ json_unpack(root, "{s:o}", "dev", &devs);
+
+ if (devs) {
+ chain->dev_expr = json_parse_devs(ctx, devs);
+ if (!chain->dev_expr) {
+ json_error(ctx, "Invalid chain dev.");
+ chain_free(chain);
+ return NULL;
+ }
+ }
+
if (!json_unpack(root, "{s:s}", "policy", &policy)) {
chain->policy = parse_policy(policy);
- if (chain->policy < 0) {
+ if (!chain->policy) {
json_error(ctx, "Unknown policy '%s'.", policy);
chain_free(chain);
return NULL;
@@ -2665,7 +3170,7 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root,
if (op != CMD_DELETE &&
json_unpack_err(ctx, root, "{s:o}", "expr", &tmp))
return NULL;
- else if (op == CMD_DELETE &&
+ else if ((op == CMD_DELETE || op == CMD_DESTROY) &&
json_unpack_err(ctx, root, "{s:I}", "handle", &h.handle.id))
return NULL;
@@ -2676,7 +3181,7 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root,
h.table.name = xstrdup(h.table.name);
h.chain.name = xstrdup(h.chain.name);
- if (op == CMD_DELETE)
+ if (op == CMD_DELETE || op == CMD_DESTROY)
return cmd_alloc(op, obj, &h, int_loc, NULL);
if (!json_is_array(tmp)) {
@@ -2712,8 +3217,7 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root,
return NULL;
}
- rule->num_stmts++;
- list_add_tail(&stmt->list, &rule->stmts);
+ rule_stmt_append(rule, stmt);
}
if (op == CMD_ADD)
@@ -2725,14 +3229,18 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root,
static int string_to_nft_object(const char *str)
{
const char *obj_tbl[__NFT_OBJECT_MAX] = {
- [NFT_OBJECT_COUNTER] = "counter",
- [NFT_OBJECT_QUOTA] = "quota",
- [NFT_OBJECT_LIMIT] = "limit",
- [NFT_OBJECT_SECMARK] = "secmark",
+ [NFT_OBJECT_COUNTER] = "counter",
+ [NFT_OBJECT_QUOTA] = "quota",
+ [NFT_OBJECT_CT_HELPER] = "ct helper",
+ [NFT_OBJECT_LIMIT] = "limit",
+ [NFT_OBJECT_CT_TIMEOUT] = "ct timeout",
+ [NFT_OBJECT_SECMARK] = "secmark",
+ [NFT_OBJECT_CT_EXPECT] = "ct expectation",
+ [NFT_OBJECT_SYNPROXY] = "synproxy",
};
unsigned int i;
- for (i = 0; i < NFT_OBJECT_MAX; i++) {
+ for (i = 0; i <= NFT_OBJECT_MAX; i++) {
if (obj_tbl[i] && !strcmp(str, obj_tbl[i]))
return i;
}
@@ -2748,6 +3256,7 @@ static int string_to_set_flag(const char *str)
{ NFT_SET_CONSTANT, "constant" },
{ NFT_SET_INTERVAL, "interval" },
{ NFT_SET_TIMEOUT, "timeout" },
+ { NFT_SET_EVAL, "dynamic" },
};
unsigned int i;
@@ -2762,9 +3271,9 @@ static struct cmd *json_parse_cmd_add_set(struct json_ctx *ctx, json_t *root,
enum cmd_ops op, enum cmd_obj obj)
{
struct handle h = { 0 };
- const char *family = "", *policy, *dtype_ext = NULL;
+ const char *family = "", *policy;
+ json_t *tmp, *stmt_json;
struct set *set;
- json_t *tmp;
if (json_unpack_err(ctx, root, "{s:s, s:s}",
"family", &family,
@@ -2773,7 +3282,7 @@ static struct cmd *json_parse_cmd_add_set(struct json_ctx *ctx, json_t *root,
if (op != CMD_DELETE &&
json_unpack_err(ctx, root, "{s:s}", "name", &h.set.name)) {
return NULL;
- } else if (op == CMD_DELETE &&
+ } else if ((op == CMD_DELETE || op == CMD_DESTROY) &&
json_unpack(root, "{s:s}", "name", &h.set.name) &&
json_unpack(root, "{s:I}", "handle", &h.handle.id)) {
json_error(ctx, "Either name or handle required to delete a set.");
@@ -2790,14 +3299,16 @@ static struct cmd *json_parse_cmd_add_set(struct json_ctx *ctx, json_t *root,
switch (op) {
case CMD_DELETE:
+ case CMD_DESTROY:
case CMD_LIST:
case CMD_FLUSH:
+ case CMD_RESET:
return cmd_alloc(op, obj, &h, int_loc, NULL);
default:
break;
}
- set = set_alloc(NULL);
+ set = set_alloc(&internal_location);
if (json_unpack(root, "{s:o}", "type", &tmp)) {
json_error(ctx, "Invalid set type.");
@@ -2813,15 +3324,19 @@ static struct cmd *json_parse_cmd_add_set(struct json_ctx *ctx, json_t *root,
return NULL;
}
- if (!json_unpack(root, "{s:s}", "map", &dtype_ext)) {
- set->objtype = string_to_nft_object(dtype_ext);
+ if (!json_unpack(root, "{s:o}", "map", &tmp)) {
+ if (json_is_string(tmp)) {
+ const char *s = json_string_value(tmp);
+
+ set->objtype = string_to_nft_object(s);
+ }
if (set->objtype) {
set->flags |= NFT_SET_OBJECT;
- } else if (datatype_lookup_byname(dtype_ext)) {
- set->datatype = datatype_lookup_byname(dtype_ext);
+ } else if ((set->data = json_parse_dtype_expr(ctx, tmp))) {
set->flags |= NFT_SET_MAP;
} else {
- json_error(ctx, "Invalid map type '%s'.", dtype_ext);
+ json_error(ctx, "Invalid map type '%s'.",
+ json_dumps(tmp, 0));
set_free(set);
handle_free(&h);
return NULL;
@@ -2870,6 +3385,10 @@ static struct cmd *json_parse_cmd_add_set(struct json_ctx *ctx, json_t *root,
if (!json_unpack(root, "{s:i}", "gc-interval", &set->gc_int))
set->gc_int *= 1000;
json_unpack(root, "{s:i}", "size", &set->desc.size);
+ json_unpack(root, "{s:b}", "auto-merge", &set->automerge);
+
+ if (!json_unpack(root, "{s:o}", "stmt", &stmt_json))
+ json_parse_set_stmt_list(ctx, &set->stmt_list, stmt_json);
handle_merge(&set->handle, &h);
@@ -2911,37 +3430,6 @@ static struct cmd *json_parse_cmd_add_element(struct json_ctx *ctx,
return cmd_alloc(op, cmd_obj, &h, int_loc, expr);
}
-static struct expr *json_parse_flowtable_devs(struct json_ctx *ctx,
- json_t *root)
-{
- struct expr *tmp, *expr = compound_expr_alloc(int_loc, EXPR_INVALID);
- const char *dev;
- json_t *value;
- size_t index;
-
- if (!json_unpack(root, "s", &dev)) {
- tmp = symbol_expr_alloc(int_loc, SYMBOL_VALUE, NULL, dev);
- compound_expr_add(expr, tmp);
- return expr;
- }
- if (!json_is_array(root)) {
- expr_free(expr);
- return NULL;
- }
-
- json_array_foreach(root, index, value) {
- if (json_unpack(value, "s", &dev)) {
- json_error(ctx, "Invalid flowtable dev at index %zu.",
- index);
- expr_free(expr);
- return NULL;
- }
- tmp = symbol_expr_alloc(int_loc, SYMBOL_VALUE, NULL, dev);
- compound_expr_add(expr, tmp);
- }
- return expr;
-}
-
static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx,
json_t *root, enum cmd_ops op,
enum cmd_obj cmd_obj)
@@ -2949,33 +3437,44 @@ static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx,
const char *family, *hook, *hookstr;
struct flowtable *flowtable;
struct handle h = { 0 };
- json_t *devs;
+ json_t *devs = NULL;
int prio;
- if (json_unpack_err(ctx, root, "{s:s, s:s, s:s}",
+ if (json_unpack_err(ctx, root, "{s:s, s:s}",
"family", &family,
- "table", &h.table.name,
- "name", &h.flowtable))
+ "table", &h.table.name))
return NULL;
+ if (op != CMD_DELETE &&
+ json_unpack_err(ctx, root, "{s:s}", "name", &h.flowtable.name)) {
+ return NULL;
+ } else if ((op == CMD_DELETE || op == CMD_DESTROY) &&
+ json_unpack(root, "{s:s}", "name", &h.flowtable.name) &&
+ json_unpack(root, "{s:I}", "handle", &h.handle.id)) {
+ json_error(ctx, "Either name or handle required to delete a flowtable.");
+ return NULL;
+ }
+
if (parse_family(family, &h.family)) {
json_error(ctx, "Unknown family '%s'.", family);
return NULL;
}
h.table.name = xstrdup(h.table.name);
- h.flowtable = xstrdup(h.flowtable);
+ if (h.flowtable.name)
+ h.flowtable.name = xstrdup(h.flowtable.name);
- if (op == CMD_DELETE)
+ if (op == CMD_DELETE || op == CMD_LIST || op == CMD_DESTROY)
return cmd_alloc(op, cmd_obj, &h, int_loc, NULL);
- if (json_unpack_err(ctx, root, "{s:s, s:I, s:o}",
+ if (json_unpack_err(ctx, root, "{s:s, s:i}",
"hook", &hook,
- "prio", &prio,
- "dev", &devs)) {
+ "prio", &prio)) {
handle_free(&h);
return NULL;
}
+ json_unpack(root, "{s:o}", "dev", &devs);
+
hookstr = chain_hookname_lookup(hook);
if (!hookstr) {
json_error(ctx, "Invalid flowtable hook '%s'.", hook);
@@ -2984,18 +3483,20 @@ static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx,
}
flowtable = flowtable_alloc(int_loc);
- flowtable->hookstr = hookstr;
+ flowtable->hook.name = hookstr;
flowtable->priority.expr =
constant_expr_alloc(int_loc, &integer_type,
BYTEORDER_HOST_ENDIAN,
sizeof(int) * BITS_PER_BYTE, &prio);
- flowtable->dev_expr = json_parse_flowtable_devs(ctx, devs);
- if (!flowtable->dev_expr) {
- json_error(ctx, "Invalid flowtable dev.");
- flowtable_free(flowtable);
- handle_free(&h);
- return NULL;
+ if (devs) {
+ flowtable->dev_expr = json_parse_devs(ctx, devs);
+ if (!flowtable->dev_expr) {
+ json_error(ctx, "Invalid flowtable dev.");
+ flowtable_free(flowtable);
+ handle_free(&h);
+ return NULL;
+ }
}
return cmd_alloc(op, cmd_obj, &h, int_loc, flowtable);
}
@@ -3006,7 +3507,7 @@ static int json_parse_ct_timeout_policy(struct json_ctx *ctx,
json_t *tmp, *val;
const char *key;
- if (!json_unpack(root, "{s:o}", "policy", &tmp))
+ if (json_unpack(root, "{s:o}", "policy", &tmp))
return 0;
if (!json_is_object(tmp)) {
@@ -3014,7 +3515,6 @@ static int json_parse_ct_timeout_policy(struct json_ctx *ctx,
return 1;
}
- init_list_head(&obj->ct_timeout.timeout_list);
json_object_foreach(tmp, key, val) {
struct timeout_state *ts;
@@ -3039,8 +3539,8 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
{
const char *family, *tmp, *rate_unit = "packets", *burst_unit = "bytes";
uint32_t l3proto = NFPROTO_UNSPEC;
+ int inv = 0, flags = 0, i, j;
struct handle h = { 0 };
- int inv = 0, flags = 0;
struct obj *obj;
json_t *jflags;
@@ -3052,7 +3552,7 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
cmd_obj == NFT_OBJECT_CT_HELPER) &&
json_unpack_err(ctx, root, "{s:s}", "name", &h.obj.name)) {
return NULL;
- } else if (op == CMD_DELETE &&
+ } else if ((op == CMD_DELETE || op == CMD_DESTROY) &&
cmd_obj != NFT_OBJECT_CT_HELPER &&
json_unpack(root, "{s:s}", "name", &h.obj.name) &&
json_unpack(root, "{s:I}", "handle", &h.handle.id)) {
@@ -3068,7 +3568,7 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
if (h.obj.name)
h.obj.name = xstrdup(h.obj.name);
- if (op == CMD_DELETE || op == CMD_LIST) {
+ if (op == CMD_DELETE || op == CMD_LIST || op == CMD_DESTROY) {
if (cmd_obj == NFT_OBJECT_CT_HELPER)
return cmd_alloc_obj_ct(op, NFT_OBJECT_CT_HELPER,
&h, int_loc, obj_alloc(int_loc));
@@ -3077,6 +3577,9 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
obj = obj_alloc(int_loc);
+ if (!json_unpack(root, "{s:s}", "comment", &obj->comment))
+ obj->comment = xstrdup(obj->comment);
+
switch (cmd_obj) {
case CMD_OBJ_COUNTER:
obj->type = NFT_OBJECT_COUNTER;
@@ -3159,8 +3662,9 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
obj_free(obj);
return NULL;
}
- obj->ct_helper.l3proto = l3proto;
+ obj->ct_timeout.l3proto = l3proto;
+ init_list_head(&obj->ct_timeout.timeout_list);
if (json_parse_ct_timeout_policy(ctx, root, obj)) {
obj_free(obj);
return NULL;
@@ -3187,11 +3691,12 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
return NULL;
}
}
- if (!json_unpack(root, "{s:o}", "dport", &tmp))
- obj->ct_expect.dport = atoi(tmp);
- json_unpack(root, "{s:I}", "timeout", &obj->ct_expect.timeout);
- if (!json_unpack(root, "{s:o}", "size", &tmp))
- obj->ct_expect.size = atoi(tmp);
+ if (!json_unpack(root, "{s:i}", "dport", &i))
+ obj->ct_expect.dport = i;
+ if (!json_unpack(root, "{s:i}", "timeout", &i))
+ obj->ct_expect.timeout = i;
+ if (!json_unpack(root, "{s:i}", "size", &i))
+ obj->ct_expect.size = i;
break;
case CMD_OBJ_LIMIT:
obj->type = NFT_OBJECT_LIMIT;
@@ -3203,7 +3708,7 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
}
json_unpack(root, "{s:s}", "rate_unit", &rate_unit);
json_unpack(root, "{s:b}", "inv", &inv);
- json_unpack(root, "{s:I}", "burst", &obj->limit.burst);
+ json_unpack(root, "{s:i}", "burst", &obj->limit.burst);
json_unpack(root, "{s:s}", "burst_unit", &burst_unit);
if (!strcmp(rate_unit, "packets")) {
@@ -3221,11 +3726,12 @@ static struct cmd *json_parse_cmd_add_object(struct json_ctx *ctx,
case CMD_OBJ_SYNPROXY:
obj->type = NFT_OBJECT_SYNPROXY;
if (json_unpack_err(ctx, root, "{s:i, s:i}",
- "mss", &obj->synproxy.mss,
- "wscale", &obj->synproxy.wscale)) {
+ "mss", &i, "wscale", &j)) {
obj_free(obj);
return NULL;
}
+ obj->synproxy.mss = i;
+ obj->synproxy.wscale = j;
obj->synproxy.flags |= NF_SYNPROXY_OPT_MSS;
obj->synproxy.flags |= NF_SYNPROXY_OPT_WSCALE;
if (!json_unpack(root, "{s:o}", "flags", &jflags)) {
@@ -3261,7 +3767,7 @@ static struct cmd *json_parse_cmd_add(struct json_ctx *ctx,
{ "rule", CMD_OBJ_RULE, json_parse_cmd_add_rule },
{ "set", CMD_OBJ_SET, json_parse_cmd_add_set },
{ "map", CMD_OBJ_SET, json_parse_cmd_add_set },
- { "element", CMD_OBJ_SETELEM, json_parse_cmd_add_element },
+ { "element", CMD_OBJ_ELEMENTS, json_parse_cmd_add_element },
{ "flowtable", CMD_OBJ_FLOWTABLE, json_parse_cmd_add_flowtable },
{ "counter", CMD_OBJ_COUNTER, json_parse_cmd_add_object },
{ "quota", CMD_OBJ_QUOTA, json_parse_cmd_add_object },
@@ -3269,7 +3775,8 @@ static struct cmd *json_parse_cmd_add(struct json_ctx *ctx,
{ "ct timeout", NFT_OBJECT_CT_TIMEOUT, json_parse_cmd_add_object },
{ "ct expectation", NFT_OBJECT_CT_EXPECT, json_parse_cmd_add_object },
{ "limit", CMD_OBJ_LIMIT, json_parse_cmd_add_object },
- { "secmark", CMD_OBJ_SECMARK, json_parse_cmd_add_object }
+ { "secmark", CMD_OBJ_SECMARK, json_parse_cmd_add_object },
+ { "synproxy", CMD_OBJ_SYNPROXY, json_parse_cmd_add_object }
};
unsigned int i;
json_t *tmp;
@@ -3371,8 +3878,7 @@ static struct cmd *json_parse_cmd_replace(struct json_ctx *ctx,
return NULL;
}
- rule->num_stmts++;
- list_add_tail(&stmt->list, &rule->stmts);
+ rule_stmt_append(rule, stmt);
}
if (op == CMD_REPLACE)
@@ -3467,6 +3973,39 @@ static struct cmd *json_parse_cmd_list(struct json_ctx *ctx,
return NULL;
}
+static struct cmd *json_parse_cmd_reset_rule(struct json_ctx *ctx,
+ json_t *root, enum cmd_ops op,
+ enum cmd_obj obj)
+{
+ struct handle h = {
+ .family = NFPROTO_UNSPEC,
+ };
+ const char *family = NULL, *table = NULL, *chain = NULL;
+
+
+ if (obj == CMD_OBJ_RULE &&
+ json_unpack_err(ctx, root, "{s:s, s:s, s:s, s:I}",
+ "family", &family, "table", &table,
+ "chain", &chain, "handle", &h.handle.id))
+ return NULL;
+ else if (obj == CMD_OBJ_RULES) {
+ json_unpack(root, "{s:s}", "family", &family);
+ json_unpack(root, "{s:s}", "table", &table);
+ json_unpack(root, "{s:s}", "chain", &chain);
+ }
+
+ if (family && parse_family(family, &h.family)) {
+ json_error(ctx, "Unknown family '%s'.", family);
+ return NULL;
+ }
+ if (table) {
+ h.table.name = xstrdup(table);
+ if (chain)
+ h.chain.name = xstrdup(chain);
+ }
+ return cmd_alloc(op, obj, &h, int_loc, NULL);
+}
+
static struct cmd *json_parse_cmd_reset(struct json_ctx *ctx,
json_t *root, enum cmd_ops op)
{
@@ -3480,6 +4019,11 @@ static struct cmd *json_parse_cmd_reset(struct json_ctx *ctx,
{ "counters", CMD_OBJ_COUNTERS, json_parse_cmd_list_multiple },
{ "quota", CMD_OBJ_QUOTA, json_parse_cmd_add_object },
{ "quotas", CMD_OBJ_QUOTAS, json_parse_cmd_list_multiple },
+ { "rule", CMD_OBJ_RULE, json_parse_cmd_reset_rule },
+ { "rules", CMD_OBJ_RULES, json_parse_cmd_reset_rule },
+ { "element", CMD_OBJ_ELEMENTS, json_parse_cmd_add_element },
+ { "set", CMD_OBJ_SET, json_parse_cmd_add_set },
+ { "map", CMD_OBJ_MAP, json_parse_cmd_add_set },
};
unsigned int i;
json_t *tmp;
@@ -3578,6 +4122,7 @@ static struct cmd *json_parse_cmd(struct json_ctx *ctx, json_t *root)
{ "reset", CMD_RESET, json_parse_cmd_reset },
{ "flush", CMD_FLUSH, json_parse_cmd_flush },
{ "rename", CMD_RENAME, json_parse_cmd_rename },
+ { "destroy", CMD_DESTROY, json_parse_cmd_add },
//{ "export", CMD_EXPORT, json_parse_cmd_export },
//{ "monitor", CMD_MONITOR, json_parse_cmd_monitor },
//{ "describe", CMD_DESCRIBE, json_parse_cmd_describe }
@@ -3600,13 +4145,14 @@ static int json_verify_metainfo(struct json_ctx *ctx, json_t *root)
{
int schema_version;
- if (!json_unpack(root, "{s:i}", "json_schema_version", &schema_version))
- return 0;
-
- if (schema_version > JSON_SCHEMA_VERSION) {
- json_error(ctx, "Schema version %d not supported, maximum supported version is %d\n",
- schema_version, JSON_SCHEMA_VERSION);
- return 1;
+ if (!json_unpack(root, "{s:i}", "json_schema_version", &schema_version)) {
+ if (schema_version > JSON_SCHEMA_VERSION) {
+ json_error(ctx,
+ "Schema version %d not supported, maximum"
+ " supported version is %d\n",
+ schema_version, JSON_SCHEMA_VERSION);
+ return 1;
+ }
}
return 0;
@@ -3614,20 +4160,33 @@ static int json_verify_metainfo(struct json_ctx *ctx, json_t *root)
struct json_cmd_assoc {
struct json_cmd_assoc *next;
+ struct hlist_node hnode;
const struct cmd *cmd;
json_t *json;
};
-static struct json_cmd_assoc *json_cmd_list = NULL;
+#define CMD_ASSOC_HSIZE 512
+static struct hlist_head json_cmd_assoc_hash[CMD_ASSOC_HSIZE];
+static struct json_cmd_assoc *json_cmd_assoc_list;
static void json_cmd_assoc_free(void)
{
struct json_cmd_assoc *cur;
+ struct hlist_node *pos, *n;
+ int i;
- while (json_cmd_list) {
- cur = json_cmd_list;
- json_cmd_list = cur->next;
- free(cur);
+ while (json_cmd_assoc_list) {
+ cur = json_cmd_assoc_list->next;
+ free(json_cmd_assoc_list);
+ json_cmd_assoc_list = cur;
+ }
+
+ for (i = 0; i < CMD_ASSOC_HSIZE; i++) {
+ hlist_for_each_entry_safe(cur, pos, n,
+ &json_cmd_assoc_hash[i], hnode) {
+ hlist_del(&cur->hnode);
+ free(cur);
+ }
}
}
@@ -3635,20 +4194,33 @@ static void json_cmd_assoc_add(json_t *json, const struct cmd *cmd)
{
struct json_cmd_assoc *new = xzalloc(sizeof *new);
- new->next = json_cmd_list;
new->json = json;
new->cmd = cmd;
- json_cmd_list = new;
+ new->next = json_cmd_assoc_list;
+
+ json_cmd_assoc_list = new;
}
static json_t *seqnum_to_json(const uint32_t seqnum)
{
- const struct json_cmd_assoc *cur;
+ struct json_cmd_assoc *cur;
+ struct hlist_node *n;
+ int key;
+
+ while (json_cmd_assoc_list) {
+ cur = json_cmd_assoc_list;
+ json_cmd_assoc_list = cur->next;
+
+ key = cur->cmd->seqnum % CMD_ASSOC_HSIZE;
+ hlist_add_head(&cur->hnode, &json_cmd_assoc_hash[key]);
+ }
- for (cur = json_cmd_list; cur; cur = cur->next) {
+ key = seqnum % CMD_ASSOC_HSIZE;
+ hlist_for_each_entry(cur, n, &json_cmd_assoc_hash[key], hnode) {
if (cur->cmd->seqnum == seqnum)
return cur->json;
}
+
return NULL;
}
@@ -3708,16 +4280,16 @@ int nft_parse_json_buffer(struct nft_ctx *nft, const char *buf,
struct list_head *msgs, struct list_head *cmds)
{
struct json_ctx ctx = {
- .indesc = {
- .type = INDESC_BUFFER,
- .data = buf,
- },
.nft = nft,
.msgs = msgs,
.cmds = cmds,
};
int ret;
+ json_indesc.type = INDESC_BUFFER;
+ json_indesc.data = buf;
+
+ parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
nft->json_root = json_loads(buf, 0, NULL);
if (!nft->json_root)
return -EINVAL;
@@ -3735,10 +4307,6 @@ int nft_parse_json_filename(struct nft_ctx *nft, const char *filename,
struct list_head *msgs, struct list_head *cmds)
{
struct json_ctx ctx = {
- .indesc = {
- .type = INDESC_FILE,
- .name = filename,
- },
.nft = nft,
.msgs = msgs,
.cmds = cmds,
@@ -3746,6 +4314,10 @@ int nft_parse_json_filename(struct nft_ctx *nft, const char *filename,
json_error_t err;
int ret;
+ json_indesc.type = INDESC_FILE;
+ json_indesc.name = filename;
+
+ parser_init(nft, nft->state, msgs, cmds, nft->top_scope);
nft->json_root = json_load_file(filename, 0, &err);
if (!nft->json_root)
return -EINVAL;
@@ -3816,14 +4388,20 @@ static uint64_t handle_from_nlmsg(const struct nlmsghdr *nlh)
}
int json_events_cb(const struct nlmsghdr *nlh, struct netlink_mon_handler *monh)
{
- json_t *tmp, *json = seqnum_to_json(nlh->nlmsg_seq);
uint64_t handle = handle_from_nlmsg(nlh);
+ json_t *tmp, *json;
void *iter;
- /* might be anonymous set, ignore message */
- if (!json || !handle)
+ if (!handle)
return MNL_CB_OK;
+ json = seqnum_to_json(nlh->nlmsg_seq);
+ if (!json) {
+ json_echo_error(monh, "No JSON command found with seqnum %lu\n",
+ nlh->nlmsg_seq);
+ return MNL_CB_OK;
+ }
+
tmp = json_object_get(json, "add");
if (!tmp)
tmp = json_object_get(json, "insert");
@@ -3848,11 +4426,20 @@ int json_events_cb(const struct nlmsghdr *nlh, struct netlink_mon_handler *monh)
void json_print_echo(struct nft_ctx *ctx)
{
- if (!ctx->json_root)
- return;
-
- json_dumpf(ctx->json_root, ctx->output.output_fp, JSON_PRESERVE_ORDER);
- json_cmd_assoc_free();
- json_decref(ctx->json_root);
- ctx->json_root = NULL;
+ if (!ctx->json_root) {
+ if (!ctx->json_echo)
+ return;
+
+ ctx->json_echo = json_pack("{s:o}", "nftables", ctx->json_echo);
+ json_dumpf(ctx->json_echo, ctx->output.output_fp, JSON_PRESERVE_ORDER);
+ json_decref(ctx->json_echo);
+ ctx->json_echo = NULL;
+ fprintf(ctx->output.output_fp, "\n");
+ fflush(ctx->output.output_fp);
+ } else {
+ json_dumpf(ctx->json_root, ctx->output.output_fp, JSON_PRESERVE_ORDER);
+ json_cmd_assoc_free();
+ json_decref(ctx->json_root);
+ ctx->json_root = NULL;
+ }
}
diff --git a/src/payload.c b/src/payload.c
index 3576400b..44aa834c 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -10,15 +10,16 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <stddef.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <linux/netfilter.h>
#include <linux/if_ether.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp6.h>
#include <rule.h>
#include <expression.h>
@@ -45,6 +46,10 @@ static void payload_expr_print(const struct expr *expr, struct output_ctx *octx)
const struct proto_desc *desc;
const struct proto_hdr_template *tmpl;
+ if (expr->payload.inner_desc &&
+ expr->payload.inner_desc != expr->payload.desc)
+ nft_print(octx, "%s ", expr->payload.inner_desc->name);
+
desc = expr->payload.desc;
tmpl = expr->payload.tmpl;
if (payload_is_known(expr))
@@ -65,6 +70,7 @@ bool payload_expr_cmp(const struct expr *e1, const struct expr *e2)
static void payload_expr_clone(struct expr *new, const struct expr *expr)
{
+ new->payload.inner_desc = expr->payload.inner_desc;
new->payload.desc = expr->payload.desc;
new->payload.tmpl = expr->payload.tmpl;
new->payload.base = expr->payload.base;
@@ -80,9 +86,10 @@ static void payload_expr_clone(struct expr *new, const struct expr *expr)
* Update protocol context for relational payload expressions.
*/
static void payload_expr_pctx_update(struct proto_ctx *ctx,
- const struct expr *expr)
+ const struct location *loc,
+ const struct expr *left,
+ const struct expr *right)
{
- const struct expr *left = expr->left, *right = expr->right;
const struct proto_desc *base, *desc;
unsigned int proto = 0;
@@ -94,15 +101,165 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx,
base = ctx->protocol[left->payload.base].desc;
desc = proto_find_upper(base, proto);
- if (!desc)
+ if (!desc) {
+ if (base == &proto_icmp) {
+ /* proto 0 is ECHOREPLY, just pretend its ECHO.
+ * Not doing this would need an additional marker
+ * bit to tell when icmp.type was set.
+ */
+ ctx->th_dep.icmp.type = proto ? proto : ICMP_ECHO;
+ } else if (base == &proto_icmp6) {
+ if (proto == ICMP6_ECHO_REPLY)
+ proto = ICMP6_ECHO_REQUEST;
+ ctx->th_dep.icmp.type = proto;
+ }
return;
+ }
assert(desc->base <= PROTO_BASE_MAX);
if (desc->base == base->base) {
- assert(base->length > 0);
- ctx->protocol[base->base].offset += base->length;
+ if (!left->payload.is_raw) {
+ if (desc->base == PROTO_BASE_LL_HDR &&
+ ctx->stacked_ll_count < PROTO_CTX_NUM_PROTOS) {
+ assert(base->length > 0);
+ ctx->stacked_ll[ctx->stacked_ll_count] = base;
+ ctx->stacked_ll_count++;
+ }
+ }
+ }
+ proto_ctx_update(ctx, desc->base, loc, desc);
+}
+
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_DESC 0
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE 1
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_BASE 2
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET 3
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_LEN 4
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC 5
+#define NFTNL_UDATA_SET_KEY_PAYLOAD_MAX 6
+
+static unsigned int expr_payload_type(const struct proto_desc *desc,
+ const struct proto_hdr_template *tmpl)
+{
+ if (desc->id == PROTO_DESC_UNKNOWN)
+ return 0;
+
+ return (unsigned int)(tmpl - &desc->templates[0]);
+}
+
+static int payload_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ const struct proto_hdr_template *tmpl = expr->payload.tmpl;
+ const struct proto_desc *desc = expr->payload.desc;
+ unsigned int type = expr_payload_type(desc, tmpl);
+
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_DESC, desc->id);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE, type);
+
+ if (desc->id == 0) {
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_BASE,
+ expr->payload.base);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET,
+ expr->payload.offset);
+ }
+ if (expr->dtype->type == TYPE_INTEGER)
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_LEN, expr->len);
+
+ if (expr->payload.inner_desc) {
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC,
+ expr->payload.inner_desc->id);
}
- proto_ctx_update(ctx, desc->base, &expr->location, desc);
+
+ return 0;
+}
+
+const struct proto_desc *find_proto_desc(const struct nftnl_udata *ud)
+{
+ return proto_find_desc(nftnl_udata_get_u32(ud));
+}
+
+static int payload_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_SET_KEY_PAYLOAD_DESC:
+ case NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE:
+ case NFTNL_UDATA_SET_KEY_PAYLOAD_BASE:
+ case NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET:
+ case NFTNL_UDATA_SET_KEY_PAYLOAD_LEN:
+ case NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *payload_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_SET_KEY_PAYLOAD_MAX + 1] = {};
+ unsigned int type, base, offset, len = 0;
+ const struct proto_desc *desc;
+ bool is_raw = false;
+ struct expr *expr;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ payload_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_SET_KEY_PAYLOAD_DESC] ||
+ !ud[NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE])
+ return NULL;
+
+ desc = find_proto_desc(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_DESC]);
+ if (!desc) {
+ if (!ud[NFTNL_UDATA_SET_KEY_PAYLOAD_BASE] ||
+ !ud[NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET])
+ return NULL;
+
+ base = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_BASE]);
+ offset = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET]);
+ is_raw = true;
+ }
+
+ type = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_TYPE]);
+ if (ud[NFTNL_UDATA_SET_KEY_PAYLOAD_LEN])
+ len = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_LEN]);
+
+ expr = payload_expr_alloc(&internal_location, desc, type);
+
+ if (len)
+ expr->len = len;
+
+ if (is_raw) {
+ struct datatype *dtype;
+
+ expr->payload.base = base;
+ expr->payload.offset = offset;
+ expr->payload.is_raw = true;
+ expr->len = len;
+ dtype = datatype_clone(&xinteger_type);
+ dtype->size = len;
+ dtype->byteorder = BYTEORDER_BIG_ENDIAN;
+ __datatype_set(expr, dtype);
+ }
+
+ if (ud[NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC]) {
+ desc = find_proto_desc(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC]);
+ expr->payload.inner_desc = desc;
+ }
+
+ return expr;
}
const struct expr_ops payload_expr_ops = {
@@ -113,6 +270,8 @@ const struct expr_ops payload_expr_ops = {
.cmp = payload_expr_cmp,
.clone = payload_expr_clone,
.pctx_update = payload_expr_pctx_update,
+ .build_udata = payload_expr_build_udata,
+ .parse_udata = payload_expr_parse_udata,
};
/*
@@ -177,7 +336,7 @@ void payload_init_raw(struct expr *expr, enum proto_bases base,
expr->payload.base = base;
expr->payload.offset = offset;
expr->len = len;
- expr->dtype = &integer_type;
+ expr->dtype = &xinteger_type;
if (base != PROTO_BASE_TRANSPORT_HDR)
return;
@@ -246,9 +405,11 @@ static int payload_add_dependency(struct eval_ctx *ctx,
{
const struct proto_hdr_template *tmpl;
struct expr *dep, *left, *right;
+ struct proto_ctx *pctx;
struct stmt *stmt;
- int protocol = proto_find_num(desc, upper);
+ int protocol;
+ protocol = proto_find_num(desc, upper);
if (protocol < 0)
return expr_error(ctx->msgs, expr,
"conflicting protocols specified: %s vs. %s",
@@ -265,20 +426,28 @@ static int payload_add_dependency(struct eval_ctx *ctx,
constant_data_ptr(protocol, tmpl->len));
dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
+
stmt = expr_stmt_alloc(&dep->location, dep);
- if (stmt_evaluate(ctx, stmt) < 0) {
- return expr_error(ctx->msgs, expr,
- "dependency statement is invalid");
+ if (stmt_dependency_evaluate(ctx, stmt) < 0)
+ return -1;
+
+ if (ctx->inner_desc) {
+ if (tmpl->meta_key)
+ left->meta.inner_desc = ctx->inner_desc;
+ else
+ left->payload.inner_desc = ctx->inner_desc;
}
- relational_expr_pctx_update(&ctx->pctx, dep);
+
+ pctx = eval_proto_ctx(ctx);
+ relational_expr_pctx_update(pctx, dep);
*res = stmt;
return 0;
}
static const struct proto_desc *
-payload_get_get_ll_hdr(const struct eval_ctx *ctx)
+payload_get_get_ll_hdr(const struct proto_ctx *pctx)
{
- switch (ctx->pctx.family) {
+ switch (pctx->family) {
case NFPROTO_INET:
return &proto_inet;
case NFPROTO_BRIDGE:
@@ -295,9 +464,11 @@ payload_get_get_ll_hdr(const struct eval_ctx *ctx)
static const struct proto_desc *
payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+
switch (expr->payload.base) {
case PROTO_BASE_LL_HDR:
- return payload_get_get_ll_hdr(ctx);
+ return payload_get_get_ll_hdr(pctx);
case PROTO_BASE_TRANSPORT_HDR:
if (expr->payload.desc == &proto_icmp ||
expr->payload.desc == &proto_icmp6 ||
@@ -305,13 +476,21 @@ payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr)
const struct proto_desc *desc, *desc_upper;
struct stmt *nstmt;
- desc = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
+ desc = pctx->protocol[PROTO_BASE_LL_HDR].desc;
if (!desc) {
- desc = payload_get_get_ll_hdr(ctx);
+ desc = payload_get_get_ll_hdr(pctx);
if (!desc)
break;
}
+ /* this tunnel protocol does not encapsulate an inner
+ * link layer, use proto_netdev which relies on
+ * NFT_META_PROTOCOL for dependencies.
+ */
+ if (expr->payload.inner_desc &&
+ !(expr->payload.inner_desc->inner.flags & NFT_INNER_LL))
+ desc = &proto_netdev;
+
desc_upper = &proto_ip6;
if (expr->payload.desc == &proto_icmp ||
expr->payload.desc == &proto_igmp)
@@ -357,11 +536,14 @@ payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr)
int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
struct stmt **res)
{
- const struct hook_proto_desc *h = &hook_proto_desc[ctx->pctx.family];
+ const struct hook_proto_desc *h;
const struct proto_desc *desc;
+ struct proto_ctx *pctx;
struct stmt *stmt;
uint16_t type;
+ pctx = eval_proto_ctx(ctx);
+ h = &hook_proto_desc[pctx->family];
if (expr->payload.base < h->base) {
if (expr->payload.base < h->base - 1)
return expr_error(ctx->msgs, expr,
@@ -374,15 +556,15 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
"for this family");
stmt = meta_stmt_meta_iiftype(&expr->location, type);
- if (stmt_evaluate(ctx, stmt) < 0) {
- return expr_error(ctx->msgs, expr,
- "dependency statement is invalid");
- }
+ if (stmt_dependency_evaluate(ctx, stmt) < 0)
+ return -1;
+
*res = stmt;
+
return 0;
}
- desc = ctx->pctx.protocol[expr->payload.base - 1].desc;
+ desc = pctx->protocol[expr->payload.base - 1].desc;
/* Special case for mixed IPv4/IPv6 and bridge tables */
if (desc == NULL)
desc = payload_gen_special_dependency(ctx, expr);
@@ -393,7 +575,7 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
"no %s protocol specified",
proto_base_names[expr->payload.base - 1]);
- if (ctx->pctx.family == NFPROTO_BRIDGE && desc == &proto_eth) {
+ if (pctx->family == NFPROTO_BRIDGE && desc == &proto_eth) {
/* prefer netdev proto, which adds dependencies based
* on skb->protocol.
*
@@ -418,11 +600,13 @@ int exthdr_gen_dependency(struct eval_ctx *ctx, const struct expr *expr,
enum proto_bases pb, struct stmt **res)
{
const struct proto_desc *desc;
+ struct proto_ctx *pctx;
- desc = ctx->pctx.protocol[pb].desc;
+ pctx = eval_proto_ctx(ctx);
+ desc = pctx->protocol[pb].desc;
if (desc == NULL) {
if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT) {
- switch (ctx->pctx.family) {
+ switch (pctx->family) {
case NFPROTO_NETDEV:
case NFPROTO_BRIDGE:
case NFPROTO_INET:
@@ -468,6 +652,41 @@ void payload_dependency_reset(struct payload_dep_ctx *ctx)
memset(ctx, 0, sizeof(*ctx));
}
+static bool payload_dependency_store_icmp_type(struct payload_dep_ctx *ctx,
+ const struct stmt *stmt)
+{
+ struct expr *dep = stmt->expr;
+ const struct proto_desc *desc;
+ const struct expr *right;
+ uint8_t type;
+
+ if (dep->left->etype != EXPR_PAYLOAD)
+ return false;
+
+ right = dep->right;
+ if (right->etype != EXPR_VALUE || right->len != BITS_PER_BYTE)
+ return false;
+
+ desc = dep->left->payload.desc;
+ if (desc == &proto_icmp) {
+ type = mpz_get_uint8(right->value);
+
+ if (type == ICMP_ECHOREPLY)
+ type = ICMP_ECHO;
+
+ ctx->icmp_type = type;
+
+ return type == ICMP_ECHO;
+ } else if (desc == &proto_icmp6) {
+ type = mpz_get_uint8(right->value);
+
+ ctx->icmp_type = type;
+ return type == ICMP6_ECHO_REQUEST || type == ICMP6_ECHO_REPLY;
+ }
+
+ return false;
+}
+
/**
* payload_dependency_store - store a possibly redundant protocol match
*
@@ -478,8 +697,12 @@ void payload_dependency_reset(struct payload_dep_ctx *ctx)
void payload_dependency_store(struct payload_dep_ctx *ctx,
struct stmt *stmt, enum proto_bases base)
{
- ctx->pbase = base + 1;
- ctx->pdep = stmt;
+ bool ignore_dep = payload_dependency_store_icmp_type(ctx, stmt);
+
+ if (ignore_dep)
+ return;
+
+ ctx->pdeps[base + 1] = stmt;
}
/**
@@ -494,26 +717,145 @@ void payload_dependency_store(struct payload_dep_ctx *ctx,
bool payload_dependency_exists(const struct payload_dep_ctx *ctx,
enum proto_bases base)
{
- return ctx->pbase != PROTO_BASE_INVALID &&
- ctx->pbase == base &&
- ctx->pdep != NULL;
+ if (ctx->pdeps[base])
+ return true;
+
+ return base == PROTO_BASE_TRANSPORT_HDR &&
+ ctx->pdeps[PROTO_BASE_INNER_HDR];
+}
+
+/**
+ * payload_dependency_get - return a payload dependency if available
+ * @ctx: payload dependency context
+ * @base: payload protocol base
+ *
+ * If we have seen a protocol key payload expression for this base, we return
+ * it.
+ */
+struct expr *payload_dependency_get(struct payload_dep_ctx *ctx,
+ enum proto_bases base)
+{
+ if (ctx->pdeps[base])
+ return ctx->pdeps[base]->expr;
+
+ if (base == PROTO_BASE_TRANSPORT_HDR &&
+ ctx->pdeps[PROTO_BASE_INNER_HDR])
+ return ctx->pdeps[PROTO_BASE_INNER_HDR]->expr;
+
+ return NULL;
}
-void payload_dependency_release(struct payload_dep_ctx *ctx)
+static void __payload_dependency_release(struct payload_dep_ctx *ctx,
+ enum proto_bases base)
{
- list_del(&ctx->pdep->list);
- stmt_free(ctx->pdep);
+ list_del(&ctx->pdeps[base]->list);
+ stmt_free(ctx->pdeps[base]);
- ctx->pbase = PROTO_BASE_INVALID;
- if (ctx->pdep == ctx->prev)
+ if (ctx->pdeps[base] == ctx->prev)
ctx->prev = NULL;
- ctx->pdep = NULL;
+ ctx->pdeps[base] = NULL;
+}
+
+void payload_dependency_release(struct payload_dep_ctx *ctx,
+ enum proto_bases base)
+{
+ if (ctx->pdeps[base])
+ __payload_dependency_release(ctx, base);
+ else if (base == PROTO_BASE_TRANSPORT_HDR &&
+ ctx->pdeps[PROTO_BASE_INNER_HDR])
+ __payload_dependency_release(ctx, PROTO_BASE_INNER_HDR);
+}
+
+static uint8_t icmp_dep_to_type(enum icmp_hdr_field_type t)
+{
+ switch (t) {
+ case PROTO_ICMP_ANY:
+ BUG("Invalid map for simple dependency");
+ case PROTO_ICMP_ECHO: return ICMP_ECHO;
+ case PROTO_ICMP6_ECHO: return ICMP6_ECHO_REQUEST;
+ case PROTO_ICMP_MTU: return ICMP_DEST_UNREACH;
+ case PROTO_ICMP_ADDRESS: return ICMP_REDIRECT;
+ case PROTO_ICMP6_MTU: return ICMP6_PACKET_TOO_BIG;
+ case PROTO_ICMP6_MGMQ: return MLD_LISTENER_QUERY;
+ case PROTO_ICMP6_PPTR: return ICMP6_PARAM_PROB;
+ case PROTO_ICMP6_REDIRECT: return ND_REDIRECT;
+ case PROTO_ICMP6_ADDRESS: return ND_NEIGHBOR_SOLICIT;
+ }
+
+ BUG("Missing icmp type mapping");
+}
+
+static bool icmp_dep_type_match(enum icmp_hdr_field_type t, uint8_t type)
+{
+ switch (t) {
+ case PROTO_ICMP_ECHO:
+ return type == ICMP_ECHO || type == ICMP_ECHOREPLY;
+ case PROTO_ICMP6_ECHO:
+ return type == ICMP6_ECHO_REQUEST || type == ICMP6_ECHO_REPLY;
+ case PROTO_ICMP6_ADDRESS:
+ return type == ND_NEIGHBOR_SOLICIT ||
+ type == ND_NEIGHBOR_ADVERT ||
+ type == ND_REDIRECT ||
+ type == MLD_LISTENER_QUERY ||
+ type == MLD_LISTENER_REPORT ||
+ type == MLD_LISTENER_REDUCTION;
+ case PROTO_ICMP_ADDRESS:
+ case PROTO_ICMP_MTU:
+ case PROTO_ICMP6_MTU:
+ case PROTO_ICMP6_MGMQ:
+ case PROTO_ICMP6_PPTR:
+ case PROTO_ICMP6_REDIRECT:
+ return icmp_dep_to_type(t) == type;
+ case PROTO_ICMP_ANY:
+ return true;
+ }
+ BUG("Missing icmp type mapping");
+}
+
+static bool payload_may_dependency_kill_icmp(struct payload_dep_ctx *ctx, struct expr *expr)
+{
+ const struct expr *dep = payload_dependency_get(ctx, expr->payload.base);
+ enum icmp_hdr_field_type icmp_dep;
+
+ icmp_dep = expr->payload.tmpl->icmp_dep;
+ if (icmp_dep == PROTO_ICMP_ANY)
+ return false;
+
+ if (dep->left->payload.desc != expr->payload.desc)
+ return false;
+
+ if (expr->payload.tmpl->icmp_dep == PROTO_ICMP_ECHO ||
+ expr->payload.tmpl->icmp_dep == PROTO_ICMP6_ECHO ||
+ expr->payload.tmpl->icmp_dep == PROTO_ICMP6_ADDRESS)
+ return false;
+
+ return ctx->icmp_type == icmp_dep_to_type(icmp_dep);
+}
+
+static bool payload_may_dependency_kill_ll(struct payload_dep_ctx *ctx, struct expr *expr)
+{
+ const struct expr *dep = payload_dependency_get(ctx, expr->payload.base);
+
+ /* Never remove a 'vlan type 0x...' expression, they are never added
+ * implicitly
+ */
+ if (dep->left->payload.desc == &proto_vlan)
+ return false;
+
+ /* 'vlan id 2' implies 'ether type 8021Q'. If a different protocol is
+ * tested, this is not a redundant expression.
+ */
+ if (dep->left->payload.desc == &proto_eth &&
+ dep->right->etype == EXPR_VALUE && dep->right->len == 16)
+ return mpz_get_uint16(dep->right->value) == ETH_P_8021Q;
+
+ return true;
}
static bool payload_may_dependency_kill(struct payload_dep_ctx *ctx,
unsigned int family, struct expr *expr)
{
- struct expr *dep = ctx->pdep->expr;
+ struct expr *dep = payload_dependency_get(ctx, expr->payload.base);
/* Protocol key payload expression at network base such as 'ip6 nexthdr'
* need to be left in place since it implicitly restricts matching to
@@ -538,12 +880,29 @@ static bool payload_may_dependency_kill(struct payload_dep_ctx *ctx,
* for stacked protocols if we only have protcol type matches.
*/
if (dep->left->etype == EXPR_PAYLOAD && dep->op == OP_EQ &&
- expr->flags & EXPR_F_PROTOCOL &&
- expr->payload.base == dep->left->payload.base)
- return false;
+ expr->payload.base == dep->left->payload.base) {
+ if (expr->flags & EXPR_F_PROTOCOL)
+ return false;
+
+ if (expr->payload.base == PROTO_BASE_LL_HDR)
+ return payload_may_dependency_kill_ll(ctx, expr);
+ }
+
break;
}
+ if (expr->payload.base != PROTO_BASE_TRANSPORT_HDR)
+ return true;
+
+ if (dep->left->payload.base != PROTO_BASE_TRANSPORT_HDR)
+ return true;
+
+ if (dep->left->payload.desc == &proto_icmp)
+ return payload_may_dependency_kill_icmp(ctx, expr);
+
+ if (dep->left->payload.desc == &proto_icmp6)
+ return payload_may_dependency_kill_icmp(ctx, expr);
+
return true;
}
@@ -560,9 +919,10 @@ static bool payload_may_dependency_kill(struct payload_dep_ctx *ctx,
void payload_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
unsigned int family)
{
- if (payload_dependency_exists(ctx, expr->payload.base) &&
+ if (expr->payload.desc != &proto_unknown &&
+ payload_dependency_exists(ctx, expr->payload.base) &&
payload_may_dependency_kill(ctx, family, expr))
- payload_dependency_release(ctx);
+ payload_dependency_release(ctx, expr->payload.base);
}
void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
@@ -571,21 +931,53 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
switch (expr->exthdr.op) {
case NFT_EXTHDR_OP_TCPOPT:
if (payload_dependency_exists(ctx, PROTO_BASE_TRANSPORT_HDR))
- payload_dependency_release(ctx);
+ payload_dependency_release(ctx, PROTO_BASE_TRANSPORT_HDR);
break;
case NFT_EXTHDR_OP_IPV6:
if (payload_dependency_exists(ctx, PROTO_BASE_NETWORK_HDR))
- payload_dependency_release(ctx);
+ payload_dependency_release(ctx, PROTO_BASE_NETWORK_HDR);
break;
case NFT_EXTHDR_OP_IPV4:
if (payload_dependency_exists(ctx, PROTO_BASE_NETWORK_HDR))
- payload_dependency_release(ctx);
+ payload_dependency_release(ctx, PROTO_BASE_NETWORK_HDR);
break;
default:
break;
}
}
+static const struct proto_desc *get_stacked_desc(const struct proto_ctx *ctx,
+ const struct proto_desc *top,
+ const struct expr *e,
+ unsigned int *skip)
+{
+ unsigned int i, total, payload_offset = e->payload.offset;
+
+ assert(e->etype == EXPR_PAYLOAD);
+
+ if (e->payload.base != PROTO_BASE_LL_HDR ||
+ payload_offset < top->length) {
+ *skip = 0;
+ return top;
+ }
+
+ for (i = 0, total = 0; i < ctx->stacked_ll_count; i++) {
+ const struct proto_desc *stacked;
+
+ stacked = ctx->stacked_ll[i];
+ if (payload_offset < stacked->length) {
+ *skip = total;
+ return stacked;
+ }
+
+ payload_offset -= stacked->length;
+ total += stacked->length;
+ }
+
+ *skip = total;
+ return top;
+}
+
/**
* payload_expr_complete - fill in type information of a raw payload expr
*
@@ -597,9 +989,10 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
*/
void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx)
{
+ unsigned int payload_offset = expr->payload.offset;
const struct proto_desc *desc;
const struct proto_hdr_template *tmpl;
- unsigned int i;
+ unsigned int i, total;
assert(expr->etype == EXPR_PAYLOAD);
@@ -608,13 +1001,26 @@ void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx)
return;
assert(desc->base == expr->payload.base);
+ desc = get_stacked_desc(ctx, desc, expr, &total);
+ payload_offset -= total;
+
for (i = 0; i < array_size(desc->templates); i++) {
tmpl = &desc->templates[i];
- if (tmpl->offset != expr->payload.offset ||
+ if (tmpl->offset != payload_offset ||
tmpl->len != expr->len)
continue;
+
+ if (tmpl->meta_key && i == 0)
+ continue;
+
+ if (tmpl->icmp_dep && ctx->th_dep.icmp.type &&
+ !icmp_dep_type_match(tmpl->icmp_dep,
+ ctx->th_dep.icmp.type))
+ continue;
+
expr->dtype = tmpl->dtype;
expr->payload.desc = desc;
+ expr->byteorder = tmpl->byteorder;
expr->payload.tmpl = tmpl;
return;
}
@@ -659,6 +1065,7 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask,
unsigned int payload_len = expr->len;
const struct proto_desc *desc;
unsigned int off, i, len = 0;
+ unsigned int total;
assert(expr->etype == EXPR_PAYLOAD);
@@ -668,10 +1075,8 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask,
assert(desc->base == expr->payload.base);
- if (ctx->protocol[expr->payload.base].offset) {
- assert(payload_offset >= ctx->protocol[expr->payload.base].offset);
- payload_offset -= ctx->protocol[expr->payload.base].offset;
- }
+ desc = get_stacked_desc(ctx, desc, expr, &total);
+ payload_offset -= total;
off = round_up(mask->len, BITS_PER_BYTE) - mask_len;
payload_offset += off;
@@ -718,25 +1123,35 @@ bool payload_expr_trim(struct expr *expr, struct expr *mask,
void payload_expr_expand(struct list_head *list, struct expr *expr,
const struct proto_ctx *ctx)
{
+ unsigned int payload_offset = expr->payload.offset;
const struct proto_hdr_template *tmpl;
const struct proto_desc *desc;
+ unsigned int i, total;
struct expr *new;
- unsigned int i;
assert(expr->etype == EXPR_PAYLOAD);
desc = ctx->protocol[expr->payload.base].desc;
- if (desc == NULL)
+ if (desc == NULL || desc == &proto_unknown)
goto raw;
+
assert(desc->base == expr->payload.base);
+ desc = get_stacked_desc(ctx, desc, expr, &total);
+ payload_offset -= total;
+
for (i = 1; i < array_size(desc->templates); i++) {
tmpl = &desc->templates[i];
if (tmpl->len == 0)
break;
- if (tmpl->offset != expr->payload.offset)
+ if (tmpl->offset != payload_offset)
+ continue;
+
+ if (tmpl->icmp_dep && ctx->th_dep.icmp.type &&
+ !icmp_dep_type_match(tmpl->icmp_dep,
+ ctx->th_dep.icmp.type))
continue;
if (tmpl->len <= expr->len) {
@@ -744,15 +1159,25 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
list_add_tail(&new->list, list);
expr->len -= tmpl->len;
expr->payload.offset += tmpl->len;
+ payload_offset += tmpl->len;
if (expr->len == 0)
return;
+ } else if (expr->len > 0) {
+ new = payload_expr_alloc(&expr->location, desc, i);
+ new->len = expr->len;
+ list_add_tail(&new->list, list);
+ return;
} else
break;
}
raw:
new = payload_expr_alloc(&expr->location, NULL, 0);
- payload_init_raw(new, expr->payload.base, expr->payload.offset,
+ payload_init_raw(new, expr->payload.base, payload_offset,
expr->len);
+
+ if (expr->payload.inner_desc)
+ new->dtype = &integer_type;
+
list_add_tail(&new->list, list);
}
@@ -774,6 +1199,9 @@ bool payload_can_merge(const struct expr *e1, const struct expr *e2)
{
unsigned int total;
+ if (e1->payload.inner_desc != e2->payload.inner_desc)
+ return false;
+
if (!payload_is_adjacent(e1, e2))
return false;
@@ -830,5 +1258,221 @@ struct expr *payload_expr_join(const struct expr *e1, const struct expr *e2)
expr->payload.base = e1->payload.base;
expr->payload.offset = e1->payload.offset;
expr->len = e1->len + e2->len;
+ expr->payload.inner_desc = e1->payload.inner_desc;
+
return expr;
}
+
+static struct stmt *
+__payload_gen_icmp_simple_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ const struct datatype *icmp_type,
+ const struct proto_desc *desc,
+ uint8_t type)
+{
+ struct expr *left, *right, *dep;
+
+ left = payload_expr_alloc(&expr->location, desc, desc->protocol_key);
+ right = constant_expr_alloc(&expr->location, icmp_type,
+ BYTEORDER_BIG_ENDIAN, BITS_PER_BYTE,
+ constant_data_ptr(type, BITS_PER_BYTE));
+
+ dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
+ return expr_stmt_alloc(&dep->location, dep);
+}
+
+static struct stmt *
+__payload_gen_icmp_echo_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ uint8_t echo, uint8_t reply,
+ const struct datatype *icmp_type,
+ const struct proto_desc *desc)
+{
+ struct expr *left, *right, *dep, *set;
+
+ left = payload_expr_alloc(&expr->location, desc, desc->protocol_key);
+
+ set = set_expr_alloc(&expr->location, NULL);
+
+ right = constant_expr_alloc(&expr->location, icmp_type,
+ BYTEORDER_BIG_ENDIAN, BITS_PER_BYTE,
+ constant_data_ptr(echo, BITS_PER_BYTE));
+ right = set_elem_expr_alloc(&expr->location, right);
+ compound_expr_add(set, right);
+
+ right = constant_expr_alloc(&expr->location, icmp_type,
+ BYTEORDER_BIG_ENDIAN, BITS_PER_BYTE,
+ constant_data_ptr(reply, BITS_PER_BYTE));
+ right = set_elem_expr_alloc(&expr->location, right);
+ compound_expr_add(set, right);
+
+ dep = relational_expr_alloc(&expr->location, OP_IMPLICIT, left, set);
+ return expr_stmt_alloc(&dep->location, dep);
+}
+
+static struct stmt *
+__payload_gen_icmp6_addr_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ const struct proto_desc *desc)
+{
+ static const uint8_t icmp_addr_types[] = {
+ MLD_LISTENER_QUERY,
+ MLD_LISTENER_REPORT,
+ MLD_LISTENER_REDUCTION,
+ ND_NEIGHBOR_SOLICIT,
+ ND_NEIGHBOR_ADVERT,
+ ND_REDIRECT
+ };
+ struct expr *left, *right, *dep, *set;
+ size_t i;
+
+ left = payload_expr_alloc(&expr->location, desc, desc->protocol_key);
+
+ set = set_expr_alloc(&expr->location, NULL);
+
+ for (i = 0; i < array_size(icmp_addr_types); ++i) {
+ right = constant_expr_alloc(&expr->location, &icmp6_type_type,
+ BYTEORDER_BIG_ENDIAN, BITS_PER_BYTE,
+ constant_data_ptr(icmp_addr_types[i],
+ BITS_PER_BYTE));
+ right = set_elem_expr_alloc(&expr->location, right);
+ compound_expr_add(set, right);
+ }
+
+ dep = relational_expr_alloc(&expr->location, OP_IMPLICIT, left, set);
+ return expr_stmt_alloc(&dep->location, dep);
+}
+
+int payload_gen_icmp_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ struct stmt **res)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ const struct proto_hdr_template *tmpl;
+ const struct proto_desc *desc;
+ struct stmt *stmt = NULL;
+ uint8_t type;
+
+ assert(expr->etype == EXPR_PAYLOAD);
+
+ tmpl = expr->payload.tmpl;
+ desc = expr->payload.desc;
+
+ switch (tmpl->icmp_dep) {
+ case PROTO_ICMP_ANY:
+ BUG("No dependency needed");
+ break;
+ case PROTO_ICMP_ECHO:
+ /* do not test ICMP_ECHOREPLY here: its 0 */
+ if (pctx->th_dep.icmp.type == ICMP_ECHO)
+ goto done;
+
+ type = ICMP_ECHO;
+ if (pctx->th_dep.icmp.type)
+ goto bad_proto;
+
+ stmt = __payload_gen_icmp_echo_dependency(ctx, expr,
+ ICMP_ECHO, ICMP_ECHOREPLY,
+ &icmp_type_type,
+ desc);
+ break;
+ case PROTO_ICMP_MTU:
+ case PROTO_ICMP_ADDRESS:
+ type = icmp_dep_to_type(tmpl->icmp_dep);
+ if (pctx->th_dep.icmp.type == type)
+ goto done;
+ if (pctx->th_dep.icmp.type)
+ goto bad_proto;
+ stmt = __payload_gen_icmp_simple_dependency(ctx, expr,
+ &icmp_type_type,
+ desc, type);
+ break;
+ case PROTO_ICMP6_ECHO:
+ if (pctx->th_dep.icmp.type == ICMP6_ECHO_REQUEST ||
+ pctx->th_dep.icmp.type == ICMP6_ECHO_REPLY)
+ goto done;
+
+ type = ICMP6_ECHO_REQUEST;
+ if (pctx->th_dep.icmp.type)
+ goto bad_proto;
+
+ stmt = __payload_gen_icmp_echo_dependency(ctx, expr,
+ ICMP6_ECHO_REQUEST,
+ ICMP6_ECHO_REPLY,
+ &icmp6_type_type,
+ desc);
+ break;
+ case PROTO_ICMP6_ADDRESS:
+ if (icmp_dep_type_match(PROTO_ICMP6_ADDRESS,
+ pctx->th_dep.icmp.type))
+ goto done;
+ type = ND_NEIGHBOR_SOLICIT;
+ if (pctx->th_dep.icmp.type)
+ goto bad_proto;
+ stmt = __payload_gen_icmp6_addr_dependency(ctx, expr, desc);
+ break;
+ case PROTO_ICMP6_REDIRECT:
+ case PROTO_ICMP6_MTU:
+ case PROTO_ICMP6_MGMQ:
+ case PROTO_ICMP6_PPTR:
+ type = icmp_dep_to_type(tmpl->icmp_dep);
+ if (pctx->th_dep.icmp.type == type)
+ goto done;
+ if (pctx->th_dep.icmp.type)
+ goto bad_proto;
+ stmt = __payload_gen_icmp_simple_dependency(ctx, expr,
+ &icmp6_type_type,
+ desc, type);
+ break;
+ break;
+ default:
+ BUG("Unhandled icmp dependency code");
+ }
+
+ pctx->th_dep.icmp.type = type;
+
+ if (stmt_dependency_evaluate(ctx, stmt) < 0)
+ return -1;
+done:
+ *res = stmt;
+ return 0;
+
+bad_proto:
+ return expr_error(ctx->msgs, expr, "incompatible icmp match: rule has %d, need %u",
+ pctx->th_dep.icmp.type, type);
+}
+
+int payload_gen_inner_dependency(struct eval_ctx *ctx, const struct expr *expr,
+ struct stmt **res)
+{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
+ const struct proto_hdr_template *tmpl;
+ const struct proto_desc *desc, *inner_desc;
+ struct expr *left, *right, *dep;
+ struct stmt *stmt = NULL;
+ int protocol;
+
+ assert(expr->etype == EXPR_PAYLOAD);
+
+ inner_desc = expr->payload.inner_desc;
+ desc = pctx->protocol[inner_desc->base - 1].desc;
+ if (desc == NULL)
+ desc = &proto_ip;
+
+ tmpl = &inner_desc->templates[0];
+ assert(tmpl);
+
+ protocol = proto_find_num(desc, inner_desc);
+ if (protocol < 0)
+ return expr_error(ctx->msgs, expr,
+ "conflicting protocols specified: %s vs. %s",
+ desc->name, inner_desc->name);
+
+ left = meta_expr_alloc(&expr->location, tmpl->meta_key);
+
+ right = constant_expr_alloc(&expr->location, tmpl->dtype,
+ tmpl->dtype->byteorder, tmpl->len,
+ constant_data_ptr(protocol, tmpl->len));
+
+ dep = relational_expr_alloc(&expr->location, OP_EQ, left, right);
+ stmt = expr_stmt_alloc(&dep->location, dep);
+
+ *res = stmt;
+ return 0;
+}
diff --git a/src/print.c b/src/print.c
index d1b25e8b..8aefa961 100644
--- a/src/print.c
+++ b/src/print.c
@@ -2,11 +2,12 @@
* Copyright (c) 2017 Phil Sutter <phil@nwl.cc>
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
*/
+#include <nft.h>
+
#include <stdarg.h>
#include <nftables.h>
#include <utils.h>
diff --git a/src/proto.c b/src/proto.c
index 40ce590e..553b6a44 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -9,10 +9,9 @@
*
*/
+#include <nft.h>
+
#include <stddef.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
#include <net/if_arp.h>
#include <arpa/inet.h>
#include <linux/netfilter.h>
@@ -28,6 +27,7 @@ const char *proto_base_names[] = {
[PROTO_BASE_LL_HDR] = "link layer",
[PROTO_BASE_NETWORK_HDR] = "network layer",
[PROTO_BASE_TRANSPORT_HDR] = "transport layer",
+ [PROTO_BASE_INNER_HDR] = "payload data",
};
const char *proto_base_tokens[] = {
@@ -35,6 +35,7 @@ const char *proto_base_tokens[] = {
[PROTO_BASE_LL_HDR] = "ll",
[PROTO_BASE_NETWORK_HDR] = "nh",
[PROTO_BASE_TRANSPORT_HDR] = "th",
+ [PROTO_BASE_INNER_HDR] = "ih",
};
const struct proto_hdr_template proto_unknown_template =
@@ -58,6 +59,8 @@ proto_find_upper(const struct proto_desc *base, unsigned int num)
unsigned int i;
for (i = 0; i < array_size(base->protocols); i++) {
+ if (!base->protocols[i].desc)
+ break;
if (base->protocols[i].num == num)
return base->protocols[i].desc;
}
@@ -76,12 +79,38 @@ int proto_find_num(const struct proto_desc *base,
unsigned int i;
for (i = 0; i < array_size(base->protocols); i++) {
+ if (!base->protocols[i].desc)
+ break;
if (base->protocols[i].desc == desc)
return base->protocols[i].num;
}
return -1;
}
+static const struct proto_desc *inner_protocols[] = {
+ &proto_vxlan,
+ &proto_geneve,
+ &proto_gre,
+ &proto_gretap,
+};
+
+const struct proto_desc *proto_find_inner(uint32_t type, uint32_t hdrsize,
+ uint32_t flags)
+{
+ const struct proto_desc *desc;
+ unsigned int i;
+
+ for (i = 0; i < array_size(inner_protocols); i++) {
+ desc = inner_protocols[i];
+ if (desc->inner.type == type &&
+ desc->inner.hdrsize == hdrsize &&
+ desc->inner.flags == flags)
+ return inner_protocols[i];
+ }
+
+ return &proto_unknown;
+}
+
static const struct dev_proto_desc dev_proto_desc[] = {
DEV_PROTO_DESC(ARPHRD_ETHER, &proto_eth),
};
@@ -104,6 +133,8 @@ int proto_dev_type(const struct proto_desc *desc, uint16_t *res)
return 0;
}
for (j = 0; j < array_size(base->protocols); j++) {
+ if (!base->protocols[j].desc)
+ break;
if (base->protocols[j].desc == desc) {
*res = dev_proto_desc[i].type;
return 0;
@@ -146,14 +177,20 @@ static void proto_ctx_debug(const struct proto_ctx *ctx, enum proto_bases base,
if (!(debug_mask & NFT_DEBUG_PROTO_CTX))
return;
- pr_debug("update %s protocol context:\n", proto_base_names[base]);
+ if (base == PROTO_BASE_LL_HDR && ctx->stacked_ll_count) {
+ pr_debug(" saved ll headers:");
+ for (i = 0; i < ctx->stacked_ll_count; i++)
+ pr_debug(" %s", ctx->stacked_ll[i]->name);
+ }
+
+ pr_debug("update %s protocol context%s:\n",
+ proto_base_names[base], ctx->inner ? " (inner)" : "");
+
for (i = PROTO_BASE_LL_HDR; i <= PROTO_BASE_MAX; i++) {
pr_debug(" %-20s: %s",
proto_base_names[i],
ctx->protocol[i].desc ? ctx->protocol[i].desc->name :
"none");
- if (ctx->protocol[i].offset)
- pr_debug(" (offset: %u)", ctx->protocol[i].offset);
if (i == base)
pr_debug(" <-");
pr_debug("\n");
@@ -169,7 +206,7 @@ static void proto_ctx_debug(const struct proto_ctx *ctx, enum proto_bases base,
* @debug_mask: display debugging information
*/
void proto_ctx_init(struct proto_ctx *ctx, unsigned int family,
- unsigned int debug_mask)
+ unsigned int debug_mask, bool inner)
{
const struct hook_proto_desc *h = &hook_proto_desc[family];
@@ -177,6 +214,7 @@ void proto_ctx_init(struct proto_ctx *ctx, unsigned int family,
ctx->family = family;
ctx->protocol[h->base].desc = h->desc;
ctx->debug_mask = debug_mask;
+ ctx->inner = inner;
proto_ctx_debug(ctx, h->base, debug_mask);
}
@@ -193,12 +231,71 @@ void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base,
const struct location *loc,
const struct proto_desc *desc)
{
+ bool found = false;
+ unsigned int i;
+
+ switch (base) {
+ case PROTO_BASE_LL_HDR:
+ case PROTO_BASE_NETWORK_HDR:
+ break;
+ case PROTO_BASE_TRANSPORT_HDR:
+ if (ctx->protocol[base].num_protos >= PROTO_CTX_NUM_PROTOS)
+ break;
+
+ for (i = 0; i < ctx->protocol[base].num_protos; i++) {
+ if (ctx->protocol[base].protos[i].desc == desc) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ i = ctx->protocol[base].num_protos++;
+ ctx->protocol[base].protos[i].desc = desc;
+ ctx->protocol[base].protos[i].location = *loc;
+ }
+ break;
+ case PROTO_BASE_INNER_HDR:
+ break;
+ default:
+ BUG("unknown protocol base %d", base);
+ }
+
ctx->protocol[base].location = *loc;
ctx->protocol[base].desc = desc;
proto_ctx_debug(ctx, base, ctx->debug_mask);
}
+bool proto_ctx_is_ambiguous(struct proto_ctx *ctx, enum proto_bases base)
+{
+ return ctx->protocol[base].num_protos > 1;
+}
+
+const struct proto_desc *proto_ctx_find_conflict(struct proto_ctx *ctx,
+ enum proto_bases base,
+ const struct proto_desc *desc)
+{
+ unsigned int i;
+
+ switch (base) {
+ case PROTO_BASE_LL_HDR:
+ case PROTO_BASE_NETWORK_HDR:
+ if (desc != ctx->protocol[base].desc)
+ return ctx->protocol[base].desc;
+ break;
+ case PROTO_BASE_TRANSPORT_HDR:
+ for (i = 0; i < ctx->protocol[base].num_protos; i++) {
+ if (desc != ctx->protocol[base].protos[i].desc)
+ return ctx->protocol[base].protos[i].desc;
+ }
+ break;
+ default:
+ BUG("unknown protocol base %d", base);
+ }
+
+ return NULL;
+}
+
#define HDR_TEMPLATE(__name, __dtype, __type, __member) \
PROTO_HDR_TEMPLATE(__name, __dtype, \
BYTEORDER_BIG_ENDIAN, \
@@ -207,6 +304,8 @@ void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base,
#define HDR_FIELD(__name, __struct, __member) \
HDR_TEMPLATE(__name, &integer_type, __struct, __member)
+#define HDR_HEX_FIELD(__name, __struct, __member) \
+ HDR_TEMPLATE(__name, &xinteger_type, __struct, __member)
#define HDR_BITFIELD(__name, __dtype, __offset, __len) \
PROTO_HDR_TEMPLATE(__name, __dtype, BYTEORDER_BIG_ENDIAN, \
__offset, __len)
@@ -227,6 +326,7 @@ void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base,
const struct proto_desc proto_ah = {
.name = "ah",
+ .id = PROTO_DESC_AH,
.base = PROTO_BASE_TRANSPORT_HDR,
.protocol_key = AHHDR_NEXTHDR,
.protocols = {
@@ -263,6 +363,7 @@ const struct proto_desc proto_ah = {
const struct proto_desc proto_esp = {
.name = "esp",
+ .id = PROTO_DESC_ESP,
.base = PROTO_BASE_TRANSPORT_HDR,
.templates = {
[ESPHDR_SPI] = ESPHDR_FIELD("spi", spi),
@@ -279,6 +380,7 @@ const struct proto_desc proto_esp = {
const struct proto_desc proto_comp = {
.name = "comp",
+ .id = PROTO_DESC_COMP,
.base = PROTO_BASE_TRANSPORT_HDR,
.protocol_key = COMPHDR_NEXTHDR,
.protocols = {
@@ -336,23 +438,37 @@ const struct datatype icmp_type_type = {
.sym_tbl = &icmp_type_tbl,
};
-#define ICMPHDR_FIELD(__name, __member) \
- HDR_FIELD(__name, struct icmphdr, __member)
+#define ICMP46HDR_FIELD(__token, __dtype, __struct, __member, __dep) \
+ { \
+ .token = (__token), \
+ .dtype = &__dtype, \
+ .byteorder = BYTEORDER_BIG_ENDIAN, \
+ .offset = offsetof(__struct, __member) * 8, \
+ .len = field_sizeof(__struct, __member) * 8, \
+ .icmp_dep = (__dep), \
+ }
+
+#define ICMPHDR_FIELD(__token, __member, __dep) \
+ ICMP46HDR_FIELD(__token, integer_type, struct icmphdr, __member, __dep)
+
#define ICMPHDR_TYPE(__name, __type, __member) \
- HDR_TYPE(__name, __type, struct icmphdr, __member)
+ HDR_TYPE(__name, __type, struct icmphdr, __member)
const struct proto_desc proto_icmp = {
.name = "icmp",
+ .id = PROTO_DESC_ICMP,
.base = PROTO_BASE_TRANSPORT_HDR,
+ .protocol_key = ICMPHDR_TYPE,
.checksum_key = ICMPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
.templates = {
[ICMPHDR_TYPE] = ICMPHDR_TYPE("type", &icmp_type_type, type),
[ICMPHDR_CODE] = ICMPHDR_TYPE("code", &icmp_code_type, code),
- [ICMPHDR_CHECKSUM] = ICMPHDR_FIELD("checksum", checksum),
- [ICMPHDR_ID] = ICMPHDR_FIELD("id", un.echo.id),
- [ICMPHDR_SEQ] = ICMPHDR_FIELD("sequence", un.echo.sequence),
- [ICMPHDR_GATEWAY] = ICMPHDR_FIELD("gateway", un.gateway),
- [ICMPHDR_MTU] = ICMPHDR_FIELD("mtu", un.frag.mtu),
+ [ICMPHDR_CHECKSUM] = ICMPHDR_FIELD("checksum", checksum, PROTO_ICMP_ANY),
+ [ICMPHDR_ID] = ICMPHDR_FIELD("id", un.echo.id, PROTO_ICMP_ECHO),
+ [ICMPHDR_SEQ] = ICMPHDR_FIELD("sequence", un.echo.sequence, PROTO_ICMP_ECHO),
+ [ICMPHDR_GATEWAY] = ICMPHDR_FIELD("gateway", un.gateway, PROTO_ICMP_ADDRESS),
+ [ICMPHDR_MTU] = ICMPHDR_FIELD("mtu", un.frag.mtu, PROTO_ICMP_MTU),
},
};
@@ -395,8 +511,10 @@ const struct datatype igmp_type_type = {
const struct proto_desc proto_igmp = {
.name = "igmp",
+ .id = PROTO_DESC_IGMP,
.base = PROTO_BASE_TRANSPORT_HDR,
.checksum_key = IGMPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
.templates = {
[IGMPHDR_TYPE] = IGMPHDR_TYPE("type", &igmp_type_type, igmp_type),
[IGMPHDR_MRT] = IGMPHDR_FIELD("mrt", igmp_code),
@@ -415,18 +533,25 @@ const struct proto_desc proto_igmp = {
const struct proto_desc proto_udp = {
.name = "udp",
+ .id = PROTO_DESC_UDP,
.base = PROTO_BASE_TRANSPORT_HDR,
.checksum_key = UDPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
.templates = {
[UDPHDR_SPORT] = INET_SERVICE("sport", struct udphdr, source),
[UDPHDR_DPORT] = INET_SERVICE("dport", struct udphdr, dest),
[UDPHDR_LENGTH] = UDPHDR_FIELD("length", len),
[UDPHDR_CHECKSUM] = UDPHDR_FIELD("checksum", check),
},
+ .protocols = {
+ PROTO_LINK(0, &proto_vxlan),
+ PROTO_LINK(0, &proto_geneve),
+ },
};
const struct proto_desc proto_udplite = {
.name = "udplite",
+ .id = PROTO_DESC_UDPLITE,
.base = PROTO_BASE_TRANSPORT_HDR,
.templates = {
[UDPHDR_SPORT] = INET_SERVICE("sport", struct udphdr, source),
@@ -472,8 +597,10 @@ const struct datatype tcp_flag_type = {
const struct proto_desc proto_tcp = {
.name = "tcp",
+ .id = PROTO_DESC_TCP,
.base = PROTO_BASE_TRANSPORT_HDR,
.checksum_key = TCPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
.templates = {
[TCPHDR_SPORT] = INET_SERVICE("sport", struct tcphdr, source),
[TCPHDR_DPORT] = INET_SERVICE("dport", struct tcphdr, dest),
@@ -534,6 +661,7 @@ const struct datatype dccp_pkttype_type = {
const struct proto_desc proto_dccp = {
.name = "dccp",
+ .id = PROTO_DESC_DCCP,
.base = PROTO_BASE_TRANSPORT_HDR,
.templates = {
[DCCPHDR_SPORT] = INET_SERVICE("sport", struct dccp_hdr, dccph_sport),
@@ -552,7 +680,10 @@ const struct proto_desc proto_dccp = {
const struct proto_desc proto_sctp = {
.name = "sctp",
+ .id = PROTO_DESC_SCTP,
.base = PROTO_BASE_TRANSPORT_HDR,
+ .checksum_key = SCTPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_SCTP,
.templates = {
[SCTPHDR_SPORT] = INET_SERVICE("sport", struct sctphdr, source),
[SCTPHDR_DPORT] = INET_SERVICE("dport", struct sctphdr, dest),
@@ -566,6 +697,7 @@ const struct proto_desc proto_sctp = {
*/
const struct proto_desc proto_th = {
.name = "th",
+ .id = PROTO_DESC_TH,
.base = PROTO_BASE_TRANSPORT_HDR,
.templates = {
[THDR_SPORT] = INET_SERVICE("sport", struct udphdr, source),
@@ -590,7 +722,9 @@ static const struct symbol_table dscp_type_tbl = {
SYMBOL("cs5", 0x28),
SYMBOL("cs6", 0x30),
SYMBOL("cs7", 0x38),
+ SYMBOL("df", 0x00),
SYMBOL("be", 0x00),
+ SYMBOL("lephb", 0x01),
SYMBOL("af11", 0x0a),
SYMBOL("af12", 0x0c),
SYMBOL("af13", 0x0e),
@@ -603,6 +737,7 @@ static const struct symbol_table dscp_type_tbl = {
SYMBOL("af41", 0x22),
SYMBOL("af42", 0x24),
SYMBOL("af43", 0x26),
+ SYMBOL("va", 0x2c),
SYMBOL("ef", 0x2e),
SYMBOL_LIST_END
},
@@ -641,6 +776,42 @@ const struct datatype ecn_type = {
.sym_tbl = &ecn_type_tbl,
};
+#define GREHDR_TEMPLATE(__name, __dtype, __member) \
+ HDR_TEMPLATE(__name, __dtype, struct grehdr, __member)
+#define GREHDR_TYPE(__name, __member) \
+ GREHDR_TEMPLATE(__name, &ethertype_type, __member)
+
+const struct proto_desc proto_gre = {
+ .name = "gre",
+ .id = PROTO_DESC_GRE,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .templates = {
+ [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8),
+ [GREHDR_FLAGS] = HDR_BITFIELD("flags", &integer_type, 0, 5),
+ [GREHDR_VERSION] = HDR_BITFIELD("version", &integer_type, 13, 3),
+ [GREHDR_PROTOCOL] = HDR_BITFIELD("protocol", &ethertype_type, 16, 16),
+ },
+ .inner = {
+ .hdrsize = sizeof(struct grehdr),
+ .flags = NFT_INNER_NH | NFT_INNER_TH,
+ .type = NFT_INNER_GENEVE + 1,
+ },
+};
+
+const struct proto_desc proto_gretap = {
+ .name = "gretap",
+ .id = PROTO_DESC_GRETAP,
+ .base = PROTO_BASE_TRANSPORT_HDR,
+ .templates = {
+ [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8),
+ },
+ .inner = {
+ .hdrsize = sizeof(struct grehdr),
+ .flags = NFT_INNER_LL | NFT_INNER_NH | NFT_INNER_TH,
+ .type = NFT_INNER_GENEVE + 2,
+ },
+};
+
#define IPHDR_FIELD(__name, __member) \
HDR_FIELD(__name, struct iphdr, __member)
#define IPHDR_ADDR(__name, __member) \
@@ -648,8 +819,10 @@ const struct datatype ecn_type = {
const struct proto_desc proto_ip = {
.name = "ip",
+ .id = PROTO_DESC_IP,
.base = PROTO_BASE_NETWORK_HDR,
.checksum_key = IPHDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
.protocols = {
PROTO_LINK(IPPROTO_ICMP, &proto_icmp),
PROTO_LINK(IPPROTO_IGMP, &proto_igmp),
@@ -662,6 +835,8 @@ const struct proto_desc proto_ip = {
PROTO_LINK(IPPROTO_TCP, &proto_tcp),
PROTO_LINK(IPPROTO_DCCP, &proto_dccp),
PROTO_LINK(IPPROTO_SCTP, &proto_sctp),
+ PROTO_LINK(IPPROTO_GRE, &proto_gre),
+ PROTO_LINK(IPPROTO_GRE, &proto_gretap),
},
.templates = {
[0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8),
@@ -671,7 +846,7 @@ const struct proto_desc proto_ip = {
[IPHDR_ECN] = HDR_BITFIELD("ecn", &ecn_type, 14, 2),
[IPHDR_LENGTH] = IPHDR_FIELD("length", tot_len),
[IPHDR_ID] = IPHDR_FIELD("id", id),
- [IPHDR_FRAG_OFF] = IPHDR_FIELD("frag-off", frag_off),
+ [IPHDR_FRAG_OFF] = HDR_HEX_FIELD("frag-off", struct iphdr, frag_off),
[IPHDR_TTL] = IPHDR_FIELD("ttl", ttl),
[IPHDR_PROTOCOL] = INET_PROTOCOL("protocol", struct iphdr, protocol),
[IPHDR_CHECKSUM] = IPHDR_FIELD("checksum", check),
@@ -737,24 +912,33 @@ const struct datatype icmp6_type_type = {
.sym_tbl = &icmp6_type_tbl,
};
-#define ICMP6HDR_FIELD(__name, __member) \
- HDR_FIELD(__name, struct icmp6_hdr, __member)
+#define ICMP6HDR_FIELD(__token, __member, __dep) \
+ ICMP46HDR_FIELD(__token, integer_type, struct icmp6_hdr, __member, __dep)
#define ICMP6HDR_TYPE(__name, __type, __member) \
HDR_TYPE(__name, __type, struct icmp6_hdr, __member)
const struct proto_desc proto_icmp6 = {
.name = "icmpv6",
+ .id = PROTO_DESC_ICMPV6,
.base = PROTO_BASE_TRANSPORT_HDR,
+ .protocol_key = ICMP6HDR_TYPE,
.checksum_key = ICMP6HDR_CHECKSUM,
+ .checksum_type = NFT_PAYLOAD_CSUM_INET,
.templates = {
[ICMP6HDR_TYPE] = ICMP6HDR_TYPE("type", &icmp6_type_type, icmp6_type),
[ICMP6HDR_CODE] = ICMP6HDR_TYPE("code", &icmpv6_code_type, icmp6_code),
- [ICMP6HDR_CHECKSUM] = ICMP6HDR_FIELD("checksum", icmp6_cksum),
- [ICMP6HDR_PPTR] = ICMP6HDR_FIELD("parameter-problem", icmp6_pptr),
- [ICMP6HDR_MTU] = ICMP6HDR_FIELD("mtu", icmp6_mtu),
- [ICMP6HDR_ID] = ICMP6HDR_FIELD("id", icmp6_id),
- [ICMP6HDR_SEQ] = ICMP6HDR_FIELD("sequence", icmp6_seq),
- [ICMP6HDR_MAXDELAY] = ICMP6HDR_FIELD("max-delay", icmp6_maxdelay),
+ [ICMP6HDR_CHECKSUM] = ICMP6HDR_FIELD("checksum", icmp6_cksum, PROTO_ICMP_ANY),
+ [ICMP6HDR_PPTR] = ICMP6HDR_FIELD("parameter-problem", icmp6_pptr, PROTO_ICMP6_PPTR),
+ [ICMP6HDR_MTU] = ICMP6HDR_FIELD("mtu", icmp6_mtu, PROTO_ICMP6_MTU),
+ [ICMP6HDR_ID] = ICMP6HDR_FIELD("id", icmp6_id, PROTO_ICMP6_ECHO),
+ [ICMP6HDR_SEQ] = ICMP6HDR_FIELD("sequence", icmp6_seq, PROTO_ICMP6_ECHO),
+ [ICMP6HDR_MAXDELAY] = ICMP6HDR_FIELD("max-delay", icmp6_maxdelay, PROTO_ICMP6_MGMQ),
+ [ICMP6HDR_TADDR] = ICMP46HDR_FIELD("taddr", ip6addr_type,
+ struct nd_neighbor_solicit, nd_ns_target,
+ PROTO_ICMP6_ADDRESS),
+ [ICMP6HDR_DADDR] = ICMP46HDR_FIELD("daddr", ip6addr_type,
+ struct nd_redirect, nd_rd_dst,
+ PROTO_ICMP6_REDIRECT),
},
};
@@ -771,6 +955,7 @@ const struct proto_desc proto_icmp6 = {
const struct proto_desc proto_ip6 = {
.name = "ip6",
+ .id = PROTO_DESC_IP6,
.base = PROTO_BASE_NETWORK_HDR,
.protocols = {
PROTO_LINK(IPPROTO_ESP, &proto_esp),
@@ -784,6 +969,8 @@ const struct proto_desc proto_ip6 = {
PROTO_LINK(IPPROTO_ICMP, &proto_icmp),
PROTO_LINK(IPPROTO_IGMP, &proto_igmp),
PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6),
+ PROTO_LINK(IPPROTO_GRE, &proto_gre),
+ PROTO_LINK(IPPROTO_GRE, &proto_gretap),
},
.templates = {
[0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8),
@@ -849,6 +1036,8 @@ const struct proto_desc proto_inet_service = {
PROTO_LINK(IPPROTO_ICMP, &proto_icmp),
PROTO_LINK(IPPROTO_IGMP, &proto_igmp),
PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6),
+ PROTO_LINK(IPPROTO_GRE, &proto_gre),
+ PROTO_LINK(IPPROTO_GRE, &proto_gretap),
},
.templates = {
[0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8),
@@ -892,6 +1081,7 @@ const struct datatype arpop_type = {
const struct proto_desc proto_arp = {
.name = "arp",
+ .id = PROTO_DESC_ARP,
.base = PROTO_BASE_NETWORK_HDR,
.templates = {
[ARPHDR_HRD] = ARPHDR_FIELD("htype", htype),
@@ -900,8 +1090,8 @@ const struct proto_desc proto_arp = {
[ARPHDR_PLN] = ARPHDR_FIELD("plen", plen),
[ARPHDR_OP] = ARPHDR_TYPE("operation", &arpop_type, oper),
[ARPHDR_SADDR_ETHER] = ARPHDR_TYPE("saddr ether", &etheraddr_type, sha),
- [ARPHDR_DADDR_ETHER] = ARPHDR_TYPE("daddr ether", &etheraddr_type, tha),
[ARPHDR_SADDR_IP] = ARPHDR_TYPE("saddr ip", &ipaddr_type, spa),
+ [ARPHDR_DADDR_ETHER] = ARPHDR_TYPE("daddr ether", &etheraddr_type, tha),
[ARPHDR_DADDR_IP] = ARPHDR_TYPE("daddr ip", &ipaddr_type, tpa),
},
.format = {
@@ -925,6 +1115,7 @@ const struct proto_desc proto_arp = {
const struct proto_desc proto_vlan = {
.name = "vlan",
+ .id = PROTO_DESC_VLAN,
.base = PROTO_BASE_LL_HDR,
.protocol_key = VLANHDR_TYPE,
.length = sizeof(struct vlan_hdr) * BITS_PER_BYTE,
@@ -933,10 +1124,12 @@ const struct proto_desc proto_vlan = {
PROTO_LINK(__constant_htons(ETH_P_ARP), &proto_arp),
PROTO_LINK(__constant_htons(ETH_P_IPV6), &proto_ip6),
PROTO_LINK(__constant_htons(ETH_P_8021Q), &proto_vlan),
+ PROTO_LINK(__constant_htons(ETH_P_8021AD), &proto_vlan),
},
.templates = {
[VLANHDR_PCP] = VLANHDR_BITFIELD("pcp", 0, 3),
+ [VLANHDR_DEI] = VLANHDR_BITFIELD("dei", 3, 1),
[VLANHDR_CFI] = VLANHDR_BITFIELD("cfi", 3, 1),
[VLANHDR_VID] = VLANHDR_BITFIELD("id", 4, 12),
[VLANHDR_TYPE] = VLANHDR_TYPE("type", &ethertype_type, vlan_type),
@@ -962,6 +1155,10 @@ static const struct symbol_table ethertype_tbl = {
SYMBOL("ip", __constant_htons(ETH_P_IP)),
SYMBOL("arp", __constant_htons(ETH_P_ARP)),
SYMBOL("ip6", __constant_htons(ETH_P_IPV6)),
+ SYMBOL("8021q", __constant_htons(ETH_P_8021Q)),
+ SYMBOL("8021ad", __constant_htons(ETH_P_8021AD)),
+
+ /* for compatibility with older versions */
SYMBOL("vlan", __constant_htons(ETH_P_8021Q)),
SYMBOL_LIST_END
},
@@ -996,6 +1193,7 @@ const struct datatype ethertype_type = {
const struct proto_desc proto_eth = {
.name = "ether",
+ .id = PROTO_DESC_ETHER,
.base = PROTO_BASE_LL_HDR,
.protocol_key = ETHHDR_TYPE,
.length = sizeof(struct ether_header) * BITS_PER_BYTE,
@@ -1004,6 +1202,7 @@ const struct proto_desc proto_eth = {
PROTO_LINK(__constant_htons(ETH_P_ARP), &proto_arp),
PROTO_LINK(__constant_htons(ETH_P_IPV6), &proto_ip6),
PROTO_LINK(__constant_htons(ETH_P_8021Q), &proto_vlan),
+ PROTO_LINK(__constant_htons(ETH_P_8021AD), &proto_vlan),
},
.templates = {
[ETHHDR_DADDR] = ETHHDR_ADDR("daddr", ether_dhost),
@@ -1019,6 +1218,57 @@ const struct proto_desc proto_eth = {
};
/*
+ * VXLAN
+ */
+
+const struct proto_desc proto_vxlan = {
+ .name = "vxlan",
+ .id = PROTO_DESC_VXLAN,
+ .base = PROTO_BASE_INNER_HDR,
+ .templates = {
+ [VXLANHDR_FLAGS] = HDR_BITFIELD("flags", &bitmask_type, 0, 8),
+ [VXLANHDR_VNI] = HDR_BITFIELD("vni", &integer_type, (4 * BITS_PER_BYTE), 24),
+ },
+ .protocols = {
+ PROTO_LINK(__constant_htons(ETH_P_IP), &proto_ip),
+ PROTO_LINK(__constant_htons(ETH_P_ARP), &proto_arp),
+ PROTO_LINK(__constant_htons(ETH_P_IPV6), &proto_ip6),
+ PROTO_LINK(__constant_htons(ETH_P_8021Q), &proto_vlan),
+ },
+ .inner = {
+ .hdrsize = sizeof(struct vxlanhdr),
+ .flags = NFT_INNER_HDRSIZE | NFT_INNER_LL | NFT_INNER_NH | NFT_INNER_TH,
+ .type = NFT_INNER_VXLAN,
+ },
+};
+
+/*
+ * GENEVE
+ */
+
+const struct proto_desc proto_geneve = {
+ .name = "geneve",
+ .id = PROTO_DESC_GENEVE,
+ .base = PROTO_BASE_INNER_HDR,
+ .templates = {
+ [GNVHDR_TYPE] = HDR_TYPE("type", &ethertype_type, struct gnvhdr, type),
+ [GNVHDR_VNI] = HDR_BITFIELD("vni", &integer_type, (4 * BITS_PER_BYTE), 24),
+ },
+ .protocols = {
+ PROTO_LINK(__constant_htons(ETH_P_IP), &proto_ip),
+ PROTO_LINK(__constant_htons(ETH_P_ARP), &proto_arp),
+ PROTO_LINK(__constant_htons(ETH_P_IPV6), &proto_ip6),
+ PROTO_LINK(__constant_htons(ETH_P_8021Q), &proto_vlan),
+ },
+ .inner = {
+ .hdrsize = sizeof(struct gnvhdr),
+ .flags = NFT_INNER_HDRSIZE | NFT_INNER_LL | NFT_INNER_NH | NFT_INNER_TH,
+ .type = NFT_INNER_GENEVE,
+ },
+};
+
+
+/*
* Dummy protocol for netdev tables.
*/
const struct proto_desc proto_netdev = {
@@ -1029,8 +1279,42 @@ const struct proto_desc proto_netdev = {
PROTO_LINK(__constant_htons(ETH_P_ARP), &proto_arp),
PROTO_LINK(__constant_htons(ETH_P_IPV6), &proto_ip6),
PROTO_LINK(__constant_htons(ETH_P_8021Q), &proto_vlan),
+ PROTO_LINK(__constant_htons(ETH_P_8021AD), &proto_vlan),
},
.templates = {
[0] = PROTO_META_TEMPLATE("protocol", &ethertype_type, NFT_META_PROTOCOL, 16),
},
};
+
+static const struct proto_desc *const proto_definitions[PROTO_DESC_MAX + 1] = {
+ [PROTO_DESC_AH] = &proto_ah,
+ [PROTO_DESC_ESP] = &proto_esp,
+ [PROTO_DESC_COMP] = &proto_comp,
+ [PROTO_DESC_ICMP] = &proto_icmp,
+ [PROTO_DESC_IGMP] = &proto_igmp,
+ [PROTO_DESC_UDP] = &proto_udp,
+ [PROTO_DESC_UDPLITE] = &proto_udplite,
+ [PROTO_DESC_TCP] = &proto_tcp,
+ [PROTO_DESC_DCCP] = &proto_dccp,
+ [PROTO_DESC_SCTP] = &proto_sctp,
+ [PROTO_DESC_TH] = &proto_th,
+ [PROTO_DESC_IP] = &proto_ip,
+ [PROTO_DESC_IP6] = &proto_ip6,
+ [PROTO_DESC_ICMPV6] = &proto_icmp6,
+ [PROTO_DESC_ARP] = &proto_arp,
+ [PROTO_DESC_VLAN] = &proto_vlan,
+ [PROTO_DESC_ETHER] = &proto_eth,
+ [PROTO_DESC_VXLAN] = &proto_vxlan,
+ [PROTO_DESC_GENEVE] = &proto_geneve,
+ [PROTO_DESC_GRE] = &proto_gre,
+ [PROTO_DESC_GRETAP] = &proto_gretap,
+};
+
+const struct proto_desc *proto_find_desc(enum proto_desc_id desc_id)
+{
+ if (desc_id >= PROTO_DESC_UNKNOWN &&
+ desc_id <= PROTO_DESC_MAX)
+ return proto_definitions[desc_id];
+
+ return NULL;
+}
diff --git a/src/rbtree.c b/src/rbtree.c
deleted file mode 100644
index 325c0123..00000000
--- a/src/rbtree.c
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Red Black Trees
- * (C) 1999 Andrea Arcangeli <andrea@suse.de>
- * (C) 2002 David Woodhouse <dwmw2@infradead.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <rbtree.h>
-
-static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
-{
- struct rb_node *right = node->rb_right;
- struct rb_node *parent = rb_parent(node);
-
- if ((node->rb_right = right->rb_left))
- rb_set_parent(right->rb_left, node);
- right->rb_left = node;
-
- rb_set_parent(right, parent);
-
- if (parent)
- {
- if (node == parent->rb_left)
- parent->rb_left = right;
- else
- parent->rb_right = right;
- }
- else
- root->rb_node = right;
- rb_set_parent(node, right);
-}
-
-static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
-{
- struct rb_node *left = node->rb_left;
- struct rb_node *parent = rb_parent(node);
-
- if ((node->rb_left = left->rb_right))
- rb_set_parent(left->rb_right, node);
- left->rb_right = node;
-
- rb_set_parent(left, parent);
-
- if (parent)
- {
- if (node == parent->rb_right)
- parent->rb_right = left;
- else
- parent->rb_left = left;
- }
- else
- root->rb_node = left;
- rb_set_parent(node, left);
-}
-
-void rb_insert_color(struct rb_node *node, struct rb_root *root)
-{
- struct rb_node *parent, *gparent;
-
- while ((parent = rb_parent(node)) && rb_is_red(parent))
- {
- gparent = rb_parent(parent);
-
- if (parent == gparent->rb_left)
- {
- {
- register struct rb_node *uncle = gparent->rb_right;
- if (uncle && rb_is_red(uncle))
- {
- rb_set_black(uncle);
- rb_set_black(parent);
- rb_set_red(gparent);
- node = gparent;
- continue;
- }
- }
-
- if (parent->rb_right == node)
- {
- register struct rb_node *tmp;
- __rb_rotate_left(parent, root);
- tmp = parent;
- parent = node;
- node = tmp;
- }
-
- rb_set_black(parent);
- rb_set_red(gparent);
- __rb_rotate_right(gparent, root);
- } else {
- {
- register struct rb_node *uncle = gparent->rb_left;
- if (uncle && rb_is_red(uncle))
- {
- rb_set_black(uncle);
- rb_set_black(parent);
- rb_set_red(gparent);
- node = gparent;
- continue;
- }
- }
-
- if (parent->rb_left == node)
- {
- register struct rb_node *tmp;
- __rb_rotate_right(parent, root);
- tmp = parent;
- parent = node;
- node = tmp;
- }
-
- rb_set_black(parent);
- rb_set_red(gparent);
- __rb_rotate_left(gparent, root);
- }
- }
-
- rb_set_black(root->rb_node);
-}
-
-static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
- struct rb_root *root)
-{
- struct rb_node *other;
-
- while ((!node || rb_is_black(node)) && node != root->rb_node)
- {
- if (parent->rb_left == node)
- {
- other = parent->rb_right;
- if (rb_is_red(other))
- {
- rb_set_black(other);
- rb_set_red(parent);
- __rb_rotate_left(parent, root);
- other = parent->rb_right;
- }
- if ((!other->rb_left || rb_is_black(other->rb_left)) &&
- (!other->rb_right || rb_is_black(other->rb_right)))
- {
- rb_set_red(other);
- node = parent;
- parent = rb_parent(node);
- }
- else
- {
- if (!other->rb_right || rb_is_black(other->rb_right))
- {
- struct rb_node *o_left;
- if ((o_left = other->rb_left))
- rb_set_black(o_left);
- rb_set_red(other);
- __rb_rotate_right(other, root);
- other = parent->rb_right;
- }
- rb_set_color(other, rb_color(parent));
- rb_set_black(parent);
- if (other->rb_right)
- rb_set_black(other->rb_right);
- __rb_rotate_left(parent, root);
- node = root->rb_node;
- break;
- }
- }
- else
- {
- other = parent->rb_left;
- if (rb_is_red(other))
- {
- rb_set_black(other);
- rb_set_red(parent);
- __rb_rotate_right(parent, root);
- other = parent->rb_left;
- }
- if ((!other->rb_left || rb_is_black(other->rb_left)) &&
- (!other->rb_right || rb_is_black(other->rb_right)))
- {
- rb_set_red(other);
- node = parent;
- parent = rb_parent(node);
- }
- else
- {
- if (!other->rb_left || rb_is_black(other->rb_left))
- {
- register struct rb_node *o_right;
- if ((o_right = other->rb_right))
- rb_set_black(o_right);
- rb_set_red(other);
- __rb_rotate_left(other, root);
- other = parent->rb_left;
- }
- rb_set_color(other, rb_color(parent));
- rb_set_black(parent);
- if (other->rb_left)
- rb_set_black(other->rb_left);
- __rb_rotate_right(parent, root);
- node = root->rb_node;
- break;
- }
- }
- }
- if (node)
- rb_set_black(node);
-}
-
-void rb_erase(struct rb_node *node, struct rb_root *root)
-{
- struct rb_node *child, *parent;
- int color;
-
- if (!node->rb_left)
- child = node->rb_right;
- else if (!node->rb_right)
- child = node->rb_left;
- else
- {
- struct rb_node *old = node, *left;
-
- node = node->rb_right;
- while ((left = node->rb_left) != NULL)
- node = left;
- child = node->rb_right;
- parent = rb_parent(node);
- color = rb_color(node);
-
- if (child)
- rb_set_parent(child, parent);
- if (parent == old) {
- parent->rb_right = child;
- parent = node;
- } else
- parent->rb_left = child;
-
- node->rb_parent_color = old->rb_parent_color;
- node->rb_right = old->rb_right;
- node->rb_left = old->rb_left;
-
- if (rb_parent(old))
- {
- if (rb_parent(old)->rb_left == old)
- rb_parent(old)->rb_left = node;
- else
- rb_parent(old)->rb_right = node;
- } else
- root->rb_node = node;
-
- rb_set_parent(old->rb_left, node);
- if (old->rb_right)
- rb_set_parent(old->rb_right, node);
- goto color;
- }
-
- parent = rb_parent(node);
- color = rb_color(node);
-
- if (child)
- rb_set_parent(child, parent);
- if (parent)
- {
- if (parent->rb_left == node)
- parent->rb_left = child;
- else
- parent->rb_right = child;
- }
- else
- root->rb_node = child;
-
- color:
- if (color == RB_BLACK)
- __rb_erase_color(child, parent, root);
-}
-
-/*
- * This function returns the first node (in sort order) of the tree.
- */
-struct rb_node *rb_first(struct rb_root *root)
-{
- struct rb_node *n;
-
- n = root->rb_node;
- if (!n)
- return NULL;
- while (n->rb_left)
- n = n->rb_left;
- return n;
-}
-
-struct rb_node *rb_last(struct rb_root *root)
-{
- struct rb_node *n;
-
- n = root->rb_node;
- if (!n)
- return NULL;
- while (n->rb_right)
- n = n->rb_right;
- return n;
-}
-
-struct rb_node *rb_next(struct rb_node *node)
-{
- struct rb_node *parent;
-
- if (rb_parent(node) == node)
- return NULL;
-
- /* If we have a right-hand child, go down and then left as far
- as we can. */
- if (node->rb_right) {
- node = node->rb_right;
- while (node->rb_left)
- node=node->rb_left;
- return node;
- }
-
- /* No right-hand children. Everything down and left is
- smaller than us, so any 'next' node must be in the general
- direction of our parent. Go up the tree; any time the
- ancestor is a right-hand child of its parent, keep going
- up. First time it's a left-hand child of its parent, said
- parent is our 'next' node. */
- while ((parent = rb_parent(node)) && node == parent->rb_right)
- node = parent;
-
- return parent;
-}
-
-struct rb_node *rb_prev(struct rb_node *node)
-{
- struct rb_node *parent;
-
- if (rb_parent(node) == node)
- return NULL;
-
- /* If we have a left-hand child, go down and then right as far
- as we can. */
- if (node->rb_left) {
- node = node->rb_left;
- while (node->rb_right)
- node=node->rb_right;
- return node;
- }
-
- /* No left-hand children. Go up till we find an ancestor which
- is a right-hand child of its parent */
- while ((parent = rb_parent(node)) && node == parent->rb_left)
- node = parent;
-
- return parent;
-}
-
-void rb_replace_node(struct rb_node *victim, struct rb_node *new,
- struct rb_root *root)
-{
- struct rb_node *parent = rb_parent(victim);
-
- /* Set the surrounding nodes to point to the replacement */
- if (parent) {
- if (victim == parent->rb_left)
- parent->rb_left = new;
- else
- parent->rb_right = new;
- } else {
- root->rb_node = new;
- }
- if (victim->rb_left)
- rb_set_parent(victim->rb_left, new);
- if (victim->rb_right)
- rb_set_parent(victim->rb_right, new);
-
- /* Copy the pointers/colour from the victim to the replacement */
- *new = *victim;
-}
diff --git a/src/rt.c b/src/rt.c
index b19c44d6..9320b832 100644
--- a/src/rt.c
+++ b/src/rt.c
@@ -8,12 +8,11 @@
* published by the Free Software Foundation.
*/
+#include <nft.h>
+
#include <errno.h>
#include <stddef.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
#include <arpa/inet.h>
#include <linux/netfilter.h>
@@ -26,7 +25,7 @@
void realm_table_rt_init(struct nft_ctx *ctx)
{
- ctx->output.tbl.realm = rt_symbol_table_init("/etc/iproute2/rt_realms");
+ ctx->output.tbl.realm = rt_symbol_table_init("rt_realms");
}
void realm_table_rt_exit(struct nft_ctx *ctx)
@@ -46,16 +45,22 @@ static struct error_record *realm_type_parse(struct parse_ctx *ctx,
return symbolic_constant_parse(ctx, sym, ctx->tbl->realm, res);
}
+static void realm_type_describe(struct output_ctx *octx)
+{
+ rt_symbol_table_describe(octx, "rt_realms",
+ octx->tbl.realm, &realm_type);
+}
+
const struct datatype realm_type = {
.type = TYPE_REALM,
.name = "realm",
.desc = "routing realm",
+ .describe = realm_type_describe,
.byteorder = BYTEORDER_HOST_ENDIAN,
.size = 4 * BITS_PER_BYTE,
.basetype = &integer_type,
.print = realm_type_print,
.parse = realm_type_parse,
- .flags = DTYPE_F_PREFIX,
};
const struct rt_template rt_templates[] = {
@@ -114,6 +119,55 @@ static void rt_expr_clone(struct expr *new, const struct expr *expr)
new->rt.key = expr->rt.key;
}
+#define NFTNL_UDATA_RT_KEY 0
+#define NFTNL_UDATA_RT_MAX 1
+
+static int rt_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_RT_KEY, expr->rt.key);
+
+ return 0;
+}
+
+static int rt_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_RT_KEY:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *rt_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_RT_MAX + 1] = {};
+ uint32_t key;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ rt_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_RT_KEY])
+ return NULL;
+
+ key = nftnl_udata_get_u32(ud[NFTNL_UDATA_RT_KEY]);
+
+ return rt_expr_alloc(&internal_location, key, false);
+}
+
const struct expr_ops rt_expr_ops = {
.type = EXPR_RT,
.name = "rt",
@@ -121,6 +175,8 @@ const struct expr_ops rt_expr_ops = {
.json = rt_expr_json,
.cmp = rt_expr_cmp,
.clone = rt_expr_clone,
+ .parse_udata = rt_expr_parse_udata,
+ .build_udata = rt_expr_build_udata,
};
struct expr *rt_expr_alloc(const struct location *loc, enum nft_rt_keys key,
diff --git a/src/rule.c b/src/rule.c
index 2d35bae4..45289cc0 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -8,11 +8,10 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <stddef.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
#include <inttypes.h>
#include <errno.h>
@@ -25,6 +24,9 @@
#include <misspell.h>
#include <json.h>
#include <cache.h>
+#include <owner.h>
+#include <intervals.h>
+#include "nftutils.h"
#include <libnftnl/common.h>
#include <libnftnl/ruleset.h>
@@ -71,10 +73,10 @@ static uint32_t tcp_dflt_timeout[] = {
static uint32_t udp_dflt_timeout[] = {
[NFTNL_CTTIMEOUT_UDP_UNREPLIED] = 30,
- [NFTNL_CTTIMEOUT_UDP_REPLIED] = 180,
+ [NFTNL_CTTIMEOUT_UDP_REPLIED] = 120,
};
-struct timeout_protocol timeout_protocol[IPPROTO_MAX] = {
+struct timeout_protocol timeout_protocol[UINT8_MAX + 1] = {
[IPPROTO_TCP] = {
.array_size = NFTNL_CTTIMEOUT_TCP_MAX,
.state_to_name = tcp_state_to_name,
@@ -102,11 +104,11 @@ int timeout_str2num(uint16_t l4proto, struct timeout_state *ts)
void handle_free(struct handle *h)
{
- xfree(h->table.name);
- xfree(h->chain.name);
- xfree(h->set.name);
- xfree(h->flowtable);
- xfree(h->obj.name);
+ free_const(h->table.name);
+ free_const(h->chain.name);
+ free_const(h->set.name);
+ free_const(h->flowtable.name);
+ free_const(h->obj.name);
}
void handle_merge(struct handle *dst, const struct handle *src)
@@ -125,8 +127,8 @@ void handle_merge(struct handle *dst, const struct handle *src)
dst->set.name = xstrdup(src->set.name);
dst->set.location = src->set.location;
}
- if (dst->flowtable == NULL && src->flowtable != NULL)
- dst->flowtable = xstrdup(src->flowtable);
+ if (dst->flowtable.name == NULL && src->flowtable.name != NULL)
+ dst->flowtable.name = xstrdup(src->flowtable.name);
if (dst->obj.name == NULL && src->obj.name != NULL)
dst->obj.name = xstrdup(src->obj.name);
if (dst->handle.id == 0)
@@ -137,176 +139,6 @@ void handle_merge(struct handle *dst, const struct handle *src)
dst->index = src->index;
}
-static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
- struct nft_cache *cache)
-{
- int ret;
-
- ret = netlink_list_tables(ctx, h);
- if (ret < 0)
- return -1;
-
- list_splice_tail_init(&ctx->list, &cache->list);
- return 0;
-}
-
-static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
-{
- struct rule *rule, *nrule;
- struct table *table;
- struct chain *chain;
- struct set *set;
- int ret;
-
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
- if (flags & NFT_CACHE_SET_BIT) {
- ret = netlink_list_sets(ctx, &table->handle);
- list_splice_tail_init(&ctx->list, &table->sets);
- if (ret < 0)
- return -1;
- }
- if (flags & NFT_CACHE_SETELEM_BIT) {
- list_for_each_entry(set, &table->sets, list) {
- ret = netlink_list_setelems(ctx, &set->handle,
- set);
- if (ret < 0)
- return -1;
- }
- }
- if (flags & NFT_CACHE_CHAIN_BIT) {
- ret = netlink_list_chains(ctx, &table->handle);
- if (ret < 0)
- return -1;
- list_splice_tail_init(&ctx->list, &table->chains);
- }
- if (flags & NFT_CACHE_FLOWTABLE_BIT) {
- ret = netlink_list_flowtables(ctx, &table->handle);
- if (ret < 0)
- return -1;
- list_splice_tail_init(&ctx->list, &table->flowtables);
- }
- if (flags & NFT_CACHE_OBJECT_BIT) {
- ret = netlink_list_objs(ctx, &table->handle);
- if (ret < 0)
- return -1;
- list_splice_tail_init(&ctx->list, &table->objs);
- }
-
- if (flags & NFT_CACHE_RULE_BIT) {
- ret = netlink_list_rules(ctx, &table->handle);
- list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
- chain = chain_lookup(table, &rule->handle);
- list_move_tail(&rule->list, &chain->rules);
- }
- if (ret < 0)
- return -1;
- }
- }
- return 0;
-}
-
-static int cache_init(struct netlink_ctx *ctx, unsigned int flags)
-{
- struct handle handle = {
- .family = NFPROTO_UNSPEC,
- };
- int ret;
-
- if (flags == NFT_CACHE_EMPTY)
- return 0;
-
- /* assume NFT_CACHE_TABLE is always set. */
- ret = cache_init_tables(ctx, &handle, &ctx->nft->cache);
- if (ret < 0)
- return ret;
- ret = cache_init_objects(ctx, flags);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static bool cache_is_complete(struct nft_cache *cache, unsigned int flags)
-{
- return (cache->flags & flags) == flags;
-}
-
-static bool cache_is_updated(struct nft_cache *cache, uint16_t genid)
-{
- return genid && genid == cache->genid;
-}
-
-bool cache_needs_update(struct nft_cache *cache)
-{
- return cache->flags & NFT_CACHE_UPDATE;
-}
-
-int cache_update(struct nft_ctx *nft, unsigned int flags, struct list_head *msgs)
-{
- struct netlink_ctx ctx = {
- .list = LIST_HEAD_INIT(ctx.list),
- .nft = nft,
- .msgs = msgs,
- };
- struct nft_cache *cache = &nft->cache;
- uint32_t genid, genid_stop, oldflags;
- int ret;
-replay:
- ctx.seqnum = cache->seqnum++;
- genid = mnl_genid_get(&ctx);
- if (cache_is_complete(cache, flags) &&
- cache_is_updated(cache, genid))
- return 0;
-
- if (cache->genid)
- cache_release(cache);
-
- if (flags & NFT_CACHE_FLUSHED) {
- oldflags = flags;
- flags = NFT_CACHE_EMPTY;
- if (oldflags & NFT_CACHE_UPDATE)
- flags |= NFT_CACHE_UPDATE;
- goto skip;
- }
-
- ret = cache_init(&ctx, flags);
- if (ret < 0) {
- cache_release(cache);
- if (errno == EINTR) {
- nft->nf_sock = nft_mnl_socket_reopen(nft->nf_sock);
- goto replay;
- }
- return -1;
- }
-
- genid_stop = mnl_genid_get(&ctx);
- if (genid != genid_stop) {
- cache_release(cache);
- goto replay;
- }
-skip:
- cache->genid = genid;
- cache->flags = flags;
- return 0;
-}
-
-static void __cache_flush(struct list_head *table_list)
-{
- struct table *table, *next;
-
- list_for_each_entry_safe(table, next, table_list, list) {
- list_del(&table->list);
- table_free(table);
- }
-}
-
-void cache_release(struct nft_cache *cache)
-{
- __cache_flush(&cache->list);
- cache->genid = 0;
- cache->flags = NFT_CACHE_EMPTY;
-}
-
/* internal ID to uniquely identify a set in the batch */
static uint32_t set_id;
@@ -314,11 +146,15 @@ struct set *set_alloc(const struct location *loc)
{
struct set *set;
+ assert(loc);
+
set = xzalloc(sizeof(*set));
set->refcnt = 1;
set->handle.set_id = ++set_id;
- if (loc != NULL)
- set->location = *loc;
+ set->location = *loc;
+
+ init_list_head(&set->stmt_list);
+
return set;
}
@@ -326,18 +162,19 @@ struct set *set_clone(const struct set *set)
{
struct set *new_set;
- new_set = set_alloc(NULL);
+ new_set = set_alloc(&internal_location);
handle_merge(&new_set->handle, &set->handle);
new_set->flags = set->flags;
new_set->gc_int = set->gc_int;
new_set->timeout = set->timeout;
new_set->key = expr_clone(set->key);
- new_set->datatype = datatype_get(set->datatype);
- new_set->datalen = set->datalen;
+ if (set->data)
+ new_set->data = expr_clone(set->data);
new_set->objtype = set->objtype;
new_set->policy = set->policy;
new_set->automerge = set->automerge;
- new_set->desc.size = set->desc.size;
+ new_set->desc = set->desc;
+ init_list_head(&new_set->stmt_list);
return new_set;
}
@@ -350,30 +187,20 @@ struct set *set_get(struct set *set)
void set_free(struct set *set)
{
+ struct stmt *stmt, *next;
+
if (--set->refcnt > 0)
return;
- if (set->init != NULL)
- expr_free(set->init);
+
+ expr_free(set->init);
+ if (set->comment)
+ free_const(set->comment);
handle_free(&set->handle);
+ list_for_each_entry_safe(stmt, next, &set->stmt_list, list)
+ stmt_free(stmt);
expr_free(set->key);
- set_datatype_destroy(set->datatype);
- xfree(set);
-}
-
-void set_add_hash(struct set *set, struct table *table)
-{
- list_add_tail(&set->list, &table->sets);
-}
-
-struct set *set_lookup(const struct table *table, const char *name)
-{
- struct set *set;
-
- list_for_each_entry(set, &table->sets, list) {
- if (!strcmp(set->handle.set.name, name))
- return set;
- }
- return NULL;
+ expr_free(set->data);
+ free(set);
}
struct set *set_lookup_fuzzy(const char *set_name,
@@ -386,14 +213,10 @@ struct set *set_lookup_fuzzy(const char *set_name,
string_misspell_init(&st);
- list_for_each_entry(table, &cache->list, list) {
- list_for_each_entry(set, &table->sets, list) {
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
if (set_is_anonymous(set->flags))
continue;
- if (!strcmp(set->handle.set.name, set_name)) {
- *t = table;
- return set;
- }
if (string_misspell_update(set->handle.set.name,
set_name, set, &st))
*t = table;
@@ -405,17 +228,13 @@ struct set *set_lookup_fuzzy(const char *set_name,
struct set *set_lookup_global(uint32_t family, const char *table,
const char *name, struct nft_cache *cache)
{
- struct handle h;
struct table *t;
- h.family = family;
- h.table.name = table;
-
- t = table_lookup(&h, cache);
+ t = table_cache_find(&cache->table_cache, table, family);
if (t == NULL)
return NULL;
- return set_lookup(t, name);
+ return set_cache_find(t, name);
}
struct print_fmt_options {
@@ -438,16 +257,51 @@ const char *set_policy2str(uint32_t policy)
}
}
+static void set_print_key(const struct expr *expr, struct output_ctx *octx)
+{
+ const struct datatype *dtype = expr->dtype;
+
+ if (dtype->size || dtype->type == TYPE_VERDICT)
+ nft_print(octx, "%s", dtype->name);
+ else
+ expr_print(expr, octx);
+}
+
+static void set_print_key_and_data(const struct set *set, struct output_ctx *octx)
+{
+ bool use_typeof = set->key_typeof_valid;
+
+ nft_print(octx, "%s ", use_typeof ? "typeof" : "type");
+
+ if (use_typeof)
+ expr_print(set->key, octx);
+ else
+ set_print_key(set->key, octx);
+
+ if (set_is_datamap(set->flags)) {
+ nft_print(octx, " : ");
+ if (set->data->flags & EXPR_F_INTERVAL)
+ nft_print(octx, "interval ");
+
+ if (use_typeof)
+ expr_print(set->data, octx);
+ else
+ set_print_key(set->data, octx);
+ } else if (set_is_objmap(set->flags)) {
+ nft_print(octx, " : %s", obj_type_name(set->objtype));
+ }
+}
+
static void set_print_declaration(const struct set *set,
struct print_fmt_options *opts,
struct output_ctx *octx)
{
const char *delim = "";
+ struct stmt *stmt;
const char *type;
uint32_t flags;
- if ((set->flags & (NFT_SET_EVAL | NFT_SET_ANONYMOUS)) ==
- (NFT_SET_EVAL | NFT_SET_ANONYMOUS))
+ if (set_is_meter(set->flags))
type = "meter";
else if (set_is_map(set->flags))
type = "map";
@@ -466,13 +320,9 @@ static void set_print_declaration(const struct set *set,
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, set->handle.handle.id);
- nft_print(octx, "%s", opts->nl);
- nft_print(octx, "%s%stype %s",
- opts->tab, opts->tab, set->key->dtype->name);
- if (set_is_datamap(set->flags))
- nft_print(octx, " : %s", set->datatype->name);
- else if (set_is_objmap(set->flags))
- nft_print(octx, " : %s", obj_type_name(set->objtype));
+ nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
+
+ set_print_key_and_data(set, octx);
nft_print(octx, "%s", opts->stmt_separator);
@@ -517,6 +367,23 @@ static void set_print_declaration(const struct set *set,
}
nft_print(octx, "%s", opts->stmt_separator);
}
+
+ if (!list_empty(&set->stmt_list)) {
+ unsigned int flags = octx->flags;
+
+ nft_print(octx, "%s%s", opts->tab, opts->tab);
+
+ octx->flags |= NFT_CTX_OUTPUT_STATELESS;
+ list_for_each_entry(stmt, &set->stmt_list, list) {
+ stmt_print(stmt, octx);
+ if (!list_is_last(&stmt->list, &set->stmt_list))
+ nft_print(octx, " ");
+ }
+ octx->flags = flags;
+
+ nft_print(octx, "%s", opts->stmt_separator);
+ }
+
if (set->automerge)
nft_print(octx, "%s%sauto-merge%s", opts->tab, opts->tab,
opts->stmt_separator);
@@ -531,14 +398,22 @@ static void set_print_declaration(const struct set *set,
time_print(set->gc_int, octx);
nft_print(octx, "%s", opts->stmt_separator);
}
+
+ if (set->comment) {
+ nft_print(octx, "%s%scomment \"%s\"%s",
+ opts->tab, opts->tab,
+ set->comment,
+ opts->stmt_separator);
+ }
}
static void do_set_print(const struct set *set, struct print_fmt_options *opts,
- struct output_ctx *octx)
+ struct output_ctx *octx)
{
set_print_declaration(set, opts, octx);
- if (set->flags & NFT_SET_EVAL && nft_output_stateless(octx)) {
+ if ((set_is_meter(set->flags) && nft_output_stateless(octx)) ||
+ nft_output_terse(octx)) {
nft_print(octx, "%s}%s", opts->tab, opts->nl);
return;
}
@@ -579,6 +454,8 @@ struct rule *rule_alloc(const struct location *loc, const struct handle *h)
{
struct rule *rule;
+ assert(loc);
+
rule = xzalloc(sizeof(*rule));
rule->location = *loc;
init_list_head(&rule->list);
@@ -602,8 +479,8 @@ void rule_free(struct rule *rule)
return;
stmt_list_free(&rule->stmts);
handle_free(&rule->handle);
- xfree(rule->comment);
- xfree(rule);
+ free_const(rule->comment);
+ free(rule);
}
void rule_print(const struct rule *rule, struct output_ctx *octx)
@@ -645,6 +522,28 @@ struct rule *rule_lookup_by_index(const struct chain *chain, uint64_t index)
return NULL;
}
+void rule_stmt_append(struct rule *rule, struct stmt *stmt)
+{
+ list_add_tail(&stmt->list, &rule->stmts);
+ rule->num_stmts++;
+}
+
+void rule_stmt_insert_at(struct rule *rule, struct stmt *nstmt,
+ struct stmt *stmt)
+{
+ list_add_tail(&nstmt->list, &stmt->list);
+ rule->num_stmts++;
+}
+
+struct scope *scope_alloc(void)
+{
+ struct scope *scope = xzalloc(sizeof(struct scope));
+
+ init_list_head(&scope->symbols);
+
+ return scope;
+}
+
struct scope *scope_init(struct scope *scope, const struct scope *parent)
{
scope->parent = parent;
@@ -658,12 +557,18 @@ void scope_release(const struct scope *scope)
list_for_each_entry_safe(sym, next, &scope->symbols, list) {
assert(sym->refcnt == 1);
list_del(&sym->list);
- xfree(sym->identifier);
+ free_const(sym->identifier);
expr_free(sym->expr);
- xfree(sym);
+ free(sym);
}
}
+void scope_free(struct scope *scope)
+{
+ scope_release(scope);
+ free(scope);
+}
+
void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr)
{
struct symbol *sym;
@@ -692,9 +597,9 @@ struct symbol *symbol_get(const struct scope *scope, const char *identifier)
static void symbol_put(struct symbol *sym)
{
if (--sym->refcnt == 0) {
- xfree(sym->identifier);
+ free_const(sym->identifier);
expr_free(sym->expr);
- xfree(sym);
+ free(sym);
}
}
@@ -774,6 +679,7 @@ static const char * const chain_hookname_str_array[] = {
"postrouting",
"output",
"ingress",
+ "egress",
NULL,
};
@@ -789,16 +695,19 @@ const char *chain_hookname_lookup(const char *name)
return NULL;
}
-struct chain *chain_alloc(const char *name)
+/* internal ID to uniquely identify a set in the batch */
+static uint32_t chain_id;
+
+struct chain *chain_alloc(void)
{
struct chain *chain;
chain = xzalloc(sizeof(*chain));
+ chain->location = internal_location;
chain->refcnt = 1;
+ chain->handle.chain_id = ++chain_id;
init_list_head(&chain->rules);
init_list_head(&chain->scope.symbols);
- if (name != NULL)
- chain->handle.chain.name = xstrdup(name);
chain->policy = NULL;
return chain;
@@ -813,32 +722,36 @@ struct chain *chain_get(struct chain *chain)
void chain_free(struct chain *chain)
{
struct rule *rule, *next;
+ int i;
if (--chain->refcnt > 0)
return;
list_for_each_entry_safe(rule, next, &chain->rules, list)
rule_free(rule);
handle_free(&chain->handle);
- scope_release(&chain->scope);
- xfree(chain->type);
- if (chain->dev != NULL)
- xfree(chain->dev);
+ free_const(chain->type.str);
+ expr_free(chain->dev_expr);
+ for (i = 0; i < chain->dev_array_len; i++)
+ free_const(chain->dev_array[i]);
+ free(chain->dev_array);
expr_free(chain->priority.expr);
expr_free(chain->policy);
- xfree(chain);
-}
+ free_const(chain->comment);
-void chain_add_hash(struct chain *chain, struct table *table)
-{
- list_add_tail(&chain->list, &table->chains);
+ /* MUST be released after all expressions, they could
+ * hold refcounts.
+ */
+ scope_release(&chain->scope);
+ free(chain);
}
-struct chain *chain_lookup(const struct table *table, const struct handle *h)
+struct chain *chain_binding_lookup(const struct table *table,
+ const char *chain_name)
{
struct chain *chain;
- list_for_each_entry(chain, &table->chains, list) {
- if (!strcmp(chain->handle.chain.name, h->chain.name))
+ list_for_each_entry(chain, &table->chain_bindings, cache.list) {
+ if (!strcmp(chain->handle.chain.name, chain_name))
return chain;
}
return NULL;
@@ -852,14 +765,13 @@ struct chain *chain_lookup_fuzzy(const struct handle *h,
struct table *table;
struct chain *chain;
+ if (!h->chain.name)
+ return NULL;
+
string_misspell_init(&st);
- list_for_each_entry(table, &cache->list, list) {
- list_for_each_entry(chain, &table->chains, list) {
- if (!strcmp(chain->handle.chain.name, h->chain.name)) {
- *t = table;
- return chain;
- }
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
if (string_misspell_update(chain->handle.chain.name,
h->chain.name, chain, &st))
*t = table;
@@ -907,6 +819,8 @@ const char *hooknum2str(unsigned int family, unsigned int hooknum)
return "postrouting";
case NF_INET_LOCAL_OUT:
return "output";
+ case NF_INET_INGRESS:
+ return "ingress";
default:
break;
};
@@ -919,6 +833,8 @@ const char *hooknum2str(unsigned int family, unsigned int hooknum)
return "forward";
case NF_ARP_OUT:
return "output";
+ case __NF_ARP_INGRESS:
+ return "ingress";
default:
break;
}
@@ -927,6 +843,8 @@ const char *hooknum2str(unsigned int family, unsigned int hooknum)
switch (hooknum) {
case NF_NETDEV_INGRESS:
return "ingress";
+ case NF_NETDEV_EGRESS:
+ return "egress";
}
break;
default:
@@ -952,7 +870,7 @@ struct prio_tag {
const char *str;
};
-const static struct prio_tag std_prios[] = {
+static const struct prio_tag std_prios[] = {
{ NF_IP_PRI_RAW, "raw" },
{ NF_IP_PRI_MANGLE, "mangle" },
{ NF_IP_PRI_NAT_DST, "dstnat" },
@@ -961,7 +879,7 @@ const static struct prio_tag std_prios[] = {
{ NF_IP_PRI_NAT_SRC, "srcnat" },
};
-const static struct prio_tag bridge_std_prios[] = {
+static const struct prio_tag bridge_std_prios[] = {
{ NF_BR_PRI_NAT_DST_BRIDGED, "dstnat" },
{ NF_BR_PRI_FILTER_BRIDGED, "filter" },
{ NF_BR_PRI_NAT_DST_OTHER, "out" },
@@ -1015,7 +933,8 @@ static bool std_prio_family_hook_compat(int prio, int family, int hook)
case NFPROTO_INET:
case NFPROTO_IPV4:
case NFPROTO_IPV6:
- if (hook == NF_INET_PRE_ROUTING)
+ if (hook == NF_INET_PRE_ROUTING ||
+ hook == NF_INET_LOCAL_OUT)
return true;
}
break;
@@ -1024,7 +943,8 @@ static bool std_prio_family_hook_compat(int prio, int family, int hook)
case NFPROTO_INET:
case NFPROTO_IPV4:
case NFPROTO_IPV6:
- if (hook == NF_INET_POST_ROUTING)
+ if (hook == NF_INET_LOCAL_IN ||
+ hook == NF_INET_POST_ROUTING)
return true;
}
}
@@ -1057,10 +977,11 @@ static const char *prio2str(const struct output_ctx *octx,
const struct expr *expr)
{
const struct prio_tag *prio_arr;
- int std_prio, offset, prio;
+ const uint32_t reach = 10;
const char *std_prio_str;
- const int reach = 10;
+ int std_prio, prio;
size_t i, arr_size;
+ int64_t offset;
mpz_export_data(&prio, expr->value, BYTEORDER_HOST_ENDIAN, sizeof(int));
if (family == NFPROTO_BRIDGE) {
@@ -1075,19 +996,21 @@ static const char *prio2str(const struct output_ctx *octx,
for (i = 0; i < arr_size; ++i) {
std_prio = prio_arr[i].val;
std_prio_str = prio_arr[i].str;
- if (abs(prio - std_prio) <= reach) {
+
+ offset = (int64_t)prio - std_prio;
+ if (llabs(offset) <= reach) {
if (!std_prio_family_hook_compat(std_prio,
family, hook))
break;
- offset = prio - std_prio;
+
strncpy(buf, std_prio_str, bufsize);
if (offset > 0)
snprintf(buf + strlen(buf),
- bufsize - strlen(buf), " + %d",
+ bufsize - strlen(buf), " + %" PRIu64,
offset);
else if (offset < 0)
snprintf(buf + strlen(buf),
- bufsize - strlen(buf), " - %d",
+ bufsize - strlen(buf), " - %" PRIu64,
-offset);
return buf;
}
@@ -1101,20 +1024,34 @@ static void chain_print_declaration(const struct chain *chain,
struct output_ctx *octx)
{
char priobuf[STD_PRIO_BUFSIZE];
- int policy;
+ int policy, i;
+
+ if (chain->flags & CHAIN_F_BINDING)
+ return;
nft_print(octx, "\tchain %s {", chain->handle.chain.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id);
+ if (chain->comment)
+ nft_print(octx, "\n\t\tcomment \"%s\"", chain->comment);
nft_print(octx, "\n");
if (chain->flags & CHAIN_F_BASECHAIN) {
- nft_print(octx, "\t\ttype %s hook %s", chain->type,
- hooknum2str(chain->handle.family, chain->hooknum));
- if (chain->dev != NULL)
- nft_print(octx, " device \"%s\"", chain->dev);
+ nft_print(octx, "\t\ttype %s hook %s", chain->type.str,
+ hooknum2str(chain->handle.family, chain->hook.num));
+ if (chain->dev_array_len == 1) {
+ nft_print(octx, " device \"%s\"", chain->dev_array[0]);
+ } else if (chain->dev_array_len > 1) {
+ nft_print(octx, " devices = { ");
+ for (i = 0; i < chain->dev_array_len; i++) {
+ nft_print(octx, "%s", chain->dev_array[i]);
+ if (i + 1 != chain->dev_array_len)
+ nft_print(octx, ", ");
+ }
+ nft_print(octx, " }");
+ }
nft_print(octx, " priority %s;",
prio2str(octx, priobuf, sizeof(priobuf),
- chain->handle.family, chain->hooknum,
+ chain->handle.family, chain->hook.num,
chain->priority.expr));
if (chain->policy) {
mpz_export_data(&policy, chain->policy->value,
@@ -1122,21 +1059,35 @@ static void chain_print_declaration(const struct chain *chain,
nft_print(octx, " policy %s;",
chain_policy2str(policy));
}
+ if (chain->flags & CHAIN_F_HW_OFFLOAD)
+ nft_print(octx, " flags offload;");
+
nft_print(octx, "\n");
}
}
-static void chain_print(const struct chain *chain, struct output_ctx *octx)
+void chain_rules_print(const struct chain *chain, struct output_ctx *octx,
+ const char *indent)
{
+ unsigned int flags = octx->flags;
struct rule *rule;
- chain_print_declaration(chain, octx);
+ if (chain->flags & CHAIN_F_BINDING)
+ octx->flags &= ~NFT_CTX_OUTPUT_HANDLE;
list_for_each_entry(rule, &chain->rules, list) {
- nft_print(octx, "\t\t");
+ nft_print(octx, "\t\t%s", indent ? : "");
rule_print(rule, octx);
nft_print(octx, "\n");
}
+
+ octx->flags = flags;
+}
+
+static void chain_print(const struct chain *chain, struct output_ctx *octx)
+{
+ chain_print_declaration(chain, octx);
+ chain_rules_print(chain, octx, NULL);
nft_print(octx, "\t}\n");
}
@@ -1151,10 +1102,23 @@ void chain_print_plain(const struct chain *chain, struct output_ctx *octx)
if (chain->flags & CHAIN_F_BASECHAIN) {
mpz_export_data(&policy, chain->policy->value,
BYTEORDER_HOST_ENDIAN, sizeof(int));
- nft_print(octx, " { type %s hook %s priority %s; policy %s; }",
- chain->type, chain->hookstr,
+ nft_print(octx, " { type %s hook %s ",
+ chain->type.str, chain->hook.name);
+
+ if (chain->dev_array_len > 0) {
+ int i;
+
+ nft_print(octx, "devices = { ");
+ for (i = 0; i < chain->dev_array_len; i++) {
+ nft_print(octx, "%s", chain->dev_array[i]);
+ if (i + 1 != chain->dev_array_len)
+ nft_print(octx, ", ");
+ }
+ nft_print(octx, " } ");
+ }
+ nft_print(octx, "priority %s; policy %s; }",
prio2str(octx, priobuf, sizeof(priobuf),
- chain->handle.family, chain->hooknum,
+ chain->handle.family, chain->hook.num,
chain->priority.expr),
chain_policy2str(policy));
}
@@ -1167,33 +1131,64 @@ struct table *table_alloc(void)
struct table *table;
table = xzalloc(sizeof(*table));
+ table->location = internal_location;
init_list_head(&table->chains);
init_list_head(&table->sets);
init_list_head(&table->objs);
init_list_head(&table->flowtables);
+ init_list_head(&table->chain_bindings);
init_list_head(&table->scope.symbols);
table->refcnt = 1;
+ cache_init(&table->chain_cache);
+ cache_init(&table->set_cache);
+ cache_init(&table->obj_cache);
+ cache_init(&table->ft_cache);
+
return table;
}
void table_free(struct table *table)
{
struct chain *chain, *next;
+ struct flowtable *ft, *nft;
struct set *set, *nset;
struct obj *obj, *nobj;
if (--table->refcnt > 0)
return;
+ if (table->comment)
+ free_const(table->comment);
list_for_each_entry_safe(chain, next, &table->chains, list)
chain_free(chain);
+ list_for_each_entry_safe(chain, next, &table->chain_bindings, cache.list)
+ chain_free(chain);
+ /* this is implicitly releasing chains in the hashtable cache */
+ list_for_each_entry_safe(chain, next, &table->chain_cache.list, cache.list)
+ chain_free(chain);
list_for_each_entry_safe(set, nset, &table->sets, list)
set_free(set);
+ /* this is implicitly releasing sets in the hashtable cache */
+ list_for_each_entry_safe(set, nset, &table->set_cache.list, cache.list)
+ set_free(set);
+ list_for_each_entry_safe(ft, nft, &table->flowtables, list)
+ flowtable_free(ft);
+ /* this is implicitly releasing flowtables in the hashtable cache */
+ list_for_each_entry_safe(ft, nft, &table->ft_cache.list, cache.list)
+ flowtable_free(ft);
list_for_each_entry_safe(obj, nobj, &table->objs, list)
obj_free(obj);
+ /* this is implicitly releasing objs in the hashtable cache */
+ list_for_each_entry_safe(obj, nobj, &table->obj_cache.list, cache.list)
+ obj_free(obj);
+
handle_free(&table->handle);
scope_release(&table->scope);
- xfree(table);
+ cache_free(&table->chain_cache);
+ cache_free(&table->set_cache);
+ cache_free(&table->obj_cache);
+ cache_free(&table->ft_cache);
+ free(table);
}
struct table *table_get(struct table *table)
@@ -1202,24 +1197,6 @@ struct table *table_get(struct table *table)
return table;
}
-void table_add_hash(struct table *table, struct nft_cache *cache)
-{
- list_add_tail(&table->list, &cache->list);
-}
-
-struct table *table_lookup(const struct handle *h,
- const struct nft_cache *cache)
-{
- struct table *table;
-
- list_for_each_entry(table, &cache->list, list) {
- if (table->handle.family == h->family &&
- !strcmp(table->handle.table.name, h->table.name))
- return table;
- }
- return NULL;
-}
-
struct table *table_lookup_fuzzy(const struct handle *h,
const struct nft_cache *cache)
{
@@ -1228,39 +1205,48 @@ struct table *table_lookup_fuzzy(const struct handle *h,
string_misspell_init(&st);
- list_for_each_entry(table, &cache->list, list) {
- if (!strcmp(table->handle.table.name, h->table.name))
- return table;
-
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
string_misspell_update(table->handle.table.name,
h->table.name, table, &st);
}
return st.obj;
}
-const char *table_flags_name[TABLE_FLAGS_MAX] = {
+static const char *table_flags_name[TABLE_FLAGS_MAX] = {
"dormant",
+ "owner",
};
-static void table_print_options(const struct table *table, const char **delim,
- struct output_ctx *octx)
+const char *table_flag_name(uint32_t flag)
+{
+ if (flag >= TABLE_FLAGS_MAX)
+ return "unknown";
+
+ return table_flags_name[flag];
+}
+
+static void table_print_flags(const struct table *table, const char **delim,
+ struct output_ctx *octx)
{
uint32_t flags = table->flags;
+ bool comma = false;
int i;
- if (flags) {
- nft_print(octx, "\tflags ");
+ if (!table->flags)
+ return;
- for (i = 0; i < TABLE_FLAGS_MAX; i++) {
- if (flags & 0x1)
- nft_print(octx, "%s", table_flags_name[i]);
- flags >>= 1;
- if (flags)
+ nft_print(octx, "\tflags ");
+ for (i = 0; i < TABLE_FLAGS_MAX; i++) {
+ if (flags & (1 << i)) {
+ if (comma)
nft_print(octx, ",");
+
+ nft_print(octx, "%s", table_flag_name(i));
+ comma = true;
}
- nft_print(octx, "\n");
- *delim = "\n";
}
+ nft_print(octx, "\n");
+ *delim = "\n";
}
static void table_print(const struct table *table, struct output_ctx *octx)
@@ -1272,30 +1258,43 @@ static void table_print(const struct table *table, struct output_ctx *octx)
const char *delim = "";
const char *family = family2str(table->handle.family);
+ if (table->has_xt_stmts)
+ fprintf(octx->error_fp,
+ "# Warning: table %s %s is managed by iptables-nft, do not touch!\n",
+ family, table->handle.table.name);
+
nft_print(octx, "table %s %s {", family, table->handle.table.name);
+ if (nft_output_handle(octx) || table->flags & TABLE_F_OWNER)
+ nft_print(octx, " #");
if (nft_output_handle(octx))
- nft_print(octx, " # handle %" PRIu64, table->handle.handle.id);
+ nft_print(octx, " handle %" PRIu64, table->handle.handle.id);
+ if (table->flags & TABLE_F_OWNER)
+ nft_print(octx, " progname %s", get_progname(table->owner));
+
nft_print(octx, "\n");
- table_print_options(table, &delim, octx);
+ table_print_flags(table, &delim, octx);
+
+ if (table->comment)
+ nft_print(octx, "\tcomment \"%s\"\n", table->comment);
- list_for_each_entry(obj, &table->objs, list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
nft_print(octx, "%s", delim);
obj_print(obj, octx);
delim = "\n";
}
- list_for_each_entry(set, &table->sets, list) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
if (set_is_anonymous(set->flags))
continue;
nft_print(octx, "%s", delim);
set_print(set, octx);
delim = "\n";
}
- list_for_each_entry(flowtable, &table->flowtables, list) {
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
nft_print(octx, "%s", delim);
flowtable_print(flowtable, octx);
delim = "\n";
}
- list_for_each_entry(chain, &table->chains, list) {
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
nft_print(octx, "%s", delim);
chain_print(chain, octx);
delim = "\n";
@@ -1309,6 +1308,8 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
{
struct cmd *cmd;
+ assert(loc);
+
cmd = xzalloc(sizeof(*cmd));
init_list_head(&cmd->list);
cmd->op = op;
@@ -1316,75 +1317,12 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
cmd->handle = *h;
cmd->location = *loc;
cmd->data = data;
- return cmd;
-}
+ cmd->attr = xzalloc_array(NFT_NLATTR_LOC_MAX,
+ sizeof(struct nlerr_loc));
+ cmd->attr_array_len = NFT_NLATTR_LOC_MAX;
+ init_list_head(&cmd->collapse_list);
-void nft_cmd_expand(struct cmd *cmd)
-{
- struct list_head new_cmds;
- struct flowtable *ft;
- struct table *table;
- struct chain *chain;
- struct rule *rule;
- struct set *set;
- struct obj *obj;
- struct cmd *new;
- struct handle h;
-
- init_list_head(&new_cmds);
-
- switch (cmd->obj) {
- case CMD_OBJ_TABLE:
- table = cmd->table;
- if (!table)
- return;
-
- list_for_each_entry(chain, &table->chains, list) {
- memset(&h, 0, sizeof(h));
- handle_merge(&h, &chain->handle);
- new = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &h,
- &chain->location, chain_get(chain));
- list_add_tail(&new->list, &new_cmds);
- }
- list_for_each_entry(obj, &table->objs, list) {
- handle_merge(&obj->handle, &table->handle);
- memset(&h, 0, sizeof(h));
- handle_merge(&h, &obj->handle);
- new = cmd_alloc(CMD_ADD, obj_type_to_cmd(obj->type), &h,
- &obj->location, obj_get(obj));
- list_add_tail(&new->list, &new_cmds);
- }
- list_for_each_entry(set, &table->sets, list) {
- handle_merge(&set->handle, &table->handle);
- memset(&h, 0, sizeof(h));
- handle_merge(&h, &set->handle);
- new = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &h,
- &set->location, set_get(set));
- list_add_tail(&new->list, &new_cmds);
- }
- list_for_each_entry(ft, &table->flowtables, list) {
- handle_merge(&ft->handle, &table->handle);
- memset(&h, 0, sizeof(h));
- handle_merge(&h, &ft->handle);
- new = cmd_alloc(CMD_ADD, CMD_OBJ_FLOWTABLE, &h,
- &ft->location, flowtable_get(ft));
- list_add_tail(&new->list, &new_cmds);
- }
- list_for_each_entry(chain, &table->chains, list) {
- list_for_each_entry(rule, &chain->rules, list) {
- memset(&h, 0, sizeof(h));
- handle_merge(&h, &rule->handle);
- new = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &h,
- &rule->location,
- rule_get(rule));
- list_add_tail(&new->list, &new_cmds);
- }
- }
- list_splice(&new_cmds, &cmd->list);
- break;
- default:
- break;
- }
+ return cmd;
}
struct markup *markup_alloc(uint32_t format)
@@ -1399,7 +1337,7 @@ struct markup *markup_alloc(uint32_t format)
void markup_free(struct markup *m)
{
- xfree(m);
+ free(m);
}
struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event)
@@ -1417,8 +1355,8 @@ struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event)
void monitor_free(struct monitor *m)
{
- xfree(m->event);
- xfree(m);
+ free_const(m->event);
+ free(m);
}
void cmd_free(struct cmd *cmd)
@@ -1426,10 +1364,15 @@ void cmd_free(struct cmd *cmd)
handle_free(&cmd->handle);
if (cmd->data != NULL) {
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_ELEMENTS:
expr_free(cmd->expr);
+ if (cmd->elem.set)
+ set_free(cmd->elem.set);
break;
case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ case CMD_OBJ_METER:
+ case CMD_OBJ_SETELEMS:
set_free(cmd->set);
break;
case CMD_OBJ_RULE:
@@ -1467,60 +1410,66 @@ void cmd_free(struct cmd *cmd)
BUG("invalid command object type %u\n", cmd->obj);
}
}
- xfree(cmd->arg);
- xfree(cmd);
+ free(cmd->attr);
+ free_const(cmd->arg);
+ free(cmd);
}
#include <netlink.h>
#include <mnl.h>
-static int __do_add_setelems(struct netlink_ctx *ctx, struct set *set,
- struct expr *expr, uint32_t flags)
+static int __do_add_elements(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct set *set, struct expr *expr, uint32_t flags)
{
expr->set_flags |= set->flags;
- if (mnl_nft_setelem_add(ctx, set, expr, flags) < 0)
+ if (mnl_nft_setelem_add(ctx, cmd, set, expr, flags) < 0)
return -1;
return 0;
}
-static int do_add_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
+static int do_add_elements(struct netlink_ctx *ctx, struct cmd *cmd,
uint32_t flags)
{
- struct handle *h = &cmd->handle;
struct expr *init = cmd->expr;
- struct table *table;
- struct set *set;
-
- table = table_lookup(h, &ctx->nft->cache);
- set = set_lookup(table, h->set.name);
+ struct set *set = cmd->elem.set;
- if (set->flags & NFT_SET_INTERVAL &&
- set_to_intervals(ctx->msgs, set, init, true,
- ctx->nft->debug_mask, set->automerge,
- &ctx->nft->output) < 0)
+ if (set_is_non_concat_range(set) &&
+ set_to_intervals(set, init, true) < 0)
return -1;
- return __do_add_setelems(ctx, set, init, flags);
+ return __do_add_elements(ctx, cmd, set, init, flags);
+}
+
+static int do_add_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
+ uint32_t flags)
+{
+ struct set *set = cmd->set;
+
+ return __do_add_elements(ctx, cmd, set, set->init, flags);
}
-static int do_add_set(struct netlink_ctx *ctx, const struct cmd *cmd,
+static int do_add_set(struct netlink_ctx *ctx, struct cmd *cmd,
uint32_t flags)
{
struct set *set = cmd->set;
if (set->init != NULL) {
- if (set->flags & NFT_SET_INTERVAL &&
- set_to_intervals(ctx->msgs, set, set->init, true,
- ctx->nft->debug_mask, set->automerge,
- &ctx->nft->output) < 0)
+ /* Update set->init->size (NFTNL_SET_DESC_SIZE) before adding
+ * the set to the kernel. Calling this from do_add_setelems()
+ * comes too late which might result in spurious ENFILE errors.
+ */
+ if (set_is_non_concat_range(set) &&
+ set_to_intervals(set, set->init, true) < 0)
return -1;
}
+
if (mnl_nft_set_add(ctx, cmd, flags) < 0)
return -1;
- if (set->init != NULL) {
- return __do_add_setelems(ctx, set, set->init, flags);
- }
+
+ if (set_is_anonymous(set->flags))
+ return __do_add_elements(ctx, cmd, set, set->init, flags);
+
return 0;
}
@@ -1540,8 +1489,10 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)
return mnl_nft_rule_add(ctx, cmd, flags | NLM_F_APPEND);
case CMD_OBJ_SET:
return do_add_set(ctx, cmd, flags);
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_SETELEMS:
return do_add_setelems(ctx, cmd, flags);
+ case CMD_OBJ_ELEMENTS:
+ return do_add_elements(ctx, cmd, flags);
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
@@ -1588,21 +1539,14 @@ static int do_command_insert(struct netlink_ctx *ctx, struct cmd *cmd)
static int do_delete_setelems(struct netlink_ctx *ctx, struct cmd *cmd)
{
- struct handle *h = &cmd->handle;
- struct expr *expr = cmd->expr;
- struct table *table;
- struct set *set;
-
- table = table_lookup(h, &ctx->nft->cache);
- set = set_lookup(table, h->set.name);
+ struct expr *expr = cmd->elem.expr;
+ struct set *set = cmd->elem.set;
- if (set->flags & NFT_SET_INTERVAL &&
- set_to_intervals(ctx->msgs, set, expr, false,
- ctx->nft->debug_mask, set->automerge,
- &ctx->nft->output) < 0)
+ if (set_is_non_concat_range(set) &&
+ set_to_intervals(set, expr, false) < 0)
return -1;
- if (mnl_nft_setelem_del(ctx, cmd) < 0)
+ if (mnl_nft_setelem_del(ctx, cmd, &cmd->handle, cmd->elem.expr) < 0)
return -1;
return 0;
@@ -1619,7 +1563,7 @@ static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
return mnl_nft_rule_del(ctx, cmd);
case CMD_OBJ_SET:
return mnl_nft_set_del(ctx, cmd);
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_ELEMENTS:
return do_delete_setelems(ctx, cmd);
case CMD_OBJ_COUNTER:
return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_COUNTER);
@@ -1644,8 +1588,7 @@ static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
}
}
-static int do_list_table(struct netlink_ctx *ctx, struct cmd *cmd,
- struct table *table)
+static int do_list_table(struct netlink_ctx *ctx, struct table *table)
{
table_print(table, &ctx->nft->output);
return 0;
@@ -1653,15 +1596,10 @@ static int do_list_table(struct netlink_ctx *ctx, struct cmd *cmd,
static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
{
- struct print_fmt_options opts = {
- .tab = "\t",
- .nl = "\n",
- .stmt_separator = "\n",
- };
struct table *table;
struct set *set;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
@@ -1670,18 +1608,17 @@ static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
family2str(table->handle.family),
table->handle.table.name);
- list_for_each_entry(set, &table->sets, list) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
if (cmd->obj == CMD_OBJ_SETS &&
!set_is_literal(set->flags))
continue;
if (cmd->obj == CMD_OBJ_METERS &&
- !(set->flags & NFT_SET_EVAL))
+ !set_is_meter_compat(set->flags))
continue;
if (cmd->obj == CMD_OBJ_MAPS &&
!map_is_literal(set->flags))
continue;
- set_print_declaration(set, &opts, &ctx->nft->output);
- nft_print(&ctx->nft->output, "%s}%s", opts.tab, opts.nl);
+ set_print(set, &ctx->nft->output);
}
nft_print(&ctx->nft->output, "}\n");
@@ -1693,9 +1630,10 @@ struct obj *obj_alloc(const struct location *loc)
{
struct obj *obj;
+ assert(loc);
+
obj = xzalloc(sizeof(*obj));
- if (loc != NULL)
- obj->location = *loc;
+ obj->location = *loc;
obj->refcnt = 1;
return obj;
@@ -1711,26 +1649,18 @@ void obj_free(struct obj *obj)
{
if (--obj->refcnt > 0)
return;
+ free_const(obj->comment);
handle_free(&obj->handle);
- xfree(obj);
-}
+ if (obj->type == NFT_OBJECT_CT_TIMEOUT) {
+ struct timeout_state *ts, *next;
-void obj_add_hash(struct obj *obj, struct table *table)
-{
- list_add_tail(&obj->list, &table->objs);
-}
-
-struct obj *obj_lookup(const struct table *table, const char *name,
- uint32_t type)
-{
- struct obj *obj;
-
- list_for_each_entry(obj, &table->objs, list) {
- if (!strcmp(obj->handle.obj.name, name) &&
- obj->type == type)
- return obj;
+ list_for_each_entry_safe(ts, next, &obj->ct_timeout.timeout_list, head) {
+ list_del(&ts->head);
+ free_const(ts->timeout_str);
+ free(ts);
+ }
}
- return NULL;
+ free(obj);
}
struct obj *obj_lookup_fuzzy(const char *obj_name,
@@ -1743,12 +1673,8 @@ struct obj *obj_lookup_fuzzy(const char *obj_name,
string_misspell_init(&st);
- list_for_each_entry(table, &cache->list, list) {
- list_for_each_entry(obj, &table->objs, list) {
- if (!strcmp(obj->handle.obj.name, obj_name)) {
- *t = table;
- return obj;
- }
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
if (string_misspell_update(obj->handle.obj.name,
obj_name, obj, &st))
*t = table;
@@ -1759,10 +1685,10 @@ struct obj *obj_lookup_fuzzy(const char *obj_name,
static void print_proto_name_proto(uint8_t l4, struct output_ctx *octx)
{
- const struct protoent *p = getprotobynumber(l4);
+ char name[NFT_PROTONAME_MAXSIZE];
- if (p)
- nft_print(octx, "%s", p->p_name);
+ if (nft_getprotobynumber(l4, name, sizeof(name)))
+ nft_print(octx, "%s", name);
else
nft_print(octx, "%d", l4);
}
@@ -1777,11 +1703,14 @@ static void print_proto_timeout_policy(uint8_t l4, const uint32_t *timeout,
nft_print(octx, "%s%spolicy = { ", opts->tab, opts->tab);
for (i = 0; i < timeout_protocol[l4].array_size; i++) {
if (timeout[i] != timeout_protocol[l4].dflt_timeout[i]) {
+ uint64_t timeout_ms;
+
if (comma)
nft_print(octx, ", ");
- nft_print(octx, "%s : %u",
- timeout_protocol[l4].state_to_name[i],
- timeout[i]);
+ timeout_ms = timeout[i] * 1000u;
+ nft_print(octx, "%s : ",
+ timeout_protocol[l4].state_to_name[i]);
+ time_print(timeout_ms, octx);
comma = true;
}
}
@@ -1804,6 +1733,16 @@ static const char *synproxy_timestamp_to_str(const uint32_t flags)
return "";
}
+static void obj_print_comment(const struct obj *obj,
+ struct print_fmt_options *opts,
+ struct output_ctx *octx)
+{
+ if (obj->comment)
+ nft_print(octx, "%s%s%scomment \"%s\"",
+ opts->nl, opts->tab, opts->tab,
+ obj->comment);
+}
+
static void obj_print_data(const struct obj *obj,
struct print_fmt_options *opts,
struct output_ctx *octx)
@@ -1813,13 +1752,14 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
- nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
- if (nft_output_stateless(octx)) {
- nft_print(octx, "packets 0 bytes 0");
- break;
- }
- nft_print(octx, "packets %" PRIu64 " bytes %" PRIu64 "%s",
- obj->counter.packets, obj->counter.bytes, opts->nl);
+
+ obj_print_comment(obj, opts, octx);
+ if (nft_output_stateless(octx))
+ nft_print(octx, "%s", opts->nl);
+ else
+ nft_print(octx, "%s%s%spackets %" PRIu64 " bytes %" PRIu64 "%s",
+ opts->nl, opts->tab, opts->tab,
+ obj->counter.packets, obj->counter.bytes, opts->nl);
break;
case NFT_OBJECT_QUOTA: {
const char *data_unit;
@@ -1828,6 +1768,8 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
data_unit = get_rate(obj->quota.bytes, &bytes);
nft_print(octx, "%s%" PRIu64 " %s",
@@ -1845,6 +1787,8 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
nft_print(octx, "\"%s\"%s", obj->secmark.ctx, opts->nl);
break;
@@ -1852,6 +1796,8 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
nft_print(octx, "%s", opts->nl);
nft_print(octx, "%s%stype \"%s\" protocol ",
opts->tab, opts->tab, obj->ct_helper.name);
@@ -1866,10 +1812,12 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
nft_print(octx, "%s", opts->nl);
nft_print(octx, "%s%sprotocol ", opts->tab, opts->tab);
print_proto_name_proto(obj->ct_timeout.l4proto, octx);
- nft_print(octx, "%s", opts->nl);
+ nft_print(octx, "%s", opts->stmt_separator);
nft_print(octx, "%s%sl3proto %s%s",
opts->tab, opts->tab,
family2str(obj->ct_timeout.l3proto),
@@ -1881,6 +1829,8 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
nft_print(octx, "%s", opts->nl);
nft_print(octx, "%s%sprotocol ", opts->tab, opts->tab);
print_proto_name_proto(obj->ct_expect.l4proto, octx);
@@ -1909,6 +1859,8 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
switch (obj->limit.type) {
case NFT_LIMIT_PKTS:
@@ -1946,6 +1898,8 @@ static void obj_print_data(const struct obj *obj,
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+ obj_print_comment(obj, opts, octx);
+
if (flags & NF_SYNPROXY_OPT_MSS) {
nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
nft_print(octx, "mss %u", obj->synproxy.mss);
@@ -1978,7 +1932,7 @@ static const char * const obj_type_name_array[] = {
[NFT_OBJECT_CT_EXPECT] = "ct expectation",
};
-const char *obj_type_name(enum stmt_types type)
+const char *obj_type_name(unsigned int type)
{
assert(type <= NFT_OBJECT_MAX && obj_type_name_array[type]);
@@ -1996,7 +1950,7 @@ static uint32_t obj_type_cmd_array[NFT_OBJECT_MAX + 1] = {
[NFT_OBJECT_CT_EXPECT] = CMD_OBJ_CT_EXPECT,
};
-uint32_t obj_type_to_cmd(uint32_t type)
+enum cmd_obj obj_type_to_cmd(uint32_t type)
{
assert(type <= NFT_OBJECT_MAX && obj_type_cmd_array[type]);
@@ -2054,7 +2008,7 @@ static int do_list_obj(struct netlink_ctx *ctx, struct cmd *cmd, uint32_t type)
struct table *table;
struct obj *obj;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
@@ -2063,14 +2017,14 @@ static int do_list_obj(struct netlink_ctx *ctx, struct cmd *cmd, uint32_t type)
strcmp(cmd->handle.table.name, table->handle.table.name))
continue;
- if (list_empty(&table->objs))
+ if (list_empty(&table->obj_cache.list))
continue;
nft_print(&ctx->nft->output, "table %s %s {\n",
family2str(table->handle.family),
table->handle.table.name);
- list_for_each_entry(obj, &table->objs, list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
if (obj->type != type ||
(cmd->handle.obj.name != NULL &&
strcmp(cmd->handle.obj.name, obj->handle.obj.name)))
@@ -2088,9 +2042,10 @@ struct flowtable *flowtable_alloc(const struct location *loc)
{
struct flowtable *flowtable;
+ assert(loc);
+
flowtable = xzalloc(sizeof(*flowtable));
- if (loc != NULL)
- flowtable->location = *loc;
+ flowtable->location = *loc;
flowtable->refcnt = 1;
return flowtable;
@@ -2104,16 +2059,20 @@ struct flowtable *flowtable_get(struct flowtable *flowtable)
void flowtable_free(struct flowtable *flowtable)
{
+ int i;
+
if (--flowtable->refcnt > 0)
return;
handle_free(&flowtable->handle);
expr_free(flowtable->priority.expr);
- xfree(flowtable);
-}
+ expr_free(flowtable->dev_expr);
-void flowtable_add_hash(struct flowtable *flowtable, struct table *table)
-{
- list_add_tail(&flowtable->list, &table->flowtables);
+ if (flowtable->dev_array != NULL) {
+ for (i = 0; i < flowtable->dev_array_len; i++)
+ free_const(flowtable->dev_array[i]);
+ free(flowtable->dev_array);
+ }
+ free(flowtable);
}
static void flowtable_print_declaration(const struct flowtable *flowtable,
@@ -2131,22 +2090,35 @@ static void flowtable_print_declaration(const struct flowtable *flowtable,
if (opts->table != NULL)
nft_print(octx, " %s", opts->table);
- nft_print(octx, " %s {%s", flowtable->handle.flowtable, opts->nl);
+ nft_print(octx, " %s {", flowtable->handle.flowtable.name);
+ if (nft_output_handle(octx))
+ nft_print(octx, " # handle %" PRIu64, flowtable->handle.handle.id);
+ nft_print(octx, "%s", opts->nl);
nft_print(octx, "%s%shook %s priority %s%s",
opts->tab, opts->tab,
- hooknum2str(NFPROTO_NETDEV, flowtable->hooknum),
+ hooknum2str(NFPROTO_NETDEV, flowtable->hook.num),
prio2str(octx, priobuf, sizeof(priobuf), NFPROTO_NETDEV,
- flowtable->hooknum, flowtable->priority.expr),
+ flowtable->hook.num, flowtable->priority.expr),
opts->stmt_separator);
- nft_print(octx, "%s%sdevices = { ", opts->tab, opts->tab);
- for (i = 0; i < flowtable->dev_array_len; i++) {
- nft_print(octx, "%s", flowtable->dev_array[i]);
- if (i + 1 != flowtable->dev_array_len)
- nft_print(octx, ", ");
+ if (flowtable->dev_array_len > 0) {
+ nft_print(octx, "%s%sdevices = { ", opts->tab, opts->tab);
+ for (i = 0; i < flowtable->dev_array_len; i++) {
+ nft_print(octx, "%s", flowtable->dev_array[i]);
+ if (i + 1 != flowtable->dev_array_len)
+ nft_print(octx, ", ");
+ }
+ nft_print(octx, " }%s", opts->stmt_separator);
}
- nft_print(octx, " }%s", opts->stmt_separator);
+
+ if (flowtable->flags & NFT_FLOWTABLE_HW_OFFLOAD)
+ nft_print(octx, "%s%sflags offload%s", opts->tab, opts->tab,
+ opts->stmt_separator);
+
+ if (flowtable->flags & NFT_FLOWTABLE_COUNTER)
+ nft_print(octx, "%s%scounter%s", opts->tab, opts->tab,
+ opts->stmt_separator);
}
static void do_flowtable_print(const struct flowtable *flowtable,
@@ -2168,6 +2140,45 @@ void flowtable_print(const struct flowtable *s, struct output_ctx *octx)
do_flowtable_print(s, &opts, octx);
}
+struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
+ const struct nft_cache *cache,
+ const struct table **t)
+{
+ struct string_misspell_state st;
+ struct table *table;
+ struct flowtable *ft;
+
+ string_misspell_init(&st);
+
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ list_for_each_entry(ft, &table->ft_cache.list, cache.list) {
+ if (string_misspell_update(ft->handle.flowtable.name,
+ ft_name, ft, &st))
+ *t = table;
+ }
+ }
+ return st.obj;
+}
+
+static int do_list_flowtable(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct table *table)
+{
+ struct flowtable *ft;
+
+ ft = ft_cache_find(table, cmd->handle.flowtable.name);
+ if (!ft)
+ return -1;
+
+ nft_print(&ctx->nft->output, "table %s %s {\n",
+ family2str(table->handle.family),
+ table->handle.table.name);
+
+ flowtable_print(ft, &ctx->nft->output);
+ nft_print(&ctx->nft->output, "}\n");
+
+ return 0;
+}
+
static int do_list_flowtables(struct netlink_ctx *ctx, struct cmd *cmd)
{
struct print_fmt_options opts = {
@@ -2178,7 +2189,7 @@ static int do_list_flowtables(struct netlink_ctx *ctx, struct cmd *cmd)
struct flowtable *flowtable;
struct table *table;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
@@ -2187,7 +2198,7 @@ static int do_list_flowtables(struct netlink_ctx *ctx, struct cmd *cmd)
family2str(table->handle.family),
table->handle.table.name);
- list_for_each_entry(flowtable, &table->flowtables, list) {
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
flowtable_print_declaration(flowtable, &opts, &ctx->nft->output);
nft_print(&ctx->nft->output, "%s}%s", opts.tab, opts.nl);
}
@@ -2202,20 +2213,15 @@ static int do_list_ruleset(struct netlink_ctx *ctx, struct cmd *cmd)
unsigned int family = cmd->handle.family;
struct table *table;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (family != NFPROTO_UNSPEC &&
table->handle.family != family)
continue;
- cmd->handle.family = table->handle.family;
- cmd->handle.table.name = table->handle.table.name;
-
- if (do_list_table(ctx, cmd, table) < 0)
+ if (do_list_table(ctx, table) < 0)
return -1;
}
- cmd->handle.table.name = NULL;
-
return 0;
}
@@ -2223,7 +2229,7 @@ static int do_list_tables(struct netlink_ctx *ctx, struct cmd *cmd)
{
struct table *table;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
@@ -2239,9 +2245,14 @@ static int do_list_tables(struct netlink_ctx *ctx, struct cmd *cmd)
static void table_print_declaration(struct table *table,
struct output_ctx *octx)
{
- nft_print(octx, "table %s %s {\n",
- family2str(table->handle.family),
- table->handle.table.name);
+ const char *family = family2str(table->handle.family);
+
+ if (table->has_xt_stmts)
+ fprintf(octx->error_fp,
+ "# Warning: table %s %s is managed by iptables-nft, do not touch!\n",
+ family, table->handle.table.name);
+
+ nft_print(octx, "table %s %s {\n", family, table->handle.table.name);
}
static int do_list_chain(struct netlink_ctx *ctx, struct cmd *cmd,
@@ -2251,13 +2262,9 @@ static int do_list_chain(struct netlink_ctx *ctx, struct cmd *cmd,
table_print_declaration(table, &ctx->nft->output);
- list_for_each_entry(chain, &table->chains, list) {
- if (chain->handle.family != cmd->handle.family ||
- strcmp(cmd->handle.chain.name, chain->handle.chain.name) != 0)
- continue;
-
+ chain = chain_cache_find(table, cmd->handle.chain.name);
+ if (chain)
chain_print(chain, &ctx->nft->output);
- }
nft_print(&ctx->nft->output, "}\n");
@@ -2269,14 +2276,14 @@ static int do_list_chains(struct netlink_ctx *ctx, struct cmd *cmd)
struct table *table;
struct chain *chain;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
table_print_declaration(table, &ctx->nft->output);
- list_for_each_entry(chain, &table->chains, list) {
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
chain_print_declaration(chain, &ctx->nft->output);
nft_print(&ctx->nft->output, "\t}\n");
}
@@ -2287,9 +2294,15 @@ static int do_list_chains(struct netlink_ctx *ctx, struct cmd *cmd)
}
static void __do_list_set(struct netlink_ctx *ctx, struct cmd *cmd,
- struct table *table, struct set *set)
+ struct set *set)
{
+ struct table *table = table_alloc();
+
+ table->handle.table.name = xstrdup(cmd->handle.table.name);
+ table->handle.family = cmd->handle.family;
table_print_declaration(table, &ctx->nft->output);
+ table_free(table);
+
set_print(set, &ctx->nft->output);
nft_print(&ctx->nft->output, "}\n");
}
@@ -2297,17 +2310,30 @@ static void __do_list_set(struct netlink_ctx *ctx, struct cmd *cmd,
static int do_list_set(struct netlink_ctx *ctx, struct cmd *cmd,
struct table *table)
{
- struct set *set;
+ struct set *set = cmd->set;
- set = set_lookup(table, cmd->handle.set.name);
- if (set == NULL)
- return -1;
+ if (!set) {
+ set = set_cache_find(table, cmd->handle.set.name);
+ if (set == NULL)
+ return -1;
+ }
- __do_list_set(ctx, cmd, table, set);
+ __do_list_set(ctx, cmd, set);
return 0;
}
+static int do_list_hooks(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ const char *devname = cmd->handle.obj.name;
+ int hooknum = -1;
+
+ if (cmd->handle.chain.name)
+ hooknum = cmd->handle.chain_id;
+
+ return mnl_nft_dump_nf_hooks(ctx, cmd->handle.family, hooknum, devname);
+}
+
static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
{
struct table *table = NULL;
@@ -2316,13 +2342,14 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
return do_command_list_json(ctx, cmd);
if (cmd->handle.table.name != NULL)
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
-
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
switch (cmd->obj) {
case CMD_OBJ_TABLE:
if (!cmd->handle.table.name)
return do_list_tables(ctx, cmd);
- return do_list_table(ctx, cmd, table);
+ return do_list_table(ctx, table);
case CMD_OBJ_CHAIN:
return do_list_chain(ctx, cmd, table);
case CMD_OBJ_CHAINS:
@@ -2332,6 +2359,8 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_SET:
return do_list_set(ctx, cmd, table);
case CMD_OBJ_RULESET:
+ case CMD_OBJ_RULES:
+ case CMD_OBJ_RULE:
return do_list_ruleset(ctx, cmd);
case CMD_OBJ_METERS:
return do_list_sets(ctx, cmd);
@@ -2351,8 +2380,10 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_CT_HELPERS:
return do_list_obj(ctx, cmd, NFT_OBJECT_CT_HELPER);
case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_CT_TIMEOUTS:
return do_list_obj(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_CT_EXPECTATIONS:
return do_list_obj(ctx, cmd, NFT_OBJECT_CT_EXPECT);
case CMD_OBJ_LIMIT:
case CMD_OBJ_LIMITS:
@@ -2363,8 +2394,12 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_SYNPROXY:
case CMD_OBJ_SYNPROXYS:
return do_list_obj(ctx, cmd, NFT_OBJECT_SYNPROXY);
+ case CMD_OBJ_FLOWTABLE:
+ return do_list_flowtable(ctx, cmd, table);
case CMD_OBJ_FLOWTABLES:
return do_list_flowtables(ctx, cmd);
+ case CMD_OBJ_HOOKS:
+ return do_list_hooks(ctx, cmd);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -2372,17 +2407,16 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
return 0;
}
-static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
- struct table *table)
+static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd, bool reset)
{
struct set *set, *new_set;
struct expr *init;
int err;
- set = set_lookup(table, cmd->handle.set.name);
+ set = cmd->elem.set;
/* Create a list of elements based of what we got from command line. */
- if (set->flags & NFT_SET_INTERVAL)
+ if (set_is_non_concat_range(set))
init = get_set_intervals(set, cmd->expr);
else
init = cmd->expr;
@@ -2391,11 +2425,11 @@ static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
/* Fetch from kernel the elements that have been requested .*/
err = netlink_get_setelem(ctx, &cmd->handle, &cmd->location,
- table, new_set, init);
+ cmd->elem.set, new_set, init, reset);
if (err >= 0)
- __do_list_set(ctx, cmd, table, new_set);
+ __do_list_set(ctx, cmd, new_set);
- if (set->flags & NFT_SET_INTERVAL)
+ if (set_is_non_concat_range(set))
expr_free(init);
set_free(new_set);
@@ -2405,14 +2439,9 @@ static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
static int do_command_get(struct netlink_ctx *ctx, struct cmd *cmd)
{
- struct table *table = NULL;
-
- if (cmd->handle.table.name != NULL)
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
-
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
- return do_get_setelems(ctx, cmd, table);
+ case CMD_OBJ_ELEMENTS:
+ return do_get_setelems(ctx, cmd, false);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -2441,19 +2470,41 @@ static int do_command_reset(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_QUOTA:
type = NFT_OBJECT_QUOTA;
break;
+ case CMD_OBJ_RULES:
+ ret = netlink_reset_rules(ctx, cmd, true);
+ if (ret < 0)
+ return ret;
+
+ return do_command_list(ctx, cmd);
+ case CMD_OBJ_RULE:
+ return netlink_reset_rules(ctx, cmd, false);
+ case CMD_OBJ_ELEMENTS:
+ return do_get_setelems(ctx, cmd, true);
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ ret = netlink_list_setelems(ctx, &cmd->handle, cmd->set, true);
+ if (ret < 0)
+ return ret;
+
+ return do_command_list(ctx, cmd);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
ret = netlink_reset_objs(ctx, cmd, type, dump);
list_for_each_entry_safe(obj, next, &ctx->list, list) {
- table = table_lookup(&obj->handle, &ctx->nft->cache);
- list_move(&obj->list, &table->objs);
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ obj->handle.table.name,
+ obj->handle.family);
+ if (!obj_cache_find(table, obj->handle.obj.name, obj->type)) {
+ list_del(&obj->list);
+ obj_cache_add(obj, table);
+ }
}
if (ret < 0)
return ret;
- return do_list_obj(ctx, cmd, type);
+ return do_command_list(ctx, cmd);
}
static int do_command_flush(struct netlink_ctx *ctx, struct cmd *cmd)
@@ -2476,12 +2527,14 @@ static int do_command_flush(struct netlink_ctx *ctx, struct cmd *cmd)
static int do_command_rename(struct netlink_ctx *ctx, struct cmd *cmd)
{
- struct table *table = table_lookup(&cmd->handle, &ctx->nft->cache);
+ struct table *table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
const struct chain *chain;
switch (cmd->obj) {
case CMD_OBJ_CHAIN:
- chain = chain_lookup(table, &cmd->handle);
+ chain = chain_cache_find(table, cmd->handle.chain.name);
return mnl_nft_chain_rename(ctx, cmd, chain);
default:
@@ -2490,23 +2543,6 @@ static int do_command_rename(struct netlink_ctx *ctx, struct cmd *cmd)
return 0;
}
-static bool need_cache(const struct cmd *cmd)
-{
- /*
- * - new rules in default format
- * - new elements
- */
- if (((cmd->monitor->flags & (1 << NFT_MSG_NEWRULE)) &&
- (cmd->monitor->format == NFTNL_OUTPUT_DEFAULT)) ||
- (cmd->monitor->flags & (1 << NFT_MSG_NEWSETELEM)))
- return true;
-
- if (cmd->monitor->flags & (1 << NFT_MSG_TRACE))
- return true;
-
- return false;
-}
-
static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
{
struct netlink_mon_handler monhandler = {
@@ -2521,8 +2557,6 @@ static int do_command_monitor(struct netlink_ctx *ctx, struct cmd *cmd)
if (nft_output_json(&ctx->nft->output))
monhandler.format = NFTNL_OUTPUT_JSON;
- monhandler.cache_needed = need_cache(cmd);
-
return netlink_monitor(&monhandler, ctx->nft->nf_sock);
}
@@ -2570,6 +2604,7 @@ int do_command(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_REPLACE:
return do_command_replace(ctx, cmd);
case CMD_DELETE:
+ case CMD_DESTROY:
return do_command_delete(ctx, cmd);
case CMD_GET:
return do_command_get(ctx, cmd);
@@ -2685,49 +2720,78 @@ static void payload_do_merge(struct stmt *sa[], unsigned int n)
}
/**
- * payload_try_merge - try to merge consecutive payload match statements
+ * stmt_reduce - reduce statements in rule
*
* @rule: nftables rule
*
+ * This function aims to:
+ *
+ * - remove redundant statement, e.g. remove 'meta protocol ip' if family is ip
+ * - merge consecutive payload match statements
+ *
* Locate sequences of payload match statements referring to adjacent
* header locations and merge those using only equality relations.
*
* As a side-effect, payload match statements are ordered in ascending
* order according to the location of the payload.
*/
-static void payload_try_merge(const struct rule *rule)
+static void stmt_reduce(const struct rule *rule)
{
+ struct stmt *stmt, *dstmt = NULL, *next;
struct stmt *sa[rule->num_stmts];
- struct stmt *stmt, *next;
unsigned int idx = 0;
list_for_each_entry_safe(stmt, next, &rule->stmts, list) {
+ /* delete this redundant statement */
+ if (dstmt) {
+ list_del(&dstmt->list);
+ stmt_free(dstmt);
+ dstmt = NULL;
+ }
+
/* Must not merge across other statements */
- if (stmt->ops->type != STMT_EXPRESSION)
- goto do_merge;
+ if (stmt->ops->type != STMT_EXPRESSION) {
+ if (idx >= 2)
+ payload_do_merge(sa, idx);
+ idx = 0;
+ continue;
+ }
if (stmt->expr->etype != EXPR_RELATIONAL)
continue;
- if (stmt->expr->left->etype != EXPR_PAYLOAD)
- continue;
if (stmt->expr->right->etype != EXPR_VALUE)
continue;
- switch (stmt->expr->op) {
- case OP_EQ:
- case OP_IMPLICIT:
- case OP_NEQ:
- break;
- default:
- continue;
- }
- sa[idx++] = stmt;
- continue;
-do_merge:
- if (idx < 2)
- continue;
- payload_do_merge(sa, idx);
- idx = 0;
+ if (stmt->expr->left->etype == EXPR_PAYLOAD) {
+ switch (stmt->expr->op) {
+ case OP_EQ:
+ case OP_IMPLICIT:
+ break;
+ default:
+ continue;
+ }
+
+ sa[idx++] = stmt;
+ } else if (stmt->expr->left->etype == EXPR_META) {
+ switch (stmt->expr->op) {
+ case OP_EQ:
+ case OP_IMPLICIT:
+ if (stmt->expr->left->meta.key == NFT_META_PROTOCOL &&
+ !stmt->expr->left->meta.inner_desc) {
+ uint16_t protocol;
+
+ protocol = mpz_get_uint16(stmt->expr->right->value);
+ if ((rule->handle.family == NFPROTO_IPV4 &&
+ protocol == ETH_P_IP) ||
+ (rule->handle.family == NFPROTO_IPV6 &&
+ protocol == ETH_P_IPV6))
+ dstmt = stmt;
+ }
+ break;
+ default:
+ break;
+ }
+ }
}
if (idx > 1)
@@ -2736,6 +2800,6 @@ do_merge:
struct error_record *rule_postprocess(struct rule *rule)
{
- payload_try_merge(rule);
+ stmt_reduce(rule);
return NULL;
}
diff --git a/src/scanner.l b/src/scanner.l
index 3de5a9e0..e4d20e69 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -10,12 +10,15 @@
%{
+#include <nft.h>
+
#include <limits.h>
#include <glob.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/types.h>
#include <linux/netfilter.h>
+#include <sys/stat.h>
#include <nftables.h>
#include <erec.h>
@@ -98,6 +101,8 @@ static void reset_pos(struct parser_state *state, struct location *loc)
state->indesc->column = 1;
}
+static void scanner_push_start_cond(void *scanner, enum startcond_type type);
+
#define YY_USER_ACTION { \
update_pos(yyget_extra(yyscanner), yylloc, yyleng); \
update_offset(yyget_extra(yyscanner), yylloc, yyleng); \
@@ -119,8 +124,9 @@ hexstring 0[xX]{hexdigit}+
letter [a-zA-Z]
string ({letter}|[_.])({letter}|{digit}|[/\-_\.])*
quotedstring \"[^"]*\"
-asteriskstring ({string}\*|{string}\\\*)
+asteriskstring ({string}\*|{string}\\\*|\\\*|{string}\\\*{string})
comment #.*$
+comment_line ^[ \t]*#.*\n
slash \/
timestring ([0-9]+d)?([0-9]+h)?([0-9]+m)?([0-9]+s)?([0-9]+ms)?
@@ -192,6 +198,62 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
%option yylineno
%option nodefault
%option warn
+%option stack
+%s SCANSTATE_ARP
+%s SCANSTATE_AT
+%s SCANSTATE_CT
+%s SCANSTATE_COUNTER
+%s SCANSTATE_ETH
+%s SCANSTATE_GRE
+%s SCANSTATE_ICMP
+%s SCANSTATE_IGMP
+%s SCANSTATE_IP
+%s SCANSTATE_IP6
+%s SCANSTATE_LAST
+%s SCANSTATE_LIMIT
+%s SCANSTATE_META
+%s SCANSTATE_POLICY
+%s SCANSTATE_QUOTA
+%s SCANSTATE_SCTP
+%s SCANSTATE_SECMARK
+%s SCANSTATE_TCP
+%s SCANSTATE_TYPE
+%s SCANSTATE_VLAN
+%s SCANSTATE_XT
+%s SCANSTATE_CMD_DESTROY
+%s SCANSTATE_CMD_EXPORT
+%s SCANSTATE_CMD_IMPORT
+%s SCANSTATE_CMD_LIST
+%s SCANSTATE_CMD_MONITOR
+%s SCANSTATE_CMD_RESET
+%s SCANSTATE_EXPR_AH
+%s SCANSTATE_EXPR_COMP
+%s SCANSTATE_EXPR_DCCP
+%s SCANSTATE_EXPR_DST
+%s SCANSTATE_EXPR_ESP
+%s SCANSTATE_EXPR_FIB
+%s SCANSTATE_EXPR_FRAG
+%s SCANSTATE_EXPR_HASH
+%s SCANSTATE_EXPR_HBH
+%s SCANSTATE_EXPR_IPSEC
+%s SCANSTATE_EXPR_MH
+%s SCANSTATE_EXPR_NUMGEN
+%s SCANSTATE_EXPR_OSF
+%s SCANSTATE_EXPR_QUEUE
+%s SCANSTATE_EXPR_RT
+%s SCANSTATE_EXPR_SCTP_CHUNK
+%s SCANSTATE_EXPR_SOCKET
+%s SCANSTATE_EXPR_TH
+%s SCANSTATE_EXPR_UDP
+%s SCANSTATE_EXPR_UDPLITE
+
+%s SCANSTATE_STMT_DUP
+%s SCANSTATE_STMT_FWD
+%s SCANSTATE_STMT_LOG
+%s SCANSTATE_STMT_NAT
+%s SCANSTATE_STMT_REJECT
+%s SCANSTATE_STMT_SYNPROXY
+%s SCANSTATE_STMT_TPROXY
%%
@@ -232,7 +294,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"/" { return SLASH; }
"-" { return DASH; }
"*" { return ASTERISK; }
-"@" { return AT; }
+"@" { scanner_push_start_cond(yyscanner, SCANSTATE_AT); return AT; }
"$" { return '$'; }
"=" { return '='; }
"vmap" { return VMAP; }
@@ -246,29 +308,36 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"describe" { return DESCRIBE; }
+<SCANSTATE_CMD_LIST,SCANSTATE_CMD_MONITOR>{
+ "chains" { return CHAINS; }
+ "sets" { return SETS; }
+ "tables" { return TABLES; }
+}
+<SCANSTATE_CMD_MONITOR>{
+ "rules" { return RULES; }
+ "trace" { return TRACE; }
+}
"hook" { return HOOK; }
"device" { return DEVICE; }
"devices" { return DEVICES; }
"table" { return TABLE; }
-"tables" { return TABLES; }
"chain" { return CHAIN; }
-"chains" { return CHAINS; }
"rule" { return RULE; }
-"rules" { return RULES; }
-"sets" { return SETS; }
"set" { return SET; }
"element" { return ELEMENT; }
"map" { return MAP; }
-"maps" { return MAPS; }
"flowtable" { return FLOWTABLE; }
"handle" { return HANDLE; }
"ruleset" { return RULESET; }
-"trace" { return TRACE; }
-
-"socket" { return SOCKET; }
-"transparent" { return TRANSPARENT;}
-"tproxy" { return TPROXY; }
+"socket" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_SOCKET); return SOCKET; }
+<SCANSTATE_EXPR_SOCKET>{
+ "transparent" { return TRANSPARENT; }
+ "wildcard" { return WILDCARD; }
+ "cgroupv2" { return CGROUPV2; }
+ "level" { return LEVEL; }
+}
+"tproxy" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_TPROXY); return TPROXY; }
"accept" { return ACCEPT; }
"drop" { return DROP; }
@@ -276,7 +345,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"jump" { return JUMP; }
"goto" { return GOTO; }
"return" { return RETURN; }
-"to" { return TO; }
+<SCANSTATE_EXPR_QUEUE,SCANSTATE_STMT_DUP,SCANSTATE_STMT_FWD,SCANSTATE_STMT_NAT,SCANSTATE_STMT_TPROXY,SCANSTATE_IP,SCANSTATE_IP6>"to" { return TO; } /* XXX: SCANSTATE_IP is a workaround */
"inet" { return INET; }
"netdev" { return NETDEV; }
@@ -288,13 +357,15 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"insert" { return INSERT; }
"delete" { return DELETE; }
"get" { return GET; }
-"list" { return LIST; }
-"reset" { return RESET; }
+"list" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_LIST); return LIST; }
+"reset" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_RESET); return RESET; }
"flush" { return FLUSH; }
"rename" { return RENAME; }
-"import" { return IMPORT; }
-"export" { return EXPORT; }
-"monitor" { return MONITOR; }
+"import" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_IMPORT); return IMPORT; }
+"export" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_EXPORT); return EXPORT; }
+"monitor" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_MONITOR); return MONITOR; }
+"destroy" { scanner_push_start_cond(yyscanner, SCANSTATE_CMD_DESTROY); return DESTROY; }
+
"position" { return POSITION; }
"index" { return INDEX; }
@@ -309,200 +380,342 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"elements" { return ELEMENTS; }
"expires" { return EXPIRES; }
-"policy" { return POLICY; }
+"policy" { scanner_push_start_cond(yyscanner, SCANSTATE_POLICY); return POLICY; }
"size" { return SIZE; }
-"performance" { return PERFORMANCE; }
-"memory" { return MEMORY; }
+<SCANSTATE_POLICY>{
+ "performance" { return PERFORMANCE; }
+ "memory" { return MEMORY; }
+}
"flow" { return FLOW; }
"offload" { return OFFLOAD; }
"meter" { return METER; }
-"meters" { return METERS; }
-
-"flowtables" { return FLOWTABLES; }
-
-"counter" { return COUNTER; }
-"name" { return NAME; }
-"packets" { return PACKETS; }
-"bytes" { return BYTES; }
-"avgpkt" { return AVGPKT; }
-
-"counters" { return COUNTERS; }
-"quotas" { return QUOTAS; }
-"limits" { return LIMITS; }
-"synproxys" { return SYNPROXYS; }
-
-"log" { return LOG; }
-"prefix" { return PREFIX; }
-"group" { return GROUP; }
-"snaplen" { return SNAPLEN; }
-"queue-threshold" { return QUEUE_THRESHOLD; }
-"level" { return LEVEL; }
-
-"queue" { return QUEUE;}
-"num" { return QUEUENUM;}
-"bypass" { return BYPASS;}
-"fanout" { return FANOUT;}
-
-"limit" { return LIMIT; }
-"rate" { return RATE; }
-"burst" { return BURST; }
-"until" { return UNTIL; }
-"over" { return OVER; }
-
-"quota" { return QUOTA; }
-"used" { return USED; }
-
-"nanosecond" { return NANOSECOND; }
-"microsecond" { return MICROSECOND; }
-"millisecond" { return MILLISECOND; }
-"second" { return SECOND; }
-"minute" { return MINUTE; }
+
+<SCANSTATE_CMD_LIST>{
+ "meters" { return METERS; }
+ "flowtables" { return FLOWTABLES; }
+ "limits" { return LIMITS; }
+ "maps" { return MAPS; }
+ "secmarks" { return SECMARKS; }
+ "synproxys" { return SYNPROXYS; }
+ "hooks" { return HOOKS; }
+}
+
+"counter" { scanner_push_start_cond(yyscanner, SCANSTATE_COUNTER); return COUNTER; }
+<SCANSTATE_COUNTER,SCANSTATE_LIMIT,SCANSTATE_QUOTA,SCANSTATE_STMT_SYNPROXY,SCANSTATE_EXPR_OSF>"name" { return NAME; }
+<SCANSTATE_COUNTER,SCANSTATE_CT,SCANSTATE_LIMIT>"packets" { return PACKETS; }
+<SCANSTATE_COUNTER,SCANSTATE_CT,SCANSTATE_LIMIT,SCANSTATE_QUOTA>"bytes" { return BYTES; }
+
+"last" { scanner_push_start_cond(yyscanner, SCANSTATE_LAST); return LAST; }
+<SCANSTATE_LAST>{
+ "never" { return NEVER; }
+}
+
+<SCANSTATE_CMD_LIST,SCANSTATE_CMD_RESET>{
+ "counters" { return COUNTERS; }
+ "quotas" { return QUOTAS; }
+ "rules" { return RULES; }
+}
+
+"log" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_LOG); return LOG; }
+<SCANSTATE_STMT_LOG,SCANSTATE_STMT_NAT,SCANSTATE_IP,SCANSTATE_IP6>"prefix" { return PREFIX; }
+<SCANSTATE_STMT_LOG>{
+ "snaplen" { return SNAPLEN; }
+ "queue-threshold" { return QUEUE_THRESHOLD; }
+ "level" { return LEVEL; }
+ "group" { return GROUP; }
+}
+
+"queue" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_QUEUE); return QUEUE;}
+<SCANSTATE_EXPR_QUEUE>{
+ "num" { return QUEUENUM;}
+ "bypass" { return BYPASS;}
+ "fanout" { return FANOUT;}
+}
+"limit" { scanner_push_start_cond(yyscanner, SCANSTATE_LIMIT); return LIMIT; }
+<SCANSTATE_LIMIT>{
+ "rate" { return RATE; }
+ "burst" { return BURST; }
+
+ /* time_unit */
+ "second" { return SECOND; }
+ "minute" { return MINUTE; }
+ "week" { return WEEK; }
+}
+<SCANSTATE_CT,SCANSTATE_LIMIT,SCANSTATE_QUOTA>"over" { return OVER; }
+
+"quota" { scanner_push_start_cond(yyscanner, SCANSTATE_QUOTA); return QUOTA; }
+<SCANSTATE_QUOTA>{
+ "until" { return UNTIL; }
+}
+
+<SCANSTATE_QUOTA,SCANSTATE_LAST>"used" { return USED; }
+
"hour" { return HOUR; }
"day" { return DAY; }
-"week" { return WEEK; }
-"reject" { return _REJECT; }
-"with" { return WITH; }
-"icmpx" { return ICMPX; }
+"reject" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_REJECT); return _REJECT; }
+<SCANSTATE_STMT_REJECT>{
+ "with" { return WITH; }
+ "icmpx" { return ICMPX; }
+}
-"snat" { return SNAT; }
-"dnat" { return DNAT; }
-"masquerade" { return MASQUERADE; }
-"redirect" { return REDIRECT; }
+"snat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return SNAT; }
+"dnat" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return DNAT; }
+"masquerade" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return MASQUERADE; }
+"redirect" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_NAT); return REDIRECT; }
"random" { return RANDOM; }
-"fully-random" { return FULLY_RANDOM; }
-"persistent" { return PERSISTENT; }
+<SCANSTATE_STMT_NAT>{
+ "fully-random" { return FULLY_RANDOM; }
+ "persistent" { return PERSISTENT; }
+ "port" { return PORT; }
+}
-"ll" { return LL_HDR; }
-"nh" { return NETWORK_HDR; }
-"th" { return TRANSPORT_HDR; }
+<SCANSTATE_AT>{
+ "ll" { return LL_HDR; }
+ "nh" { return NETWORK_HDR; }
+}
+"th" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_TH); return TRANSPORT_HDR; }
"bridge" { return BRIDGE; }
-"ether" { return ETHER; }
-"saddr" { return SADDR; }
-"daddr" { return DADDR; }
-"type" { return TYPE; }
-
-"vlan" { return VLAN; }
-"id" { return ID; }
-"cfi" { return CFI; }
-"pcp" { return PCP; }
-
-"arp" { return ARP; }
-"htype" { return HTYPE; }
-"ptype" { return PTYPE; }
-"hlen" { return HLEN; }
-"plen" { return PLEN; }
-"operation" { return OPERATION; }
-
-"ip" { return IP; }
-"version" { return HDRVERSION; }
-"hdrlength" { return HDRLENGTH; }
-"dscp" { return DSCP; }
+"ether" { scanner_push_start_cond(yyscanner, SCANSTATE_ETH); return ETHER; }
+<SCANSTATE_ARP,SCANSTATE_CT,SCANSTATE_ETH,SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_EXPR_FIB,SCANSTATE_EXPR_IPSEC>{
+ "saddr" { return SADDR; }
+ "daddr" { return DADDR; }
+}
+"type" { scanner_push_start_cond(yyscanner, SCANSTATE_TYPE); return TYPE; }
+"typeof" { return TYPEOF; }
+
+"vlan" { scanner_push_start_cond(yyscanner, SCANSTATE_VLAN); return VLAN; }
+<SCANSTATE_CT,SCANSTATE_EXPR_FRAG,SCANSTATE_VLAN,SCANSTATE_IP,SCANSTATE_ICMP>"id" { return ID; }
+<SCANSTATE_VLAN>{
+ "cfi" { return CFI; }
+ "dei" { return DEI; }
+ "pcp" { return PCP; }
+}
+"8021ad" { yylval->string = xstrdup(yytext); return STRING; }
+"8021q" { yylval->string = xstrdup(yytext); return STRING; }
+
+"arp" { scanner_push_start_cond(yyscanner, SCANSTATE_ARP); return ARP; }
+<SCANSTATE_ARP>{
+ "htype" { return HTYPE; }
+ "ptype" { return PTYPE; }
+ "hlen" { return HLEN; }
+ "plen" { return PLEN; }
+ "operation" { return OPERATION; }
+}
+
+"ip" { scanner_push_start_cond(yyscanner, SCANSTATE_IP); return IP; }
+<SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_EXPR_OSF,SCANSTATE_GRE>{
+ "version" { return HDRVERSION; }
+}
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_DST,SCANSTATE_EXPR_HBH,SCANSTATE_EXPR_MH,SCANSTATE_EXPR_RT,SCANSTATE_IP>{
+ "hdrlength" { return HDRLENGTH; }
+}
+<SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_TYPE>{
+ "dscp" { return DSCP; }
+}
"ecn" { return ECN; }
-"length" { return LENGTH; }
-"frag-off" { return FRAG_OFF; }
-"ttl" { return TTL; }
-"protocol" { return PROTOCOL; }
-"checksum" { return CHECKSUM; }
-
-"lsrr" { return LSRR; }
-"rr" { return RR; }
-"ssrr" { return SSRR; }
-"ra" { return RA; }
-
-"value" { return VALUE; }
-"ptr" { return PTR; }
-
-"echo" { return ECHO; }
-"eol" { return EOL; }
-"maxseg" { return MAXSEG; }
-"noop" { return NOOP; }
-"sack" { return SACK; }
-"sack0" { return SACK0; }
-"sack1" { return SACK1; }
-"sack2" { return SACK2; }
-"sack3" { return SACK3; }
-"sack-permitted" { return SACK_PERMITTED; }
-"timestamp" { return TIMESTAMP; }
-"time" { return TIME; }
+<SCANSTATE_EXPR_UDP,SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_META,SCANSTATE_TCP,SCANSTATE_SCTP,SCANSTATE_EXPR_SCTP_CHUNK>"length" { return LENGTH; }
+<SCANSTATE_EXPR_FRAG,SCANSTATE_IP>{
+ "frag-off" { return FRAG_OFF; }
+}
+<SCANSTATE_EXPR_OSF,SCANSTATE_IP>{
+ "ttl" { return TTL; }
+}
+<SCANSTATE_CT,SCANSTATE_IP,SCANSTATE_META,SCANSTATE_TYPE,SCANSTATE_GRE>"protocol" { return PROTOCOL; }
+<SCANSTATE_EXPR_MH,SCANSTATE_EXPR_UDP,SCANSTATE_EXPR_UDPLITE,SCANSTATE_ICMP,SCANSTATE_IGMP,SCANSTATE_IP,SCANSTATE_SCTP,SCANSTATE_TCP>{
+ "checksum" { return CHECKSUM; }
+}
-"kind" { return KIND; }
-"count" { return COUNT; }
-"left" { return LEFT; }
-"right" { return RIGHT; }
-"tsval" { return TSVAL; }
-"tsecr" { return TSECR; }
+<SCANSTATE_IP>{
+ "lsrr" { return LSRR; }
+ "rr" { return RR; }
+ "ssrr" { return SSRR; }
+ "ra" { return RA; }
-"icmp" { return ICMP; }
-"code" { return CODE; }
-"sequence" { return SEQUENCE; }
-"gateway" { return GATEWAY; }
-"mtu" { return MTU; }
+ "ptr" { return PTR; }
+ "value" { return VALUE; }
-"igmp" { return IGMP; }
-"mrt" { return MRT; }
+ "option" { return OPTION; }
+ "options" { return OPTIONS; }
+}
-"ip6" { return IP6; }
-"priority" { return PRIORITY; }
-"flowlabel" { return FLOWLABEL; }
-"nexthdr" { return NEXTHDR; }
-"hoplimit" { return HOPLIMIT; }
+<SCANSTATE_TCP>{
+ /* tcp header fields */
+ "ackseq" { return ACKSEQ; }
+ "doff" { return DOFF; }
+ "window" { return WINDOW; }
+ "urgptr" { return URGPTR; }
+
+ /* tcp option types */
+ "echo" { return ECHO; }
+ "eol" { return EOL; }
+ "maxseg" { return MSS; }
+ "mss" { return MSS; }
+ "nop" { return NOP; }
+ "noop" { return NOP; }
+ "sack" { return SACK; }
+ "sack0" { return SACK0; }
+ "sack1" { return SACK1; }
+ "sack2" { return SACK2; }
+ "sack3" { return SACK3; }
+ "sack-permitted" { return SACK_PERM; }
+ "sack-perm" { return SACK_PERM; }
+ "timestamp" { return TIMESTAMP; }
+ "fastopen" { return FASTOPEN; }
+ "mptcp" { return MPTCP; }
+ "md5sig" { return MD5SIG; }
+
+ /* tcp option fields */
+ "left" { return LEFT; }
+ "right" { return RIGHT; }
+ "count" { return COUNT; }
+ "tsval" { return TSVAL; }
+ "tsecr" { return TSECR; }
+ "subtype" { return SUBTYPE; }
+
+ "options" { return OPTIONS; }
+ "option" { return OPTION; }
+}
+"time" { return TIME; }
-"icmpv6" { return ICMP6; }
-"param-problem" { return PPTR; }
-"max-delay" { return MAXDELAY; }
+"icmp" { scanner_push_start_cond(yyscanner, SCANSTATE_ICMP); return ICMP; }
+"icmpv6" { scanner_push_start_cond(yyscanner, SCANSTATE_ICMP); return ICMP6; }
+<SCANSTATE_ICMP>{
+ "gateway" { return GATEWAY; }
+ "code" { return CODE; }
+ "param-problem" { return PPTR; }
+ "max-delay" { return MAXDELAY; }
+ "mtu" { return MTU; }
+ "taddr" { return TADDR; }
+ "daddr" { return DADDR; }
+}
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_ESP,SCANSTATE_ICMP,SCANSTATE_TCP>{
+ "sequence" { return SEQUENCE; }
+}
-"ah" { return AH; }
-"reserved" { return RESERVED; }
-"spi" { return SPI; }
+"igmp" { scanner_push_start_cond(yyscanner, SCANSTATE_IGMP); return IGMP; }
+<SCANSTATE_IGMP>{
+ "mrt" { return MRT; }
+ "group" { return GROUP; }
+}
-"esp" { return ESP; }
+"ip6" { scanner_push_start_cond(yyscanner, SCANSTATE_IP6); return IP6; }
+"priority" { return PRIORITY; }
+<SCANSTATE_IP6>{
+ "flowlabel" { return FLOWLABEL; }
+ "hoplimit" { return HOPLIMIT; }
+}
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_COMP,SCANSTATE_EXPR_DST,SCANSTATE_EXPR_FRAG,SCANSTATE_EXPR_HBH,SCANSTATE_EXPR_MH,SCANSTATE_EXPR_RT,SCANSTATE_IP6>{
+ "nexthdr" { return NEXTHDR; }
+}
-"comp" { return COMP; }
+"ah" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_AH); return AH; }
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_FRAG,SCANSTATE_EXPR_MH,SCANSTATE_TCP>{
+ "reserved" { return RESERVED; }
+}
+<SCANSTATE_EXPR_AH,SCANSTATE_EXPR_ESP,SCANSTATE_EXPR_IPSEC>"spi" { return SPI; }
+
+"esp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_ESP); return ESP; }
+
+"comp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_COMP); return COMP; }
+<SCANSTATE_EXPR_COMP>{
+ "cpi" { return CPI; }
+}
"flags" { return FLAGS; }
-"cpi" { return CPI; }
-"udp" { return UDP; }
-"udplite" { return UDPLITE; }
-"sport" { return SPORT; }
-"dport" { return DPORT; }
+"udp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_UDP); return UDP; }
+"udplite" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_UDPLITE); return UDPLITE; }
+<SCANSTATE_EXPR_UDPLITE>{
+ "csumcov" { return CSUMCOV; }
+}
+<SCANSTATE_EXPR_DCCP,SCANSTATE_SCTP,SCANSTATE_TCP,SCANSTATE_EXPR_TH,SCANSTATE_EXPR_UDP,SCANSTATE_EXPR_UDPLITE>{
+ "sport" { return SPORT; }
+}
+<SCANSTATE_CT,SCANSTATE_EXPR_DCCP,SCANSTATE_SCTP,SCANSTATE_TCP,SCANSTATE_EXPR_TH,SCANSTATE_EXPR_UDP,SCANSTATE_EXPR_UDPLITE>{
+ "dport" { return DPORT; }
+}
+<SCANSTATE_EXPR_DCCP>{
+ "option" { return OPTION; }
+}
+
+"vxlan" { return VXLAN; }
+"vni" { return VNI; }
-"tcp" { return TCP; }
-"ackseq" { return ACKSEQ; }
-"doff" { return DOFF; }
-"window" { return WINDOW; }
-"urgptr" { return URGPTR; }
-"option" { return OPTION; }
+"geneve" { return GENEVE; }
-"dccp" { return DCCP; }
+"gre" { scanner_push_start_cond(yyscanner, SCANSTATE_GRE); return GRE; }
+"gretap" { scanner_push_start_cond(yyscanner, SCANSTATE_GRE); return GRETAP; }
-"sctp" { return SCTP; }
-"vtag" { return VTAG; }
+"tcp" { scanner_push_start_cond(yyscanner, SCANSTATE_TCP); return TCP; }
-"rt" { return RT; }
-"rt0" { return RT0; }
-"rt2" { return RT2; }
-"srh" { return RT4; }
-"seg-left" { return SEG_LEFT; }
-"addr" { return ADDR; }
-"last-entry" { return LAST_ENT; }
-"tag" { return TAG; }
-"sid" { return SID; }
+"dccp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_DCCP); return DCCP; }
-"hbh" { return HBH; }
+"sctp" { scanner_push_start_cond(yyscanner, SCANSTATE_SCTP); return SCTP; }
-"frag" { return FRAG; }
-"reserved2" { return RESERVED2; }
-"more-fragments" { return MORE_FRAGMENTS; }
+<SCANSTATE_SCTP>{
+ "chunk" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_SCTP_CHUNK); return CHUNK; }
+ "vtag" { return VTAG; }
+}
+
+<SCANSTATE_EXPR_SCTP_CHUNK>{
+ "data" { return DATA; }
+ "init" { return INIT; }
+ "init-ack" { return INIT_ACK; }
+ "heartbeat" { return HEARTBEAT; }
+ "heartbeat-ack" { return HEARTBEAT_ACK; }
+ "abort" { return ABORT; }
+ "shutdown" { return SHUTDOWN; }
+ "shutdown-ack" { return SHUTDOWN_ACK; }
+ "error" { return ERROR; }
+ "cookie-echo" { return COOKIE_ECHO; }
+ "cookie-ack" { return COOKIE_ACK; }
+ "ecne" { return ECNE; }
+ "cwr" { return CWR; }
+ "shutdown-complete" { return SHUTDOWN_COMPLETE; }
+ "asconf-ack" { return ASCONF_ACK; }
+ "forward-tsn" { return FORWARD_TSN; }
+ "asconf" { return ASCONF; }
+
+ "tsn" { return TSN; }
+ "sack" { return SACK; }
+ "stream" { return STREAM; }
+ "ssn" { return SSN; }
+ "ppid" { return PPID; }
+ "init-tag" { return INIT_TAG; }
+ "a-rwnd" { return A_RWND; }
+ "num-outbound-streams" { return NUM_OSTREAMS; }
+ "num-inbound-streams" { return NUM_ISTREAMS; }
+ "initial-tsn" { return INIT_TSN; }
+ "cum-tsn-ack" { return CUM_TSN_ACK; }
+ "num-gap-ack-blocks" { return NUM_GACK_BLOCKS; }
+ "num-dup-tsns" { return NUM_DUP_TSNS; }
+ "lowest-tsn" { return LOWEST_TSN; }
+ "seqno" { return SEQNO; }
+ "new-cum-tsn" { return NEW_CUM_TSN; }
+}
+
+"rt" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT; }
+"rt0" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT0; }
+"rt2" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT2; }
+"srh" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_RT); return RT4; }
+<SCANSTATE_EXPR_RT,SCANSTATE_STMT_NAT,SCANSTATE_IP,SCANSTATE_IP6>"addr" { return ADDR; }
+
+"hbh" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HBH); return HBH; }
-"dst" { return DST; }
+"frag" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_FRAG); return FRAG; }
+<SCANSTATE_EXPR_FRAG>{
+ "reserved2" { return RESERVED2; }
+ "more-fragments" { return MORE_FRAGMENTS; }
+}
+
+"dst" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_DST); return DST; }
-"mh" { return MH; }
+"mh" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_MH); return MH; }
-"meta" { return META; }
+"meta" { scanner_push_start_cond(yyscanner, SCANSTATE_META); return META; }
"mark" { return MARK; }
"iif" { return IIF; }
"iifname" { return IIFNAME; }
@@ -524,73 +737,98 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"oifgroup" { return OIFGROUP; }
"cgroup" { return CGROUP; }
-"classid" { return CLASSID; }
-"nexthop" { return NEXTHOP; }
-
-"ct" { return CT; }
-"l3proto" { return L3PROTOCOL; }
-"proto-src" { return PROTO_SRC; }
-"proto-dst" { return PROTO_DST; }
-"zone" { return ZONE; }
-"original" { return ORIGINAL; }
-"reply" { return REPLY; }
-"direction" { return DIRECTION; }
-"event" { return EVENT; }
-"expectation" { return EXPECTATION; }
-"expiration" { return EXPIRATION; }
-"helper" { return HELPER; }
-"helpers" { return HELPERS; }
-"label" { return LABEL; }
-"state" { return STATE; }
-"status" { return STATUS; }
-
-"numgen" { return NUMGEN; }
-"inc" { return INC; }
-"mod" { return MOD; }
-"offset" { return OFFSET; }
-
-"jhash" { return JHASH; }
-"symhash" { return SYMHASH; }
-"seed" { return SEED; }
-
-"dup" { return DUP; }
-"fwd" { return FWD; }
-
-"fib" { return FIB; }
-
-"osf" { return OSF; }
-
-"synproxy" { return SYNPROXY; }
-"mss" { return MSS; }
-"wscale" { return WSCALE; }
-"sack-perm" { return SACKPERM; }
+<SCANSTATE_EXPR_RT>{
+ "nexthop" { return NEXTHOP; }
+ "seg-left" { return SEG_LEFT; }
+ "mtu" { return MTU; }
+ "last-entry" { return LAST_ENT; }
+ "tag" { return TAG; }
+ "sid" { return SID; }
+}
+<SCANSTATE_EXPR_RT,SCANSTATE_TYPE>{
+ "classid" { return CLASSID; }
+}
+
+"ct" { scanner_push_start_cond(yyscanner, SCANSTATE_CT); return CT; }
+<SCANSTATE_CT>{
+ "avgpkt" { return AVGPKT; }
+ "l3proto" { return L3PROTOCOL; }
+ "proto-src" { return PROTO_SRC; }
+ "proto-dst" { return PROTO_DST; }
+ "zone" { return ZONE; }
+ "original" { return ORIGINAL; }
+ "reply" { return REPLY; }
+ "direction" { return DIRECTION; }
+ "event" { return EVENT; }
+ "expectation" { return EXPECTATION; }
+ "expiration" { return EXPIRATION; }
+ "helper" { return HELPER; }
+ "helpers" { return HELPERS; }
+ "label" { return LABEL; }
+ "state" { return STATE; }
+ "status" { return STATUS; }
+ "count" { return COUNT; }
+}
+
+"numgen" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_NUMGEN); return NUMGEN; }
+<SCANSTATE_EXPR_NUMGEN>{
+ "inc" { return INC; }
+}
+
+"jhash" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return JHASH; }
+"symhash" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_HASH); return SYMHASH; }
+
+<SCANSTATE_EXPR_HASH>{
+ "seed" { return SEED; }
+}
+<SCANSTATE_EXPR_HASH,SCANSTATE_EXPR_NUMGEN>{
+ "mod" { return MOD; }
+ "offset" { return OFFSET; }
+}
+"dup" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_DUP); return DUP; }
+"fwd" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_FWD); return FWD; }
+
+"fib" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_FIB); return FIB; }
+
+"osf" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_OSF); return OSF; }
+
+"synproxy" { scanner_push_start_cond(yyscanner, SCANSTATE_STMT_SYNPROXY); return SYNPROXY; }
+<SCANSTATE_STMT_SYNPROXY>{
+ "wscale" { return WSCALE; }
+ "maxseg" { return MSS; }
+ "mss" { return MSS; }
+ "timestamp" { return TIMESTAMP; }
+ "sack-permitted" { return SACK_PERM; }
+ "sack-perm" { return SACK_PERM; }
+}
"notrack" { return NOTRACK; }
-"options" { return OPTIONS; }
"all" { return ALL; }
-"xml" { return XML; }
-"json" { return JSON; }
-"vm" { return VM; }
+<SCANSTATE_CMD_EXPORT,SCANSTATE_CMD_IMPORT,SCANSTATE_CMD_MONITOR>{
+ "xml" { return XML; }
+ "json" { return JSON; }
+ "vm" { return VM; }
+}
"exists" { return EXISTS; }
"missing" { return MISSING; }
"exthdr" { return EXTHDR; }
-"ipsec" { return IPSEC; }
-"mode" { return MODE; }
-"reqid" { return REQID; }
-"spnum" { return SPNUM; }
-"transport" { return TRANSPORT; }
-"tunnel" { return TUNNEL; }
+"ipsec" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_IPSEC); return IPSEC; }
+<SCANSTATE_EXPR_IPSEC>{
+ "reqid" { return REQID; }
+ "spnum" { return SPNUM; }
+
+ "in" { return IN; }
+ "out" { return OUT; }
+}
-"in" { return IN; }
-"out" { return OUT; }
+"secmark" { scanner_push_start_cond(yyscanner, SCANSTATE_SECMARK); return SECMARK; }
-"secmark" { return SECMARK; }
-"secmarks" { return SECMARKS; }
+"xt" { scanner_push_start_cond(yyscanner, SCANSTATE_XT); return XT; }
{addrstring} {
yylval->string = xstrdup(yytext);
@@ -608,9 +846,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
return STRING;
}
-{decstring} {
+{hexstring} {
errno = 0;
- yylval->val = strtoull(yytext, NULL, 0);
+ yylval->val = strtoull(yytext, NULL, 16);
if (errno != 0) {
yylval->string = xstrdup(yytext);
return STRING;
@@ -618,10 +856,13 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
return NUM;
}
-{hexstring} {
+{decstring} {
+ int base = yytext[0] == '0' ? 8 : 10;
+ char *end;
+
errno = 0;
- yylval->val = strtoull(yytext, NULL, 0);
- if (errno != 0) {
+ yylval->val = strtoull(yytext, &end, base);
+ if (errno != 0 || *end) {
yylval->string = xstrdup(yytext);
return STRING;
}
@@ -660,6 +901,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
{tab}+
{space}+
+{comment_line} {
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ }
{comment}
<<EOF>> {
@@ -673,26 +917,45 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
%%
+static void scanner_push_indesc(struct parser_state *state,
+ struct input_descriptor *indesc)
+{
+ if (!state->indesc)
+ list_add_tail(&indesc->list, &state->indesc_list);
+ else
+ list_add(&indesc->list, &state->indesc->list);
+
+ state->indesc = indesc;
+}
+
+static void scanner_pop_indesc(struct parser_state *state)
+{
+ if (!list_is_first(&state->indesc->list, &state->indesc_list)) {
+ state->indesc = list_entry(state->indesc->list.prev,
+ struct input_descriptor, list);
+ } else {
+ state->indesc = NULL;
+ }
+}
+
static void scanner_pop_buffer(yyscan_t scanner)
{
struct parser_state *state = yyget_extra(scanner);
yypop_buffer_state(scanner);
- state->indesc = state->indescs[--state->indesc_idx];
+ scanner_pop_indesc(state);
}
-static struct error_record *scanner_push_file(struct nft_ctx *nft, void *scanner,
- const char *filename, const struct location *loc)
+static void scanner_push_file(struct nft_ctx *nft, void *scanner,
+ FILE *f, const char *filename,
+ const struct location *loc,
+ const struct input_descriptor *parent_indesc)
{
struct parser_state *state = yyget_extra(scanner);
struct input_descriptor *indesc;
YY_BUFFER_STATE b;
- if (state->indesc_idx == MAX_INCLUDE_DEPTH)
- return error(loc, "Include nested too deeply, max %u levels",
- MAX_INCLUDE_DEPTH);
-
- b = yy_create_buffer(nft->f[state->indesc_idx], YY_BUF_SIZE, scanner);
+ b = yy_create_buffer(f, YY_BUF_SIZE, scanner);
yypush_buffer_state(b, scanner);
indesc = xzalloc(sizeof(struct input_descriptor));
@@ -701,33 +964,100 @@ static struct error_record *scanner_push_file(struct nft_ctx *nft, void *scanner
indesc->location = *loc;
indesc->type = INDESC_FILE;
indesc->name = xstrdup(filename);
+ indesc->f = f;
+ if (!parent_indesc) {
+ indesc->depth = 1;
+ } else {
+ indesc->depth = parent_indesc->depth + 1;
+ }
init_pos(indesc);
- state->indescs[state->indesc_idx] = indesc;
- state->indesc = state->indescs[state->indesc_idx++];
- list_add_tail(&indesc->list, &state->indesc_list);
+ scanner_push_indesc(state, indesc);
+}
+
+enum nft_include_type {
+ NFT_INCLUDE,
+ NFT_CMDLINE,
+};
+
+static bool __is_useable(unsigned int type, enum nft_include_type t)
+{
+ type &= S_IFMT;
+ switch (type) {
+ case S_IFREG: return true;
+ case S_IFIFO:
+ return t == NFT_CMDLINE; /* disallow include /path/to/fifo */
+ default:
+ break;
+ }
+
+ return false;
+}
+
+/* need to use stat() to, fopen() will block for named fifos */
+static bool filename_is_useable(const char *name)
+{
+ struct stat sb;
+ int err;
+
+ err = stat(name, &sb);
+ if (err)
+ return false;
+
+ return __is_useable(sb.st_mode, NFT_INCLUDE);
+}
+
+static bool fp_is_useable(FILE *fp, enum nft_include_type t)
+{
+ int fd = fileno(fp);
+ struct stat sb;
+ int err;
+
+ if (fd < 0)
+ return false;
- return NULL;
+ err = fstat(fd, &sb);
+ if (err < 0)
+ return false;
+
+ return __is_useable(sb.st_mode, t);
}
static int include_file(struct nft_ctx *nft, void *scanner,
- const char *filename, const struct location *loc)
+ const char *filename, const struct location *loc,
+ const struct input_descriptor *parent_indesc,
+ enum nft_include_type includetype)
+
{
struct parser_state *state = yyget_extra(scanner);
struct error_record *erec;
FILE *f;
+ if (parent_indesc && parent_indesc->depth == MAX_INCLUDE_DEPTH) {
+ erec = error(loc, "Include nested too deeply, max %u levels",
+ MAX_INCLUDE_DEPTH);
+ goto err;
+ }
+
+ if (includetype == NFT_INCLUDE && !filename_is_useable(filename)) {
+ erec = error(loc, "Not a regular file: \"%s\"\n", filename);
+ goto err;
+ }
+
f = fopen(filename, "r");
if (f == NULL) {
erec = error(loc, "Could not open file \"%s\": %s\n",
filename, strerror(errno));
goto err;
}
- nft->f[state->indesc_idx] = f;
- erec = scanner_push_file(nft, scanner, filename, loc);
- if (erec != NULL)
+ if (!fp_is_useable(f, includetype)) {
+ fclose(f);
+ erec = error(loc, "Not a regular file: \"%s\"\n", filename);
goto err;
+ }
+
+ scanner_push_file(nft, scanner, f, filename, loc, parent_indesc);
return 0;
err:
erec_queue(erec, state->msgs);
@@ -738,6 +1068,7 @@ static int include_glob(struct nft_ctx *nft, void *scanner, const char *pattern,
const struct location *loc)
{
struct parser_state *state = yyget_extra(scanner);
+ struct input_descriptor *indesc = state->indesc;
struct error_record *erec = NULL;
bool wildcard = false;
glob_t glob_data;
@@ -786,7 +1117,7 @@ static int include_glob(struct nft_ctx *nft, void *scanner, const char *pattern,
ret = glob(pattern, flags, NULL, &glob_data);
if (ret == 0) {
char *path;
- int len;
+ size_t len;
/* reverse alphabetical order due to stack */
for (i = glob_data.gl_pathc; i > 0; i--) {
@@ -798,7 +1129,7 @@ static int include_glob(struct nft_ctx *nft, void *scanner, const char *pattern,
if (len == 0 || path[len - 1] == '/')
continue;
- ret = include_file(nft, scanner, path, loc);
+ ret = include_file(nft, scanner, path, loc, indesc, NFT_INCLUDE);
if (ret != 0)
goto err;
}
@@ -835,7 +1166,7 @@ err:
int scanner_read_file(struct nft_ctx *nft, const char *filename,
const struct location *loc)
{
- return include_file(nft, nft->scanner, filename, loc);
+ return include_file(nft, nft->scanner, filename, loc, NULL, NFT_CMDLINE);
}
static bool search_in_include_path(const char *filename)
@@ -901,16 +1232,14 @@ void scanner_push_buffer(void *scanner, const struct input_descriptor *indesc,
const char *buffer)
{
struct parser_state *state = yyget_extra(scanner);
+ struct input_descriptor *new_indesc;
YY_BUFFER_STATE b;
- state->indesc = xzalloc(sizeof(struct input_descriptor));
- state->indescs[state->indesc_idx] = state->indesc;
- state->indesc_idx++;
-
- memcpy(state->indesc, indesc, sizeof(*state->indesc));
- state->indesc->data = buffer;
- state->indesc->name = NULL;
- list_add_tail(&state->indesc->list, &state->indesc_list);
+ new_indesc = xzalloc(sizeof(struct input_descriptor));
+ memcpy(new_indesc, indesc, sizeof(*new_indesc));
+ new_indesc->data = buffer;
+ new_indesc->name = xstrdup(indesc->name);
+ scanner_push_indesc(state, new_indesc);
b = yy_scan_string(buffer, scanner);
assert(b != NULL);
@@ -924,14 +1253,16 @@ void *scanner_init(struct parser_state *state)
yylex_init_extra(state, &scanner);
yyset_out(NULL, scanner);
+ state->startcond_active = xzalloc_array(__SC_MAX,
+ sizeof(*state->startcond_active));
return scanner;
}
static void input_descriptor_destroy(const struct input_descriptor *indesc)
{
if (indesc->name)
- xfree(indesc->name);
- xfree(indesc);
+ free_const(indesc->name);
+ free_const(indesc);
}
static void input_descriptor_list_destroy(struct parser_state *state)
@@ -939,6 +1270,10 @@ static void input_descriptor_list_destroy(struct parser_state *state)
struct input_descriptor *indesc, *next;
list_for_each_entry_safe(indesc, next, &state->indesc_list, list) {
+ if (indesc->f) {
+ fclose(indesc->f);
+ indesc->f = NULL;
+ }
list_del(&indesc->list);
input_descriptor_destroy(indesc);
}
@@ -948,15 +1283,44 @@ void scanner_destroy(struct nft_ctx *nft)
{
struct parser_state *state = yyget_extra(nft->scanner);
- do {
- yypop_buffer_state(nft->scanner);
-
- if (nft->f[state->indesc_idx]) {
- fclose(nft->f[state->indesc_idx]);
- nft->f[state->indesc_idx] = NULL;
- }
- } while (state->indesc_idx--);
-
input_descriptor_list_destroy(state);
+ free(state->startcond_active);
+
yylex_destroy(nft->scanner);
}
+
+static void scanner_push_start_cond(void *scanner, enum startcond_type type)
+{
+ struct parser_state *state = yyget_extra(scanner);
+
+ state->startcond_type = type;
+ state->startcond_active[type]++;
+
+ yy_push_state((int)type, scanner);
+}
+
+void scanner_pop_start_cond(void *scanner, enum startcond_type t)
+{
+ struct parser_state *state = yyget_extra(scanner);
+
+ state->startcond_active[t]--;
+
+ if (state->startcond_type != t) {
+ state->flex_state_pop++;
+ return; /* Can't pop just yet! */
+ }
+
+ while (state->flex_state_pop) {
+ state->flex_state_pop--;
+ state->startcond_type = yy_top_state(scanner);
+ yy_pop_state(scanner);
+
+ t = state->startcond_type;
+ if (state->startcond_active[t])
+ return;
+ }
+
+ state->startcond_type = yy_top_state(scanner);
+
+ yy_pop_state(scanner);
+}
diff --git a/src/sctp_chunk.c b/src/sctp_chunk.c
new file mode 100644
index 00000000..24a07e20
--- /dev/null
+++ b/src/sctp_chunk.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright Red Hat
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
+ */
+
+#include <nft.h>
+
+#include <exthdr.h>
+#include <sctp_chunk.h>
+
+
+#define PHT(__token, __offset, __len) \
+ PROTO_HDR_TEMPLATE(__token, &integer_type, BYTEORDER_BIG_ENDIAN, \
+ __offset, __len)
+
+static const struct exthdr_desc sctp_chunk_data = {
+ .name = "data",
+ .type = SCTP_CHUNK_TYPE_DATA,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_DATA_TSN] = PHT("tsn", 32, 32),
+ [SCTP_CHUNK_DATA_STREAM] = PHT("stream", 64, 16),
+ [SCTP_CHUNK_DATA_SSN] = PHT("ssn", 80, 16),
+ [SCTP_CHUNK_DATA_PPID] = PHT("ppid", 96, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_init = {
+ .name = "init",
+ .type = SCTP_CHUNK_TYPE_INIT,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_INIT_TAG] = PHT("init-tag", 32, 32),
+ [SCTP_CHUNK_INIT_RWND] = PHT("a-rwnd", 64, 32),
+ [SCTP_CHUNK_INIT_OSTREAMS] = PHT("num-outbound-streams", 96, 16),
+ [SCTP_CHUNK_INIT_ISTREAMS] = PHT("num-inbound-streams", 112, 16),
+ [SCTP_CHUNK_INIT_TSN] = PHT("initial-tsn", 128, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_init_ack = {
+ .name = "init-ack",
+ .type = SCTP_CHUNK_TYPE_INIT_ACK,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_INIT_TAG] = PHT("init-tag", 32, 32),
+ [SCTP_CHUNK_INIT_RWND] = PHT("a-rwnd", 64, 32),
+ [SCTP_CHUNK_INIT_OSTREAMS] = PHT("num-outbound-streams", 96, 16),
+ [SCTP_CHUNK_INIT_ISTREAMS] = PHT("num-inbound-streams", 112, 16),
+ [SCTP_CHUNK_INIT_TSN] = PHT("initial-tsn", 128, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_sack = {
+ .name = "sack",
+ .type = SCTP_CHUNK_TYPE_SACK,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_SACK_CTSN_ACK] = PHT("cum-tsn-ack", 32, 32),
+ [SCTP_CHUNK_SACK_RWND] = PHT("a-rwnd", 64, 32),
+ [SCTP_CHUNK_SACK_GACK_BLOCKS] = PHT("num-gap-ack-blocks", 96, 16),
+ [SCTP_CHUNK_SACK_DUP_TSNS] = PHT("num-dup-tsns", 112, 16),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_shutdown = {
+ .name = "shutdown",
+ .type = SCTP_CHUNK_TYPE_SHUTDOWN,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_SHUTDOWN_CTSN_ACK] = PHT("cum-tsn-ack", 32, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_ecne = {
+ .name = "ecne",
+ .type = SCTP_CHUNK_TYPE_ECNE,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_ECNE_CWR_MIN_TSN] = PHT("lowest-tsn", 32, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_cwr = {
+ .name = "cwr",
+ .type = SCTP_CHUNK_TYPE_CWR,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_ECNE_CWR_MIN_TSN] = PHT("lowest-tsn", 32, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_asconf_ack = {
+ .name = "asconf-ack",
+ .type = SCTP_CHUNK_TYPE_ASCONF_ACK,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_ASCONF_SEQNO] = PHT("seqno", 32, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_forward_tsn = {
+ .name = "forward-tsn",
+ .type = SCTP_CHUNK_TYPE_FORWARD_TSN,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_FORWARD_TSN_NCTSN] = PHT("new-cum-tsn", 32, 32),
+ },
+};
+
+static const struct exthdr_desc sctp_chunk_asconf = {
+ .name = "asconf",
+ .type = SCTP_CHUNK_TYPE_ASCONF,
+ .templates = {
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8),
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8),
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),
+ [SCTP_CHUNK_ASCONF_SEQNO] = PHT("seqno", 32, 32),
+ },
+};
+
+#define SCTP_CHUNK_DESC_GENERATOR(descname, hname, desctype) \
+static const struct exthdr_desc sctp_chunk_##descname = { \
+ .name = #hname, \
+ .type = SCTP_CHUNK_TYPE_##desctype, \
+ .templates = { \
+ [SCTP_CHUNK_COMMON_TYPE] = PHT("type", 0, 8), \
+ [SCTP_CHUNK_COMMON_FLAGS] = PHT("flags", 8, 8), \
+ [SCTP_CHUNK_COMMON_LENGTH] = PHT("length", 16, 16),\
+ }, \
+};
+
+SCTP_CHUNK_DESC_GENERATOR(heartbeat, heartbeat, HEARTBEAT)
+SCTP_CHUNK_DESC_GENERATOR(heartbeat_ack, heartbeat-ack, HEARTBEAT_ACK)
+SCTP_CHUNK_DESC_GENERATOR(abort, abort, ABORT)
+SCTP_CHUNK_DESC_GENERATOR(shutdown_ack, shutdown-ack, SHUTDOWN_ACK)
+SCTP_CHUNK_DESC_GENERATOR(error, error, ERROR)
+SCTP_CHUNK_DESC_GENERATOR(cookie_echo, cookie-echo, COOKIE_ECHO)
+SCTP_CHUNK_DESC_GENERATOR(cookie_ack, cookie-ack, COOKIE_ACK)
+SCTP_CHUNK_DESC_GENERATOR(shutdown_complete, shutdown-complete, SHUTDOWN_COMPLETE)
+
+#undef SCTP_CHUNK_DESC_GENERATOR
+
+static const struct exthdr_desc *sctp_chunk_protocols[] = {
+ [SCTP_CHUNK_TYPE_DATA] = &sctp_chunk_data,
+ [SCTP_CHUNK_TYPE_INIT] = &sctp_chunk_init,
+ [SCTP_CHUNK_TYPE_INIT_ACK] = &sctp_chunk_init_ack,
+ [SCTP_CHUNK_TYPE_SACK] = &sctp_chunk_sack,
+ [SCTP_CHUNK_TYPE_HEARTBEAT] = &sctp_chunk_heartbeat,
+ [SCTP_CHUNK_TYPE_HEARTBEAT_ACK] = &sctp_chunk_heartbeat_ack,
+ [SCTP_CHUNK_TYPE_ABORT] = &sctp_chunk_abort,
+ [SCTP_CHUNK_TYPE_SHUTDOWN] = &sctp_chunk_shutdown,
+ [SCTP_CHUNK_TYPE_SHUTDOWN_ACK] = &sctp_chunk_shutdown_ack,
+ [SCTP_CHUNK_TYPE_ERROR] = &sctp_chunk_error,
+ [SCTP_CHUNK_TYPE_COOKIE_ECHO] = &sctp_chunk_cookie_echo,
+ [SCTP_CHUNK_TYPE_COOKIE_ACK] = &sctp_chunk_cookie_ack,
+ [SCTP_CHUNK_TYPE_ECNE] = &sctp_chunk_ecne,
+ [SCTP_CHUNK_TYPE_CWR] = &sctp_chunk_cwr,
+ [SCTP_CHUNK_TYPE_SHUTDOWN_COMPLETE] = &sctp_chunk_shutdown_complete,
+ [SCTP_CHUNK_TYPE_ASCONF_ACK] = &sctp_chunk_asconf_ack,
+ [SCTP_CHUNK_TYPE_FORWARD_TSN] = &sctp_chunk_forward_tsn,
+ [SCTP_CHUNK_TYPE_ASCONF] = &sctp_chunk_asconf,
+};
+
+const struct exthdr_desc *sctp_chunk_protocol_find(const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < array_size(sctp_chunk_protocols); i++) {
+ if (sctp_chunk_protocols[i] &&
+ !strcmp(sctp_chunk_protocols[i]->name, name))
+ return sctp_chunk_protocols[i];
+ }
+ return NULL;
+}
+
+struct expr *sctp_chunk_expr_alloc(const struct location *loc,
+ unsigned int type, unsigned int field)
+{
+ const struct proto_hdr_template *tmpl;
+ const struct exthdr_desc *desc = NULL;
+ struct expr *expr;
+
+ if (type < array_size(sctp_chunk_protocols))
+ desc = sctp_chunk_protocols[type];
+
+ if (!desc)
+ return NULL;
+
+ tmpl = &desc->templates[field];
+ if (!tmpl)
+ return NULL;
+
+ expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
+ BYTEORDER_BIG_ENDIAN, tmpl->len);
+ expr->exthdr.desc = desc;
+ expr->exthdr.tmpl = tmpl;
+ expr->exthdr.op = NFT_EXTHDR_OP_SCTP;
+ expr->exthdr.raw_type = desc->type;
+ expr->exthdr.offset = tmpl->offset;
+
+ return expr;
+}
+
+void sctp_chunk_init_raw(struct expr *expr, uint8_t type, unsigned int off,
+ unsigned int len, uint32_t flags)
+{
+ const struct proto_hdr_template *tmpl;
+ unsigned int i;
+
+ assert(expr->etype == EXPR_EXTHDR);
+
+ expr->len = len;
+ expr->exthdr.flags = flags;
+ expr->exthdr.offset = off;
+ expr->exthdr.op = NFT_EXTHDR_OP_SCTP;
+
+ if (flags & NFT_EXTHDR_F_PRESENT)
+ datatype_set(expr, &boolean_type);
+ else
+ datatype_set(expr, &integer_type);
+
+ if (type >= array_size(sctp_chunk_protocols))
+ return;
+
+ expr->exthdr.desc = sctp_chunk_protocols[type];
+ expr->exthdr.flags = flags;
+ assert(expr->exthdr.desc != NULL);
+
+ for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) {
+ tmpl = &expr->exthdr.desc->templates[i];
+ if (tmpl->offset != off || tmpl->len != len)
+ continue;
+
+ if ((flags & NFT_EXTHDR_F_PRESENT) == 0)
+ datatype_set(expr, tmpl->dtype);
+
+ expr->exthdr.tmpl = tmpl;
+ break;
+ }
+}
diff --git a/src/segtree.c b/src/segtree.c
index 5d6ecd4f..5e6f857f 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -8,8 +8,8 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
-#include <stdlib.h>
-#include <string.h>
+#include <nft.h>
+
#include <inttypes.h>
#include <arpa/inet.h>
@@ -19,596 +19,47 @@
#include <expression.h>
#include <gmputil.h>
#include <utils.h>
-#include <rbtree.h>
-
-/**
- * struct seg_tree - segment tree
- *
- * @root: the rbtree's root
- * @type: the datatype of the dimension
- * @dwidth: width of the dimension
- * @byteorder: byteorder of elements
- * @debug_mask: display debugging information
- */
-struct seg_tree {
- struct rb_root root;
- const struct datatype *keytype;
- unsigned int keylen;
- const struct datatype *datatype;
- unsigned int datalen;
- enum byteorder byteorder;
- unsigned int debug_mask;
-};
-
-enum elementary_interval_flags {
- EI_F_INTERVAL_END = 0x1,
- EI_F_INTERVAL_OPEN = 0x2,
-};
-
-/**
- * struct elementary_interval - elementary interval [left, right]
- *
- * @rb_node: seg_tree rb node
- * @list: list node for linearized tree
- * @left: left endpoint
- * @right: right endpoint
- * @size: interval size (right - left)
- * @flags: flags
- * @expr: associated expression
- */
-struct elementary_interval {
- union {
- struct rb_node rb_node;
- struct list_head list;
- };
-
- mpz_t left;
- mpz_t right;
- mpz_t size;
-
- enum elementary_interval_flags flags;
- struct expr *expr;
-};
-
-static void seg_tree_init(struct seg_tree *tree, const struct set *set,
- struct expr *init, unsigned int debug_mask)
-{
- struct expr *first;
-
- first = list_entry(init->expressions.next, struct expr, list);
- tree->root = RB_ROOT;
- tree->keytype = set->key->dtype;
- tree->keylen = set->key->len;
- tree->datatype = set->datatype;
- tree->datalen = set->datalen;
- tree->byteorder = first->byteorder;
- tree->debug_mask = debug_mask;
-}
-
-static struct elementary_interval *ei_alloc(const mpz_t left, const mpz_t right,
- struct expr *expr,
- enum elementary_interval_flags flags)
-{
- struct elementary_interval *ei;
-
- ei = xzalloc(sizeof(*ei));
- mpz_init_set(ei->left, left);
- mpz_init_set(ei->right, right);
- mpz_init(ei->size);
- mpz_sub(ei->size, right, left);
- if (expr != NULL)
- ei->expr = expr_get(expr);
- ei->flags = flags;
- return ei;
-}
-
-static void ei_destroy(struct elementary_interval *ei)
-{
- mpz_clear(ei->left);
- mpz_clear(ei->right);
- mpz_clear(ei->size);
- if (ei->expr != NULL)
- expr_free(ei->expr);
- xfree(ei);
-}
-
-/**
- * ei_lookup - find elementary interval containing point p
- *
- * @tree: segment tree
- * @p: the point
- */
-static struct elementary_interval *ei_lookup(struct seg_tree *tree, const mpz_t p)
-{
- struct rb_node *n = tree->root.rb_node;
- struct elementary_interval *ei;
-
- while (n != NULL) {
- ei = rb_entry(n, struct elementary_interval, rb_node);
-
- if (mpz_cmp(p, ei->left) >= 0 &&
- mpz_cmp(p, ei->right) <= 0)
- return ei;
- else if (mpz_cmp(p, ei->left) <= 0)
- n = n->rb_left;
- else if (mpz_cmp(p, ei->right) > 0)
- n = n->rb_right;
- }
- return NULL;
-}
-
-static void ei_remove(struct seg_tree *tree, struct elementary_interval *ei)
-{
- rb_erase(&ei->rb_node, &tree->root);
-}
-
-static void __ei_insert(struct seg_tree *tree, struct elementary_interval *new)
-{
- struct rb_node **p = &tree->root.rb_node;
- struct rb_node *parent = NULL;
- struct elementary_interval *ei;
-
- while (*p != NULL) {
- parent = *p;
- ei = rb_entry(parent, struct elementary_interval, rb_node);
-
- if (mpz_cmp(new->left, ei->left) >= 0 &&
- mpz_cmp(new->left, ei->right) <= 0)
- break;
- else if (mpz_cmp(new->left, ei->left) <= 0)
- p = &(*p)->rb_left;
- else if (mpz_cmp(new->left, ei->left) > 0)
- p = &(*p)->rb_right;
- }
-
- rb_link_node(&new->rb_node, parent, p);
- rb_insert_color(&new->rb_node, &tree->root);
-}
-
-static bool segtree_debug(unsigned int debug_mask)
-{
- if (debug_mask & NFT_DEBUG_SEGTREE)
- return true;
-
- return false;
-}
-
-/**
- * ei_insert - insert an elementary interval into the tree
- *
- * @tree: the seg_tree
- * @new: the elementary interval
- *
- * New entries take precedence over existing ones. Insertions are assumed to
- * be ordered by descending interval size, meaning the new interval never
- * extends over more than two existing intervals.
- */
-static int ei_insert(struct list_head *msgs, struct seg_tree *tree,
- struct elementary_interval *new, bool merge)
-{
- struct elementary_interval *lei, *rei;
- mpz_t p;
-
- mpz_init2(p, tree->keylen);
-
- /*
- * Lookup the intervals containing the left and right endpoints.
- */
- lei = ei_lookup(tree, new->left);
- rei = ei_lookup(tree, new->right);
-
- if (segtree_debug(tree->debug_mask))
- pr_gmp_debug("insert: [%Zx %Zx]\n", new->left, new->right);
-
- if (lei != NULL && rei != NULL && lei == rei) {
- if (!merge)
- goto err;
- /*
- * The new interval is entirely contained in the same interval,
- * split it into two parts:
- *
- * [lei_left, new_left) and (new_right, rei_right]
- */
- if (segtree_debug(tree->debug_mask))
- pr_gmp_debug("split [%Zx %Zx]\n", lei->left, lei->right);
-
- ei_remove(tree, lei);
-
- mpz_sub_ui(p, new->left, 1);
- if (mpz_cmp(lei->left, p) <= 0)
- __ei_insert(tree, ei_alloc(lei->left, p, lei->expr, 0));
-
- mpz_add_ui(p, new->right, 1);
- if (mpz_cmp(p, rei->right) < 0)
- __ei_insert(tree, ei_alloc(p, rei->right, lei->expr, 0));
- ei_destroy(lei);
- } else {
- if (lei != NULL) {
- if (!merge)
- goto err;
- /*
- * Left endpoint is within lei, adjust it so we have:
- *
- * [lei_left, new_left)[new_left, new_right]
- */
- if (segtree_debug(tree->debug_mask)) {
- pr_gmp_debug("adjust left [%Zx %Zx]\n",
- lei->left, lei->right);
- }
-
- mpz_sub_ui(lei->right, new->left, 1);
- mpz_sub(lei->size, lei->right, lei->left);
- if (mpz_sgn(lei->size) < 0) {
- ei_remove(tree, lei);
- ei_destroy(lei);
- }
- }
- if (rei != NULL) {
- if (!merge)
- goto err;
- /*
- * Right endpoint is within rei, adjust it so we have:
- *
- * [new_left, new_right](new_right, rei_right]
- */
- if (segtree_debug(tree->debug_mask)) {
- pr_gmp_debug("adjust right [%Zx %Zx]\n",
- rei->left, rei->right);
- }
-
- mpz_add_ui(rei->left, new->right, 1);
- mpz_sub(rei->size, rei->right, rei->left);
- if (mpz_sgn(rei->size) < 0) {
- ei_remove(tree, rei);
- ei_destroy(rei);
- }
- }
- }
-
- __ei_insert(tree, new);
-
- mpz_clear(p);
-
- return 0;
-err:
- errno = EEXIST;
- return expr_binary_error(msgs, lei->expr, new->expr,
- "conflicting intervals specified");
-}
-
-/*
- * Sort intervals according to their priority, which is defined inversely to
- * their size.
- *
- * The beginning of the interval is used as secondary sorting criterion. This
- * makes sure that overlapping ranges with equal priority are next to each
- * other, allowing to easily detect unsolvable conflicts during insertion.
- *
- * Note: unsolvable conflicts can only occur when using ranges or two identical
- * prefix specifications.
- */
-static int interval_cmp(const void *p1, const void *p2)
-{
- const struct elementary_interval *e1 = *(void * const *)p1;
- const struct elementary_interval *e2 = *(void * const *)p2;
- mpz_t d;
- int ret;
-
- mpz_init(d);
-
- mpz_sub(d, e2->size, e1->size);
- if (mpz_cmp_ui(d, 0))
- ret = mpz_sgn(d);
- else
- ret = mpz_cmp(e1->left, e2->left);
-
- mpz_clear(d);
- return ret;
-}
-
-static unsigned int expr_to_intervals(const struct expr *set,
- unsigned int keylen,
- struct elementary_interval **intervals)
-{
- struct elementary_interval *ei;
- struct expr *i, *next;
- unsigned int n;
- mpz_t low, high;
-
- mpz_init2(low, keylen);
- mpz_init2(high, keylen);
-
- /*
- * Convert elements to intervals.
- */
- n = 0;
- list_for_each_entry_safe(i, next, &set->expressions, list) {
- range_expr_value_low(low, i);
- range_expr_value_high(high, i);
- ei = ei_alloc(low, high, i, 0);
- intervals[n++] = ei;
- }
- mpz_clear(high);
- mpz_clear(low);
-
- return n;
-}
-
-/* This function checks for overlaps in two ways:
- *
- * 1) A new interval end intersects an existing interval.
- * 2) New intervals that are larger than existing ones, that don't intersect
- * at all, but that wrap the existing ones.
- */
-static bool interval_overlap(const struct elementary_interval *e1,
- const struct elementary_interval *e2)
-{
- if (mpz_cmp(e1->left, e2->left) == 0 &&
- mpz_cmp(e1->right, e2->right) == 0)
- return false;
-
- return (mpz_cmp(e1->left, e2->left) >= 0 &&
- mpz_cmp(e1->left, e2->right) <= 0) ||
- (mpz_cmp(e1->right, e2->left) >= 0 &&
- mpz_cmp(e1->right, e2->right) <= 0) ||
- (mpz_cmp(e1->left, e2->left) <= 0 &&
- mpz_cmp(e1->right, e2->right) >= 0);
-}
-
-static int set_overlap(struct list_head *msgs, const struct set *set,
- struct expr *init, unsigned int keylen)
-{
- struct elementary_interval *new_intervals[init->size];
- struct elementary_interval *intervals[set->init->size];
- unsigned int n, m, i, j;
- int ret = 0;
-
- n = expr_to_intervals(init, keylen, new_intervals);
- m = expr_to_intervals(set->init, keylen, intervals);
-
- for (i = 0; i < n; i++) {
- for (j = 0; j < m; j++) {
- if (!interval_overlap(new_intervals[i], intervals[j]))
- continue;
- expr_error(msgs, new_intervals[i]->expr,
- "interval overlaps with an existing one");
- errno = EEXIST;
- ret = -1;
- goto out;
- }
- }
-out:
- for (i = 0; i < n; i++)
- ei_destroy(new_intervals[i]);
- for (i = 0; i < m; i++)
- ei_destroy(intervals[i]);
-
- return ret;
-}
-
-static int set_to_segtree(struct list_head *msgs, struct set *set,
- struct expr *init, struct seg_tree *tree,
- bool add, bool merge)
+static enum byteorder get_key_byteorder(const struct expr *e)
{
- struct elementary_interval *intervals[init->size];
- struct expr *i, *next;
- unsigned int n;
- int err;
-
- /* We are updating an existing set with new elements, check if the new
- * interval overlaps with any of the existing ones.
- */
- if (add && set->init && set->init != init) {
- err = set_overlap(msgs, set, init, tree->keylen);
- if (err < 0)
- return err;
- }
-
- n = expr_to_intervals(init, tree->keylen, intervals);
-
- list_for_each_entry_safe(i, next, &init->expressions, list) {
- list_del(&i->list);
- expr_free(i);
- }
-
- /*
- * Sort intervals by priority.
- */
- qsort(intervals, n, sizeof(intervals[0]), interval_cmp);
-
- /*
- * Insert elements into tree
- */
- for (n = 0; n < init->size; n++) {
- err = ei_insert(msgs, tree, intervals[n], merge);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-static bool segtree_needs_first_segment(const struct set *set,
- const struct expr *init, bool add)
-{
- if (add) {
- /* Add the first segment in four situations:
- *
- * 1) This is an anonymous set.
- * 2) This set exists and it is empty.
- * 3) New empty set and, separately, new elements are added.
- * 4) This set is created with a number of initial elements.
+ enum datatypes basetype = expr_basetype(e)->type;
+
+ switch (basetype) {
+ case TYPE_INTEGER:
+ /* For ranges, integers MUST be in BYTEORDER_BIG_ENDIAN.
+ * If the LHS (lookup key, e.g. 'meta mark', is host endian,
+ * a byteorder expression is injected to convert the register
+ * content before lookup.
*/
- if ((set_is_anonymous(set->flags)) ||
- (set->init && set->init->size == 0) ||
- (set->init == NULL && init) ||
- (set->init == init)) {
- return true;
- }
- } else {
- /* If the set is empty after the removal, we have to
- * remove the first non-matching segment too.
- */
- if (set->init && set->init->size - init->size == 0)
- return true;
- }
- /* This is an update for a set that already contains elements, so don't
- * add the first non-matching elements otherwise we hit EEXIST.
- */
- return false;
-}
-
-static void segtree_linearize(struct list_head *list, const struct set *set,
- const struct expr *init, struct seg_tree *tree,
- bool add, bool merge)
-{
- bool needs_first_segment = segtree_needs_first_segment(set, init, add);
- struct elementary_interval *ei, *nei, *prev = NULL;
- struct rb_node *node, *next;
- mpz_t p, q;
-
- mpz_init2(p, tree->keylen);
- mpz_init2(q, tree->keylen);
-
- /*
- * Convert the tree of open intervals to half-closed map expressions.
- */
- rb_for_each_entry_safe(ei, node, next, &tree->root, rb_node) {
- if (segtree_debug(tree->debug_mask))
- pr_gmp_debug("iter: [%Zx %Zx]\n", ei->left, ei->right);
-
- if (prev == NULL) {
- /*
- * If the first segment doesn't begin at zero, insert a
- * non-matching segment to cover [0, first_left).
- */
- if (needs_first_segment && mpz_cmp_ui(ei->left, 0)) {
- mpz_set_ui(p, 0);
- mpz_sub_ui(q, ei->left, 1);
- nei = ei_alloc(p, q, NULL, EI_F_INTERVAL_END);
- list_add_tail(&nei->list, list);
- }
- } else {
- /*
- * If the previous segment doesn't end directly left to
- * this one, insert a non-matching segment to cover
- * (prev_right, ei_left).
- */
- mpz_add_ui(p, prev->right, 1);
- if (mpz_cmp(p, ei->left) < 0 ||
- !(set->flags & NFT_SET_ANONYMOUS)) {
- mpz_sub_ui(q, ei->left, 1);
- nei = ei_alloc(p, q, NULL, EI_F_INTERVAL_END);
- list_add_tail(&nei->list, list);
- } else if (add && merge &&
- ei->expr->etype != EXPR_MAPPING) {
- /* Merge contiguous segments only in case of
- * new additions.
- */
- mpz_set(prev->right, ei->right);
- ei_remove(tree, ei);
- ei_destroy(ei);
- continue;
- }
- }
-
- ei_remove(tree, ei);
- list_add_tail(&ei->list, list);
-
- prev = ei;
- }
-
- /*
- * If the last segment doesn't end at the right side of the dimension,
- * insert a non-matching segment to cover (last_right, end].
- */
- if (mpz_scan0(prev->right, 0) != tree->keylen) {
- mpz_add_ui(p, prev->right, 1);
- mpz_bitmask(q, tree->keylen);
- nei = ei_alloc(p, q, NULL, EI_F_INTERVAL_END);
- list_add_tail(&nei->list, list);
- } else {
- prev->flags |= EI_F_INTERVAL_OPEN;
- }
-
- mpz_clear(p);
- mpz_clear(q);
-}
-
-static void set_insert_interval(struct expr *set, struct seg_tree *tree,
- const struct elementary_interval *ei)
-{
- struct expr *expr;
-
- expr = constant_expr_alloc(&internal_location, tree->keytype,
- tree->byteorder, tree->keylen, NULL);
- mpz_set(expr->value, ei->left);
- expr = set_elem_expr_alloc(&internal_location, expr);
-
- if (ei->expr != NULL) {
- if (ei->expr->etype == EXPR_MAPPING) {
- if (ei->expr->left->comment)
- expr->comment = xstrdup(ei->expr->left->comment);
- if (ei->expr->left->timeout)
- expr->timeout = ei->expr->left->timeout;
- expr = mapping_expr_alloc(&ei->expr->location, expr,
- expr_get(ei->expr->right));
- } else {
- if (ei->expr->comment)
- expr->comment = xstrdup(ei->expr->comment);
- if (ei->expr->timeout)
- expr->timeout = ei->expr->timeout;
- }
+ return BYTEORDER_BIG_ENDIAN;
+ case TYPE_STRING:
+ return BYTEORDER_HOST_ENDIAN;
+ default:
+ break;
}
- if (ei->flags & EI_F_INTERVAL_END)
- expr->flags |= EXPR_F_INTERVAL_END;
- if (ei->flags & EI_F_INTERVAL_OPEN)
- expr->elem_flags |= NFTNL_SET_ELEM_F_INTERVAL_OPEN;
-
- compound_expr_add(set, expr);
+ return BYTEORDER_INVALID;
}
-int set_to_intervals(struct list_head *errs, struct set *set,
- struct expr *init, bool add, unsigned int debug_mask,
- bool merge, struct output_ctx *octx)
+static void interval_expr_copy(struct expr *dst, struct expr *src)
{
- struct elementary_interval *ei, *next;
- struct seg_tree tree;
- LIST_HEAD(list);
-
- seg_tree_init(&tree, set, init, debug_mask);
- if (set_to_segtree(errs, set, init, &tree, add, merge) < 0)
- return -1;
- segtree_linearize(&list, set, init, &tree, add, merge);
-
- init->size = 0;
- list_for_each_entry_safe(ei, next, &list, list) {
- if (segtree_debug(tree.debug_mask)) {
- pr_gmp_debug("list: [%.*Zx %.*Zx]\n",
- 2 * tree.keylen / BITS_PER_BYTE, ei->left,
- 2 * tree.keylen / BITS_PER_BYTE, ei->right);
- }
- set_insert_interval(init, &tree, ei);
- ei_destroy(ei);
- }
-
- if (segtree_debug(tree.debug_mask)) {
- expr_print(init, octx);
- pr_gmp_debug("\n");
- }
-
- return 0;
+ if (src->comment)
+ dst->comment = xstrdup(src->comment);
+ if (src->timeout)
+ dst->timeout = src->timeout;
+ if (src->expiration)
+ dst->expiration = src->expiration;
+
+ list_splice_init(&src->stmt_list, &dst->stmt_list);
}
static void set_elem_add(const struct set *set, struct expr *init, mpz_t value,
- uint32_t flags)
+ uint32_t flags, enum byteorder byteorder)
{
struct expr *expr;
expr = constant_expr_alloc(&internal_location, set->key->dtype,
- set->key->byteorder, set->key->len, NULL);
+ byteorder, set->key->len, NULL);
mpz_set(expr->value, value);
expr = set_elem_expr_alloc(&internal_location, expr);
expr->flags = flags;
@@ -618,6 +69,7 @@ static void set_elem_add(const struct set *set, struct expr *init, mpz_t value,
struct expr *get_set_intervals(const struct set *set, const struct expr *init)
{
+ enum byteorder byteorder = get_key_byteorder(set->key);
struct expr *new_init;
mpz_t low, high;
struct expr *i;
@@ -630,14 +82,24 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
list_for_each_entry(i, &init->expressions, list) {
switch (i->key->etype) {
case EXPR_VALUE:
- set_elem_add(set, new_init, i->key->value, i->flags);
+ set_elem_add(set, new_init, i->key->value,
+ i->flags, byteorder);
+ break;
+ case EXPR_CONCAT:
+ compound_expr_add(new_init, expr_clone(i));
+ i->flags |= EXPR_F_INTERVAL_END;
+ compound_expr_add(new_init, expr_clone(i));
+ break;
+ case EXPR_SET_ELEM_CATCHALL:
+ compound_expr_add(new_init, expr_clone(i));
break;
default:
range_expr_value_low(low, i);
- set_elem_add(set, new_init, low, 0);
+ set_elem_add(set, new_init, low, 0, i->byteorder);
range_expr_value_high(high, i);
mpz_add_ui(high, high, 1);
- set_elem_add(set, new_init, high, EXPR_F_INTERVAL_END);
+ set_elem_add(set, new_init, high,
+ EXPR_F_INTERVAL_END, i->byteorder);
break;
}
}
@@ -648,79 +110,103 @@ struct expr *get_set_intervals(const struct set *set, const struct expr *init)
return new_init;
}
-static struct expr *get_set_interval_find(const struct table *table,
- const char *set_name,
+static struct expr *get_set_interval_find(const struct set *cache_set,
struct expr *left,
struct expr *right)
{
+ const struct set *set = cache_set;
struct expr *range = NULL;
- struct set *set;
- mpz_t low, high;
struct expr *i;
+ mpz_t val;
- set = set_lookup(table, set_name);
- mpz_init2(low, set->key->len);
- mpz_init2(high, set->key->len);
+ mpz_init2(val, set->key->len);
list_for_each_entry(i, &set->init->expressions, list) {
switch (i->key->etype) {
+ case EXPR_VALUE:
+ if (expr_basetype(i->key)->type != TYPE_STRING)
+ break;
+ /* string type, check if its a range (wildcard). */
+ /* fall-through */
+ case EXPR_PREFIX:
case EXPR_RANGE:
- range_expr_value_low(low, i);
- range_expr_value_high(high, i);
- if (mpz_cmp(left->key->value, low) >= 0 &&
- mpz_cmp(right->key->value, high) <= 0) {
- range = range_expr_alloc(&internal_location,
- expr_clone(left->key),
- expr_clone(right->key));
- goto out;
- }
- break;
+ range_expr_value_low(val, i);
+ if (left && mpz_cmp(left->key->value, val))
+ break;
+
+ range_expr_value_high(val, i);
+ if (right && mpz_cmp(right->key->value, val))
+ break;
+
+ range = expr_clone(i->key);
+ goto out;
default:
break;
}
}
out:
- mpz_clear(low);
- mpz_clear(high);
+ mpz_clear(val);
return range;
}
-static struct expr *get_set_interval_end(const struct table *table,
- const char *set_name,
- struct expr *left)
+static struct expr *expr_value(struct expr *expr)
{
- struct expr *i, *range = NULL;
- struct set *set;
- mpz_t low, high;
+ switch (expr->etype) {
+ case EXPR_MAPPING:
+ return expr->left->key;
+ case EXPR_SET_ELEM:
+ return expr->key;
+ case EXPR_VALUE:
+ return expr;
+ default:
+ BUG("invalid expression type %s\n", expr_name(expr));
+ }
+}
- set = set_lookup(table, set_name);
- mpz_init2(low, set->key->len);
- mpz_init2(high, set->key->len);
+static struct expr *__expr_to_set_elem(struct expr *low, struct expr *expr)
+{
+ struct expr *elem = set_elem_expr_alloc(&low->location, expr);
- list_for_each_entry(i, &set->init->expressions, list) {
- switch (i->key->etype) {
- case EXPR_RANGE:
- range_expr_value_low(low, i);
- if (mpz_cmp(low, left->key->value) == 0) {
- range = range_expr_alloc(&internal_location,
- expr_clone(left->key),
- expr_clone(i->key->right));
- goto out;
- }
- break;
- default:
- break;
- }
+ if (low->etype == EXPR_MAPPING) {
+ interval_expr_copy(elem, low->left);
+
+ elem = mapping_expr_alloc(&low->location, elem,
+ expr_clone(low->right));
+ } else {
+ interval_expr_copy(elem, low);
}
-out:
- mpz_clear(low);
- mpz_clear(high);
+ elem->flags |= EXPR_F_KERNEL;
- return range;
+ return elem;
+}
+
+static struct expr *expr_to_set_elem(struct expr *e)
+{
+ unsigned int len = div_round_up(e->len, BITS_PER_BYTE);
+ unsigned int str_len;
+ char data[len + 1];
+ struct expr *expr;
+
+ if (expr_basetype(expr_value(e))->type != TYPE_STRING)
+ return expr_clone(e);
+
+ mpz_export_data(data, expr_value(e)->value, BYTEORDER_BIG_ENDIAN, len);
+
+ str_len = strnlen(data, len);
+ if (str_len >= len || str_len == 0)
+ return expr_clone(e);
+
+ data[str_len] = '*';
+
+ expr = constant_expr_alloc(&e->location, e->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ (str_len + 1) * BITS_PER_BYTE, data);
+
+ return __expr_to_set_elem(e, expr);
}
-int get_set_decompose(struct table *table, struct set *set)
+int get_set_decompose(struct set *cache_set, struct set *set)
{
struct expr *i, *next, *range;
struct expr *left = NULL;
@@ -733,36 +219,38 @@ int get_set_decompose(struct table *table, struct set *set)
list_del(&left->list);
list_del(&i->list);
mpz_sub_ui(i->key->value, i->key->value, 1);
- range = get_set_interval_find(table, set->handle.set.name,
- left, i);
+ range = get_set_interval_find(cache_set, left, i);
if (!range) {
+ expr_free(left);
+ expr_free(i);
expr_free(new_init);
errno = ENOENT;
return -1;
}
+ expr_free(left);
+ expr_free(i);
compound_expr_add(new_init, range);
left = NULL;
} else {
if (left) {
- range = get_set_interval_end(table,
- set->handle.set.name,
- left);
+ range = get_set_interval_find(cache_set,
+ left, NULL);
if (range)
compound_expr_add(new_init, range);
else
compound_expr_add(new_init,
- expr_clone(left));
+ expr_to_set_elem(left));
}
left = i;
}
}
if (left) {
- range = get_set_interval_end(table, set->handle.set.name, left);
+ range = get_set_interval_find(cache_set, left, NULL);
if (range)
compound_expr_add(new_init, range);
else
- compound_expr_add(new_init, expr_clone(left));
+ compound_expr_add(new_init, expr_to_set_elem(left));
}
expr_free(set->init);
@@ -784,24 +272,15 @@ static bool range_is_prefix(const mpz_t range)
return ret;
}
-static struct expr *expr_value(struct expr *expr)
-{
- switch (expr->etype) {
- case EXPR_MAPPING:
- return expr->left->key;
- case EXPR_SET_ELEM:
- return expr->key;
- default:
- BUG("invalid expression type %s\n", expr_name(expr));
- }
-}
-
static int expr_value_cmp(const void *p1, const void *p2)
{
struct expr *e1 = *(void * const *)p1;
struct expr *e2 = *(void * const *)p2;
int ret;
+ if (expr_value(e1)->etype == EXPR_CONCAT)
+ return -1;
+
ret = mpz_cmp(expr_value(e1)->value, expr_value(e2)->value);
if (ret == 0) {
if (e1->flags & EXPR_F_INTERVAL_END)
@@ -813,12 +292,251 @@ static int expr_value_cmp(const void *p1, const void *p2)
return ret;
}
+/* Given start and end elements of a range, check if it can be represented as
+ * a single netmask, and if so, how long, by returning zero or a positive value.
+ */
+static int range_mask_len(const mpz_t start, const mpz_t end, unsigned int len)
+{
+ mpz_t tmp_start, tmp_end;
+ int ret;
+
+ mpz_init_set(tmp_start, start);
+ mpz_init_set(tmp_end, end);
+
+ while (mpz_cmp(tmp_start, tmp_end) <= 0 &&
+ !mpz_tstbit(tmp_start, 0) && mpz_tstbit(tmp_end, 0) &&
+ len--) {
+ mpz_fdiv_q_2exp(tmp_start, tmp_start, 1);
+ mpz_fdiv_q_2exp(tmp_end, tmp_end, 1);
+ }
+
+ ret = !mpz_cmp(tmp_start, tmp_end) ? (int)len : -1;
+
+ mpz_clear(tmp_start);
+ mpz_clear(tmp_end);
+
+ return ret;
+}
+
+/* Given a set with two elements (start and end), transform them into a
+ * concatenation of ranges. That is, from a list of start expressions and a list
+ * of end expressions, form a list of start - end expressions.
+ */
+void concat_range_aggregate(struct expr *set)
+{
+ struct expr *i, *start = NULL, *end, *r1, *r2, *next, *r1_next, *tmp;
+ struct list_head *r2_next;
+ int prefix_len, free_r1;
+ mpz_t range, p;
+
+ list_for_each_entry_safe(i, next, &set->expressions, list) {
+ if (!start) {
+ start = i;
+ continue;
+ }
+ end = i;
+
+ /* Walk over r1 (start expression) and r2 (end) in parallel,
+ * form ranges between corresponding r1 and r2 expressions,
+ * store them by replacing r2 expressions, and free r1
+ * expressions.
+ */
+ r2 = list_first_entry(&expr_value(end)->expressions,
+ struct expr, list);
+ list_for_each_entry_safe(r1, r1_next,
+ &expr_value(start)->expressions,
+ list) {
+ bool string_type = false;
+
+ mpz_init(range);
+ mpz_init(p);
+
+ r2_next = r2->list.next;
+ free_r1 = 0;
+
+ if (!mpz_cmp(r1->value, r2->value)) {
+ free_r1 = 1;
+ goto next;
+ }
+
+ if (expr_basetype(r1)->type == TYPE_STRING &&
+ expr_basetype(r2)->type == TYPE_STRING) {
+ string_type = true;
+ mpz_switch_byteorder(r1->value, r1->len / BITS_PER_BYTE);
+ mpz_switch_byteorder(r2->value, r2->len / BITS_PER_BYTE);
+ }
+
+ mpz_sub(range, r2->value, r1->value);
+ mpz_sub_ui(range, range, 1);
+ mpz_and(p, r1->value, range);
+
+ /* Check if we are forced, or if it's anyway preferable,
+ * to express the range as a wildcard string, or two points
+ * instead of a netmask.
+ */
+ prefix_len = range_mask_len(r1->value, r2->value,
+ r1->len);
+ if (string_type) {
+ mpz_switch_byteorder(r1->value, r1->len / BITS_PER_BYTE);
+ mpz_switch_byteorder(r2->value, r2->len / BITS_PER_BYTE);
+ }
+
+ if (prefix_len >= 0 &&
+ (prefix_len % BITS_PER_BYTE) == 0 &&
+ string_type) {
+ unsigned int str_len = prefix_len / BITS_PER_BYTE;
+ char data[str_len + 2];
+
+ mpz_export_data(data, r1->value, BYTEORDER_HOST_ENDIAN, str_len);
+ data[str_len] = '*';
+
+ tmp = constant_expr_alloc(&r1->location, r1->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ (str_len + 1) * BITS_PER_BYTE, data);
+ tmp->len = r2->len;
+ list_replace(&r2->list, &tmp->list);
+ r2_next = tmp->list.next;
+ expr_free(r2);
+ free_r1 = 1;
+ goto next;
+ }
+
+ if (prefix_len < 0 ||
+ !(r1->dtype->flags & DTYPE_F_PREFIX)) {
+ tmp = range_expr_alloc(&r1->location, r1,
+ r2);
+
+ list_replace(&r2->list, &tmp->list);
+ r2_next = tmp->list.next;
+ } else {
+ tmp = prefix_expr_alloc(&r1->location, r1,
+ prefix_len);
+ tmp->len = r2->len;
+
+ list_replace(&r2->list, &tmp->list);
+ r2_next = tmp->list.next;
+ expr_free(r2);
+ }
+
+next:
+ mpz_clear(p);
+ mpz_clear(range);
+
+ r2 = list_entry(r2_next, typeof(*r2), list);
+ compound_expr_remove(start, r1);
+
+ if (free_r1)
+ expr_free(r1);
+ }
+
+ compound_expr_remove(set, start);
+ expr_free(start);
+ start = NULL;
+ }
+}
+
+static struct expr *interval_to_prefix(struct expr *low, struct expr *i, const mpz_t range)
+{
+ unsigned int prefix_len;
+ struct expr *prefix;
+
+ prefix_len = expr_value(i)->len - mpz_scan0(range, 0);
+ prefix = prefix_expr_alloc(&low->location,
+ expr_clone(expr_value(low)),
+ prefix_len);
+ prefix->len = expr_value(i)->len;
+
+ return __expr_to_set_elem(low, prefix);
+}
+
+static struct expr *interval_to_string(struct expr *low, struct expr *i, const mpz_t range)
+{
+ unsigned int len = div_round_up(i->len, BITS_PER_BYTE);
+ unsigned int prefix_len, str_len;
+ char data[len + 2];
+ struct expr *expr;
+
+ prefix_len = expr_value(i)->len - mpz_scan0(range, 0);
+
+ if (prefix_len > i->len || prefix_len % BITS_PER_BYTE)
+ return interval_to_prefix(low, i, range);
+
+ mpz_export_data(data, expr_value(low)->value, BYTEORDER_BIG_ENDIAN, len);
+
+ str_len = strnlen(data, len);
+ if (str_len >= len || str_len == 0)
+ return interval_to_prefix(low, i, range);
+
+ data[str_len] = '*';
+
+ expr = constant_expr_alloc(&low->location, low->dtype,
+ BYTEORDER_HOST_ENDIAN,
+ (str_len + 1) * BITS_PER_BYTE, data);
+
+ return __expr_to_set_elem(low, expr);
+}
+
+static struct expr *interval_to_range(struct expr *low, struct expr *i, mpz_t range)
+{
+ struct expr *tmp;
+
+ tmp = constant_expr_alloc(&low->location, low->dtype,
+ low->byteorder, expr_value(low)->len,
+ NULL);
+
+ mpz_add(range, range, expr_value(low)->value);
+ mpz_set(tmp->value, range);
+
+ tmp = range_expr_alloc(&low->location,
+ expr_clone(expr_value(low)),
+ tmp);
+
+ return __expr_to_set_elem(low, tmp);
+}
+
+static void
+add_interval(struct expr *set, struct expr *low, struct expr *i)
+{
+ struct expr *expr;
+ mpz_t range, p;
+
+ mpz_init(range);
+ mpz_init(p);
+
+ mpz_sub(range, expr_value(i)->value, expr_value(low)->value);
+ if (i->etype != EXPR_VALUE)
+ mpz_sub_ui(range, range, 1);
+
+ mpz_and(p, expr_value(low)->value, range);
+
+ if (!mpz_cmp_ui(range, 0)) {
+ if (expr_basetype(low)->type == TYPE_STRING)
+ mpz_switch_byteorder(expr_value(low)->value,
+ expr_value(low)->len / BITS_PER_BYTE);
+ low->flags |= EXPR_F_KERNEL;
+ expr = expr_get(low);
+ } else if (range_is_prefix(range) && !mpz_cmp_ui(p, 0)) {
+
+ if (i->dtype->flags & DTYPE_F_PREFIX)
+ expr = interval_to_prefix(low, i, range);
+ else if (expr_basetype(i)->type == TYPE_STRING)
+ expr = interval_to_string(low, i, range);
+ else
+ expr = interval_to_range(low, i, range);
+ } else
+ expr = interval_to_range(low, i, range);
+
+ compound_expr_add(set, expr);
+
+ mpz_clear(range);
+ mpz_clear(p);
+}
+
void interval_map_decompose(struct expr *set)
{
+ struct expr *i, *next, *low = NULL, *end, *catchall = NULL, *key;
struct expr **elements, **ranges;
- struct expr *i, *next, *low = NULL, *end;
unsigned int n, m, size;
- mpz_t range, p;
bool interval;
if (set->size == 0)
@@ -827,12 +545,20 @@ void interval_map_decompose(struct expr *set)
elements = xmalloc_array(set->size, sizeof(struct expr *));
ranges = xmalloc_array(set->size * 2, sizeof(struct expr *));
- mpz_init(range);
- mpz_init(p);
-
/* Sort elements */
n = 0;
list_for_each_entry_safe(i, next, &set->expressions, list) {
+ key = NULL;
+ if (i->etype == EXPR_SET_ELEM)
+ key = i->key;
+ else if (i->etype == EXPR_MAPPING)
+ key = i->left->key;
+
+ if (key && key->etype == EXPR_SET_ELEM_CATCHALL) {
+ list_del(&i->list);
+ catchall = i;
+ continue;
+ }
compound_expr_remove(set, i);
elements[n++] = i;
}
@@ -877,83 +603,7 @@ void interval_map_decompose(struct expr *set)
}
}
- mpz_sub(range, expr_value(i)->value, expr_value(low)->value);
- mpz_sub_ui(range, range, 1);
-
- mpz_and(p, expr_value(low)->value, range);
-
- if (!mpz_cmp_ui(range, 0))
- compound_expr_add(set, expr_get(low));
- else if ((!range_is_prefix(range) ||
- !(i->dtype->flags & DTYPE_F_PREFIX)) ||
- mpz_cmp_ui(p, 0)) {
- struct expr *tmp;
-
- tmp = constant_expr_alloc(&low->location, low->dtype,
- low->byteorder, expr_value(low)->len,
- NULL);
-
- mpz_add(range, range, expr_value(low)->value);
- mpz_set(tmp->value, range);
-
- tmp = range_expr_alloc(&low->location,
- expr_clone(expr_value(low)),
- tmp);
- tmp = set_elem_expr_alloc(&low->location, tmp);
-
- if (low->etype == EXPR_MAPPING) {
- if (low->left->comment)
- tmp->comment = xstrdup(low->left->comment);
- if (low->left->timeout)
- tmp->timeout = low->left->timeout;
- if (low->left->expiration)
- tmp->expiration = low->left->expiration;
-
- tmp = mapping_expr_alloc(&tmp->location, tmp,
- expr_clone(low->right));
- } else {
- if (low->comment)
- tmp->comment = xstrdup(low->comment);
- if (low->timeout)
- tmp->timeout = low->timeout;
- if (low->expiration)
- tmp->expiration = low->expiration;
- }
-
- compound_expr_add(set, tmp);
- } else {
- struct expr *prefix;
- unsigned int prefix_len;
-
- prefix_len = expr_value(i)->len - mpz_scan0(range, 0);
- prefix = prefix_expr_alloc(&low->location,
- expr_clone(expr_value(low)),
- prefix_len);
- prefix->len = expr_value(i)->len;
-
- prefix = set_elem_expr_alloc(&low->location, prefix);
-
- if (low->etype == EXPR_MAPPING) {
- if (low->left->comment)
- prefix->comment = xstrdup(low->left->comment);
- if (low->left->timeout)
- prefix->timeout = low->left->timeout;
- if (low->left->expiration)
- prefix->expiration = low->left->expiration;
-
- prefix = mapping_expr_alloc(&low->location, prefix,
- expr_clone(low->right));
- } else {
- if (low->comment)
- prefix->comment = xstrdup(low->comment);
- if (low->timeout)
- prefix->timeout = low->timeout;
- if (low->left->expiration)
- prefix->expiration = low->expiration;
- }
-
- compound_expr_add(set, prefix);
- }
+ add_interval(set, low, i);
if (i->flags & EXPR_F_INTERVAL_END) {
expr_free(low);
@@ -967,23 +617,21 @@ void interval_map_decompose(struct expr *set)
i = constant_expr_alloc(&low->location, low->dtype,
low->byteorder, expr_value(low)->len, NULL);
- mpz_init_bitmask(i->value, i->len);
+ mpz_bitmask(i->value, i->len);
if (!mpz_cmp(i->value, expr_value(low)->value)) {
- expr_free(i);
- i = low;
+ compound_expr_add(set, low);
} else {
- i = range_expr_alloc(&low->location, expr_value(low), i);
- i = set_elem_expr_alloc(&low->location, i);
- if (low->etype == EXPR_MAPPING)
- i = mapping_expr_alloc(&i->location, i, low->right);
+ add_interval(set, low, i);
+ expr_free(low);
}
- compound_expr_add(set, i);
+ expr_free(i);
+
out:
- mpz_clear(range);
- mpz_clear(p);
+ if (catchall)
+ compound_expr_add(set, catchall);
- xfree(ranges);
- xfree(elements);
+ free(ranges);
+ free(elements);
}
diff --git a/src/socket.c b/src/socket.c
index e10b3226..8a149e63 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -4,10 +4,12 @@
* Copyright (c) 2018 Máté Eckl <ecklm94@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
*/
+#include <nft.h>
+
#include <nftables.h>
#include <expression.h>
#include <socket.h>
@@ -26,21 +28,86 @@ const struct socket_template socket_templates[] = {
.len = 4 * BITS_PER_BYTE,
.byteorder = BYTEORDER_HOST_ENDIAN,
},
+ [NFT_SOCKET_WILDCARD] = {
+ .token = "wildcard",
+ .dtype = &integer_type,
+ .len = BITS_PER_BYTE,
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ },
+ [NFT_SOCKET_CGROUPV2] = {
+ .token = "cgroupv2",
+ .dtype = &cgroupv2_type,
+ .len = 8 * BITS_PER_BYTE,
+ .byteorder = BYTEORDER_HOST_ENDIAN,
+ },
};
static void socket_expr_print(const struct expr *expr, struct output_ctx *octx)
{
nft_print(octx, "socket %s", socket_templates[expr->socket.key].token);
+ if (expr->socket.key == NFT_SOCKET_CGROUPV2)
+ nft_print(octx, " level %u", expr->socket.level);
}
static bool socket_expr_cmp(const struct expr *e1, const struct expr *e2)
{
- return e1->socket.key == e2->socket.key;
+ return e1->socket.key == e2->socket.key &&
+ e1->socket.level == e2->socket.level;
}
static void socket_expr_clone(struct expr *new, const struct expr *expr)
{
new->socket.key = expr->socket.key;
+ new->socket.level = expr->socket.level;
+}
+
+#define NFTNL_UDATA_SOCKET_KEY 0
+#define NFTNL_UDATA_SOCKET_MAX 1
+
+static int socket_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SOCKET_KEY, expr->socket.key);
+
+ return 0;
+}
+
+static int socket_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_SOCKET_KEY:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *socket_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_SOCKET_MAX + 1] = {};
+ uint32_t key;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ socket_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_SOCKET_KEY])
+ return NULL;
+
+ key = nftnl_udata_get_u32(ud[NFTNL_UDATA_SOCKET_KEY]);
+
+ return socket_expr_alloc(&internal_location, key, 0);
}
const struct expr_ops socket_expr_ops = {
@@ -50,9 +117,12 @@ const struct expr_ops socket_expr_ops = {
.json = socket_expr_json,
.cmp = socket_expr_cmp,
.clone = socket_expr_clone,
+ .build_udata = socket_expr_build_udata,
+ .parse_udata = socket_expr_parse_udata,
};
-struct expr *socket_expr_alloc(const struct location *loc, enum nft_socket_keys key)
+struct expr *socket_expr_alloc(const struct location *loc,
+ enum nft_socket_keys key, uint32_t level)
{
const struct socket_template *tmpl = &socket_templates[key];
struct expr *expr;
@@ -60,6 +130,7 @@ struct expr *socket_expr_alloc(const struct location *loc, enum nft_socket_keys
expr = expr_alloc(loc, EXPR_SOCKET, tmpl->dtype,
tmpl->byteorder, tmpl->len);
expr->socket.key = key;
+ expr->socket.level = level;
return expr;
}
diff --git a/src/statement.c b/src/statement.c
index af84e06c..ab144d63 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -8,19 +8,21 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <stddef.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
#include <inttypes.h>
-#include <string.h>
#include <syslog.h>
+#include <rule.h>
#include <arpa/inet.h>
#include <linux/netfilter.h>
+#include <linux/netfilter/nf_log.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
#include <statement.h>
+#include <tcpopt.h>
#include <utils.h>
#include <list.h>
#include <xt.h>
@@ -49,7 +51,7 @@ void stmt_free(struct stmt *stmt)
return;
if (stmt->ops->destroy)
stmt->ops->destroy(stmt);
- xfree(stmt);
+ free(stmt);
}
void stmt_list_free(struct list_head *list)
@@ -111,6 +113,50 @@ struct stmt *verdict_stmt_alloc(const struct location *loc, struct expr *expr)
return stmt;
}
+static const char *chain_verdict(const struct expr *expr)
+{
+ switch (expr->verdict) {
+ case NFT_JUMP:
+ return "jump";
+ case NFT_GOTO:
+ return "goto";
+ default:
+ BUG("unknown chain verdict");
+ }
+}
+
+static void chain_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ nft_print(octx, "%s {\n", chain_verdict(stmt->chain.expr));
+ chain_rules_print(stmt->chain.chain, octx, "\t");
+ nft_print(octx, "\t\t}");
+}
+
+static void chain_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->chain.expr);
+}
+
+static const struct stmt_ops chain_stmt_ops = {
+ .type = STMT_CHAIN,
+ .name = "chain",
+ .print = chain_stmt_print,
+ .destroy = chain_stmt_destroy,
+};
+
+struct stmt *chain_stmt_alloc(const struct location *loc, struct chain *chain,
+ enum nft_verdicts verdict)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &chain_stmt_ops);
+ stmt->chain.chain = chain;
+ stmt->chain.expr = verdict_expr_alloc(loc, verdict, NULL);
+ stmt->chain.expr->chain_id = chain->handle.chain_id;
+
+ return stmt;
+}
+
static void meter_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
{
unsigned int flags = octx->flags;
@@ -137,7 +183,7 @@ static void meter_stmt_destroy(struct stmt *stmt)
expr_free(stmt->meter.key);
expr_free(stmt->meter.set);
stmt_free(stmt->meter.stmt);
- xfree(stmt->meter.name);
+ free_const(stmt->meter.name);
}
static const struct stmt_ops meter_stmt_ops = {
@@ -155,7 +201,7 @@ struct stmt *meter_stmt_alloc(const struct location *loc)
static void connlimit_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
{
- nft_print(octx, "ct count %s%u ",
+ nft_print(octx, "ct count %s%u",
stmt->connlimit.flags ? "over " : "", stmt->connlimit.count);
}
@@ -202,6 +248,37 @@ struct stmt *counter_stmt_alloc(const struct location *loc)
return stmt;
}
+static void last_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ nft_print(octx, "last");
+
+ if (nft_output_stateless(octx))
+ return;
+
+ nft_print(octx, " used ");
+
+ if (stmt->last.set)
+ time_print(stmt->last.used, octx);
+ else
+ nft_print(octx, "never");
+}
+
+static const struct stmt_ops last_stmt_ops = {
+ .type = STMT_LAST,
+ .name = "last",
+ .print = last_stmt_print,
+ .json = last_stmt_json,
+};
+
+struct stmt *last_stmt_alloc(const struct location *loc)
+{
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &last_stmt_ops);
+ stmt->flags |= STMT_F_STATEFUL;
+ return stmt;
+}
+
static const char *objref_type[NFT_OBJECT_MAX + 1] = {
[NFT_OBJECT_COUNTER] = "counter",
[NFT_OBJECT_QUOTA] = "quota",
@@ -233,6 +310,9 @@ static void objref_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
case NFT_OBJECT_CT_EXPECT:
nft_print(octx, "ct expectation set ");
break;
+ case NFT_OBJECT_SECMARK:
+ nft_print(octx, "meta secmark set ");
+ break;
default:
nft_print(octx, "%s name ",
objref_type_name(stmt->objref.type));
@@ -297,8 +377,12 @@ int log_level_parse(const char *level)
static void log_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
{
nft_print(octx, "log");
- if (stmt->log.flags & STMT_LOG_PREFIX)
- nft_print(octx, " prefix \"%s\"", stmt->log.prefix);
+ if (stmt->log.flags & STMT_LOG_PREFIX) {
+ char prefix[NF_LOG_PREFIXLEN] = {};
+
+ expr_to_string(stmt->log.prefix, prefix);
+ nft_print(octx, " prefix \"%s\"", prefix);
+ }
if (stmt->log.flags & STMT_LOG_GROUP)
nft_print(octx, " group %u", stmt->log.group);
if (stmt->log.flags & STMT_LOG_SNAPLEN)
@@ -335,7 +419,7 @@ static void log_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
static void log_stmt_destroy(struct stmt *stmt)
{
- xfree(stmt->log.prefix);
+ expr_free(stmt->log.prefix);
}
static const struct stmt_ops log_stmt_ops = {
@@ -401,9 +485,7 @@ static void limit_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
nft_print(octx, "limit rate %s%" PRIu64 "/%s",
inv ? "over " : "", stmt->limit.rate,
get_unit(stmt->limit.unit));
- if (stmt->limit.burst && stmt->limit.burst != 5)
- nft_print(octx, " burst %u packets",
- stmt->limit.burst);
+ nft_print(octx, " burst %u packets", stmt->limit.burst);
break;
case NFT_LIMIT_PKT_BYTES:
data_unit = get_rate(stmt->limit.rate, &rate);
@@ -411,7 +493,7 @@ static void limit_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
nft_print(octx, "limit rate %s%" PRIu64 " %s/%s",
inv ? "over " : "", rate, data_unit,
get_unit(stmt->limit.unit));
- if (stmt->limit.burst > 0) {
+ if (stmt->limit.burst != 0) {
uint64_t burst;
data_unit = get_rate(stmt->limit.burst, &burst);
@@ -440,20 +522,25 @@ struct stmt *limit_stmt_alloc(const struct location *loc)
static void queue_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
{
- const char *delim = " ";
+ struct expr *e = stmt->queue.queue;
+ const char *delim = " flags ";
nft_print(octx, "queue");
- if (stmt->queue.queue != NULL) {
- nft_print(octx, " num ");
- expr_print(stmt->queue.queue, octx);
- }
+
if (stmt->queue.flags & NFT_QUEUE_FLAG_BYPASS) {
nft_print(octx, "%sbypass", delim);
delim = ",";
}
+
if (stmt->queue.flags & NFT_QUEUE_FLAG_CPU_FANOUT)
nft_print(octx, "%sfanout", delim);
+ if (e) {
+ nft_print(octx, " to ");
+ expr_print(stmt->queue.queue, octx);
+ } else {
+ nft_print(octx, " to 0");
+ }
}
static void queue_stmt_destroy(struct stmt *stmt)
@@ -469,9 +556,15 @@ static const struct stmt_ops queue_stmt_ops = {
.destroy = queue_stmt_destroy,
};
-struct stmt *queue_stmt_alloc(const struct location *loc)
+struct stmt *queue_stmt_alloc(const struct location *loc, struct expr *e, uint16_t flags)
{
- return stmt_alloc(loc, &queue_stmt_ops);
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &queue_stmt_ops);
+ stmt->queue.queue = e;
+ stmt->queue.flags = flags;
+
+ return stmt;
}
static void quota_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
@@ -516,7 +609,7 @@ static void reject_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
case NFT_REJECT_ICMPX_UNREACH:
if (stmt->reject.icmp_code == NFT_REJECT_ICMPX_PORT_UNREACH)
break;
- nft_print(octx, " with icmpx type ");
+ nft_print(octx, " with icmpx ");
expr_print(stmt->reject.expr, octx);
break;
case NFT_REJECT_ICMP_UNREACH:
@@ -525,14 +618,14 @@ static void reject_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
if (!stmt->reject.verbose_print &&
stmt->reject.icmp_code == ICMP_PORT_UNREACH)
break;
- nft_print(octx, " with icmp type ");
+ nft_print(octx, " with icmp ");
expr_print(stmt->reject.expr, octx);
break;
case NFPROTO_IPV6:
if (!stmt->reject.verbose_print &&
stmt->reject.icmp_code == ICMP6_DST_UNREACH_NOPORT)
break;
- nft_print(octx, " with icmpv6 type ");
+ nft_print(octx, " with icmpv6 ");
expr_print(stmt->reject.expr, octx);
break;
}
@@ -604,6 +697,9 @@ static void nat_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
break;
}
+ if (stmt->nat.type_flags & STMT_NAT_F_PREFIX)
+ nft_print(octx, " prefix");
+
nft_print(octx, " to");
}
@@ -672,15 +768,16 @@ const char * const set_stmt_op_names[] = {
static void set_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
{
unsigned int flags = octx->flags;
+ struct stmt *this;
nft_print(octx, "%s ", set_stmt_op_names[stmt->set.op]);
expr_print(stmt->set.set, octx);
nft_print(octx, " { ");
expr_print(stmt->set.key, octx);
- if (stmt->set.stmt) {
+ list_for_each_entry(this, &stmt->set.stmt_list, list) {
nft_print(octx, " ");
octx->flags |= NFT_CTX_OUTPUT_STATELESS;
- stmt_print(stmt->set.stmt, octx);
+ stmt_print(this, octx);
octx->flags = flags;
}
nft_print(octx, " }");
@@ -688,9 +785,12 @@ static void set_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
static void set_stmt_destroy(struct stmt *stmt)
{
+ struct stmt *this, *next;
+
expr_free(stmt->set.key);
expr_free(stmt->set.set);
- stmt_free(stmt->set.stmt);
+ list_for_each_entry_safe(this, next, &stmt->set.stmt_list, list)
+ stmt_free(this);
}
static const struct stmt_ops set_stmt_ops = {
@@ -703,21 +803,27 @@ static const struct stmt_ops set_stmt_ops = {
struct stmt *set_stmt_alloc(const struct location *loc)
{
- return stmt_alloc(loc, &set_stmt_ops);
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &set_stmt_ops);
+ init_list_head(&stmt->set.stmt_list);
+
+ return stmt;
}
static void map_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
{
unsigned int flags = octx->flags;
+ struct stmt *this;
nft_print(octx, "%s ", set_stmt_op_names[stmt->map.op]);
expr_print(stmt->map.set, octx);
nft_print(octx, " { ");
expr_print(stmt->map.key, octx);
- if (stmt->map.stmt) {
+ list_for_each_entry(this, &stmt->map.stmt_list, list) {
nft_print(octx, " ");
octx->flags |= NFT_CTX_OUTPUT_STATELESS;
- stmt_print(stmt->map.stmt, octx);
+ stmt_print(this, octx);
octx->flags = flags;
}
nft_print(octx, " : ");
@@ -727,10 +833,13 @@ static void map_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
static void map_stmt_destroy(struct stmt *stmt)
{
+ struct stmt *this, *next;
+
expr_free(stmt->map.key);
expr_free(stmt->map.data);
expr_free(stmt->map.set);
- stmt_free(stmt->map.stmt);
+ list_for_each_entry_safe(this, next, &stmt->map.stmt_list, list)
+ stmt_free(this);
}
static const struct stmt_ops map_stmt_ops = {
@@ -738,11 +847,17 @@ static const struct stmt_ops map_stmt_ops = {
.name = "map",
.print = map_stmt_print,
.destroy = map_stmt_destroy,
+ .json = map_stmt_json,
};
struct stmt *map_stmt_alloc(const struct location *loc)
{
- return stmt_alloc(loc, &map_stmt_ops);
+ struct stmt *stmt;
+
+ stmt = stmt_alloc(loc, &map_stmt_ops);
+ init_list_head(&stmt->map.stmt_list);
+
+ return stmt;
}
static void dup_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
@@ -824,6 +939,37 @@ struct stmt *fwd_stmt_alloc(const struct location *loc)
return stmt_alloc(loc, &fwd_stmt_ops);
}
+static void optstrip_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
+{
+ const struct expr *expr = stmt->optstrip.expr;
+
+ nft_print(octx, "reset ");
+ expr_print(expr, octx);
+}
+
+static void optstrip_stmt_destroy(struct stmt *stmt)
+{
+ expr_free(stmt->optstrip.expr);
+}
+
+static const struct stmt_ops optstrip_stmt_ops = {
+ .type = STMT_OPTSTRIP,
+ .name = "optstrip",
+ .print = optstrip_stmt_print,
+ .json = optstrip_stmt_json,
+ .destroy = optstrip_stmt_destroy,
+};
+
+struct stmt *optstrip_stmt_alloc(const struct location *loc, struct expr *e)
+{
+ struct stmt *stmt = stmt_alloc(loc, &optstrip_stmt_ops);
+
+ e->exthdr.flags |= NFT_EXTHDR_F_PRESENT;
+ stmt->optstrip.expr = e;
+
+ return stmt;
+}
+
static void tproxy_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
{
nft_print(octx, "tproxy");
@@ -843,7 +989,7 @@ static void tproxy_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
expr_print(stmt->tproxy.addr, octx);
}
}
- if (stmt->tproxy.port && stmt->tproxy.port->etype == EXPR_VALUE) {
+ if (stmt->tproxy.port) {
if (!stmt->tproxy.addr)
nft_print(octx, " ");
nft_print(octx, ":");
@@ -880,6 +1026,7 @@ static const struct stmt_ops xt_stmt_ops = {
.name = "xt",
.print = xt_stmt_print,
.destroy = xt_stmt_destroy,
+ .json = xt_stmt_json,
};
struct stmt *xt_stmt_alloc(const struct location *loc)
diff --git a/src/tcpopt.c b/src/tcpopt.c
index ec305d94..f977e417 100644
--- a/src/tcpopt.c
+++ b/src/tcpopt.c
@@ -1,8 +1,7 @@
+#include <nft.h>
+
#include <stddef.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
@@ -20,221 +19,269 @@ static const struct proto_hdr_template tcpopt_unknown_template =
__offset, __len)
static const struct exthdr_desc tcpopt_eol = {
.name = "eol",
- .type = TCPOPT_EOL,
+ .type = TCPOPT_KIND_EOL,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
},
};
static const struct exthdr_desc tcpopt_nop = {
- .name = "noop",
- .type = TCPOPT_NOP,
+ .name = "nop",
+ .type = TCPOPT_KIND_NOP,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
},
};
static const struct exthdr_desc tcptopt_maxseg = {
.name = "maxseg",
- .type = TCPOPT_MAXSEG,
+ .type = TCPOPT_KIND_MAXSEG,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
- [TCPOPTHDR_FIELD_SIZE] = PHT("size", 16, 16),
+ [TCPOPT_MAXSEG_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_MAXSEG_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_MAXSEG_SIZE] = PHT("size", 16, 16),
},
};
static const struct exthdr_desc tcpopt_window = {
.name = "window",
- .type = TCPOPT_WINDOW,
+ .type = TCPOPT_KIND_WINDOW,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
- [TCPOPTHDR_FIELD_COUNT] = PHT("count", 16, 8),
+ [TCPOPT_WINDOW_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_WINDOW_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_WINDOW_COUNT] = PHT("count", 16, 8),
},
};
static const struct exthdr_desc tcpopt_sack_permitted = {
- .name = "sack-permitted",
- .type = TCPOPT_SACK_PERMITTED,
+ .name = "sack-perm",
+ .type = TCPOPT_KIND_SACK_PERMITTED,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_LENGTH] = PHT("length", 8, 8),
},
};
static const struct exthdr_desc tcpopt_sack = {
.name = "sack",
- .type = TCPOPT_SACK,
+ .type = TCPOPT_KIND_SACK,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
- [TCPOPTHDR_FIELD_LEFT] = PHT("left", 16, 32),
- [TCPOPTHDR_FIELD_RIGHT] = PHT("right", 48, 32),
+ [TCPOPT_SACK_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_SACK_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_SACK_LEFT] = PHT("left", 16, 32),
+ [TCPOPT_SACK_RIGHT] = PHT("right", 48, 32),
+ [TCPOPT_SACK_LEFT1] = PHT("left", 80, 32),
+ [TCPOPT_SACK_RIGHT1] = PHT("right", 112, 32),
+ [TCPOPT_SACK_LEFT2] = PHT("left", 144, 32),
+ [TCPOPT_SACK_RIGHT2] = PHT("right", 176, 32),
+ [TCPOPT_SACK_LEFT3] = PHT("left", 208, 32),
+ [TCPOPT_SACK_RIGHT3] = PHT("right", 240, 32),
},
};
static const struct exthdr_desc tcpopt_timestamp = {
.name = "timestamp",
- .type = TCPOPT_TIMESTAMP,
+ .type = TCPOPT_KIND_TIMESTAMP,
.templates = {
- [TCPOPTHDR_FIELD_KIND] = PHT("kind", 0, 8),
- [TCPOPTHDR_FIELD_LENGTH] = PHT("length", 8, 8),
- [TCPOPTHDR_FIELD_TSVAL] = PHT("tsval", 16, 32),
- [TCPOPTHDR_FIELD_TSECR] = PHT("tsecr", 48, 32),
+ [TCPOPT_TS_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_TS_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_TS_TSVAL] = PHT("tsval", 16, 32),
+ [TCPOPT_TS_TSECR] = PHT("tsecr", 48, 32),
},
};
-#undef PHT
-#define TCPOPT_OBSOLETE ((struct exthdr_desc *)NULL)
-#define TCPOPT_ECHO 6
-#define TCPOPT_ECHO_REPLY 7
-static const struct exthdr_desc *tcpopt_protocols[] = {
- [TCPOPT_EOL] = &tcpopt_eol,
- [TCPOPT_NOP] = &tcpopt_nop,
- [TCPOPT_MAXSEG] = &tcptopt_maxseg,
- [TCPOPT_WINDOW] = &tcpopt_window,
- [TCPOPT_SACK_PERMITTED] = &tcpopt_sack_permitted,
- [TCPOPT_SACK] = &tcpopt_sack,
- [TCPOPT_ECHO] = TCPOPT_OBSOLETE,
- [TCPOPT_ECHO_REPLY] = TCPOPT_OBSOLETE,
- [TCPOPT_TIMESTAMP] = &tcpopt_timestamp,
+static const struct exthdr_desc tcpopt_fastopen = {
+ .name = "fastopen",
+ .type = TCPOPT_KIND_FASTOPEN,
+ .templates = {
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_LENGTH] = PHT("length", 8, 8),
+ },
};
-static unsigned int calc_offset(const struct exthdr_desc *desc,
- const struct proto_hdr_template *tmpl,
- unsigned int num)
-{
- if (!desc || tmpl == &tcpopt_unknown_template)
- return 0;
-
- switch (desc->type) {
- case TCPOPT_SACK:
- /* Make sure, offset calculations only apply to left and right
- * fields
- */
- return (tmpl->offset < 16) ? 0 : num * 64;
- default:
- return 0;
- }
-}
+static const struct exthdr_desc tcpopt_md5sig = {
+ .name = "md5sig",
+ .type = TCPOPT_KIND_MD5SIG,
+ .templates = {
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_LENGTH] = PHT("length", 8, 8),
+ },
+};
-static unsigned int calc_offset_reverse(const struct exthdr_desc *desc,
- const struct proto_hdr_template *tmpl,
- unsigned int offset)
-{
- if (!desc || tmpl == &tcpopt_unknown_template)
- return offset;
-
- switch (desc->type) {
- case TCPOPT_SACK:
- /* We can safely ignore the first left/right field */
- return offset < 80 ? offset : (offset % 64);
- default:
- return offset;
- }
-}
+static const struct exthdr_desc tcpopt_mptcp = {
+ .name = "mptcp",
+ .type = TCPOPT_KIND_MPTCP,
+ .templates = {
+ [TCPOPT_MPTCP_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_MPTCP_LENGTH] = PHT("length", 8, 8),
+ [TCPOPT_MPTCP_SUBTYPE] = PHT("subtype", 16, 4),
+ },
+};
-const struct exthdr_desc *tcpopthdr_protocols[__TCPOPTHDR_MAX] = {
- [TCPOPTHDR_EOL] = &tcpopt_eol,
- [TCPOPTHDR_NOOP] = &tcpopt_nop,
- [TCPOPTHDR_MAXSEG] = &tcptopt_maxseg,
- [TCPOPTHDR_WINDOW] = &tcpopt_window,
- [TCPOPTHDR_SACK_PERMITTED] = &tcpopt_sack_permitted,
- [TCPOPTHDR_SACK0] = &tcpopt_sack,
- [TCPOPTHDR_SACK1] = &tcpopt_sack,
- [TCPOPTHDR_SACK2] = &tcpopt_sack,
- [TCPOPTHDR_SACK3] = &tcpopt_sack,
- [TCPOPTHDR_ECHO] = TCPOPT_OBSOLETE,
- [TCPOPTHDR_ECHO_REPLY] = TCPOPT_OBSOLETE,
- [TCPOPTHDR_TIMESTAMP] = &tcpopt_timestamp,
+static const struct exthdr_desc tcpopt_fallback = {
+ .templates = {
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_LENGTH] = PHT("length", 8, 8),
+ },
};
+#undef PHT
-static uint8_t tcpopt_optnum[] = {
- [TCPOPTHDR_SACK0] = 0,
- [TCPOPTHDR_SACK1] = 1,
- [TCPOPTHDR_SACK2] = 2,
- [TCPOPTHDR_SACK3] = 3,
+const struct exthdr_desc *tcpopt_protocols[] = {
+ [TCPOPT_KIND_EOL] = &tcpopt_eol,
+ [TCPOPT_KIND_NOP] = &tcpopt_nop,
+ [TCPOPT_KIND_MAXSEG] = &tcptopt_maxseg,
+ [TCPOPT_KIND_WINDOW] = &tcpopt_window,
+ [TCPOPT_KIND_SACK_PERMITTED] = &tcpopt_sack_permitted,
+ [TCPOPT_KIND_SACK] = &tcpopt_sack,
+ [TCPOPT_KIND_TIMESTAMP] = &tcpopt_timestamp,
+ [TCPOPT_KIND_MD5SIG] = &tcpopt_md5sig,
+ [TCPOPT_KIND_MPTCP] = &tcpopt_mptcp,
+ [TCPOPT_KIND_FASTOPEN] = &tcpopt_fastopen,
};
-static uint8_t tcpopt_find_optnum(uint8_t optnum)
+static void tcpopt_assign_tmpl(struct expr *expr,
+ const struct proto_hdr_template *tmpl,
+ const struct exthdr_desc *desc)
{
- if (optnum > TCPOPTHDR_SACK3)
- return 0;
+ expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
- return tcpopt_optnum[optnum];
+ expr->exthdr.desc = desc;
+ expr->exthdr.tmpl = tmpl;
+ expr->exthdr.offset = tmpl->offset;
}
-struct expr *tcpopt_expr_alloc(const struct location *loc, uint8_t type,
- uint8_t field)
+/**
+ * tcpopt_expr_alloc - allocate tcp option extension expression
+ *
+ * @loc: location from parser
+ * @kind: raw tcp option value to find in packet
+ * @field: highlevel field to find in the option if @kind is present in packet
+ *
+ * Allocate a new tcp option expression.
+ * @kind is the raw option value to find in the packet.
+ * Exception: SACK may use extra OOB data that is mangled here.
+ *
+ * @field is the optional field to extract from the @type option.
+ */
+struct expr *tcpopt_expr_alloc(const struct location *loc,
+ unsigned int kind,
+ unsigned int field)
{
const struct proto_hdr_template *tmpl;
- const struct exthdr_desc *desc;
+ const struct exthdr_desc *desc = NULL;
struct expr *expr;
- uint8_t optnum;
- desc = tcpopthdr_protocols[type];
+ switch (kind) {
+ case TCPOPT_KIND_SACK1:
+ kind = TCPOPT_KIND_SACK;
+ if (field == TCPOPT_SACK_LEFT)
+ field = TCPOPT_SACK_LEFT1;
+ else if (field == TCPOPT_SACK_RIGHT)
+ field = TCPOPT_SACK_RIGHT1;
+ break;
+ case TCPOPT_KIND_SACK2:
+ kind = TCPOPT_KIND_SACK;
+ if (field == TCPOPT_SACK_LEFT)
+ field = TCPOPT_SACK_LEFT2;
+ else if (field == TCPOPT_SACK_RIGHT)
+ field = TCPOPT_SACK_RIGHT2;
+ break;
+ case TCPOPT_KIND_SACK3:
+ kind = TCPOPT_KIND_SACK;
+ if (field == TCPOPT_SACK_LEFT)
+ field = TCPOPT_SACK_LEFT3;
+ else if (field == TCPOPT_SACK_RIGHT)
+ field = TCPOPT_SACK_RIGHT3;
+ break;
+ }
+
+ if (kind < array_size(tcpopt_protocols))
+ desc = tcpopt_protocols[kind];
+
+ if (!desc) {
+ if (kind > 255)
+ return NULL;
+
+ desc = &tcpopt_fallback;
+
+ switch (field) {
+ case TCPOPT_COMMON_KIND:
+ case TCPOPT_COMMON_LENGTH:
+ tmpl = &desc->templates[field];
+ break;
+ default:
+ tmpl = &tcpopt_unknown_template;
+ break;
+ }
+
+ expr = expr_alloc(loc, EXPR_EXTHDR, &integer_type,
+ BYTEORDER_BIG_ENDIAN, 8);
+
+ expr->exthdr.raw_type = kind;
+ tcpopt_assign_tmpl(expr, tmpl, desc);
+ return expr;
+ }
+
tmpl = &desc->templates[field];
- if (!tmpl)
+ if (!tmpl || !tmpl->dtype)
return NULL;
- optnum = tcpopt_find_optnum(type);
-
expr = expr_alloc(loc, EXPR_EXTHDR, tmpl->dtype,
BYTEORDER_BIG_ENDIAN, tmpl->len);
- expr->exthdr.desc = desc;
- expr->exthdr.tmpl = tmpl;
- expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
- expr->exthdr.offset = calc_offset(desc, tmpl, optnum);
+
+ expr->exthdr.raw_type = desc->type;
+ tcpopt_assign_tmpl(expr, tmpl, desc);
return expr;
}
-void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int offset,
+void tcpopt_init_raw(struct expr *expr, uint8_t type, unsigned int off,
unsigned int len, uint32_t flags)
{
const struct proto_hdr_template *tmpl;
- unsigned int i, off;
+ unsigned int i;
assert(expr->etype == EXPR_EXTHDR);
expr->len = len;
expr->exthdr.flags = flags;
- expr->exthdr.offset = offset;
+ expr->exthdr.offset = off;
+ expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
+ expr->exthdr.tmpl = &tcpopt_unknown_template;
+
+ if (flags & NFT_EXTHDR_F_PRESENT)
+ datatype_set(expr, &boolean_type);
+ else
+ datatype_set(expr, &integer_type);
+
+ if (type >= array_size(tcpopt_protocols) ||
+ !tcpopt_protocols[type])
+ return;
- assert(type < array_size(tcpopt_protocols));
expr->exthdr.desc = tcpopt_protocols[type];
expr->exthdr.flags = flags;
- assert(expr->exthdr.desc != TCPOPT_OBSOLETE);
+ assert(expr->exthdr.desc != NULL);
for (i = 0; i < array_size(expr->exthdr.desc->templates); ++i) {
tmpl = &expr->exthdr.desc->templates[i];
- /* We have to reverse calculate the offset for the sack options
- * at this point
- */
- off = calc_offset_reverse(expr->exthdr.desc, tmpl, offset);
if (tmpl->offset != off || tmpl->len != len)
continue;
- if (flags & NFT_EXTHDR_F_PRESENT)
- datatype_set(expr, &boolean_type);
- else
+ if ((flags & NFT_EXTHDR_F_PRESENT) == 0)
datatype_set(expr, tmpl->dtype);
+
expr->exthdr.tmpl = tmpl;
- expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
break;
}
}
-bool tcpopt_find_template(struct expr *expr, const struct expr *mask,
- unsigned int *shift)
+bool tcpopt_find_template(struct expr *expr, unsigned int offset, unsigned int len)
{
if (expr->exthdr.tmpl != &tcpopt_unknown_template)
return false;
- tcpopt_init_raw(expr, expr->exthdr.desc->type, expr->exthdr.offset,
- expr->len, 0);
+ tcpopt_init_raw(expr, expr->exthdr.desc->type, offset, len, 0);
if (expr->exthdr.tmpl == &tcpopt_unknown_template)
return false;
diff --git a/src/utils.c b/src/utils.c
index 47f5b791..2aa1eb4e 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -8,12 +8,12 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <stddef.h>
-#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
-#include <string.h>
#include <nftables.h>
#include <utils.h>
@@ -24,11 +24,6 @@ void __noreturn __memory_allocation_error(const char *filename, uint32_t line)
exit(NFT_EXIT_NOMEM);
}
-void xfree(const void *ptr)
-{
- free((void *)ptr);
-}
-
void *xmalloc(size_t size)
{
void *ptr;
@@ -50,6 +45,16 @@ void *xmalloc_array(size_t nmemb, size_t size)
return xmalloc(nmemb * size);
}
+void *xzalloc_array(size_t nmemb, size_t size)
+{
+ void *ptr;
+
+ ptr = xmalloc_array(nmemb, size);
+ memset(ptr, 0, nmemb * size);
+
+ return ptr;
+}
+
void *xrealloc(void *ptr, size_t size)
{
ptr = realloc(ptr, size);
@@ -90,3 +95,8 @@ void xstrunescape(const char *in, char *out)
}
out[k++] = '\0';
}
+
+int round_pow_2(unsigned int n)
+{
+ return 1UL << fls(n - 1);
+}
diff --git a/src/xfrm.c b/src/xfrm.c
index 4dd53c32..b32b2a1d 100644
--- a/src/xfrm.c
+++ b/src/xfrm.c
@@ -1,11 +1,15 @@
/*
* XFRM (ipsec) expression
*
+ * Copyright (c) Red Hat GmbH. Author: Florian Westphal <fw@strlen.de>
+ *
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
*/
+#include <nft.h>
+
#include <nftables.h>
#include <erec.h>
#include <expression.h>
@@ -13,7 +17,6 @@
#include <datatype.h>
#include <gmputil.h>
#include <utils.h>
-#include <string.h>
#include <netinet/ip.h>
#include <linux/netfilter.h>
@@ -39,7 +42,7 @@ const struct xfrm_template xfrm_templates[] = {
[NFT_XFRM_KEY_DADDR_IP6] = XFRM_TEMPLATE_BE("daddr", &ip6addr_type, 16 * BITS_PER_BYTE),
[NFT_XFRM_KEY_SADDR_IP6] = XFRM_TEMPLATE_BE("saddr", &ip6addr_type, 16 * BITS_PER_BYTE),
[NFT_XFRM_KEY_REQID] = XFRM_TEMPLATE_HE("reqid", &integer_type, 4 * BITS_PER_BYTE),
- [NFT_XFRM_KEY_SPI] = XFRM_TEMPLATE_HE("spi", &integer_type, 4 * BITS_PER_BYTE),
+ [NFT_XFRM_KEY_SPI] = XFRM_TEMPLATE_BE("spi", &integer_type, 4 * BITS_PER_BYTE),
};
static void xfrm_expr_print(const struct expr *expr, struct output_ctx *octx)
@@ -91,6 +94,65 @@ static void xfrm_expr_clone(struct expr *new, const struct expr *expr)
memcpy(&new->xfrm, &expr->xfrm, sizeof(new->xfrm));
}
+#define NFTNL_UDATA_XFRM_KEY 0
+#define NFTNL_UDATA_XFRM_SPNUM 1
+#define NFTNL_UDATA_XFRM_DIR 2
+#define NFTNL_UDATA_XFRM_MAX 3
+
+static int xfrm_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *expr)
+{
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_XFRM_KEY, expr->xfrm.key);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_XFRM_SPNUM, expr->xfrm.spnum);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_XFRM_DIR, expr->xfrm.direction);
+
+ return 0;
+}
+
+static int xfrm_parse_udata(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_XFRM_KEY:
+ case NFTNL_UDATA_XFRM_SPNUM:
+ case NFTNL_UDATA_XFRM_DIR:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *xfrm_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_XFRM_MAX + 1] = {};
+ uint32_t key, dir, spnum;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ xfrm_parse_udata, ud);
+ if (err < 0)
+ return NULL;
+
+ if (!ud[NFTNL_UDATA_XFRM_KEY] ||
+ !ud[NFTNL_UDATA_XFRM_DIR] ||
+ !ud[NFTNL_UDATA_XFRM_SPNUM])
+ return NULL;
+
+ key = nftnl_udata_get_u32(ud[NFTNL_UDATA_XFRM_KEY]);
+ dir = nftnl_udata_get_u32(ud[NFTNL_UDATA_XFRM_DIR]);
+ spnum = nftnl_udata_get_u32(ud[NFTNL_UDATA_XFRM_SPNUM]);
+
+ return xfrm_expr_alloc(&internal_location, dir, spnum, key);
+}
+
const struct expr_ops xfrm_expr_ops = {
.type = EXPR_XFRM,
.name = "xfrm",
@@ -98,6 +160,8 @@ const struct expr_ops xfrm_expr_ops = {
.json = xfrm_expr_json,
.cmp = xfrm_expr_cmp,
.clone = xfrm_expr_clone,
+ .parse_udata = xfrm_expr_parse_udata,
+ .build_udata = xfrm_expr_build_udata,
};
struct expr *xfrm_expr_alloc(const struct location *loc,
diff --git a/src/xt.c b/src/xt.c
index b0f5a30c..f7bee216 100644
--- a/src/xt.c
+++ b/src/xt.c
@@ -2,14 +2,14 @@
* Copyright (c) 2013-2015 Pablo Neira Ayuso <pablo@netfilter.org>
* Copyright (c) 2015 Arturo Borrero Gonzalez <arturo@debian.org>
*
- * This program is free software; you can redistribute it and/or modifyi
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 (or any
+ * later) as published by the Free Software Foundation.
*/
-#include <stdlib.h>
+#include <nft.h>
+
#include <time.h>
-#include <string.h>
#include <net/if.h>
#include <getopt.h>
#include <ctype.h> /* for isspace */
@@ -28,85 +28,108 @@
#ifdef HAVE_LIBXTABLES
#include <xtables.h>
+
+static void *xt_entry_alloc(const struct xt_stmt *xt, uint32_t af);
#endif
void xt_stmt_xlate(const struct stmt *stmt, struct output_ctx *octx)
{
+ static const char *typename[NFT_XT_MAX] = {
+ [NFT_XT_MATCH] = "match",
+ [NFT_XT_TARGET] = "target",
+ [NFT_XT_WATCHER] = "watcher",
+ };
+ int rc = 0;
#ifdef HAVE_LIBXTABLES
struct xt_xlate *xl = xt_xlate_alloc(10240);
+ struct xtables_target *tg;
+ struct xt_entry_target *t;
+ struct xtables_match *mt;
+ struct xt_entry_match *m;
+ size_t size;
+ void *entry;
+
+ xtables_set_nfproto(stmt->xt.family);
+ entry = xt_entry_alloc(&stmt->xt, stmt->xt.family);
switch (stmt->xt.type) {
case NFT_XT_MATCH:
- if (stmt->xt.match->xlate) {
+ mt = xtables_find_match(stmt->xt.name, XTF_TRY_LOAD, NULL);
+ if (!mt) {
+ fprintf(octx->error_fp,
+ "# Warning: XT match %s not found\n",
+ stmt->xt.name);
+ break;
+ }
+ size = XT_ALIGN(sizeof(*m)) + stmt->xt.infolen;
+
+ m = xzalloc(size);
+ memcpy(&m->data, stmt->xt.info, stmt->xt.infolen);
+
+ m->u.match_size = size;
+ m->u.user.revision = stmt->xt.rev;
+
+ if (mt->xlate) {
struct xt_xlate_mt_params params = {
- .ip = stmt->xt.entry,
- .match = stmt->xt.match->m,
- .numeric = 0,
+ .ip = entry,
+ .match = m,
+ .numeric = 1,
};
- stmt->xt.match->xlate(xl, &params);
- nft_print(octx, "%s", xt_xlate_get(xl));
- } else if (stmt->xt.match->print) {
- printf("#");
- stmt->xt.match->print(&stmt->xt.entry,
- stmt->xt.match->m, 0);
+ rc = mt->xlate(xl, &params);
}
+ free(m);
break;
case NFT_XT_WATCHER:
case NFT_XT_TARGET:
- if (stmt->xt.target->xlate) {
+ tg = xtables_find_target(stmt->xt.name, XTF_TRY_LOAD);
+ if (!tg) {
+ fprintf(octx->error_fp,
+ "# Warning: XT target %s not found\n",
+ stmt->xt.name);
+ break;
+ }
+ size = XT_ALIGN(sizeof(*t)) + stmt->xt.infolen;
+
+ t = xzalloc(size);
+ memcpy(&t->data, stmt->xt.info, stmt->xt.infolen);
+
+ t->u.target_size = size;
+ t->u.user.revision = stmt->xt.rev;
+
+ strcpy(t->u.user.name, tg->name);
+
+ if (tg->xlate) {
struct xt_xlate_tg_params params = {
- .ip = stmt->xt.entry,
- .target = stmt->xt.target->t,
- .numeric = 0,
+ .ip = entry,
+ .target = t,
+ .numeric = 1,
};
- stmt->xt.target->xlate(xl, &params);
- nft_print(octx, "%s", xt_xlate_get(xl));
- } else if (stmt->xt.target->print) {
- printf("#");
- stmt->xt.target->print(NULL, stmt->xt.target->t, 0);
+ rc = tg->xlate(xl, &params);
}
- break;
- default:
+ free(t);
break;
}
+ if (rc == 1)
+ nft_print(octx, "%s", xt_xlate_get(xl));
xt_xlate_free(xl);
-#else
- nft_print(octx, "# xt_%s", stmt->xt.name);
+ free(entry);
#endif
+ if (!rc)
+ nft_print(octx, "xt %s \"%s\"",
+ typename[stmt->xt.type], stmt->xt.name);
}
void xt_stmt_destroy(struct stmt *stmt)
{
-#ifdef HAVE_LIBXTABLES
- switch (stmt->xt.type) {
- case NFT_XT_MATCH:
- if (!stmt->xt.match)
- break;
- if (stmt->xt.match->m)
- xfree(stmt->xt.match->m);
- xfree(stmt->xt.match);
- break;
- case NFT_XT_WATCHER:
- case NFT_XT_TARGET:
- if (!stmt->xt.target)
- break;
- if (stmt->xt.target->t)
- xfree(stmt->xt.target->t);
- xfree(stmt->xt.target);
- break;
- default:
- break;
- }
-#endif
- xfree(stmt->xt.entry);
- xfree(stmt->xt.name);
+ free_const(stmt->xt.name);
+ free(stmt->xt.info);
}
#ifdef HAVE_LIBXTABLES
-static void *xt_entry_alloc(struct xt_stmt *xt, uint32_t af)
+static void *xt_entry_alloc(const struct xt_stmt *xt, uint32_t af)
{
union nft_entry {
struct ipt_entry ipt;
@@ -173,24 +196,6 @@ static uint32_t xt_proto(const struct proto_ctx *pctx)
return 0;
}
-
-static struct xtables_target *xt_target_clone(struct xtables_target *t)
-{
- struct xtables_target *clone;
-
- clone = xzalloc(sizeof(struct xtables_target));
- memcpy(clone, t, sizeof(struct xtables_target));
- return clone;
-}
-
-static struct xtables_match *xt_match_clone(struct xtables_match *m)
-{
- struct xtables_match *clone;
-
- clone = xzalloc(sizeof(struct xtables_match));
- memcpy(clone, m, sizeof(struct xtables_match));
- return clone;
-}
#endif
/*
@@ -201,89 +206,48 @@ void netlink_parse_match(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
{
- struct stmt *stmt;
- const char *name;
-#ifdef HAVE_LIBXTABLES
- struct xtables_match *mt;
const char *mtinfo;
- struct xt_entry_match *m;
+ struct stmt *stmt;
uint32_t mt_len;
- xtables_set_nfproto(ctx->table->handle.family);
-
- name = nftnl_expr_get_str(nle, NFTNL_EXPR_MT_NAME);
-
- mt = xtables_find_match(name, XTF_TRY_LOAD, NULL);
- if (!mt) {
- fprintf(stderr, "XT match %s not found\n", name);
- return;
- }
mtinfo = nftnl_expr_get(nle, NFTNL_EXPR_MT_INFO, &mt_len);
- m = xzalloc(sizeof(struct xt_entry_match) + mt_len);
- memcpy(&m->data, mtinfo, mt_len);
-
- m->u.match_size = mt_len + XT_ALIGN(sizeof(struct xt_entry_match));
- m->u.user.revision = nftnl_expr_get_u32(nle, NFTNL_EXPR_MT_REV);
-
stmt = xt_stmt_alloc(loc);
- stmt->xt.name = strdup(name);
+ stmt->xt.name = strdup(nftnl_expr_get_str(nle, NFTNL_EXPR_MT_NAME));
stmt->xt.type = NFT_XT_MATCH;
- stmt->xt.match = xt_match_clone(mt);
- stmt->xt.match->m = m;
-#else
- name = nftnl_expr_get_str(nle, NFTNL_EXPR_MT_NAME);
+ stmt->xt.rev = nftnl_expr_get_u32(nle, NFTNL_EXPR_MT_REV);
+ stmt->xt.family = ctx->table->handle.family;
- stmt = xt_stmt_alloc(loc);
- stmt->xt.name = strdup(name);
- stmt->xt.type = NFT_XT_MATCH;
-#endif
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ stmt->xt.infolen = mt_len;
+ stmt->xt.info = xmalloc(mt_len);
+ memcpy(stmt->xt.info, mtinfo, mt_len);
+
+ ctx->table->has_xt_stmts = true;
+ rule_stmt_append(ctx->rule, stmt);
}
void netlink_parse_target(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
{
- struct stmt *stmt;
- const char *name;
-#ifdef HAVE_LIBXTABLES
- struct xtables_target *tg;
const void *tginfo;
- struct xt_entry_target *t;
- size_t size;
+ struct stmt *stmt;
uint32_t tg_len;
- xtables_set_nfproto(ctx->table->handle.family);
-
- name = nftnl_expr_get_str(nle, NFTNL_EXPR_TG_NAME);
- tg = xtables_find_target(name, XTF_TRY_LOAD);
- if (!tg) {
- fprintf(stderr, "XT target %s not found\n", name);
- return;
- }
tginfo = nftnl_expr_get(nle, NFTNL_EXPR_TG_INFO, &tg_len);
- size = XT_ALIGN(sizeof(struct xt_entry_target)) + tg_len;
- t = xzalloc(size);
- memcpy(&t->data, tginfo, tg_len);
- t->u.target_size = size;
- t->u.user.revision = nftnl_expr_get_u32(nle, NFTNL_EXPR_TG_REV);
- strcpy(t->u.user.name, tg->name);
-
stmt = xt_stmt_alloc(loc);
- stmt->xt.name = strdup(name);
+ stmt->xt.name = strdup(nftnl_expr_get_str(nle, NFTNL_EXPR_TG_NAME));
stmt->xt.type = NFT_XT_TARGET;
- stmt->xt.target = xt_target_clone(tg);
- stmt->xt.target->t = t;
-#else
- name = nftnl_expr_get_str(nle, NFTNL_EXPR_TG_NAME);
+ stmt->xt.rev = nftnl_expr_get_u32(nle, NFTNL_EXPR_TG_REV);
+ stmt->xt.family = ctx->table->handle.family;
- stmt = xt_stmt_alloc(loc);
- stmt->xt.name = strdup(name);
- stmt->xt.type = NFT_XT_TARGET;
-#endif
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ stmt->xt.infolen = tg_len;
+ stmt->xt.info = xmalloc(tg_len);
+ memcpy(stmt->xt.info, tginfo, tg_len);
+
+ ctx->table->has_xt_stmts = true;
+ rule_stmt_append(ctx->rule, stmt);
}
#ifdef HAVE_LIBXTABLES
@@ -305,11 +269,12 @@ static bool is_watcher(uint32_t family, struct stmt *stmt)
void stmt_xt_postprocess(struct rule_pp_ctx *rctx, struct stmt *stmt,
struct rule *rule)
{
- if (is_watcher(rctx->pctx.family, stmt))
+ struct dl_proto_ctx *dl = dl_proto_ctx(rctx);
+
+ if (is_watcher(dl->pctx.family, stmt))
stmt->xt.type = NFT_XT_WATCHER;
- stmt->xt.proto = xt_proto(&rctx->pctx);
- stmt->xt.entry = xt_entry_alloc(&stmt->xt, rctx->pctx.family);
+ stmt->xt.proto = xt_proto(&dl->pctx);
}
static int nft_xt_compatible_revision(const char *name, uint8_t rev, int opt)
@@ -321,7 +286,7 @@ static int nft_xt_compatible_revision(const char *name, uint8_t rev, int opt)
struct nfgenmsg *nfg;
int ret = 0;
- switch (rev) {
+ switch (opt) {
case IPT_SO_GET_REVISION_MATCH:
family = NFPROTO_IPV4;
type = 0;
@@ -383,7 +348,7 @@ err:
}
static struct option original_opts[] = {
- { NULL },
+ { },
};
static struct xtables_globals xt_nft_globals = {
@@ -395,7 +360,18 @@ static struct xtables_globals xt_nft_globals = {
void xt_init(void)
{
- /* Default to IPv4, but this changes in runtime */
- xtables_init_all(&xt_nft_globals, NFPROTO_IPV4);
+ static bool init_once;
+
+ if (!init_once) {
+ /* libxtables is full of global variables and cannot be used
+ * concurrently by multiple threads. Hence, it's fine that the
+ * "init_once" guard is not thread-safe either.
+ * Don't link against xtables if you want thread safety.
+ */
+ init_once = true;
+
+ /* Default to IPv4, but this changes in runtime */
+ xtables_init_all(&xt_nft_globals, NFPROTO_IPV4);
+ }
}
#endif
diff --git a/tests/build/run-tests.sh b/tests/build/run-tests.sh
index ccb62af3..916df2e2 100755
--- a/tests/build/run-tests.sh
+++ b/tests/build/run-tests.sh
@@ -1,32 +1,36 @@
#!/bin/bash
-log_file="`pwd`/tests.log"
+log_file="$(pwd)/tests.log"
dir=../..
-argument=( --without-cli --with-cli=linenoise --enable-debug --with-mini-gmp
+argument=( --without-cli --with-cli=linenoise --with-cli=editline --enable-debug --with-mini-gmp
--enable-man-doc --with-xtables --with-json)
ok=0
failed=0
-[ -f $log_file ] && rm -rf $log_file
+[ -f "$log_file" ] && rm -rf "$log_file"
tmpdir=$(mktemp -d)
-if [ ! -w $tmpdir ] ; then
+if [ ! -w "$tmpdir" ] ; then
echo "Failed to create tmp file" >&2
exit 0
fi
-git clone $dir $tmpdir >/dev/null 2>>$log_file
-cd $tmpdir
+git clone "$dir" "$tmpdir" &>>"$log_file"
+cd "$tmpdir" || exit
-autoreconf -fi >/dev/null 2>>$log_file
-./configure >/dev/null 2>>$log_file
+if ! autoreconf -fi &>>"$log_file" ; then
+ echo "Something went wrong. Check the log '${log_file}' for details."
+ exit 1
+fi
-echo "Testing build with distcheck"
-make distcheck >/dev/null 2>>$log_file
-rt=$?
+if ! ./configure &>>"$log_file" ; then
+ echo "Something went wrong. Check the log '${log_file}' for details."
+ exit 1
+fi
-if [ $rt != 0 ] ; then
- echo "Something went wrong. Check the log for details."
+echo "Testing build with distcheck"
+if ! make distcheck &>>"$log_file" ; then
+ echo "Something went wrong. Check the log '${log_file}' for details."
exit 1
fi
@@ -35,8 +39,8 @@ echo "Build works. Now, testing compile options"
for var in "${argument[@]}" ; do
echo "[EXECUTING] Testing compile option $var"
- ./configure $var >/dev/null 2>>$log_file
- make -j 8 >/dev/null 2>>$log_file
+ ./configure "$var" &>>"$log_file"
+ make -j 8 &>>"$log_file"
rt=$?
echo -en "\033[1A\033[K" # clean the [EXECUTING] foobar line
@@ -49,7 +53,7 @@ for var in "${argument[@]}" ; do
fi
done
-rm -rf $tmpdir
+rm -rf "$tmpdir"
echo "results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))"
-exit $failed
+[ "$failed" -eq 0 ]
diff --git a/tests/json_echo/run-test.py b/tests/json_echo/run-test.py
index a636d5f2..a6bdfc61 100755
--- a/tests/json_echo/run-test.py
+++ b/tests/json_echo/run-test.py
@@ -4,6 +4,7 @@ from __future__ import print_function
import sys
import os
import json
+import argparse
TESTS_PATH = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(TESTS_PATH, '../../py/'))
@@ -13,12 +14,26 @@ from nftables import Nftables
# Change working directory to repository root
os.chdir(TESTS_PATH + "/../..")
-if not os.path.exists('src/.libs/libnftables.so'):
- print("The nftables library does not exist. "
- "You need to build the project.")
+parser = argparse.ArgumentParser(description='Run JSON echo tests')
+parser.add_argument('-H', '--host', action='store_true',
+ help='Run tests against installed libnftables.so.1')
+parser.add_argument('-l', '--library', default=None,
+ help='Path to libntables.so, overrides --host')
+args = parser.parse_args()
+
+check_lib_path = True
+if args.library is None:
+ if args.host:
+ args.library = 'libnftables.so.1'
+ check_lib_path = False
+ else:
+ args.library = 'src/.libs/libnftables.so.1'
+
+if check_lib_path and not os.path.exists(args.library):
+ print("Library not found at '%s'." % args.library)
sys.exit(1)
-nftables = Nftables(sofile = 'src/.libs/libnftables.so')
+nftables = Nftables(sofile = args.library)
nftables.set_echo_output(True)
# various commands to work with
@@ -80,25 +95,25 @@ add_quota = { "add": {
# helper functions
def exit_err(msg):
- print("Error: %s" %msg)
+ print("Error: %s" %msg, file=sys.stderr)
sys.exit(1)
def exit_dump(e, obj):
- print("FAIL: {}".format(e))
- print("Output was:")
- json.dumps(out, sort_keys = True, indent = 4, separators = (',', ': '))
- sys.exit(1)
+ msg = "{}\n".format(e)
+ msg += "Output was:\n"
+ msg += json.dumps(obj, sort_keys = True, indent = 4, separators = (',', ': '))
+ exit_err(msg)
def do_flush():
rc, out, err = nftables.json_cmd({ "nftables": [flush_ruleset] })
- if not rc is 0:
+ if rc != 0:
exit_err("flush ruleset failed: {}".format(err))
def do_command(cmd):
if not type(cmd) is list:
cmd = [cmd]
rc, out, err = nftables.json_cmd({ "nftables": cmd })
- if not rc is 0:
+ if rc != 0:
exit_err("command failed: {}".format(err))
return out
@@ -119,7 +134,7 @@ def get_handle(output, search):
else:
data = item
- k = search.keys()[0]
+ k = list(search.keys())[0]
if not k in data:
continue
diff --git a/tests/monitor/run-tests.sh b/tests/monitor/run-tests.sh
index 0478cf60..f1ac790a 100755
--- a/tests/monitor/run-tests.sh
+++ b/tests/monitor/run-tests.sh
@@ -1,7 +1,7 @@
#!/bin/bash
cd $(dirname $0)
-nft=../../src/nft
+nft=${NFT:-../../src/nft}
debug=false
test_json=false
@@ -9,17 +9,24 @@ mydiff() {
diff -w -I '^# ' "$@"
}
-if [ "$(id -u)" != "0" ] ; then
- echo "this requires root!"
+err() {
+ echo "$*" >&2
+}
+
+die() {
+ err "$*"
exit 1
+}
+
+if [ "$(id -u)" != "0" ] ; then
+ die "this requires root!"
fi
testdir=$(mktemp -d)
if [ ! -d $testdir ]; then
- echo "Failed to create test directory" >&2
- exit 1
+ die "Failed to create test directory"
fi
-trap "rm -rf $testdir; $nft flush ruleset" EXIT
+trap 'rm -rf $testdir; $nft flush ruleset' EXIT
command_file=$(mktemp -p $testdir)
output_file=$(mktemp -p $testdir)
@@ -56,6 +63,7 @@ monitor_run_test() {
monitor_output=$(mktemp -p $testdir)
monitor_args=""
$test_json && monitor_args="vm json"
+ local rc=0
$nft -nn monitor $monitor_args >$monitor_output &
monitor_pid=$!
@@ -66,48 +74,53 @@ monitor_run_test() {
echo "command file:"
cat $command_file
}
- $nft -f $command_file || {
- echo "nft command failed!"
- kill $monitor_pid
- wait >/dev/null 2>&1
- exit 1
+ $nft -f - <$command_file || {
+ err "nft command failed!"
+ rc=1
}
sleep 0.5
kill $monitor_pid
wait >/dev/null 2>&1
$test_json && json_output_filter $monitor_output
- if ! mydiff -q $monitor_output $output_file >/dev/null 2>&1; then
- echo "monitor output differs!"
- mydiff -u $output_file $monitor_output
- exit 1
+ mydiff -q $monitor_output $output_file >/dev/null 2>&1
+ if [[ $rc == 0 && $? != 0 ]]; then
+ err "monitor output differs!"
+ mydiff -u $output_file $monitor_output >&2
+ rc=1
fi
rm $command_file
rm $output_file
touch $command_file
touch $output_file
+ return $rc
}
echo_run_test() {
echo_output=$(mktemp -p $testdir)
+ local rc=0
+
$debug && {
echo "command file:"
cat $command_file
}
- $nft -nn -e -f $command_file >$echo_output || {
- echo "nft command failed!"
- exit 1
+ $nft -nn -e -f - <$command_file >$echo_output || {
+ err "nft command failed!"
+ rc=1
}
- if ! mydiff -q $echo_output $output_file >/dev/null 2>&1; then
- echo "echo output differs!"
- mydiff -u $output_file $echo_output
- exit 1
+ mydiff -q $echo_output $output_file >/dev/null 2>&1
+ if [[ $rc == 0 && $? != 0 ]]; then
+ err "echo output differs!"
+ mydiff -u $output_file $echo_output >&2
+ rc=1
fi
rm $command_file
rm $output_file
touch $command_file
touch $output_file
+ return $rc
}
+testcases=""
while [ -n "$1" ]; do
case "$1" in
-d|--debug)
@@ -118,11 +131,19 @@ while [ -n "$1" ]; do
test_json=true
shift
;;
+ -H|--host)
+ nft=nft
+ shift
+ ;;
+ testcases/*.t)
+ testcases+=" $1"
+ shift
+ ;;
*)
echo "unknown option '$1'"
;&
-h|--help)
- echo "Usage: $(basename $0) [-j|--json] [-d|--debug]"
+ echo "Usage: $(basename $0) [-j|--json] [-d|--debug] [testcase ...]"
exit 1
;;
esac
@@ -134,12 +155,16 @@ else
variants="monitor echo"
fi
+rc=0
for variant in $variants; do
run_test=${variant}_run_test
output_append=${variant}_output_append
- for testcase in testcases/*.t; do
- echo "$variant: running tests from file $(basename $testcase)"
+ for testcase in ${testcases:-testcases/*.t}; do
+ filename=$(basename $testcase)
+ echo "$variant: running tests from file $filename"
+ rc_start=$rc
+
# files are like this:
#
# I add table ip t
@@ -153,7 +178,10 @@ for variant in $variants; do
while read dir line; do
case $dir in
I)
- $input_complete && $run_test
+ $input_complete && {
+ $run_test
+ let "rc += $?"
+ }
input_complete=false
cmd_append "$line"
;;
@@ -170,6 +198,14 @@ for variant in $variants; do
;;
esac
done <$testcase
- $input_complete && $run_test
+ $input_complete && {
+ $run_test
+ let "rc += $?"
+ }
+
+ let "rc_diff = rc - rc_start"
+ [[ $rc_diff -ne 0 ]] && \
+ echo "$variant: $rc_diff tests from file $filename failed"
done
done
+exit $rc
diff --git a/tests/monitor/testcases/map-expr.t b/tests/monitor/testcases/map-expr.t
new file mode 100644
index 00000000..8729c0b4
--- /dev/null
+++ b/tests/monitor/testcases/map-expr.t
@@ -0,0 +1,6 @@
+# first the setup
+I add table ip t
+I add map ip t m { typeof meta day . meta hour : verdict; flags interval; counter; }
+O -
+J {"add": {"table": {"family": "ip", "name": "t", "handle": 0}}}
+J {"add": {"map": {"family": "ip", "name": "m", "table": "t", "type": ["day", "hour"], "handle": 0, "map": "verdict", "flags": ["interval"], "stmt": [{"counter": null}]}}}
diff --git a/tests/monitor/testcases/object.t b/tests/monitor/testcases/object.t
index dacfed29..53a9f8c5 100644
--- a/tests/monitor/testcases/object.t
+++ b/tests/monitor/testcases/object.t
@@ -37,7 +37,7 @@ I delete ct helper ip t cth
O -
J {"delete": {"ct helper": {"family": "ip", "name": "cth", "table": "t", "handle": 0, "type": "sip", "protocol": "tcp", "l3proto": "ip"}}}
-I add ct timeout ip t ctt { protocol udp; l3proto ip; policy = { unreplied: 15, replied: 12 }; }
+I add ct timeout ip t ctt { protocol udp; l3proto ip; policy = { unreplied : 15s, replied : 12s }; }
O -
J {"add": {"ct timeout": {"family": "ip", "name": "ctt", "table": "t", "handle": 0, "protocol": "udp", "l3proto": "ip", "policy": {"unreplied": 15, "replied": 12}}}}
diff --git a/tests/monitor/testcases/set-concat-interval.t b/tests/monitor/testcases/set-concat-interval.t
new file mode 100644
index 00000000..763dc319
--- /dev/null
+++ b/tests/monitor/testcases/set-concat-interval.t
@@ -0,0 +1,12 @@
+# setup first
+I add table ip t
+I add chain ip t c
+O -
+J {"add": {"table": {"family": "ip", "name": "t", "handle": 0}}}
+J {"add": {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}}
+
+# add set with elements, monitor output expectedly differs
+I add map ip t s { typeof udp length . @ih,32,32 : verdict; flags interval; elements = { 20-80 . 0x14 : accept, 1-10 . 0xa : drop }; }
+O add map ip t s { typeof udp length . @ih,32,32 : verdict; flags interval; }
+O add element ip t s { 20-80 . 0x14 : accept }
+O add element ip t s { 1-10 . 0xa : drop }
diff --git a/tests/monitor/testcases/set-interval.t b/tests/monitor/testcases/set-interval.t
new file mode 100644
index 00000000..5053c596
--- /dev/null
+++ b/tests/monitor/testcases/set-interval.t
@@ -0,0 +1,30 @@
+# setup first
+I add table ip t
+I add chain ip t c
+O -
+J {"add": {"table": {"family": "ip", "name": "t", "handle": 0}}}
+J {"add": {"chain": {"family": "ip", "table": "t", "name": "c", "handle": 0}}}
+
+# add set with elements, monitor output expectedly differs
+I add set ip t s { type inet_service; flags interval; elements = { 20, 30-40 }; }
+O add set ip t s { type inet_service; flags interval; }
+O add element ip t s { 20 }
+O add element ip t s { 30-40 }
+J {"add": {"set": {"family": "ip", "name": "s", "table": "t", "type": "inet_service", "handle": 0, "flags": ["interval"]}}}
+J {"add": {"element": {"family": "ip", "table": "t", "name": "s", "elem": {"set": [20]}}}}
+J {"add": {"element": {"family": "ip", "table": "t", "name": "s", "elem": {"set": [{"range": [30, 40]}]}}}}
+
+# this would crash nft
+I add rule ip t c tcp dport @s
+O -
+J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": "@s"}}]}}}
+
+# test anonymous interval sets as well
+I add rule ip t c tcp dport { 20, 30-40 }
+O -
+J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": {"set": [20, {"range": [30, 40]}]}}}]}}}
+
+# ... and anon concat range
+I add rule ip t c ether saddr . ip saddr { 08:00:27:40:f7:09 . 192.168.56.10-192.168.56.12 }
+O -
+J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"concat": [{"payload": {"protocol": "ether", "field": "saddr"}}, {"payload": {"protocol": "ip", "field": "saddr"}}]}, "right": {"set": [{"concat": ["08:00:27:40:f7:09", {"range": ["192.168.56.10", "192.168.56.12"]}]}]}}}]}}}
diff --git a/tests/monitor/testcases/simple.t b/tests/monitor/testcases/simple.t
index 78fd6616..67be5c85 100644
--- a/tests/monitor/testcases/simple.t
+++ b/tests/monitor/testcases/simple.t
@@ -14,14 +14,14 @@ O -
J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": {"set": [22, 80, 443]}}}, {"accept": null}]}}}
I insert rule ip t c counter accept
-O add rule ip t c counter packets 0 bytes 0 accept
-J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"counter": {"packets": 0, "bytes": 0}}, {"accept": null}]}}}
+O insert rule ip t c counter packets 0 bytes 0 accept
+J {"insert": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"counter": {"packets": 0, "bytes": 0}}, {"accept": null}]}}}
I replace rule ip t c handle 2 accept comment "foo bar"
-O add rule ip t c accept comment "foo bar"
O delete rule ip t c handle 2
-J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "comment": "foo bar", "expr": [{"accept": null}]}}}
+O add rule ip t c handle 5 accept comment "foo bar"
J {"delete": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "expr": [{"accept": null}]}}}
+J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "comment": "foo bar", "expr": [{"accept": null}]}}}
I add counter ip t cnt
O add counter ip t cnt { packets 0 bytes 0 }
diff --git a/tests/py/README b/tests/py/README
index ed5dc58b..864a966e 100644
--- a/tests/py/README
+++ b/tests/py/README
@@ -163,4 +163,35 @@ G) Acknowledgements
Thanks to the Outreach Program for Women (OPW) for sponsoring this test
infrastructure and my mentor Pablo Neira.
+H) JSON (-j) Mode
+
+This mode is supposed to repeat the same tests using JSON syntax. For each test
+file example.t, there is supposed to be a file example.t.json holding the JSON
+equivalents of each rule in example.t. The file's syntax is similar to payload
+files: An initial comment identifies the rule belonging to the following JSON
+equivalent. Pairs of comment and JSON are separated by a single blank line.
+
+If the example.t.json file does not exist, the test script will warn and create
+(or append to) example.t.json.got. The JSON equivalent written is generated by
+applying the rule in standard syntax and listing the ruleset in JSON format.
+After thorough review, it may be renamed to example.t.json.
+
+One common case for editing the content in example.t.json.got is expected
+differences between input and output. The generated content will match the
+output while it is supposed to match the input.
+
+If a rule is expected to differ in output, the expected output must be recorded
+in example.t.json.output. Its syntax is identical to example.t.json, i.e. pairs
+of comment identifying the rule (in standard syntax) and JSON (output) format
+separated by blank lines. Note: the comment states the rule as in input, not
+output.
+
+If the example.t.json.output file does not exist and output differs from input,
+the file example.t.json.output.got is created with the actual output recorded.
+
+JSON mode will also check the payload created for the rule in JSON syntax by
+comparing it to the recorded one in example.t.payload. Should it differ, it
+will be recorded in example.t.json.payload.got. This is always a bug: A rule's
+JSON equivalent must turn into the same bytecode as the rule itself.
+
-EOF-
diff --git a/tests/py/any/counter.t b/tests/py/any/counter.t
new file mode 100644
index 00000000..1c72742c
--- /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 00000000..2d1eaa99
--- /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 00000000..6a62ffb0
--- /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 00000000..23e96bae
--- /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
index ebc08644..f73fa4e7 100644
--- a/tests/py/any/ct.t
+++ b/tests/py/any/ct.t
@@ -26,9 +26,11 @@ 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
@@ -57,6 +59,7 @@ 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
@@ -66,7 +69,7 @@ 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 1m-1h;ok;ct expiration 60s-3600s
ct expiration 1d-1h;fail
ct expiration > 4d23h59m59s;ok
ct expiration != 233;ok;ct expiration != 3m53s
@@ -74,8 +77,8 @@ 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, 1m6s-1m28s}
-ct expiration != {33-55, 66-88};ok;ct expiration != { 33s-55s, 1m6s-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
@@ -127,6 +130,8 @@ 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
@@ -139,3 +144,6 @@ 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
index 7c16f9df..a2a06025 100644
--- a/tests/py/any/ct.t.json
+++ b/tests/py/any/ct.t.json
@@ -311,6 +311,29 @@
}
]
+# 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
[
{
@@ -364,6 +387,21 @@
}
]
+# ct status ! dnat
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "op": "!",
+ "right": "dnat"
+ }
+ }
+]
+
# ct mark 0
[
{
@@ -499,6 +537,29 @@
}
]
+# ct mark set ct mark or 0x00000001
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 1
+ ]
+ }
+ }
+ }
+]
+
# ct mark 0x00000032
[
{
@@ -701,6 +762,34 @@
}
]
+# 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 }
[
{
@@ -938,39 +1027,6 @@
}
]
-# ct state . ct mark { new . 0x12345678}
-[
- {
- "match": {
- "left": {
- "concat": [
- {
- "ct": {
- "key": "state"
- }
- },
- {
- "ct": {
- "key": "mark"
- }
- }
- ]
- },
- "op": "==",
- "right": {
- "set": [
- {
- "concat": [
- "new",
- "0x12345678"
- ]
- }
- ]
- }
- }
- }
-]
-
# ct state . ct mark { new . 0x12345678, new . 0x34127856, established . 0x12785634}
[
{
@@ -1398,6 +1454,21 @@
}
]
+# ct id 12345
+[
+ {
+ "match": {
+ "left": {
+ "ct": {
+ "key": "id"
+ }
+ },
+ "op": "==",
+ "right": 12345
+ }
+ }
+]
+
# ct zone set mark map { 1 : 1, 2 : 2 }
[
{
@@ -1431,3 +1502,22 @@
}
]
+# 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
index aced3817..70ade7e3 100644
--- a/tests/py/any/ct.t.json.output
+++ b/tests/py/any/ct.t.json.output
@@ -527,14 +527,14 @@
"set": [
{
"concat": [
- "established",
- 309876276
+ "new",
+ 305419896
]
},
{
"concat": [
- "new",
- 305419896
+ "established",
+ 309876276
]
},
{
@@ -611,23 +611,23 @@
[
{
"concat": [
- "established",
- 2271560481
+ "new",
+ 305419896
]
},
{
- "accept": null
+ "drop": null
}
],
[
{
"concat": [
- "new",
- 305419896
+ "established",
+ 2271560481
]
},
{
- "drop": null
+ "accept": null
}
]
]
diff --git a/tests/py/any/ct.t.payload b/tests/py/any/ct.t.payload
index bdc6a70e..ed868e53 100644
--- a/tests/py/any/ct.t.payload
+++ b/tests/py/any/ct.t.payload
@@ -1,7 +1,7 @@
# ct state new,established, related, untracked
ip test-ip4 output
[ ct load state => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000004e ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000004e ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000000 ]
# ct state != related
@@ -28,21 +28,21 @@ ip test-ip4 output
# ct state invalid drop
ip test-ip4 output
[ ct load state => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000001 ) ^ 0x00000000 ]
+ [ 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 ]
+ [ 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 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000008 ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000000 ]
# ct direction original
@@ -84,7 +84,7 @@ ip test-ip4 output
# ct status expected
ip test-ip4 output
[ ct load status => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000001 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000000 ]
# ct status != expected
@@ -95,7 +95,7 @@ ip test-ip4 output
# ct status seen-reply
ip test-ip4 output
[ ct load status => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000002 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000000 ]
# ct status != seen-reply
@@ -127,25 +127,25 @@ ip test-ip4 output
# ct mark or 0x23 == 0x11
ip test-ip4 output
[ ct load mark => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xffffffdc ) ^ 0x00000023 ]
+ [ 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 ]
+ [ 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 ]
+ [ 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 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000001 ]
# ct mark xor 0x23 == 0x11
@@ -306,15 +306,6 @@ ip test-ip4 output
[ ct load helper => reg 1 ]
[ cmp eq reg 1 0x00707466 0x00000000 0x00000000 0x00000000 ]
-# ct state . ct mark { new . 0x12345678}
-__set%d test 3
-__set%d test 0
- element 00000008 12345678 : 0 [end]
-ip test-ip4 output
- [ ct load state => reg 1 ]
- [ ct load mark => reg 9 ]
- [ lookup reg 1 set __set%d ]
-
# ct state . ct mark { new . 0x12345678, new . 0x34127856, established . 0x12785634}
__set%d test-ip4 3
__set%d test-ip4 0
@@ -329,6 +320,13 @@ 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
@@ -371,19 +369,19 @@ ip test-ip4 output
# 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 ]
+ [ 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 ]
+ [ 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 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000020 ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000000 ]
# ct event set new
@@ -419,7 +417,7 @@ ip test-ip4 output
# 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 ]
+ [ 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
@@ -487,7 +485,7 @@ ip test-ip4 output
# 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 : 0 [end] element 00000002 87654321 : 0 [end]
+ 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 ]
@@ -496,6 +494,25 @@ ip test-ip4 output
# ct mark set ct mark or 0x00000001
ip test-ip4 output
[ ct load mark => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xfffffffe ) ^ 0x00000001 ]
+ [ 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
index a327ce6a..cf402428 100644
--- a/tests/py/any/icmpX.t.netdev
+++ b/tests/py/any/icmpX.t.netdev
@@ -1,6 +1,7 @@
:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
ip protocol icmp icmp type echo-request;ok;icmp type echo-request
icmp type echo-request;ok
diff --git a/tests/py/any/last.t b/tests/py/any/last.t
new file mode 100644
index 00000000..5c530461
--- /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 00000000..2a2b9e72
--- /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 00000000..e8ec4f47
--- /dev/null
+++ b/tests/py/any/last.t.json.output
@@ -0,0 +1,7 @@
+# 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 00000000..ed47d0f3
--- /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
index ef7f9313..2a84e3f5 100644
--- a/tests/py/any/limit.t
+++ b/tests/py/any/limit.t
@@ -1,18 +1,19 @@
: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
+*netdev;test-netdev;ingress,egress
-limit rate 400/minute;ok
-limit rate 20/second;ok
-limit rate 400/hour;ok
-limit rate 40/day;ok
-limit rate 400/week;ok
+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
@@ -21,19 +22,22 @@ 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 20/second;ok
-limit rate over 400/hour;ok
-limit rate over 40/day;ok
-limit rate over 400/week;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
@@ -41,9 +45,7 @@ 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
index 8bab7e3d..73160b27 100644
--- a/tests/py/any/limit.t.json
+++ b/tests/py/any/limit.t.json
@@ -114,12 +114,40 @@
}
]
-# limit rate 1023000 mbytes/second
+# 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": 1023000,
+ "rate": 1,
"rate_unit": "mbytes"
}
}
@@ -164,19 +192,6 @@
}
]
-# 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
[
{
@@ -304,18 +319,6 @@
}
]
-# 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
[
{
@@ -357,18 +360,3 @@
}
}
]
-
-# 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 00000000..2c94d2de
--- /dev/null
+++ b/tests/py/any/limit.t.json.output
@@ -0,0 +1,249 @@
+# 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 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"
+ }
+ }
+]
diff --git a/tests/py/any/limit.t.payload b/tests/py/any/limit.t.payload
index b0cc84b4..dc6701b3 100644
--- a/tests/py/any/limit.t.payload
+++ b/tests/py/any/limit.t.payload
@@ -1,22 +1,22 @@
# limit rate 400/minute
ip test-ip4 output
- [ limit rate 400/minute burst 0 type packets flags 0x0 ]
+ [ limit rate 400/minute burst 5 type packets flags 0x0 ]
# limit rate 20/second
ip test-ip4 output
- [ limit rate 20/second burst 0 type packets flags 0x0 ]
+ [ limit rate 20/second burst 5 type packets flags 0x0 ]
# limit rate 400/hour
ip test-ip4 output
- [ limit rate 400/hour burst 0 type packets flags 0x0 ]
+ [ limit rate 400/hour burst 5 type packets flags 0x0 ]
# limit rate 400/week
ip test-ip4 output
- [ limit rate 400/week burst 0 type packets flags 0x0 ]
+ [ limit rate 400/week burst 5 type packets flags 0x0 ]
# limit rate 40/day
ip test-ip4 output
- [ limit rate 40/day burst 0 type packets flags 0x0 ]
+ [ limit rate 40/day burst 5 type packets flags 0x0 ]
# limit rate 1023/second burst 10 packets
ip test-ip4 output
@@ -42,9 +42,18 @@ ip test-ip4 output
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
@@ -58,29 +67,25 @@ ip test-ip4 output
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 0 type packets flags 0x1 ]
+ [ limit rate 400/minute burst 5 type packets flags 0x1 ]
# limit rate over 20/second
ip test-ip4 output
- [ limit rate 20/second burst 0 type packets flags 0x1 ]
+ [ limit rate 20/second burst 5 type packets flags 0x1 ]
# limit rate over 400/hour
ip test-ip4 output
- [ limit rate 400/hour burst 0 type packets flags 0x1 ]
+ [ limit rate 400/hour burst 5 type packets flags 0x1 ]
# limit rate over 400/week
ip test-ip4 output
- [ limit rate 400/week burst 0 type packets flags 0x1 ]
+ [ limit rate 400/week burst 5 type packets flags 0x1 ]
# limit rate over 40/day
ip test-ip4 output
- [ limit rate 40/day burst 0 type packets flags 0x1 ]
+ [ limit rate 40/day burst 5 type packets flags 0x1 ]
# limit rate over 1023/second burst 10 packets
ip test-ip4 output
@@ -106,10 +111,6 @@ ip test-ip4 output
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 ]
@@ -121,8 +122,3 @@ ip test-ip4 output
# 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/meta.t b/tests/py/any/meta.t
index 86e5d258..bd10c56d 100644
--- a/tests/py/any/meta.t
+++ b/tests/py/any/meta.t
@@ -1,12 +1,13 @@
: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
+*netdev;test-netdev;ingress,egress
meta length 1000;ok
meta length 22;ok
@@ -20,8 +21,8 @@ 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, vlan, arp}
-meta protocol != {ip, arp, ip6, vlan};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
@@ -29,7 +30,7 @@ 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}
+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
@@ -55,6 +56,7 @@ 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 & 0xffffff00 == 0xffffff00
meta mark or 0x03 == 0x01;ok;meta mark | 0x00000003 == 0x00000001
meta mark or 0x03 != 0x01;ok;meta mark | 0x00000003 != 0x00000001
@@ -101,10 +103,10 @@ 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 3001-3005 accept
-meta skuid != 2001-2005 accept;ok;meta skuid != 2001-2005 accept
-meta skuid { 2001-2005, 3001-3005} accept;ok;meta skuid { 2001-2005, 3001-3005} accept
-meta skuid != { 2001-2005, 3001-3005} accept;ok;meta skuid != { 2001-2005, 3001-3005} 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
@@ -113,10 +115,8 @@ 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
-meta skgid != 2001-2005 accept;ok;meta skgid != 2001-2005 accept
-meta skgid { 2001-2005} accept;ok;meta skgid { 2001-2005} accept
-meta skgid != { 2001-2005} accept;ok;meta skgid != { 2001-2005} 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
@@ -188,14 +188,12 @@ 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
-meta cgroup != 1048577;ok;meta cgroup != 1048577
-meta cgroup { 1048577, 1048578 };ok;meta cgroup { 1048577, 1048578}
-meta cgroup != { 1048577, 1048578};ok;meta cgroup != { 1048577, 1048578}
-meta cgroup 1048577-1048578;ok;meta cgroup 1048577-1048578
-meta cgroup != 1048577-1048578;ok;meta cgroup != 1048577-1048578
-meta cgroup {1048577-1048578};ok;meta cgroup { 1048577-1048578}
-meta cgroup != { 1048577-1048578};ok;meta cgroup != { 1048577-1048578}
+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 }
@@ -205,11 +203,13 @@ 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 21:07:14" drop
+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
@@ -218,7 +218,13 @@ 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
+
+meta mark set vlan id map { 1 : 0x00000001, 4095 : 0x00004095 };ok
+!map1 typeof vlan id : meta mark;ok
+meta mark set vlan id map @map1;ok
diff --git a/tests/py/any/meta.t.json b/tests/py/any/meta.t.json
index 47dc0724..676affea 100644
--- a/tests/py/any/meta.t.json
+++ b/tests/py/any/meta.t.json
@@ -199,7 +199,7 @@
}
]
-# meta protocol != {ip, arp, ip6, vlan}
+# meta protocol != {ip, arp, ip6, 8021q}
[
{
"match": {
@@ -212,7 +212,7 @@
"ip",
"arp",
"ip6",
- "vlan"
+ "8021q"
]
}
}
@@ -662,6 +662,26 @@
}
]
+# meta mark 0xffffff00/24
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ 4294967040
+ ]
+ },
+ "op": "==",
+ "right": 4294967040
+ }
+ }
+]
+
# meta mark or 0x03 == 0x01
[
{
@@ -1476,46 +1496,6 @@
}
]
-# meta skgid { 2001-2005} accept
-[
- {
- "match": {
- "left": {
- "meta": { "key": "skgid" }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 2001, 2005 ] }
- ]
- }
- }
- },
- {
- "accept": null
- }
-]
-
-# meta skgid != { 2001-2005} accept
-[
- {
- "match": {
- "left": {
- "meta": { "key": "skgid" }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 2001, 2005 ] }
- ]
- }
- }
- },
- {
- "accept": null
- }
-]
-
# meta mark set 0xffffffc8 xor 0x16
[
{
@@ -2581,6 +2561,42 @@
}
]
+# 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
[
{
@@ -2645,7 +2661,7 @@
}
},
"op": "==",
- "right": "17:00"
+ "right": "17:00:00"
}
},
{
@@ -2706,3 +2722,99 @@
"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
+ }
+]
+
+# meta mark set vlan id map { 1 : 0x00000001, 4095 : 0x00004095 }
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ 1,
+ 1
+ ],
+ [
+ 4095,
+ 16533
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ }
+ }
+ }
+ }
+ }
+]
+
+# meta mark set vlan id map @map1
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": "@map1",
+ "key": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ }
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/any/meta.t.json.output b/tests/py/any/meta.t.json.output
index 037f6718..d46935de 100644
--- a/tests/py/any/meta.t.json.output
+++ b/tests/py/any/meta.t.json.output
@@ -10,7 +10,7 @@
"set": [
"ip",
"arp",
- "vlan",
+ "8021q",
"ip6"
]
}
@@ -18,7 +18,7 @@
}
]
-# meta protocol != {ip, arp, ip6, vlan}
+# meta protocol != {ip, arp, ip6, 8021q}
[
{
"match": {
@@ -30,7 +30,7 @@
"set": [
"ip",
"arp",
- "vlan",
+ "8021q",
"ip6"
]
}
@@ -592,24 +592,6 @@
}
]
-# 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
[
{
@@ -620,97 +602,7 @@
}
},
"op": "==",
- "right": "1970-05-23 21: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"
+ "right": "1970-05-23 22:07:14"
}
},
{
@@ -736,24 +628,6 @@
}
]
-# meta hour "17:00" drop
-[
- {
- "match": {
- "left": {
- "meta": {
- "key": "hour"
- }
- },
- "op": "==",
- "right": "17:00"
- }
- },
- {
- "drop": null
- }
-]
-
# meta hour "17:00:00" drop
[
{
@@ -772,57 +646,3 @@
}
]
-# 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
index 402caae5..49dd729b 100644
--- a/tests/py/any/meta.t.payload
+++ b/tests/py/any/meta.t.payload
@@ -68,7 +68,7 @@ ip test-ip4 input
[ meta load protocol => reg 1 ]
[ lookup reg 1 set __set%d ]
-# meta protocol != {ip, arp, ip6, vlan}
+# 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]
@@ -99,14 +99,12 @@ ip test-ip4 input
# meta l4proto 33-45
ip test-ip4 input
[ meta load l4proto => reg 1 ]
- [ byteorder reg 1 = hton(reg 1, 2, 1) ]
[ cmp gte reg 1 0x00000021 ]
[ cmp lte reg 1 0x0000002d ]
# meta l4proto != 33-45
ip test-ip4 input
[ meta load l4proto => reg 1 ]
- [ byteorder reg 1 = hton(reg 1, 2, 1) ]
[ range neq reg 1 0x00000021 0x0000002d ]
# meta l4proto { 33, 55, 67, 88}
@@ -138,13 +136,13 @@ ip test-ip4 input
# meta mark and 0x03 == 0x01
ip test-ip4 input
[ meta load mark => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000003 ) ^ 0x00000000 ]
+ [ 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 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000001 ]
# meta mark 0x10
@@ -157,16 +155,22 @@ 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 ]
+ [ 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 ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffc ) ^ 0x00000003 ]
[ cmp neq reg 1 0x00000001 ]
# meta mark xor 0x03 == 0x01
@@ -633,22 +637,6 @@ ip test-ip4 input
[ meta load iifgroup => reg 1 ]
[ cmp neq reg 1 0x00000000 ]
-# meta iifgroup {"default"}
-__set%d test-ip4 3
-__set%d test-ip4 0
- element 00000000 : 0 [end]
-ip test-ip4 input
- [ meta load iifgroup => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# meta iifgroup != {"default"}
-__set%d test-ip4 3
-__set%d test-ip4 0
- element 00000000 : 0 [end]
-ip test-ip4 input
- [ meta load iifgroup => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# meta iifgroup { 11,33}
__set%d test-ip4 3
__set%d test-ip4 0
@@ -746,7 +734,7 @@ ip test-ip4 output
# meta iif . meta oif vmap { "lo" . "lo" : drop }
__map%d test-ip4 b
__map%d test-ip4 0
- element 00000001 00000001 : 0 [end]
+ element 00000001 00000001 : drop 0 [end]
ip test-ip4 output
[ meta load iif => reg 1 ]
[ meta load oif => reg 9 ]
@@ -865,7 +853,6 @@ __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 ]
- [ byteorder reg 1 = hton(reg 1, 2, 1) ]
[ lookup reg 1 set __set%d ]
# meta l4proto != { 33-55, 66-88}
@@ -874,7 +861,6 @@ __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 ]
- [ byteorder reg 1 = hton(reg 1, 2, 1) ]
[ lookup reg 1 set __set%d 0x1 ]
# meta skuid { 2001-2005, 3001-3005} accept
@@ -981,76 +967,10 @@ ip test-ip4 input
[ meta load oifgroup => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# meta iif . meta oif { "lo" . "lo" , "dummy0" . "dummy0" }
-__set%d test-ip4 3 size 2
-__set%d test-ip4 0
- element 00000001 00000001 : 0 [end] element 00000005 00000005 : 0 [end]
-ip test-ip4 input
- [ 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, "dummy0" . "dummy0" . 0x0000000b }
-__set%d test-ip4 3 size 2
-__set%d test-ip4 0
- element 00000001 00000001 0000000a : 0 [end] element 00000005 00000005 0000000b : 0 [end]
-ip test-ip4 input
- [ 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, "dummy0" . "dummy0" : accept }
-__map%d test-ip4 b size 2
-__map%d test-ip4 0
- element 00000001 00000001 : 0 [end] element 00000005 00000005 : 0 [end]
-ip test-ip4 input
- [ meta load iif => reg 1 ]
- [ meta load oif => reg 9 ]
- [ lookup reg 1 set __map%d dreg 0 ]
-
-# meta skgid { 2001-2005} accept
-__set%d test-ip4 7 size 3
-__set%d test-ip4 0
- element 00000000 : 1 [end] element d1070000 : 0 [end] element d6070000 : 1 [end]
-ip test-ip4 input
- [ meta load skgid => reg 1 ]
- [ byteorder reg 1 = hton(reg 1, 4, 4) ]
- [ lookup reg 1 set __set%d ]
- [ immediate reg 0 accept ]
-
-# meta skgid != { 2001-2005} accept
-__set%d test-ip4 7 size 3
-__set%d test-ip4 0
- element 00000000 : 1 [end] element d1070000 : 0 [end] element d6070000 : 1 [end]
-ip test-ip4 input
- [ meta load skgid => reg 1 ]
- [ byteorder reg 1 = hton(reg 1, 4, 4) ]
- [ lookup reg 1 set __set%d 0x1 ]
- [ immediate reg 0 accept ]
-
-# meta cgroup {1048577-1048578}
-__set%d test-ip4 7 size 3
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 01001000 : 0 [end] element 03001000 : 1 [end]
-ip test-ip4 input
- [ meta load cgroup => reg 1 ]
- [ byteorder reg 1 = hton(reg 1, 4, 4) ]
- [ lookup reg 1 set __set%d ]
-
-# meta cgroup != { 1048577-1048578}
-__set%d test-ip4 7 size 3
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 01001000 : 0 [end] element 03001000 : 1 [end]
-ip test-ip4 input
- [ meta load cgroup => reg 1 ]
- [ byteorder reg 1 = hton(reg 1, 4, 4) ]
- [ 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 0x74a8f400 0x002bd849 ]
+ [ cmp eq reg 1 0x43f05400 0x002bd503 ]
[ immediate reg 0 drop ]
# meta time 12341234 drop
@@ -1083,6 +1003,20 @@ ip meta-test input
[ 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 ]
@@ -1124,3 +1058,42 @@ 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 ]
+
+# meta mark set vlan id map { 1 : 0x00000001, 4095 : 0x00004095 }
+__map%d test-ip4 b size 2
+__map%d test-ip4 0
+ element 00000100 : 00000001 0 [end] element 0000ff0f : 00004095 0 [end]
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set vlan id map @map1
+ip test-ip4 input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set map1 dreg 1 ]
+ [ meta set mark with reg 1 ]
diff --git a/tests/py/any/meta.t.payload.bridge b/tests/py/any/meta.t.payload.bridge
new file mode 100644
index 00000000..5997ccc7
--- /dev/null
+++ b/tests/py/any/meta.t.payload.bridge
@@ -0,0 +1,20 @@
+# meta mark set vlan id map { 1 : 0x00000001, 4095 : 0x00004095 }
+__map%d test-bridge b size 2
+__map%d test-bridge 0
+ element 00000100 : 00000001 0 [end] element 0000ff0f : 00004095 0 [end]
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set vlan id map @map1
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set map1 dreg 1 ]
+ [ meta set mark with reg 1 ]
diff --git a/tests/py/any/objects.t b/tests/py/any/objects.t
index 89a9545f..7b51f918 100644
--- a/tests/py/any/objects.t
+++ b/tests/py/any/objects.t
@@ -1,12 +1,13 @@
: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
+*netdev;test-netdev;ingress,egress
%cnt1 type counter;ok
%qt1 type quota 25 mbytes;ok
diff --git a/tests/py/any/queue.t b/tests/py/any/queue.t
index 75c071dd..2e511362 100644
--- a/tests/py/any/queue.t
+++ b/tests/py/any/queue.t
@@ -3,16 +3,31 @@
*ip;test-ip4;output
*ip6;test-ip6;output
*inet;test-inet;output
-*arp;test-arp;output
*bridge;test-bridge;output
-queue;ok;queue num 0
-queue num 2;ok
-queue num 65535;ok
+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 num 1-65535;ok
-- queue num {3, 4, 6};ok
-queue num 4-5 fanout bypass;ok;queue num 4-5 bypass,fanout
-queue num 4-5 fanout;ok
-queue num 4-5 bypass;ok
+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
index 48e86727..5f7f9014 100644
--- a/tests/py/any/queue.t.json
+++ b/tests/py/any/queue.t.json
@@ -84,3 +84,168 @@
}
]
+# 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.payload b/tests/py/any/queue.t.payload
index 78d939c6..2f221930 100644
--- a/tests/py/any/queue.t.payload
+++ b/tests/py/any/queue.t.payload
@@ -30,3 +30,52 @@ ip test-ip4 output
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
index 9a8db114..79dd7654 100644
--- a/tests/py/any/quota.t
+++ b/tests/py/any/quota.t
@@ -1,12 +1,13 @@
: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
+*netdev;test-netdev;ingress,egress
quota 1025 bytes;ok
quota 1 kbytes;ok
diff --git a/tests/py/any/rawpayload.t b/tests/py/any/rawpayload.t
index c3382a96..5bc9d35f 100644
--- a/tests/py/any/rawpayload.t
+++ b/tests/py/any/rawpayload.t
@@ -1,19 +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
+*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 255;ok
-@nh,8,16 0;ok
+@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 & 128 == 128
-@ll,0,8 and 0x80 eq 0x80;ok;@ll,0,8 & 128 == 128
-@ll,0,128 0xfedcba987654321001234567890abcde;ok;@ll,0,128 338770000845734292516042252062074518750
+@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
index 22028ad8..4cae4d49 100644
--- a/tests/py/any/rawpayload.t.json
+++ b/tests/py/any/rawpayload.t.json
@@ -66,7 +66,7 @@
}
]
-# @nh,8,8 255
+# @nh,8,8 0xff
[
{
"match": {
@@ -78,12 +78,12 @@
}
},
"op": "==",
- "right": 255
+ "right": "0xff"
}
}
]
-# @nh,8,16 0
+# @nh,8,16 0x0
[
{
"match": {
@@ -117,7 +117,7 @@
}
]
-# @ll,0,8 and 0x80 eq 0x80
+# @ll,0,8 & 0x80 == 0x80
[
{
"match": {
@@ -156,3 +156,51 @@
}
]
+# 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
index ccadbc57..291b237a 100644
--- a/tests/py/any/rawpayload.t.json.output
+++ b/tests/py/any/rawpayload.t.json.output
@@ -79,7 +79,7 @@
}
]
-# @ll,0,8 and 0x80 eq 0x80
+# @ll,0,8 & 0x80 == 0x80
[
{
"match": {
@@ -101,3 +101,19 @@
}
]
+# @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
index a2cc6635..fe2377e6 100644
--- a/tests/py/any/rawpayload.t.payload
+++ b/tests/py/any/rawpayload.t.payload
@@ -21,12 +21,12 @@ inet test-inet input
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d ]
-# @nh,8,8 255
+# @nh,8,8 0xff
inet test-inet input
[ payload load 1b @ network header + 1 => reg 1 ]
[ cmp eq reg 1 0x000000ff ]
-# @nh,8,16 0
+# @nh,8,16 0x0
inet test-inet input
[ payload load 2b @ network header + 1 => reg 1 ]
[ cmp eq reg 1 0x00000000 ]
@@ -34,16 +34,30 @@ inet test-inet input
# @ll,0,1 1
inet test-inet input
[ payload load 1b @ link header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000080 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000080 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000080 ]
-# @ll,0,8 and 0x80 eq 0x80
+# @ll,0,8 & 0x80 == 0x80
inet test-inet input
[ payload load 1b @ link header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000080 ) ^ 0x00000000 ]
+ [ 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/inet/tcpopt.t b/tests/py/any/tcpopt.t
index b457691f..177f01c4 100644
--- a/tests/py/inet/tcpopt.t
+++ b/tests/py/any/tcpopt.t
@@ -1,42 +1,62 @@
:input;type filter hook input priority 0
+*ip;test-ip4;input
+*ip6;test-ip6;input
*inet;test-inet;input
-tcp option eol kind 1;ok
-tcp option noop kind 1;ok
-tcp option maxseg kind 1;ok
+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 kind 1;ok
tcp option window length 1;ok
tcp option window count 1;ok
-tcp option sack-permitted kind 1;ok
-tcp option sack-permitted length 1;ok
-tcp option sack kind 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 kind 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 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/inet/tcpopt.t.json b/tests/py/any/tcpopt.t.json
index 45e9c293..87074b9d 100644
--- a/tests/py/inet/tcpopt.t.json
+++ b/tests/py/any/tcpopt.t.json
@@ -1,47 +1,44 @@
-# tcp option eol kind 1
+# tcp option eol exists
[
{
"match": {
"left": {
"tcp option": {
- "field": "kind",
"name": "eol"
}
},
- "op": "==",
- "right": 1
+ "op": "==",
+ "right": true
}
}
]
-# tcp option noop kind 1
+# tcp option nop exists
[
{
"match": {
"left": {
"tcp option": {
- "field": "kind",
- "name": "noop"
+ "name": "nop"
}
},
- "op": "==",
- "right": 1
+ "op": "==",
+ "right": true
}
}
]
-# tcp option maxseg kind 1
+# tcp option maxseg exists
[
{
"match": {
"left": {
"tcp option": {
- "field": "kind",
"name": "maxseg"
}
},
- "op": "==",
- "right": 1
+ "op": "==",
+ "right": true
}
}
]
@@ -56,7 +53,7 @@
"name": "maxseg"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -72,23 +69,7 @@
"name": "maxseg"
}
},
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option window kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "window"
- }
- },
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -104,7 +85,7 @@
"name": "window"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -120,56 +101,54 @@
"name": "window"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
]
-# tcp option sack-permitted kind 1
+# tcp option sack-perm exists
[
{
"match": {
"left": {
"tcp option": {
- "field": "kind",
- "name": "sack-permitted"
+ "name": "sack-perm"
}
},
- "op": "==",
- "right": 1
+ "op": "==",
+ "right": true
}
}
]
-# tcp option sack-permitted length 1
+# tcp option sack-perm length 1
[
{
"match": {
"left": {
"tcp option": {
"field": "length",
- "name": "sack-permitted"
+ "name": "sack-perm"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
]
-# tcp option sack kind 1
+# tcp option sack exists
[
{
"match": {
"left": {
"tcp option": {
- "field": "kind",
"name": "sack"
}
},
- "op": "==",
- "right": 1
+ "op": "==",
+ "right": true
}
}
]
@@ -184,7 +163,7 @@
"name": "sack"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -200,7 +179,7 @@
"name": "sack"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -216,7 +195,7 @@
"name": "sack0"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -232,7 +211,7 @@
"name": "sack1"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -248,7 +227,7 @@
"name": "sack2"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -264,7 +243,23 @@
"name": "sack3"
}
},
- "op": "==",
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack"
+ }
+ },
+ "op": "==",
"right": 1
}
}
@@ -280,7 +275,7 @@
"name": "sack0"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -296,7 +291,7 @@
"name": "sack1"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -312,7 +307,7 @@
"name": "sack2"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -328,24 +323,23 @@
"name": "sack3"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
]
-# tcp option timestamp kind 1
+# tcp option timestamp exists
[
{
"match": {
"left": {
"tcp option": {
- "field": "kind",
"name": "timestamp"
}
},
- "op": "==",
- "right": 1
+ "op": "==",
+ "right": true
}
}
]
@@ -360,7 +354,7 @@
"name": "timestamp"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -376,7 +370,7 @@
"name": "timestamp"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -392,12 +386,63 @@
"name": "timestamp"
}
},
- "op": "==",
+ "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
[
{
@@ -407,7 +452,7 @@
"name": "window"
}
},
- "op": "==",
+ "op": "==",
"right": true
}
}
@@ -422,7 +467,7 @@
"name": "window"
}
},
- "op": "==",
+ "op": "==",
"right": false
}
}
@@ -443,3 +488,135 @@
}
]
+# 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/inet/tcpopt.t.json.output b/tests/py/any/tcpopt.t.json.output
index ad0d25f4..ad0d25f4 100644
--- a/tests/py/inet/tcpopt.t.json.output
+++ b/tests/py/any/tcpopt.t.json.output
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
new file mode 100644
index 00000000..99b8985f
--- /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 ]
diff --git a/tests/py/arp/arp.t b/tests/py/arp/arp.t
index 2540c0a7..222b91cf 100644
--- a/tests/py/arp/arp.t
+++ b/tests/py/arp/arp.t
@@ -1,9 +1,10 @@
# filter chains available are: input, output, forward
: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
*arp;test-arp;input
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
arp htype 1;ok
arp htype != 1;ok
@@ -13,8 +14,6 @@ arp htype 33-45;ok
arp htype != 33-45;ok
arp htype { 33, 55, 67, 88};ok
arp htype != { 33, 55, 67, 88};ok
-arp htype { 33-55};ok
-arp htype != { 33-55};ok
arp ptype 0x0800;ok;arp ptype ip
@@ -24,8 +23,6 @@ arp hlen 33-45;ok
arp hlen != 33-45;ok
arp hlen { 33, 55, 67, 88};ok
arp hlen != { 33, 55, 67, 88};ok
-arp hlen { 33-55};ok
-arp hlen != { 33-55};ok
arp plen 22;ok
arp plen != 233;ok
@@ -33,8 +30,6 @@ arp plen 33-45;ok
arp plen != 33-45;ok
arp plen { 33, 55, 67, 88};ok
arp plen != { 33, 55, 67, 88};ok
-arp plen { 33-55};ok
-arp plen != {33-55};ok
arp operation {nak, inreply, inrequest, rreply, rrequest, reply, request};ok
arp operation != {nak, inreply, inrequest, rreply, rrequest, reply, request};ok
@@ -46,7 +41,6 @@ arp operation rreply;ok
arp operation inrequest;ok
arp operation inreply;ok
arp operation nak;ok
-arp operation reply;ok
arp operation != request;ok
arp operation != reply;ok
arp operation != rrequest;ok
@@ -54,11 +48,13 @@ arp operation != rreply;ok
arp operation != inrequest;ok
arp operation != inreply;ok
arp operation != nak;ok
-arp operation != reply;ok
arp saddr ip 1.2.3.4;ok
arp daddr ip 4.3.2.1;ok
arp saddr ether aa:bb:cc:aa:bb:cc;ok
arp daddr ether aa:bb:cc:aa:bb:cc;ok
+arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee;ok
+arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1;ok;arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee
+
meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566;ok;iifname "invalid" arp htype 1 arp ptype ip arp hlen 6 arp plen 4 arp daddr ip 192.168.143.16 arp daddr ether set 11:22:33:44:55:66
diff --git a/tests/py/arp/arp.t.json b/tests/py/arp/arp.t.json
index 5f2f6cd8..7ce76095 100644
--- a/tests/py/arp/arp.t.json
+++ b/tests/py/arp/arp.t.json
@@ -144,46 +144,6 @@
}
]
-# arp htype { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "htype",
- "protocol": "arp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# arp htype != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "htype",
- "protocol": "arp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# arp ptype 0x0800
[
{
@@ -314,46 +274,6 @@
}
]
-# arp hlen { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "hlen",
- "protocol": "arp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# arp hlen != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "hlen",
- "protocol": "arp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# arp plen 22
[
{
@@ -468,46 +388,6 @@
}
]
-# arp plen { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "plen",
- "protocol": "arp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# arp plen != {33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "plen",
- "protocol": "arp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# arp operation {nak, inreply, inrequest, rreply, rrequest, reply, request}
[
{
@@ -693,22 +573,6 @@
}
]
-# arp operation reply
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "operation",
- "protocol": "arp"
- }
- },
- "op": "==",
- "right": "reply"
- }
- }
-]
-
# arp operation != request
[
{
@@ -821,61 +685,61 @@
}
]
-# arp operation != reply
+# arp saddr ip 1.2.3.4
[
{
"match": {
"left": {
"payload": {
- "field": "operation",
+ "field": "saddr ip",
"protocol": "arp"
}
},
- "op": "!=",
- "right": "reply"
+ "op": "==",
+ "right": "1.2.3.4"
}
}
]
-# arp saddr ip 1.2.3.4
+# arp daddr ip 4.3.2.1
[
{
"match": {
"left": {
"payload": {
- "field": "saddr ip",
+ "field": "daddr ip",
"protocol": "arp"
}
},
"op": "==",
- "right": "1.2.3.4"
+ "right": "4.3.2.1"
}
}
]
-# arp daddr ip 4.3.2.1
+# arp saddr ether aa:bb:cc:aa:bb:cc
[
{
"match": {
"left": {
"payload": {
- "field": "daddr ip",
+ "field": "saddr ether",
"protocol": "arp"
}
},
"op": "==",
- "right": "4.3.2.1"
+ "right": "aa:bb:cc:aa:bb:cc"
}
}
]
-# arp saddr ether aa:bb:cc:aa:bb:cc
+# arp daddr ether aa:bb:cc:aa:bb:cc
[
{
"match": {
"left": {
"payload": {
- "field": "saddr ether",
+ "field": "daddr ether",
"protocol": "arp"
}
},
@@ -885,18 +749,58 @@
}
]
-# arp daddr ether aa:bb:cc:aa:bb:cc
+# arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee
[
{
"match": {
"left": {
"payload": {
+ "field": "saddr ip",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.1"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
"field": "daddr ether",
"protocol": "arp"
}
},
"op": "==",
- "right": "aa:bb:cc:aa:bb:cc"
+ "right": "fe:ed:00:c0:ff:ee"
+ }
+ }
+]
+
+# arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr ether",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "fe:ed:00:c0:ff:ee"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr ip",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.1"
}
}
]
diff --git a/tests/py/arp/arp.t.json.output b/tests/py/arp/arp.t.json.output
index b8507bff..afa75b2e 100644
--- a/tests/py/arp/arp.t.json.output
+++ b/tests/py/arp/arp.t.json.output
@@ -66,6 +66,34 @@
}
]
+# arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr ip",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.1"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr ether",
+ "protocol": "arp"
+ }
+ },
+ "op": "==",
+ "right": "fe:ed:00:c0:ff:ee"
+ }
+ }
+]
+
# meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566
[
{
diff --git a/tests/py/arp/arp.t.payload b/tests/py/arp/arp.t.payload
index 52c99329..d56927b5 100644
--- a/tests/py/arp/arp.t.payload
+++ b/tests/py/arp/arp.t.payload
@@ -45,22 +45,6 @@ arp test-arp input
[ payload load 2b @ network header + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# arp htype { 33-55}
-__set%d test-arp 7
-__set%d test-arp 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-arp test-arp input
- [ payload load 2b @ network header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# arp htype != { 33-55}
-__set%d test-arp 7
-__set%d test-arp 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-arp test-arp input
- [ payload load 2b @ network header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# arp ptype 0x0800
arp test-arp input
[ payload load 2b @ network header + 2 => reg 1 ]
@@ -103,22 +87,6 @@ arp test-arp input
[ payload load 1b @ network header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# arp hlen { 33-55}
-__set%d test-arp 7
-__set%d test-arp 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-arp test-arp input
- [ payload load 1b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# arp hlen != { 33-55}
-__set%d test-arp 7
-__set%d test-arp 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-arp test-arp input
- [ payload load 1b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# arp plen 22
arp test-arp input
[ payload load 1b @ network header + 5 => reg 1 ]
@@ -156,22 +124,6 @@ arp test-arp input
[ payload load 1b @ network header + 5 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# arp plen { 33-55}
-__set%d test-arp 7
-__set%d test-arp 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-arp test-arp input
- [ payload load 1b @ network header + 5 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# arp plen != {33-55}
-__set%d test-arp 7
-__set%d test-arp 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-arp test-arp input
- [ payload load 1b @ network header + 5 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# arp operation {nak, inreply, inrequest, rreply, rrequest, reply, request}
__set%d test-arp 3
__set%d test-arp 0
@@ -229,11 +181,6 @@ arp test-arp input
[ payload load 2b @ network header + 6 => reg 1 ]
[ cmp eq reg 1 0x00000a00 ]
-# arp operation reply
-arp test-arp input
- [ payload load 2b @ network header + 6 => reg 1 ]
- [ cmp eq reg 1 0x00000200 ]
-
# arp operation != request
arp test-arp input
[ payload load 2b @ network header + 6 => reg 1 ]
@@ -269,11 +216,6 @@ arp test-arp input
[ payload load 2b @ network header + 6 => reg 1 ]
[ cmp neq reg 1 0x00000a00 ]
-# arp operation != reply
-arp test-arp input
- [ payload load 2b @ network header + 6 => reg 1 ]
- [ cmp neq reg 1 0x00000200 ]
-
# meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566
arp test-arp input
[ meta load iifname => reg 1 ]
@@ -307,3 +249,13 @@ arp test-arp input
[ payload load 6b @ network header + 18 => reg 1 ]
[ cmp eq reg 1 0xaaccbbaa 0x0000ccbb ]
+# arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee
+arp
+ [ payload load 10b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0101a8c0 0xc000edfe 0x0000eeff ]
+
+# arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1
+arp
+ [ payload load 10b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0101a8c0 0xc000edfe 0x0000eeff ]
+
diff --git a/tests/py/arp/arp.t.payload.netdev b/tests/py/arp/arp.t.payload.netdev
index 667691ff..92df2400 100644
--- a/tests/py/arp/arp.t.payload.netdev
+++ b/tests/py/arp/arp.t.payload.netdev
@@ -61,26 +61,6 @@ netdev test-netdev ingress
[ payload load 2b @ network header + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# arp htype { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000608 ]
- [ payload load 2b @ network header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# arp htype != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000608 ]
- [ payload load 2b @ network header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# arp ptype 0x0800
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
@@ -137,26 +117,6 @@ netdev test-netdev ingress
[ payload load 1b @ network header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# arp hlen { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000608 ]
- [ payload load 1b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# arp hlen != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000608 ]
- [ payload load 1b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# arp plen 22
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
@@ -206,26 +166,6 @@ netdev test-netdev ingress
[ payload load 1b @ network header + 5 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# arp plen { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000608 ]
- [ payload load 1b @ network header + 5 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# arp plen != {33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000608 ]
- [ payload load 1b @ network header + 5 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# arp operation {nak, inreply, inrequest, rreply, rrequest, reply, request}
__set%d test-netdev 3
__set%d test-netdev 0
@@ -303,13 +243,6 @@ netdev test-netdev ingress
[ payload load 2b @ network header + 6 => reg 1 ]
[ cmp eq reg 1 0x00000a00 ]
-# arp operation reply
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000608 ]
- [ payload load 2b @ network header + 6 => reg 1 ]
- [ cmp eq reg 1 0x00000200 ]
-
# arp operation != request
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
@@ -359,13 +292,6 @@ netdev test-netdev ingress
[ payload load 2b @ network header + 6 => reg 1 ]
[ cmp neq reg 1 0x00000a00 ]
-# arp operation != reply
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000608 ]
- [ payload load 2b @ network header + 6 => reg 1 ]
- [ cmp neq reg 1 0x00000200 ]
-
# meta iifname "invalid" arp ptype 0x0800 arp htype 1 arp hlen 6 arp plen 4 @nh,192,32 0xc0a88f10 @nh,144,48 set 0x112233445566
netdev test-netdev ingress
[ meta load iifname => reg 1 ]
@@ -409,3 +335,17 @@ netdev test-netdev ingress
[ payload load 6b @ network header + 18 => reg 1 ]
[ cmp eq reg 1 0xaaccbbaa 0x0000ccbb ]
+# arp saddr ip 192.168.1.1 arp daddr ether fe:ed:00:c0:ff:ee
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 10b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0101a8c0 0xc000edfe 0x0000eeff ]
+
+# arp daddr ether fe:ed:00:c0:ff:ee arp saddr ip 192.168.1.1
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000608 ]
+ [ payload load 10b @ network header + 14 => reg 1 ]
+ [ cmp eq reg 1 0x0101a8c0 0xc000edfe 0x0000eeff ]
+
diff --git a/tests/py/bridge/chains.t b/tests/py/bridge/chains.t
index 85dde73e..e071d9a3 100644
--- a/tests/py/bridge/chains.t
+++ b/tests/py/bridge/chains.t
@@ -1,8 +1,8 @@
# filter chains available are: prerouting, input, output, forward, postrouting
-:filter-pre;type filter hook input priority 0
+:filter-pre;type filter hook prerouting priority 0
:filter-output;type filter hook output priority 0
:filter-forward;type filter hook forward priority 0
:filter-input;type filter hook input priority 0
-:filter-post;type filter hook input priority 0
+:filter-post;type filter hook postrouting priority 0
*bridge;test-bridge;filter-pre,filter-output,filter-forward,filter-input,filter-post
diff --git a/tests/py/bridge/meta.t b/tests/py/bridge/meta.t
index 94525f29..171aa610 100644
--- a/tests/py/bridge/meta.t
+++ b/tests/py/bridge/meta.t
@@ -4,5 +4,10 @@
meta obrname "br0";ok
meta ibrname "br0";ok
-meta ibrvproto vlan;ok
+meta ibrvproto vlan;ok;meta ibrvproto 8021q
meta ibrpvid 100;ok
+
+meta protocol ip udp dport 67;ok
+meta protocol ip6 udp dport 67;ok
+
+meta broute set 1;fail
diff --git a/tests/py/bridge/meta.t.json b/tests/py/bridge/meta.t.json
index a7a180c2..d7dc9d7b 100644
--- a/tests/py/bridge/meta.t.json
+++ b/tests/py/bridge/meta.t.json
@@ -32,7 +32,7 @@
"meta": { "key": "ibrvproto" }
},
"op": "==",
- "right": "vlan"
+ "right": "8021q"
}
}
]
@@ -49,3 +49,57 @@
}
}
]
+
+# meta protocol ip udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
+# meta protocol ip6 udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
diff --git a/tests/py/bridge/meta.t.payload b/tests/py/bridge/meta.t.payload
index aa8c994b..0a39842a 100644
--- a/tests/py/bridge/meta.t.payload
+++ b/tests/py/bridge/meta.t.payload
@@ -17,3 +17,21 @@ bridge test-bridge input
bridge test-bridge input
[ meta load bri_iifpvid => reg 1 ]
[ cmp eq reg 1 0x00000064 ]
+
+# meta protocol ip udp dport 67
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
+
+# meta protocol ip6 udp dport 67
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
diff --git a/tests/py/bridge/redirect.t b/tests/py/bridge/redirect.t
new file mode 100644
index 00000000..5181e799
--- /dev/null
+++ b/tests/py/bridge/redirect.t
@@ -0,0 +1,5 @@
+:prerouting;type filter hook prerouting priority 0
+
+*bridge;test-bridge;prerouting
+
+meta broute set 1;ok
diff --git a/tests/py/bridge/redirect.t.json b/tests/py/bridge/redirect.t.json
new file mode 100644
index 00000000..7e32b329
--- /dev/null
+++ b/tests/py/bridge/redirect.t.json
@@ -0,0 +1,12 @@
+# meta broute set 1
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": { "key": "broute" }
+ },
+ "value": 1
+ }
+ }
+]
+
diff --git a/tests/py/bridge/redirect.t.payload b/tests/py/bridge/redirect.t.payload
new file mode 100644
index 00000000..1fcfa5f1
--- /dev/null
+++ b/tests/py/bridge/redirect.t.payload
@@ -0,0 +1,4 @@
+# meta broute set 1
+bridge test-bridge prerouting
+ [ immediate reg 1 0x00000001 ]
+ [ meta set broute with reg 1 ]
diff --git a/tests/py/bridge/reject.t b/tests/py/bridge/reject.t
index ee7e93c8..336b51bb 100644
--- a/tests/py/bridge/reject.t
+++ b/tests/py/bridge/reject.t
@@ -3,42 +3,40 @@
*bridge;test-bridge;input
# The output is specific for bridge family
-reject with icmp type host-unreachable;ok
-reject with icmp type net-unreachable;ok
-reject with icmp type prot-unreachable;ok
-reject with icmp type port-unreachable;ok
-reject with icmp type net-prohibited;ok
-reject with icmp type host-prohibited;ok
-reject with icmp type admin-prohibited;ok
-
-reject with icmpv6 type no-route;ok
-reject with icmpv6 type admin-prohibited;ok
-reject with icmpv6 type addr-unreachable;ok
-reject with icmpv6 type port-unreachable;ok
+reject with icmp host-unreachable;ok
+reject with icmp net-unreachable;ok
+reject with icmp prot-unreachable;ok
+reject with icmp port-unreachable;ok
+reject with icmp net-prohibited;ok
+reject with icmp host-prohibited;ok
+reject with icmp admin-prohibited;ok
+
+reject with icmpv6 no-route;ok
+reject with icmpv6 admin-prohibited;ok
+reject with icmpv6 addr-unreachable;ok
+reject with icmpv6 port-unreachable;ok
mark 12345 ip protocol tcp reject with tcp reset;ok;meta mark 0x00003039 ip protocol 6 reject with tcp reset
reject;ok
-ether type ip reject;ok;reject with icmp type port-unreachable
-ether type ip6 reject;ok;reject with icmpv6 type port-unreachable
-
-reject with icmpx type host-unreachable;ok
-reject with icmpx type no-route;ok
-reject with icmpx type admin-prohibited;ok
-reject with icmpx type port-unreachable;ok;reject
-
-ether type ipv6 reject with icmp type host-unreachable;fail
-ether type ip6 reject with icmp type host-unreachable;fail
-ether type ip reject with icmpv6 type no-route;fail
-ether type vlan reject;fail
+ether type ip reject;ok;reject with icmp port-unreachable
+ether type ip6 reject;ok;reject with icmpv6 port-unreachable
+
+reject with icmpx host-unreachable;ok
+reject with icmpx no-route;ok
+reject with icmpx admin-prohibited;ok
+reject with icmpx port-unreachable;ok;reject
+
+ether type ipv6 reject with icmp host-unreachable;fail
+ether type ip6 reject with icmp host-unreachable;fail
+ether type ip reject with icmpv6 no-route;fail
+ether type vlan reject;ok;ether type 8021q reject
ether type arp reject;fail
-ether type vlan reject;fail
-ether type arp reject;fail
-ether type vlan reject with tcp reset;fail
+ether type vlan reject with tcp reset;ok;meta l4proto 6 ether type 8021q reject with tcp reset
ether type arp reject with tcp reset;fail
ip protocol udp reject with tcp reset;fail
-ether type ip reject with icmpx type admin-prohibited;ok
-ether type ip6 reject with icmpx type admin-prohibited;ok
-ether type vlan reject with icmpx type admin-prohibited;fail
-ether type arp reject with icmpx type admin-prohibited;fail
+ether type ip reject with icmpx admin-prohibited;ok
+ether type ip6 reject with icmpx admin-prohibited;ok
+ether type 8021q reject with icmpx admin-prohibited;ok
+ether type arp reject with icmpx admin-prohibited;fail
diff --git a/tests/py/bridge/reject.t.json b/tests/py/bridge/reject.t.json
index d20a1d8b..9f9e6c1e 100644
--- a/tests/py/bridge/reject.t.json
+++ b/tests/py/bridge/reject.t.json
@@ -1,4 +1,4 @@
-# reject with icmp type host-unreachable
+# reject with icmp host-unreachable
[
{
"reject": {
@@ -8,7 +8,7 @@
}
]
-# reject with icmp type net-unreachable
+# reject with icmp net-unreachable
[
{
"reject": {
@@ -18,7 +18,7 @@
}
]
-# reject with icmp type prot-unreachable
+# reject with icmp prot-unreachable
[
{
"reject": {
@@ -28,7 +28,7 @@
}
]
-# reject with icmp type port-unreachable
+# reject with icmp port-unreachable
[
{
"reject": {
@@ -38,7 +38,7 @@
}
]
-# reject with icmp type net-prohibited
+# reject with icmp net-prohibited
[
{
"reject": {
@@ -48,7 +48,7 @@
}
]
-# reject with icmp type host-prohibited
+# reject with icmp host-prohibited
[
{
"reject": {
@@ -58,7 +58,7 @@
}
]
-# reject with icmp type admin-prohibited
+# reject with icmp admin-prohibited
[
{
"reject": {
@@ -68,7 +68,7 @@
}
]
-# reject with icmpv6 type no-route
+# reject with icmpv6 no-route
[
{
"reject": {
@@ -78,7 +78,7 @@
}
]
-# reject with icmpv6 type admin-prohibited
+# reject with icmpv6 admin-prohibited
[
{
"reject": {
@@ -88,7 +88,7 @@
}
]
-# reject with icmpv6 type addr-unreachable
+# reject with icmpv6 addr-unreachable
[
{
"reject": {
@@ -98,7 +98,7 @@
}
]
-# reject with icmpv6 type port-unreachable
+# reject with icmpv6 port-unreachable
[
{
"reject": {
@@ -183,7 +183,7 @@
}
]
-# reject with icmpx type host-unreachable
+# reject with icmpx host-unreachable
[
{
"reject": {
@@ -193,7 +193,7 @@
}
]
-# reject with icmpx type no-route
+# reject with icmpx no-route
[
{
"reject": {
@@ -203,7 +203,7 @@
}
]
-# reject with icmpx type admin-prohibited
+# reject with icmpx admin-prohibited
[
{
"reject": {
@@ -213,7 +213,7 @@
}
]
-# reject with icmpx type port-unreachable
+# reject with icmpx port-unreachable
[
{
"reject": {
@@ -223,7 +223,7 @@
}
]
-# ether type ip reject with icmpx type admin-prohibited
+# ether type ip reject with icmpx admin-prohibited
[
{
"match": {
@@ -245,7 +245,7 @@
}
]
-# ether type ip6 reject with icmpx type admin-prohibited
+# ether type ip6 reject with icmpx admin-prohibited
[
{
"match": {
@@ -267,3 +267,75 @@
}
]
+# ether type vlan reject with tcp reset
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+]
+
+# ether type vlan reject
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "vlan"
+ }
+ },
+ {
+ "reject": null
+ }
+]
+
+# ether type 8021q reject with icmpx admin-prohibited
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
diff --git a/tests/py/bridge/reject.t.json.output b/tests/py/bridge/reject.t.json.output
index 4f83f803..b8a44f0e 100644
--- a/tests/py/bridge/reject.t.json.output
+++ b/tests/py/bridge/reject.t.json.output
@@ -1,103 +1,3 @@
-# reject with icmp type host-unreachable
-[
- {
- "reject": {
- "expr": "host-unreachable",
- "type": "icmp"
- }
- }
-]
-
-# reject with icmp type net-unreachable
-[
- {
- "reject": {
- "expr": "net-unreachable",
- "type": "icmp"
- }
- }
-]
-
-# reject with icmp type prot-unreachable
-[
- {
- "reject": {
- "expr": "prot-unreachable",
- "type": "icmp"
- }
- }
-]
-
-# reject with icmp type net-prohibited
-[
- {
- "reject": {
- "expr": "net-prohibited",
- "type": "icmp"
- }
- }
-]
-
-# reject with icmp type host-prohibited
-[
- {
- "reject": {
- "expr": "host-prohibited",
- "type": "icmp"
- }
- }
-]
-
-# reject with icmp type admin-prohibited
-[
- {
- "reject": {
- "expr": "admin-prohibited",
- "type": "icmp"
- }
- }
-]
-
-# reject with icmpv6 type no-route
-[
- {
- "reject": {
- "expr": "no-route",
- "type": "icmpv6"
- }
- }
-]
-
-# reject with icmpv6 type admin-prohibited
-[
- {
- "reject": {
- "expr": "admin-prohibited",
- "type": "icmpv6"
- }
- }
-]
-
-# reject with icmpv6 type addr-unreachable
-[
- {
- "reject": {
- "expr": "addr-unreachable",
- "type": "icmpv6"
- }
- }
-]
-
-# reject with icmpv6 type port-unreachable
-[
- {
- "reject": {
- "expr": "port-unreachable",
- "type": "icmpv6"
- }
- }
-]
-
# mark 12345 ip protocol tcp reject with tcp reset
[
{
@@ -130,10 +30,13 @@
}
]
-# reject with icmpx type port-unreachable
+# reject
[
{
- "reject": null
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpx"
+ }
}
]
@@ -156,3 +59,25 @@
}
}
]
+
+# ether type vlan reject
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
diff --git a/tests/py/bridge/reject.t.payload b/tests/py/bridge/reject.t.payload
index 0d10547b..bad9adc0 100644
--- a/tests/py/bridge/reject.t.payload
+++ b/tests/py/bridge/reject.t.payload
@@ -1,64 +1,64 @@
-# reject with icmp type host-unreachable
+# reject with icmp host-unreachable
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ reject type 0 code 1 ]
-# reject with icmp type net-unreachable
+# reject with icmp net-unreachable
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ reject type 0 code 0 ]
-# reject with icmp type prot-unreachable
+# reject with icmp prot-unreachable
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ reject type 0 code 2 ]
-# reject with icmp type port-unreachable
+# reject with icmp port-unreachable
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ reject type 0 code 3 ]
-# reject with icmp type net-prohibited
+# reject with icmp net-prohibited
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ reject type 0 code 9 ]
-# reject with icmp type host-prohibited
+# reject with icmp host-prohibited
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ reject type 0 code 10 ]
-# reject with icmp type admin-prohibited
+# reject with icmp admin-prohibited
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ reject type 0 code 13 ]
-# reject with icmpv6 type no-route
+# reject with icmpv6 no-route
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
[ reject type 0 code 0 ]
-# reject with icmpv6 type admin-prohibited
+# reject with icmpv6 admin-prohibited
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
[ reject type 0 code 1 ]
-# reject with icmpv6 type addr-unreachable
+# reject with icmpv6 addr-unreachable
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
[ reject type 0 code 3 ]
-# reject with icmpv6 type port-unreachable
+# reject with icmpv6 port-unreachable
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -90,31 +90,51 @@ bridge test-bridge input
[ cmp eq reg 1 0x0000dd86 ]
[ reject type 0 code 4 ]
-# reject with icmpx type host-unreachable
+# reject with icmpx host-unreachable
bridge test-bridge input
[ reject type 2 code 2 ]
-# reject with icmpx type no-route
+# reject with icmpx no-route
bridge test-bridge input
[ reject type 2 code 0 ]
-# reject with icmpx type admin-prohibited
+# reject with icmpx admin-prohibited
bridge test-bridge input
[ reject type 2 code 3 ]
-# reject with icmpx type port-unreachable
+# reject with icmpx port-unreachable
bridge test-bridge input
[ reject type 2 code 1 ]
-# ether type ip reject with icmpx type admin-prohibited
+# ether type ip reject with icmpx admin-prohibited
bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ reject type 2 code 3 ]
-# ether type ip6 reject with icmpx type admin-prohibited
+# ether type ip6 reject with icmpx admin-prohibited
bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
[ reject type 2 code 3 ]
+# ether type vlan reject
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ reject type 2 code 1 ]
+
+# ether type vlan reject with tcp reset
+bridge
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ reject type 1 code 0 ]
+
+# ether type 8021q reject with icmpx admin-prohibited
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ reject type 2 code 3 ]
+
diff --git a/tests/py/bridge/vlan.t b/tests/py/bridge/vlan.t
index 7a52a502..8fa90dac 100644
--- a/tests/py/bridge/vlan.t
+++ b/tests/py/bridge/vlan.t
@@ -1,27 +1,29 @@
: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
*bridge;test-bridge;input
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
vlan id 4094;ok
vlan id 0;ok
# bad vlan id
vlan id 4096;fail
-vlan id 4094 vlan cfi 0;ok
-vlan id 4094 vlan cfi != 1;ok
-vlan id 4094 vlan cfi 1;ok
-# bad cfi
-vlan id 4094 vlan cfi 2;fail
-vlan id 4094 vlan cfi 1 vlan pcp 8;fail
-vlan id 4094 vlan cfi 1 vlan pcp 7;ok
-vlan id 4094 vlan cfi 1 vlan pcp 3;ok
+vlan id 4094 vlan dei 0;ok
+vlan id 4094 vlan dei 1;ok
+vlan id 4094 vlan dei != 1;ok
+vlan id 4094 vlan cfi 1;ok;vlan id 4094 vlan dei 1
+# bad dei
+vlan id 4094 vlan dei 2;fail
+vlan id 4094 vlan dei 1 vlan pcp 8;fail
+vlan id 4094 vlan dei 1 vlan pcp 7;ok
+vlan id 4094 vlan dei 1 vlan pcp 3;ok
ether type vlan vlan id 4094;ok;vlan id 4094
ether type vlan vlan id 0;ok;vlan id 0
-ether type vlan vlan id 4094 vlan cfi 0;ok;vlan id 4094 vlan cfi 0
-ether type vlan vlan id 4094 vlan cfi 1;ok;vlan id 4094 vlan cfi 1
-ether type vlan vlan id 4094 vlan cfi 2;fail
+ether type vlan vlan id 4094 vlan dei 0;ok;vlan id 4094 vlan dei 0
+ether type vlan vlan id 4094 vlan dei 1;ok;vlan id 4094 vlan dei 1
+ether type vlan vlan id 4094 vlan dei 2;fail
vlan id 4094 tcp dport 22;ok
vlan id 1 ip saddr 10.0.0.1;ok
@@ -32,8 +34,23 @@ ether type vlan vlan id 1 ip saddr 10.0.0.0/23 udp dport 53;ok;vlan id 1 ip sadd
vlan id { 1, 2, 4, 100, 4095 } vlan pcp 1-3;ok
vlan id { 1, 2, 4, 100, 4096 };fail
-ether type vlan ip protocol 1 accept;ok
+ether type vlan ip protocol 1 accept;ok;ether type 8021q ip protocol 1 accept
+
+# IEEE 802.1AD
+ether type 8021ad vlan id 1 ip protocol 6 accept;ok
+ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip counter;ok
+ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip ip protocol 6;ok;ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 ip protocol 6
# illegal dependencies
ether type ip vlan id 1;fail
ether type ip vlan id 1 ip saddr 10.0.0.1;fail
+
+# mangling
+vlan id 1 vlan id set 2;ok
+
+ether saddr 00:01:02:03:04:05 vlan id 1;ok
+vlan id 2 ether saddr 0:1:2:3:4:6;ok;ether saddr 00:01:02:03:04:06 vlan id 2
+
+ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 };ok
+
+ether saddr 00:11:22:33:44:55 counter ether type 8021q;ok
diff --git a/tests/py/bridge/vlan.t.json b/tests/py/bridge/vlan.t.json
index 3fb2e4f7..7dfcdb4b 100644
--- a/tests/py/bridge/vlan.t.json
+++ b/tests/py/bridge/vlan.t.json
@@ -30,7 +30,7 @@
}
]
-# vlan id 4094 vlan cfi 0
+# vlan id 4094 vlan dei 0
[
{
"match": {
@@ -48,7 +48,7 @@
"match": {
"left": {
"payload": {
- "field": "cfi",
+ "field": "dei",
"protocol": "vlan"
}
},
@@ -58,7 +58,7 @@
}
]
-# vlan id 4094 vlan cfi != 1
+# vlan id 4094 vlan dei 1
[
{
"match": {
@@ -76,7 +76,35 @@
"match": {
"left": {
"payload": {
- "field": "cfi",
+ "field": "dei",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# vlan id 4094 vlan dei != 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 4094
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dei",
"protocol": "vlan"
}
},
@@ -104,7 +132,7 @@
"match": {
"left": {
"payload": {
- "field": "cfi",
+ "field": "dei",
"protocol": "vlan"
}
},
@@ -114,7 +142,7 @@
}
]
-# vlan id 4094 vlan cfi 1 vlan pcp 7
+# vlan id 4094 vlan dei 1 vlan pcp 7
[
{
"match": {
@@ -132,7 +160,7 @@
"match": {
"left": {
"payload": {
- "field": "cfi",
+ "field": "dei",
"protocol": "vlan"
}
},
@@ -154,7 +182,7 @@
}
]
-# vlan id 4094 vlan cfi 1 vlan pcp 3
+# vlan id 4094 vlan dei 1 vlan pcp 3
[
{
"match": {
@@ -172,7 +200,7 @@
"match": {
"left": {
"payload": {
- "field": "cfi",
+ "field": "dei",
"protocol": "vlan"
}
},
@@ -226,7 +254,7 @@
}
]
-# ether type vlan vlan id 4094 vlan cfi 0
+# ether type vlan vlan id 4094 vlan dei 0
[
{
"match": {
@@ -244,7 +272,7 @@
"match": {
"left": {
"payload": {
- "field": "cfi",
+ "field": "dei",
"protocol": "vlan"
}
},
@@ -254,7 +282,7 @@
}
]
-# ether type vlan vlan id 4094 vlan cfi 1
+# ether type vlan vlan id 4094 vlan dei 1
[
{
"match": {
@@ -272,7 +300,7 @@
"match": {
"left": {
"payload": {
- "field": "cfi",
+ "field": "dei",
"protocol": "vlan"
}
},
@@ -530,3 +558,337 @@
}
]
+# ether type 8021ad vlan id 1 ip protocol 6 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021ad"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip counter
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021ad"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "counter": {
+ "bytes": 0,
+ "packets": 0
+ }
+ }
+]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip ip protocol 6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021ad"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "tcp"
+ }
+ }
+]
+
+# vlan id 1 vlan id set 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "value": 2
+ }
+ }
+]
+
+# ether saddr 00:01:02:03:04:05 vlan id 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:01:02:03:04:05"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# vlan id 2 ether saddr 0:1:2:3:4:6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:01:02:03:04:06"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "0a:0b:0c:0d:0e:0f",
+ 42
+ ]
+ },
+ {
+ "concat": [
+ "0a:0b:0c:0d:0e:0f",
+ 4095
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ether saddr 00:11:22:33:44:55 counter ether type 8021q
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:11:22:33:44:55"
+ }
+ },
+ {
+ "counter": {
+ "bytes": 0,
+ "packets": 0
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ }
+]
diff --git a/tests/py/bridge/vlan.t.json.output b/tests/py/bridge/vlan.t.json.output
index 8f27ec0e..eea2d411 100644
--- a/tests/py/bridge/vlan.t.json.output
+++ b/tests/py/bridge/vlan.t.json.output
@@ -9,7 +9,7 @@
}
},
"op": "==",
- "right": "vlan"
+ "right": "8021q"
}
},
{
@@ -29,3 +29,207 @@
}
]
+# ether type 8021ad vlan id 1 ip protocol 6 accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021ad"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip counter
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021ad"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "counter": null
+ }
+]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip ip protocol 6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021ad"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ }
+]
+
+# ether saddr 00:11:22:33:44:55 counter ether type 8021q
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "00:11:22:33:44:55"
+ }
+ },
+ {
+ "counter": null
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "8021q"
+ }
+ }
+]
diff --git a/tests/py/bridge/vlan.t.payload b/tests/py/bridge/vlan.t.payload
index bb8925e3..2592bb96 100644
--- a/tests/py/bridge/vlan.t.payload
+++ b/tests/py/bridge/vlan.t.payload
@@ -3,7 +3,7 @@ bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
# vlan id 0
@@ -11,40 +11,51 @@ bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
-# vlan id 4094 vlan cfi 0
+# vlan id 4094 vlan cfi 1
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+
+# vlan id 4094 vlan dei 0
bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
-# vlan id 4094 vlan cfi != 1
+# vlan id 4094 vlan dei != 1
bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000010 ]
-# vlan id 4094 vlan cfi 1
+# vlan id 4094 vlan dei 1
bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000010 ]
# ether type vlan vlan id 4094
@@ -52,7 +63,7 @@ bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
# ether type vlan vlan id 0
@@ -60,29 +71,29 @@ bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
-# ether type vlan vlan id 4094 vlan cfi 0
+# ether type vlan vlan id 4094 vlan dei 0
bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
-# ether type vlan vlan id 4094 vlan cfi 1
+# ether type vlan vlan id 4094 vlan dei 1
bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000010 ]
# vlan id 4094 tcp dport 22
@@ -90,7 +101,7 @@ bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -102,7 +113,7 @@ bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 2b @ link header + 16 => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
@@ -114,12 +125,12 @@ bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 2b @ link header + 16 => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00feffff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00feffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000000a ]
# vlan id 1 ip saddr 10.0.0.0/23 udp dport 53
@@ -127,12 +138,12 @@ bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 2b @ link header + 16 => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00feffff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00feffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000000a ]
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000011 ]
@@ -144,44 +155,44 @@ bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 2b @ link header + 16 => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00feffff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00feffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000000a ]
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000011 ]
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00003500 ]
-# vlan id 4094 vlan cfi 1 vlan pcp 7
+# vlan id 4094 vlan dei 1 vlan pcp 7
bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000010 ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000e0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000e0 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x000000e0 ]
-# vlan id 4094 vlan cfi 1 vlan pcp 3
+# vlan id 4094 vlan dei 1 vlan pcp 3
bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000010 ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000e0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000e0 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000060 ]
# vlan id { 1, 2, 4, 100, 4095 } vlan pcp 1-3
@@ -192,10 +203,10 @@ bridge test-bridge input
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000e0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000e0 ) ^ 0x00000000 ]
[ cmp gte reg 1 0x00000020 ]
[ cmp lte reg 1 0x00000060 ]
@@ -209,3 +220,95 @@ bridge test-bridge input
[ cmp eq reg 1 0x00000001 ]
[ immediate reg 0 accept ]
+# ether type 8021ad vlan id 1 ip protocol 6 accept
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000a888 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 0 accept ]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip counter
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000a888 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 18 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+ [ payload load 2b @ link header + 20 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ counter pkts 0 bytes 0 ]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip ip protocol 6
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000a888 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 18 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+ [ payload load 2b @ link header + 20 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# vlan id 1 vlan id set 2
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000200 ]
+ [ payload write reg 1 => 2b @ link header + 14 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# ether saddr 00:01:02:03:04:05 vlan id 1
+bridge test-bridge input
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810504 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# vlan id 2 ether saddr 0:1:2:3:4:6
+bridge test-bridge input
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810604 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+__set%d test-bridge 3 size 2
+__set%d test-bridge 0
+ element 0d0c0b0a 00000f0e 00002a00 : 0 [end] element 0d0c0b0a 00000f0e 0000ff0f : 0 [end]
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ payload load 2b @ link header + 14 => reg 10 ]
+ [ bitwise reg 10 = ( reg 10 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# ether saddr 00:11:22:33:44:55 counter ether type 8021q
+bridge test-bridge input
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x33221100 0x00005544 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
diff --git a/tests/py/bridge/vlan.t.payload.netdev b/tests/py/bridge/vlan.t.payload.netdev
index 0a3f90a5..f3341947 100644
--- a/tests/py/bridge/vlan.t.payload.netdev
+++ b/tests/py/bridge/vlan.t.payload.netdev
@@ -5,7 +5,7 @@ netdev test-netdev ingress
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
# vlan id 0
@@ -15,46 +15,59 @@ netdev test-netdev ingress
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
-# vlan id 4094 vlan cfi 0
+# vlan id 4094 vlan dei 0
netdev test-netdev ingress
[ meta load iiftype => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
-# vlan id 4094 vlan cfi != 1
+# vlan id 4094 vlan dei != 1
netdev test-netdev ingress
[ meta load iiftype => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000010 ]
# vlan id 4094 vlan cfi 1
+netdev
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000fe0f ]
+ [ payload load 1b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000010 ]
+
+# vlan id 4094 vlan dei 1
netdev test-netdev ingress
[ meta load iiftype => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000010 ]
# ether type vlan vlan id 4094
@@ -64,7 +77,7 @@ netdev test-netdev ingress
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
# ether type vlan vlan id 0
@@ -74,33 +87,33 @@ netdev test-netdev ingress
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
-# ether type vlan vlan id 4094 vlan cfi 0
+# ether type vlan vlan id 4094 vlan dei 0
netdev test-netdev ingress
[ meta load iiftype => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
-# ether type vlan vlan id 4094 vlan cfi 1
+# ether type vlan vlan id 4094 vlan dei 1
netdev test-netdev ingress
[ meta load iiftype => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000010 ]
# vlan id 4094 tcp dport 22
@@ -110,7 +123,7 @@ netdev test-netdev ingress
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -124,7 +137,7 @@ netdev test-netdev ingress
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 2b @ link header + 16 => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
@@ -138,12 +151,12 @@ netdev test-netdev ingress
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 2b @ link header + 16 => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00feffff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00feffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000000a ]
# vlan id 1 ip saddr 10.0.0.0/23 udp dport 53
@@ -153,12 +166,12 @@ netdev test-netdev ingress
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 2b @ link header + 16 => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00feffff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00feffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000000a ]
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000011 ]
@@ -172,48 +185,48 @@ netdev test-netdev ingress
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000100 ]
[ payload load 2b @ link header + 16 => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00feffff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00feffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000000a ]
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000011 ]
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00003500 ]
-# vlan id 4094 vlan cfi 1 vlan pcp 7
+# vlan id 4094 vlan dei 1 vlan pcp 7
netdev test-netdev ingress
[ meta load iiftype => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000010 ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000e0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000e0 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x000000e0 ]
-# vlan id 4094 vlan cfi 1 vlan pcp 3
+# vlan id 4094 vlan dei 1 vlan pcp 3
netdev test-netdev ingress
[ meta load iiftype => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000fe0f ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000010 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000010 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000010 ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000e0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000e0 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000060 ]
# vlan id { 1, 2, 4, 100, 4095 } vlan pcp 1-3
@@ -226,10 +239,10 @@ netdev test-netdev ingress
[ payload load 2b @ link header + 12 => reg 1 ]
[ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
[ payload load 1b @ link header + 14 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000e0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000e0 ) ^ 0x00000000 ]
[ cmp gte reg 1 0x00000020 ]
[ cmp lte reg 1 0x00000060 ]
@@ -245,3 +258,111 @@ netdev test-netdev ingress
[ cmp eq reg 1 0x00000001 ]
[ immediate reg 0 accept ]
+# ether type 8021ad vlan id 1 ip protocol 6 accept
+netdev
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000a888 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 0 accept ]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip counter
+netdev
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000a888 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 18 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+ [ payload load 2b @ link header + 20 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ counter pkts 0 bytes 0 ]
+
+# ether type 8021ad vlan id 1 vlan type 8021q vlan id 2 vlan type ip ip protocol 6
+netdev
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x0000a888 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 18 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+ [ payload load 2b @ link header + 20 => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# vlan id 1 vlan id set 2
+netdev
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000200 ]
+ [ payload write reg 1 => 2b @ link header + 14 csum_type 0 csum_off 0 csum_flags 0x0 ]
+
+# vlan id 2 ether saddr 0:1:2:3:4:6
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810604 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# ether saddr 00:01:02:03:04:05 vlan id 1
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x03020100 0x00810504 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# ether saddr . vlan id { 0a:0b:0c:0d:0e:0f . 42, 0a:0b:0c:0d:0e:0f . 4095 }
+__set%d test-netdev 3 size 2
+__set%d test-netdev 0
+ element 0d0c0b0a 00000f0e 00002a00 : 0 [end] element 0d0c0b0a 00000f0e 0000ff0f : 0 [end]
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ payload load 2b @ link header + 14 => reg 10 ]
+ [ bitwise reg 10 = ( reg 10 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# ether saddr 00:11:22:33:44:55 counter ether type 8021q
+bridge test-bridge input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 6b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0x33221100 0x00005544 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
diff --git a/tests/py/inet/ah.t b/tests/py/inet/ah.t
index 8544d9dd..83b6202b 100644
--- a/tests/py/inet/ah.t
+++ b/tests/py/inet/ah.t
@@ -1,12 +1,11 @@
: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
-*netdev;test-netdev;ingress
-
-# nexthdr Bug to list table.
+*netdev;test-netdev;ingress,egress
- ah nexthdr esp;ok
- ah nexthdr ah;ok
@@ -22,8 +21,6 @@
ah hdrlength 11-23;ok
ah hdrlength != 11-23;ok
-ah hdrlength { 11-23};ok
-ah hdrlength != { 11-23};ok
ah hdrlength {11, 23, 44 };ok
ah hdrlength != {11, 23, 44 };ok
@@ -33,8 +30,6 @@ ah reserved 33-45;ok
ah reserved != 33-45;ok
ah reserved {23, 100};ok
ah reserved != {23, 100};ok
-ah reserved { 33-55};ok
-ah reserved != { 33-55};ok
ah spi 111;ok
ah spi != 111;ok
@@ -42,15 +37,11 @@ ah spi 111-222;ok
ah spi != 111-222;ok
ah spi {111, 122};ok
ah spi != {111, 122};ok
-ah spi { 111-122};ok
-ah spi != { 111-122};ok
# sequence
ah sequence 123;ok
ah sequence != 123;ok
ah sequence {23, 25, 33};ok
ah sequence != {23, 25, 33};ok
-ah sequence { 23-33};ok
-ah sequence != { 23-33};ok
ah sequence 23-33;ok
ah sequence != 23-33;ok
diff --git a/tests/py/inet/ah.t.json b/tests/py/inet/ah.t.json
index 4efdb0dd..217280b6 100644
--- a/tests/py/inet/ah.t.json
+++ b/tests/py/inet/ah.t.json
@@ -34,46 +34,6 @@
}
]
-# ah hdrlength { 11-23}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "hdrlength",
- "protocol": "ah"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 11, 23 ] }
- ]
- }
- }
- }
-]
-
-# ah hdrlength != { 11-23}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "hdrlength",
- "protocol": "ah"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 11, 23 ] }
- ]
- }
- }
- }
-]
-
# ah hdrlength {11, 23, 44 }
[
{
@@ -228,46 +188,6 @@
}
]
-# ah reserved { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "reserved",
- "protocol": "ah"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# ah reserved != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "reserved",
- "protocol": "ah"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# ah spi 111
[
{
@@ -378,46 +298,6 @@
}
]
-# ah spi { 111-122}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "spi",
- "protocol": "ah"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 111, 122 ] }
- ]
- }
- }
- }
-]
-
-# ah spi != { 111-122}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "spi",
- "protocol": "ah"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 111, 122 ] }
- ]
- }
- }
- }
-]
-
# ah sequence 123
[
{
@@ -494,46 +374,6 @@
}
]
-# ah sequence { 23-33}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sequence",
- "protocol": "ah"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 23, 33 ] }
- ]
- }
- }
- }
-]
-
-# ah sequence != { 23-33}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sequence",
- "protocol": "ah"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 23, 33 ] }
- ]
- }
- }
- }
-]
-
# ah sequence 23-33
[
{
diff --git a/tests/py/inet/ah.t.payload b/tests/py/inet/ah.t.payload
index 5ec5fba1..7ddd72d5 100644
--- a/tests/py/inet/ah.t.payload
+++ b/tests/py/inet/ah.t.payload
@@ -13,26 +13,6 @@ inet test-inet input
[ payload load 1b @ transport header + 1 => reg 1 ]
[ range neq reg 1 0x0000000b 0x00000017 ]
-# ah hdrlength { 11-23}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 0000000b : 0 [end] element 00000018 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000033 ]
- [ payload load 1b @ transport header + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ah hdrlength != { 11-23}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 0000000b : 0 [end] element 00000018 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000033 ]
- [ payload load 1b @ transport header + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ah hdrlength {11, 23, 44 }
__set%d test-inet 3
__set%d test-inet 0
@@ -102,26 +82,6 @@ inet test-inet input
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ah reserved { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000033 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ah reserved != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000033 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ah spi 111
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -171,26 +131,6 @@ inet test-inet input
[ payload load 4b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ah spi { 111-122}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 6f000000 : 0 [end] element 7b000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000033 ]
- [ payload load 4b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ah spi != { 111-122}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 6f000000 : 0 [end] element 7b000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000033 ]
- [ payload load 4b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ah sequence 123
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -225,26 +165,6 @@ inet test-inet input
[ payload load 4b @ transport header + 8 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ah sequence { 23-33}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 17000000 : 0 [end] element 22000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000033 ]
- [ payload load 4b @ transport header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ah sequence != { 23-33}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 17000000 : 0 [end] element 22000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000033 ]
- [ payload load 4b @ transport header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ah sequence 23-33
inet test-inet input
[ meta load l4proto => reg 1 ]
diff --git a/tests/py/inet/comp.t b/tests/py/inet/comp.t
index 0df18139..2ef53820 100644
--- a/tests/py/inet/comp.t
+++ b/tests/py/inet/comp.t
@@ -1,10 +1,11 @@
: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
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
# BUG: nft: payload.c:88: payload_expr_pctx_update: Assertion `left->payload.base + 1 <= (__PROTO_BASE_MAX - 1)' failed.
- comp nexthdr esp;ok;comp nexthdr 50
@@ -20,8 +21,6 @@ comp flags 0x33-0x45;ok
comp flags != 0x33-0x45;ok
comp flags {0x33, 0x55, 0x67, 0x88};ok
comp flags != {0x33, 0x55, 0x67, 0x88};ok
-comp flags { 0x33-0x55};ok
-comp flags != { 0x33-0x55};ok
comp cpi 22;ok
comp cpi != 233;ok
@@ -29,5 +28,3 @@ comp cpi 33-45;ok
comp cpi != 33-45;ok
comp cpi {33, 55, 67, 88};ok
comp cpi != {33, 55, 67, 88};ok
-comp cpi { 33-55};ok
-comp cpi != { 33-55};ok
diff --git a/tests/py/inet/comp.t.json b/tests/py/inet/comp.t.json
index b9b24f98..c9f6fcac 100644
--- a/tests/py/inet/comp.t.json
+++ b/tests/py/inet/comp.t.json
@@ -128,46 +128,6 @@
}
]
-# comp flags { 0x33-0x55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "flags",
- "protocol": "comp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ "0x33", "0x55" ] }
- ]
- }
- }
- }
-]
-
-# comp flags != { 0x33-0x55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "flags",
- "protocol": "comp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ "0x33", "0x55" ] }
- ]
- }
- }
- }
-]
-
# comp cpi 22
[
{
@@ -282,43 +242,3 @@
}
]
-# comp cpi { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "cpi",
- "protocol": "comp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# comp cpi != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "cpi",
- "protocol": "comp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
diff --git a/tests/py/inet/comp.t.payload b/tests/py/inet/comp.t.payload
index dec38aea..024e47cd 100644
--- a/tests/py/inet/comp.t.payload
+++ b/tests/py/inet/comp.t.payload
@@ -54,26 +54,6 @@ inet test-inet input
[ payload load 1b @ transport header + 1 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# comp flags { 0x33-0x55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000033 : 0 [end] element 00000056 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x0000006c ]
- [ payload load 1b @ transport header + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# comp flags != { 0x33-0x55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000033 : 0 [end] element 00000056 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x0000006c ]
- [ payload load 1b @ transport header + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# comp cpi 22
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -123,23 +103,3 @@ inet test-inet input
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# comp cpi { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x0000006c ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# comp cpi != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x0000006c ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
diff --git a/tests/py/inet/ct.t b/tests/py/inet/ct.t
index 3d0dffad..5312b328 100644
--- a/tests/py/inet/ct.t
+++ b/tests/py/inet/ct.t
@@ -6,7 +6,7 @@
meta nfproto ipv4 ct original saddr 1.2.3.4;ok;ct original ip saddr 1.2.3.4
ct original ip6 saddr ::1;ok
-ct original ip daddr {1.2.3.4} accept;ok
+ct original ip daddr 1.2.3.4 accept;ok
# missing protocol context
ct original saddr ::1;fail
diff --git a/tests/py/inet/ct.t.json b/tests/py/inet/ct.t.json
index e7f928ca..223ac9e7 100644
--- a/tests/py/inet/ct.t.json
+++ b/tests/py/inet/ct.t.json
@@ -39,7 +39,7 @@
}
]
-# ct original ip daddr {1.2.3.4} accept
+# ct original ip daddr 1.2.3.4 accept
[
{
"match": {
@@ -50,11 +50,7 @@
}
},
"op": "==",
- "right": {
- "set": [
- "1.2.3.4"
- ]
- }
+ "right": "1.2.3.4"
}
},
{
diff --git a/tests/py/inet/ct.t.payload b/tests/py/inet/ct.t.payload
index 3b274f8c..f7a2ef27 100644
--- a/tests/py/inet/ct.t.payload
+++ b/tests/py/inet/ct.t.payload
@@ -10,11 +10,8 @@ inet test-inet input
[ ct load src_ip6 => reg 1 , dir original ]
[ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x01000000 ]
-# ct original ip daddr {1.2.3.4} accept
-__set%d test-inet 3 size 1
-__set%d test-inet 0
- element 04030201 : 0 [end]
+# ct original ip daddr 1.2.3.4 accept
inet test-inet input
[ ct load dst_ip => reg 1 , dir original ]
- [ lookup reg 1 set __set%d ]
+ [ cmp eq reg 1 0x04030201 ]
[ immediate reg 0 accept ]
diff --git a/tests/py/inet/dccp.t b/tests/py/inet/dccp.t
index f0dd788b..99cddbe7 100644
--- a/tests/py/inet/dccp.t
+++ b/tests/py/inet/dccp.t
@@ -1,30 +1,30 @@
: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
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
dccp sport 21-35;ok
dccp sport != 21-35;ok
dccp sport {23, 24, 25};ok
dccp sport != {23, 24, 25};ok
-dccp sport { 20-50 };ok
-dccp sport ftp-data - re-mail-ck;ok;dccp sport 20-50
dccp sport 20-50;ok
-dccp sport { 20-50};ok
-dccp sport != { 20-50};ok
# dccp dport 21-35;ok
# dccp dport != 21-35;ok
dccp dport {23, 24, 25};ok
dccp dport != {23, 24, 25};ok
-dccp dport { 20-50};ok
-dccp dport != { 20-50};ok
dccp type {request, response, data, ack, dataack, closereq, close, reset, sync, syncack};ok
dccp type != {request, response, data, ack, dataack, closereq, close, reset, sync, syncack};ok
dccp type request;ok
dccp type != request;ok
+
+dccp option 0 exists;ok
+dccp option 43 missing;ok
+dccp option 255 exists;ok
+dccp option 256 exists;fail
diff --git a/tests/py/inet/dccp.t.json b/tests/py/inet/dccp.t.json
index 9260fbc5..9f47e97b 100644
--- a/tests/py/inet/dccp.t.json
+++ b/tests/py/inet/dccp.t.json
@@ -78,44 +78,6 @@
}
]
-# dccp sport { 20-50 }
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sport",
- "protocol": "dccp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 20, 50 ] }
- ]
- }
- }
- }
-]
-
-# dccp sport ftp-data - re-mail-ck
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sport",
- "protocol": "dccp"
- }
- },
- "op": "==",
- "right": {
- "range": [ "ftp-data", "re-mail-ck" ]
- }
- }
- }
-]
-
# dccp sport 20-50
[
{
@@ -134,46 +96,6 @@
}
]
-# dccp sport { 20-50}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sport",
- "protocol": "dccp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 20, 50 ] }
- ]
- }
- }
- }
-]
-
-# dccp sport != { 20-50}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sport",
- "protocol": "dccp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 20, 50 ] }
- ]
- }
- }
- }
-]
-
# dccp dport {23, 24, 25}
[
{
@@ -218,46 +140,6 @@
}
]
-# dccp dport { 20-50}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "dport",
- "protocol": "dccp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 20, 50 ] }
- ]
- }
- }
- }
-]
-
-# dccp dport != { 20-50}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "dport",
- "protocol": "dccp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 20, 50 ] }
- ]
- }
- }
- }
-]
-
# dccp type {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}
[
{
@@ -348,3 +230,47 @@
}
]
+# dccp option 0 exists
+[
+ {
+ "match": {
+ "left": {
+ "dccp option": {
+ "type": 0
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# dccp option 43 missing
+[
+ {
+ "match": {
+ "left": {
+ "dccp option": {
+ "type": 43
+ }
+ },
+ "op": "==",
+ "right": false
+ }
+ }
+]
+
+# dccp option 255 exists
+[
+ {
+ "match": {
+ "left": {
+ "dccp option": {
+ "type": 255
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
diff --git a/tests/py/inet/dccp.t.payload b/tests/py/inet/dccp.t.payload
index b5a48f40..c0b87be1 100644
--- a/tests/py/inet/dccp.t.payload
+++ b/tests/py/inet/dccp.t.payload
@@ -33,24 +33,6 @@ inet test-inet input
[ payload load 2b @ transport header + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# dccp sport { 20-50 }
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00001400 : 0 [end] element 00003300 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000021 ]
- [ payload load 2b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# dccp sport ftp-data - re-mail-ck
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000021 ]
- [ payload load 2b @ transport header + 0 => reg 1 ]
- [ cmp gte reg 1 0x00001400 ]
- [ cmp lte reg 1 0x00003200 ]
-
# dccp sport 20-50
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -59,26 +41,6 @@ inet test-inet input
[ cmp gte reg 1 0x00001400 ]
[ cmp lte reg 1 0x00003200 ]
-# dccp sport { 20-50}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00001400 : 0 [end] element 00003300 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000021 ]
- [ payload load 2b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# dccp sport != { 20-50}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00001400 : 0 [end] element 00003300 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000021 ]
- [ payload load 2b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# dccp dport {23, 24, 25}
__set%d test-ip4 3
__set%d test-ip4 0
@@ -99,26 +61,6 @@ inet test-inet input
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# dccp dport { 20-50}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00001400 : 0 [end] element 00003300 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000021 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# dccp dport != { 20-50}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00001400 : 0 [end] element 00003300 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000021 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# dccp type {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}
__set%d test-inet 3
__set%d test-inet 0
@@ -127,7 +69,7 @@ inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000021 ]
[ payload load 1b @ transport header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000001e ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000001e ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
# dccp type != {request, response, data, ack, dataack, closereq, close, reset, sync, syncack}
@@ -138,7 +80,7 @@ inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000021 ]
[ payload load 1b @ transport header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000001e ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000001e ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d 0x1 ]
# dccp type request
@@ -146,7 +88,7 @@ inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000021 ]
[ payload load 1b @ transport header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000001e ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000001e ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
# dccp type != request
@@ -154,6 +96,20 @@ inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000021 ]
[ payload load 1b @ transport header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000001e ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000001e ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000000 ]
+# dccp option 0 exists
+ip test-inet input
+ [ exthdr load 1b @ 0 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# dccp option 43 missing
+ip test-inet input
+ [ exthdr load 1b @ 43 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# dccp option 255 exists
+ip test-inet input
+ [ exthdr load 1b @ 255 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
diff --git a/tests/py/inet/dnat.t b/tests/py/inet/dnat.t
index fcdf9436..e4e169f2 100644
--- a/tests/py/inet/dnat.t
+++ b/tests/py/inet/dnat.t
@@ -6,6 +6,7 @@ iifname "foo" tcp dport 80 redirect to :8080;ok
iifname "eth0" tcp dport 443 dnat ip to 192.168.3.2;ok
iifname "eth0" tcp dport 443 dnat ip6 to [dead::beef]:4443;ok
+meta l4proto tcp dnat to :80;ok;meta l4proto 6 dnat to :80
dnat ip to ct mark map { 0x00000014 : 1.2.3.4};ok
dnat ip to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4};ok
@@ -14,3 +15,8 @@ dnat ip6 to 1.2.3.4;fail
dnat to 1.2.3.4;fail
dnat ip6 to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4};fail
ip6 daddr dead::beef dnat to 10.1.2.3;fail
+
+meta l4proto { tcp, udp } dnat ip to 1.1.1.1:80;ok;meta l4proto { 6, 17} dnat ip to 1.1.1.1:80
+ip protocol { tcp, udp } dnat ip to 1.1.1.1:80;ok;ip protocol { 6, 17} dnat ip to 1.1.1.1:80
+meta l4proto { tcp, udp } tcp dport 20 dnat to 1.1.1.1:80;fail
+ip protocol { tcp, udp } tcp dport 20 dnat to 1.1.1.1:80;fail
diff --git a/tests/py/inet/dnat.t.json b/tests/py/inet/dnat.t.json
index ac6dac62..c341a045 100644
--- a/tests/py/inet/dnat.t.json
+++ b/tests/py/inet/dnat.t.json
@@ -164,3 +164,78 @@
}
]
+# meta l4proto { tcp, udp } dnat ip to 1.1.1.1:80
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17
+ ]
+ }
+ }
+ },
+ {
+ "dnat": {
+ "addr": "1.1.1.1",
+ "family": "ip",
+ "port": 80
+ }
+ }
+]
+
+# ip protocol { tcp, udp } dnat ip to 1.1.1.1:80
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17
+ ]
+ }
+ }
+ },
+ {
+ "dnat": {
+ "addr": "1.1.1.1",
+ "family": "ip",
+ "port": 80
+ }
+ }
+]
+
+# meta l4proto tcp dnat to :80
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "dnat": {
+ "port": 80
+ }
+ }
+]
+
diff --git a/tests/py/inet/dnat.t.payload b/tests/py/inet/dnat.t.payload
index b81caf7b..ce1601ab 100644
--- a/tests/py/inet/dnat.t.payload
+++ b/tests/py/inet/dnat.t.payload
@@ -7,7 +7,7 @@ inet test-inet prerouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00005000 ]
[ immediate reg 1 0x0000901f ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# iifname "eth0" tcp dport 443 dnat ip to 192.168.3.2
inet test-inet prerouting
@@ -18,7 +18,7 @@ inet test-inet prerouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000bb01 ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
# iifname "eth0" tcp dport 443 dnat ip6 to [dead::beef]:4443
inet test-inet prerouting
@@ -30,7 +30,7 @@ inet test-inet prerouting
[ cmp eq reg 1 0x0000bb01 ]
[ immediate reg 1 0x0000adde 0x00000000 0x00000000 0xefbe0000 ]
[ immediate reg 2 0x00005b11 ]
- [ nat dnat ip6 addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 ]
+ [ nat dnat ip6 addr_min reg 1 proto_min reg 2 flags 0x2 ]
# dnat ip to ct mark map { 0x00000014 : 1.2.3.4}
__map%d test-inet b size 1
@@ -39,7 +39,7 @@ __map%d test-inet 0
inet test-inet prerouting
[ ct load mark => reg 1 ]
[ lookup reg 1 set __map%d dreg 1 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
# dnat ip to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4}
__map%d test-inet b size 1
@@ -51,4 +51,36 @@ inet test-inet prerouting
[ ct load mark => reg 1 ]
[ payload load 4b @ network header + 16 => reg 9 ]
[ lookup reg 1 set __map%d dreg 1 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# meta l4proto { tcp, udp } dnat ip to 1.1.1.1:80
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000006 : 0 [end] element 00000011 : 0 [end]
+inet
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 1 0x01010101 ]
+ [ immediate reg 2 0x00005000 ]
+ [ nat dnat ip addr_min reg 1 proto_min reg 2 flags 0x2 ]
+
+# ip protocol { tcp, udp } dnat ip to 1.1.1.1:80
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000006 : 0 [end] element 00000011 : 0 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 9 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 1 0x01010101 ]
+ [ immediate reg 2 0x00005000 ]
+ [ nat dnat ip addr_min reg 1 proto_min reg 2 flags 0x2 ]
+
+# meta l4proto tcp dnat to :80
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x00005000 ]
+ [ nat dnat inet proto_min reg 1 flags 0x2 ]
+
diff --git a/tests/py/inet/esp.t b/tests/py/inet/esp.t
index e79eeada..536260cf 100644
--- a/tests/py/inet/esp.t
+++ b/tests/py/inet/esp.t
@@ -1,10 +1,11 @@
: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
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
esp spi 100;ok
esp spi != 100;ok
@@ -12,13 +13,9 @@ esp spi 111-222;ok
esp spi != 111-222;ok
esp spi { 100, 102};ok
esp spi != { 100, 102};ok
-esp spi { 100-102};ok
-- esp spi {100-102};ok
esp sequence 22;ok
esp sequence 22-24;ok
esp sequence != 22-24;ok
esp sequence { 22, 24};ok
esp sequence != { 22, 24};ok
-esp sequence { 22-25};ok
-esp sequence != { 22-25};ok
diff --git a/tests/py/inet/esp.t.json b/tests/py/inet/esp.t.json
index 84ea9eea..a9dedd6f 100644
--- a/tests/py/inet/esp.t.json
+++ b/tests/py/inet/esp.t.json
@@ -108,26 +108,6 @@
}
]
-# esp spi { 100-102}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "spi",
- "protocol": "esp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 100, 102 ] }
- ]
- }
- }
- }
-]
-
# esp sequence 22
[
{
@@ -222,43 +202,3 @@
}
]
-# esp sequence { 22-25}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sequence",
- "protocol": "esp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 22, 25 ] }
- ]
- }
- }
- }
-]
-
-# esp sequence != { 22-25}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sequence",
- "protocol": "esp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 22, 25 ] }
- ]
- }
- }
- }
-]
-
diff --git a/tests/py/inet/esp.t.payload b/tests/py/inet/esp.t.payload
index ad68530b..0353b056 100644
--- a/tests/py/inet/esp.t.payload
+++ b/tests/py/inet/esp.t.payload
@@ -47,26 +47,6 @@ inet test-inet input
[ payload load 4b @ transport header + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# esp spi { 100-102}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 64000000 : 0 [end] element 67000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000032 ]
- [ payload load 4b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# esp spi != { 100-102}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 64000000 : 0 [end] element 67000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000032 ]
- [ payload load 4b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# esp sequence 22
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -109,23 +89,3 @@ inet test-inet input
[ payload load 4b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# esp sequence { 22-25}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 16000000 : 0 [end] element 1a000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000032 ]
- [ payload load 4b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# esp sequence != { 22-25}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 16000000 : 0 [end] element 1a000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000032 ]
- [ payload load 4b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
diff --git a/tests/py/inet/ether-ip.t b/tests/py/inet/ether-ip.t
index 0c8c7f9d..759124de 100644
--- a/tests/py/inet/ether-ip.t
+++ b/tests/py/inet/ether-ip.t
@@ -1,8 +1,9 @@
: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
+*netdev;test-netdev;ingress,egress
tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept;ok;tcp dport 22 ether saddr 00:0f:54:0c:11:04 ip daddr 1.2.3.4 accept
tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04;ok
diff --git a/tests/py/inet/ether-ip.t.payload.netdev b/tests/py/inet/ether-ip.t.payload.netdev
index 16b09212..b0fa6d84 100644
--- a/tests/py/inet/ether-ip.t.payload.netdev
+++ b/tests/py/inet/ether-ip.t.payload.netdev
@@ -13,21 +13,6 @@ netdev test-netdev ingress
[ payload load 6b @ link header + 6 => reg 1 ]
[ cmp eq reg 1 0x0c540f00 0x00000411 ]
-# tcp dport 22 ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:04
-netdev test-netdev ingress
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ cmp eq reg 1 0x00001600 ]
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 16 => reg 1 ]
- [ cmp eq reg 1 0x04030201 ]
- [ meta load iiftype => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
- [ payload load 6b @ link header + 6 => reg 1 ]
- [ cmp eq reg 1 0x0c540f00 0x00000411 ]
-
# tcp dport 22 iiftype ether ip daddr 1.2.3.4 ether saddr 00:0f:54:0c:11:4 accept
netdev test-netdev ingress
[ meta load l4proto => reg 1 ]
diff --git a/tests/py/inet/ether.t b/tests/py/inet/ether.t
index afdf8b89..8625f70b 100644
--- a/tests/py/inet/ether.t
+++ b/tests/py/inet/ether.t
@@ -1,13 +1,20 @@
: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
*bridge;test-bridge;input
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 accept;ok;tcp dport 22 ether saddr 00:0f:54:0c:11:04 accept
tcp dport 22 ether saddr 00:0f:54:0c:11:04 accept;ok
ether saddr 00:0f:54:0c:11:04 accept;ok
+
+vlan id 1;ok
+ether type vlan vlan id 2;ok;vlan id 2
+
+# invalid dependency
+ether type ip vlan id 1;fail
diff --git a/tests/py/inet/ether.t.json b/tests/py/inet/ether.t.json
index 84b184c7..c7a7f886 100644
--- a/tests/py/inet/ether.t.json
+++ b/tests/py/inet/ether.t.json
@@ -88,3 +88,35 @@
}
]
+# vlan id 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# ether type vlan vlan id 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
diff --git a/tests/py/inet/ether.t.payload b/tests/py/inet/ether.t.payload
index 53648413..8b74a781 100644
--- a/tests/py/inet/ether.t.payload
+++ b/tests/py/inet/ether.t.payload
@@ -30,3 +30,23 @@ inet test-inet input
[ cmp eq reg 1 0x0c540f00 0x00000411 ]
[ immediate reg 0 accept ]
+# vlan id 1
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# ether type vlan vlan id 2
+netdev test-netdev ingress
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
+
diff --git a/tests/py/inet/ether.t.payload.bridge b/tests/py/inet/ether.t.payload.bridge
index 4a6bccbe..0128d5f0 100644
--- a/tests/py/inet/ether.t.payload.bridge
+++ b/tests/py/inet/ether.t.payload.bridge
@@ -1,17 +1,3 @@
-# tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 meta nfproto ipv4 accept
-bridge test-bridge input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ cmp eq reg 1 0x00001600 ]
- [ meta load iiftype => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
- [ payload load 6b @ link header + 6 => reg 1 ]
- [ cmp eq reg 1 0x0c540f00 0x00000411 ]
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ immediate reg 0 accept ]
-
# tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 accept
bridge test-bridge input
[ meta load l4proto => reg 1 ]
@@ -40,10 +26,19 @@ bridge test-bridge input
[ cmp eq reg 1 0x0c540f00 0x00000411 ]
[ immediate reg 0 accept ]
-# ether saddr 00:0f:54:0c:11:04 meta nfproto ipv4
+# vlan id 1
bridge test-bridge input
- [ payload load 6b @ link header + 6 => reg 1 ]
- [ cmp eq reg 1 0x0c540f00 0x00000411 ]
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# ether type vlan vlan id 2
+bridge test-bridge input
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
diff --git a/tests/py/inet/ether.t.payload.ip b/tests/py/inet/ether.t.payload.ip
index 196930fd..7c91f412 100644
--- a/tests/py/inet/ether.t.payload.ip
+++ b/tests/py/inet/ether.t.payload.ip
@@ -1,4 +1,4 @@
-# tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 meta nfproto ipv4 accept
+# tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 accept
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -8,11 +8,9 @@ ip test-ip4 input
[ cmp eq reg 1 0x00000001 ]
[ payload load 6b @ link header + 6 => reg 1 ]
[ cmp eq reg 1 0x0c540f00 0x00000411 ]
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
[ immediate reg 0 accept ]
-# tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 accept
+# tcp dport 22 ether saddr 00:0f:54:0c:11:04 accept
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -24,32 +22,31 @@ ip test-ip4 input
[ cmp eq reg 1 0x0c540f00 0x00000411 ]
[ immediate reg 0 accept ]
-# tcp dport 22 ether saddr 00:0f:54:0c:11:04 accept
+# ether saddr 00:0f:54:0c:11:04 accept
ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ cmp eq reg 1 0x00001600 ]
[ meta load iiftype => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 6b @ link header + 6 => reg 1 ]
[ cmp eq reg 1 0x0c540f00 0x00000411 ]
[ immediate reg 0 accept ]
-# ether saddr 00:0f:54:0c:11:04 accept
+# vlan id 1
ip test-ip4 input
[ meta load iiftype => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
- [ payload load 6b @ link header + 6 => reg 1 ]
- [ cmp eq reg 1 0x0c540f00 0x00000411 ]
- [ immediate reg 0 accept ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000100 ]
-# ether saddr 00:0f:54:0c:11:04 meta nfproto ipv4
+# ether type vlan vlan id 2
ip test-ip4 input
[ meta load iiftype => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
- [ payload load 6b @ link header + 6 => reg 1 ]
- [ cmp eq reg 1 0x0c540f00 0x00000411 ]
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ payload load 2b @ link header + 14 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000200 ]
diff --git a/tests/py/inet/fib.t.payload b/tests/py/inet/fib.t.payload
index 1d4c3d94..050857d9 100644
--- a/tests/py/inet/fib.t.payload
+++ b/tests/py/inet/fib.t.payload
@@ -16,7 +16,7 @@ ip test-ip prerouting
# fib daddr . iif type vmap { blackhole : drop, prohibit : drop, unicast : accept }
__map%d test-ip b
__map%d test-ip 0
- element 00000006 : 0 [end] element 00000008 : 0 [end] element 00000001 : 0 [end]
+ element 00000006 : drop 0 [end] element 00000008 : drop 0 [end] element 00000001 : accept 0 [end]
ip test-ip prerouting
[ fib daddr . iif type => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
diff --git a/tests/py/inet/geneve.t b/tests/py/inet/geneve.t
new file mode 100644
index 00000000..101f6dfc
--- /dev/null
+++ b/tests/py/inet/geneve.t
@@ -0,0 +1,23 @@
+: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
+*netdev;test-netdev;ingress,egress
+
+geneve vni 10;fail
+udp dport 6081 geneve vni 10;ok
+udp dport 6081 geneve ip saddr 10.141.11.2;ok
+udp dport 6081 geneve ip saddr 10.141.11.0/24;ok
+udp dport 6081 geneve ip protocol 1;ok
+udp dport 6081 geneve udp sport 8888;ok
+udp dport 6081 geneve icmp type echo-reply;ok
+udp dport 6081 geneve ether saddr 62:87:4d:d6:19:05;ok
+udp dport 6081 geneve vlan id 10;ok
+udp dport 6081 geneve ip dscp 0x02;ok
+udp dport 6081 geneve ip dscp 0x02;ok
+udp dport 6081 geneve ip saddr . geneve ip daddr { 1.2.3.4 . 4.3.2.1 };ok
+
+udp dport 6081 geneve ip saddr set 1.2.3.4;fail
diff --git a/tests/py/inet/geneve.t.json b/tests/py/inet/geneve.t.json
new file mode 100644
index 00000000..a299fcd2
--- /dev/null
+++ b/tests/py/inet/geneve.t.json
@@ -0,0 +1,344 @@
+# udp dport 6081 geneve vni 10
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6081
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "vni",
+ "protocol": "geneve",
+ "tunnel": "geneve"
+ }
+ },
+ "op": "==",
+ "right": 10
+ }
+ }
+]
+
+# udp dport 6081 geneve ip saddr 10.141.11.2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6081
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip",
+ "tunnel": "geneve"
+ }
+ },
+ "op": "==",
+ "right": "10.141.11.2"
+ }
+ }
+]
+
+# udp dport 6081 geneve ip saddr 10.141.11.0/24
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6081
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip",
+ "tunnel": "geneve"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "10.141.11.0",
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# udp dport 6081 geneve ip protocol 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6081
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip",
+ "tunnel": "geneve"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# udp dport 6081 geneve udp sport 8888
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6081
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udp",
+ "tunnel": "geneve"
+ }
+ },
+ "op": "==",
+ "right": 8888
+ }
+ }
+]
+
+# udp dport 6081 geneve icmp type echo-reply
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6081
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp",
+ "tunnel": "geneve"
+ }
+ },
+ "op": "==",
+ "right": "echo-reply"
+ }
+ }
+]
+
+# udp dport 6081 geneve ether saddr 62:87:4d:d6:19:05
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6081
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether",
+ "tunnel": "geneve"
+ }
+ },
+ "op": "==",
+ "right": "62:87:4d:d6:19:05"
+ }
+ }
+]
+
+# udp dport 6081 geneve vlan id 10
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6081
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan",
+ "tunnel": "geneve"
+ }
+ },
+ "op": "==",
+ "right": 10
+ }
+ }
+]
+
+# udp dport 6081 geneve ip dscp 0x02
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6081
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip",
+ "tunnel": "geneve"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# udp dport 6081 geneve ip dscp 0x02
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6081
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip",
+ "tunnel": "geneve"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# udp dport 6081 geneve ip saddr . geneve ip daddr { 1.2.3.4 . 4.3.2.1 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 6081
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip",
+ "tunnel": "geneve"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip",
+ "tunnel": "geneve"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.2.3.4",
+ "4.3.2.1"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/geneve.t.payload b/tests/py/inet/geneve.t.payload
new file mode 100644
index 00000000..1ce54de6
--- /dev/null
+++ b/tests/py/inet/geneve.t.payload
@@ -0,0 +1,114 @@
+# udp dport 6081 geneve vni 10
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000c117 ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 3b @ unknown header + 4 => reg 1 ] ]
+ [ cmp eq reg 1 0x000a0000 ]
+
+# udp dport 6081 geneve ip saddr 10.141.11.2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000c117 ]
+ [ inner type 2 hdrsize 8 flags f [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 4b @ network header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x020b8d0a ]
+
+# udp dport 6081 geneve ip saddr 10.141.11.0/24
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000c117 ]
+ [ inner type 2 hdrsize 8 flags f [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 3b @ network header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x000b8d0a ]
+
+# udp dport 6081 geneve ip protocol 1
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000c117 ]
+ [ inner type 2 hdrsize 8 flags f [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 1b @ network header + 9 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# udp dport 6081 geneve udp sport 8888
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000c117 ]
+ [ inner type 2 hdrsize 8 flags f [ meta load l4proto => reg 1 ] ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 2b @ transport header + 0 => reg 1 ] ]
+ [ cmp eq reg 1 0x0000b822 ]
+
+# udp dport 6081 geneve icmp type echo-reply
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000c117 ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 2b @ link header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 2 hdrsize 8 flags f [ meta load l4proto => reg 1 ] ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 1b @ transport header + 0 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# udp dport 6081 geneve ether saddr 62:87:4d:d6:19:05
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000c117 ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 6b @ link header + 6 => reg 1 ] ]
+ [ cmp eq reg 1 0xd64d8762 0x00000519 ]
+
+# udp dport 6081 geneve vlan id 10
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000c117 ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 2b @ link header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 2b @ link header + 14 => reg 1 ] ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000a00 ]
+
+# udp dport 6081 geneve ip dscp 0x02
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000c117 ]
+ [ inner type 2 hdrsize 8 flags f [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 1b @ network header + 1 => reg 1 ] ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# udp dport 6081 geneve ip saddr . geneve ip daddr { 1.2.3.4 . 4.3.2.1 }
+__set%d test-ip4 3 size 1
+__set%d test-ip4 0
+ element 04030201 01020304 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000c117 ]
+ [ inner type 2 hdrsize 8 flags f [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 4b @ network header + 12 => reg 1 ] ]
+ [ inner type 2 hdrsize 8 flags f [ payload load 4b @ network header + 16 => reg 9 ] ]
+ [ lookup reg 1 set __set%d ]
+
diff --git a/tests/py/inet/gre.t b/tests/py/inet/gre.t
new file mode 100644
index 00000000..a3e046a1
--- /dev/null
+++ b/tests/py/inet/gre.t
@@ -0,0 +1,22 @@
+: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
+*netdev;test-netdev;ingress,egress
+
+gre version 0;ok
+gre ip saddr 10.141.11.2;ok
+gre ip saddr 10.141.11.0/24;ok
+gre ip protocol 1;ok
+gre udp sport 8888;ok
+gre icmp type echo-reply;ok
+gre ether saddr 62:87:4d:d6:19:05;fail
+gre vlan id 10;fail
+gre ip dscp 0x02;ok
+gre ip dscp 0x02;ok
+gre ip saddr . gre ip daddr { 1.2.3.4 . 4.3.2.1 };ok
+
+gre ip saddr set 1.2.3.4;fail
diff --git a/tests/py/inet/gre.t.json b/tests/py/inet/gre.t.json
new file mode 100644
index 00000000..c4431764
--- /dev/null
+++ b/tests/py/inet/gre.t.json
@@ -0,0 +1,177 @@
+# gre version 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "version",
+ "protocol": "gre"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# gre ip saddr 10.141.11.2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip",
+ "tunnel": "gre"
+ }
+ },
+ "op": "==",
+ "right": "10.141.11.2"
+ }
+ }
+]
+
+# gre ip saddr 10.141.11.0/24
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip",
+ "tunnel": "gre"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "10.141.11.0",
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# gre ip protocol 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip",
+ "tunnel": "gre"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# gre udp sport 8888
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udp",
+ "tunnel": "gre"
+ }
+ },
+ "op": "==",
+ "right": 8888
+ }
+ }
+]
+
+# gre icmp type echo-reply
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp",
+ "tunnel": "gre"
+ }
+ },
+ "op": "==",
+ "right": "echo-reply"
+ }
+ }
+]
+
+# gre ip dscp 0x02
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip",
+ "tunnel": "gre"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# gre ip dscp 0x02
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip",
+ "tunnel": "gre"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# gre ip saddr . gre ip daddr { 1.2.3.4 . 4.3.2.1 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip",
+ "tunnel": "gre"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip",
+ "tunnel": "gre"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.2.3.4",
+ "4.3.2.1"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/gre.t.payload b/tests/py/inet/gre.t.payload
new file mode 100644
index 00000000..333133ed
--- /dev/null
+++ b/tests/py/inet/gre.t.payload
@@ -0,0 +1,78 @@
+# gre version 0
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ payload load 1b @ transport header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000007 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# gre ip saddr 10.141.11.2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 3 hdrsize 4 flags c [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 3 hdrsize 4 flags c [ payload load 4b @ network header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x020b8d0a ]
+
+# gre ip saddr 10.141.11.0/24
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 3 hdrsize 4 flags c [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 3 hdrsize 4 flags c [ payload load 3b @ network header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x000b8d0a ]
+
+# gre ip protocol 1
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 3 hdrsize 4 flags c [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 3 hdrsize 4 flags c [ payload load 1b @ network header + 9 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# gre udp sport 8888
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 3 hdrsize 4 flags c [ meta load l4proto => reg 1 ] ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ inner type 3 hdrsize 4 flags c [ payload load 2b @ transport header + 0 => reg 1 ] ]
+ [ cmp eq reg 1 0x0000b822 ]
+
+# gre icmp type echo-reply
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 3 hdrsize 4 flags c [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 3 hdrsize 4 flags c [ meta load l4proto => reg 1 ] ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ inner type 3 hdrsize 4 flags c [ payload load 1b @ transport header + 0 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# gre ip dscp 0x02
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 3 hdrsize 4 flags c [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 3 hdrsize 4 flags c [ payload load 1b @ network header + 1 => reg 1 ] ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# gre ip saddr . gre ip daddr { 1.2.3.4 . 4.3.2.1 }
+__set%d test-ip4 3 size 1
+__set%d test-ip4 0
+ element 04030201 01020304 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 3 hdrsize 4 flags c [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 3 hdrsize 4 flags c [ payload load 4b @ network header + 12 => reg 1 ] ]
+ [ inner type 3 hdrsize 4 flags c [ payload load 4b @ network header + 16 => reg 9 ] ]
+ [ lookup reg 1 set __set%d ]
+
diff --git a/tests/py/inet/gretap.t b/tests/py/inet/gretap.t
new file mode 100644
index 00000000..cd7ee215
--- /dev/null
+++ b/tests/py/inet/gretap.t
@@ -0,0 +1,21 @@
+: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
+*netdev;test-netdev;ingress,egress
+
+gretap ip saddr 10.141.11.2;ok
+gretap ip saddr 10.141.11.0/24;ok
+gretap ip protocol 1;ok
+gretap udp sport 8888;ok
+gretap icmp type echo-reply;ok
+gretap ether saddr 62:87:4d:d6:19:05;ok
+gretap vlan id 10;ok
+gretap ip dscp 0x02;ok
+gretap ip dscp 0x02;ok
+gretap ip saddr . gretap ip daddr { 1.2.3.4 . 4.3.2.1 };ok
+
+gretap ip saddr set 1.2.3.4;fail
diff --git a/tests/py/inet/gretap.t.json b/tests/py/inet/gretap.t.json
new file mode 100644
index 00000000..36fa9782
--- /dev/null
+++ b/tests/py/inet/gretap.t.json
@@ -0,0 +1,195 @@
+# gretap ip saddr 10.141.11.2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip",
+ "tunnel": "gretap"
+ }
+ },
+ "op": "==",
+ "right": "10.141.11.2"
+ }
+ }
+]
+
+# gretap ip saddr 10.141.11.0/24
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip",
+ "tunnel": "gretap"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "10.141.11.0",
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# gretap ip protocol 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip",
+ "tunnel": "gretap"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# gretap udp sport 8888
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udp",
+ "tunnel": "gretap"
+ }
+ },
+ "op": "==",
+ "right": 8888
+ }
+ }
+]
+
+# gretap icmp type echo-reply
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp",
+ "tunnel": "gretap"
+ }
+ },
+ "op": "==",
+ "right": "echo-reply"
+ }
+ }
+]
+
+# gretap ether saddr 62:87:4d:d6:19:05
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether",
+ "tunnel": "gretap"
+ }
+ },
+ "op": "==",
+ "right": "62:87:4d:d6:19:05"
+ }
+ }
+]
+
+# gretap vlan id 10
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan",
+ "tunnel": "gretap"
+ }
+ },
+ "op": "==",
+ "right": 10
+ }
+ }
+]
+
+# gretap ip dscp 0x02
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip",
+ "tunnel": "gretap"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# gretap ip dscp 0x02
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip",
+ "tunnel": "gretap"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# gretap ip saddr . gretap ip daddr { 1.2.3.4 . 4.3.2.1 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip",
+ "tunnel": "gretap"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip",
+ "tunnel": "gretap"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.2.3.4",
+ "4.3.2.1"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/gretap.t.payload b/tests/py/inet/gretap.t.payload
new file mode 100644
index 00000000..654c71e4
--- /dev/null
+++ b/tests/py/inet/gretap.t.payload
@@ -0,0 +1,87 @@
+# gretap ip saddr 10.141.11.2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 4 hdrsize 4 flags e [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 4 hdrsize 4 flags e [ payload load 4b @ network header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x020b8d0a ]
+
+# gretap ip saddr 10.141.11.0/24
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 4 hdrsize 4 flags e [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 4 hdrsize 4 flags e [ payload load 3b @ network header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x000b8d0a ]
+
+# gretap ip protocol 1
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 4 hdrsize 4 flags e [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 4 hdrsize 4 flags e [ payload load 1b @ network header + 9 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# gretap udp sport 8888
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 4 hdrsize 4 flags e [ meta load l4proto => reg 1 ] ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ inner type 4 hdrsize 4 flags e [ payload load 2b @ transport header + 0 => reg 1 ] ]
+ [ cmp eq reg 1 0x0000b822 ]
+
+# gretap icmp type echo-reply
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 4 hdrsize 4 flags e [ payload load 2b @ link header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 4 hdrsize 4 flags e [ meta load l4proto => reg 1 ] ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ inner type 4 hdrsize 4 flags e [ payload load 1b @ transport header + 0 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# gretap ether saddr 62:87:4d:d6:19:05
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 4 hdrsize 4 flags e [ payload load 6b @ link header + 6 => reg 1 ] ]
+ [ cmp eq reg 1 0xd64d8762 0x00000519 ]
+
+# gretap vlan id 10
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 4 hdrsize 4 flags e [ payload load 2b @ link header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ inner type 4 hdrsize 4 flags e [ payload load 2b @ link header + 14 => reg 1 ] ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000a00 ]
+
+# gretap ip dscp 0x02
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 4 hdrsize 4 flags e [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 4 hdrsize 4 flags e [ payload load 1b @ network header + 1 => reg 1 ] ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# gretap ip saddr . gretap ip daddr { 1.2.3.4 . 4.3.2.1 }
+__set%d test-ip4 3 size 1
+__set%d test-ip4 0
+ element 04030201 01020304 : 0 [end]
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000002f ]
+ [ inner type 4 hdrsize 4 flags e [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 4 hdrsize 4 flags e [ payload load 4b @ network header + 12 => reg 1 ] ]
+ [ inner type 4 hdrsize 4 flags e [ payload load 4b @ network header + 16 => reg 9 ] ]
+ [ lookup reg 1 set __set%d ]
+
diff --git a/tests/py/inet/icmpX.t b/tests/py/inet/icmpX.t
index 97ff96d0..9430b3d3 100644
--- a/tests/py/inet/icmpX.t
+++ b/tests/py/inet/icmpX.t
@@ -7,4 +7,4 @@ icmp type echo-request;ok
ip6 nexthdr icmpv6 icmpv6 type echo-request;ok;ip6 nexthdr 58 icmpv6 type echo-request
icmpv6 type echo-request;ok
# must not remove 'ip protocol' dependency, this explicitly matches icmpv6-in-ipv4.
-ip protocol ipv6-icmp meta l4proto ipv6-icmp icmpv6 type 1;ok;ip protocol 58 meta l4proto 58 icmpv6 type destination-unreachable
+ip protocol ipv6-icmp meta l4proto ipv6-icmp icmpv6 type 1;ok;ip protocol 58 icmpv6 type destination-unreachable
diff --git a/tests/py/inet/icmpX.t.json.output b/tests/py/inet/icmpX.t.json.output
index 9b0bf9f7..7765cd90 100644
--- a/tests/py/inet/icmpX.t.json.output
+++ b/tests/py/inet/icmpX.t.json.output
@@ -71,15 +71,6 @@
{
"match": {
"left": {
- "meta": { "key": "l4proto" }
- },
- "op": "==",
- "right": 58
- }
- },
- {
- "match": {
- "left": {
"payload": {
"field": "type",
"protocol": "icmpv6"
diff --git a/tests/py/inet/ip.t b/tests/py/inet/ip.t
index 4eb69d73..bdb3330c 100644
--- a/tests/py/inet/ip.t
+++ b/tests/py/inet/ip.t
@@ -1,9 +1,12 @@
: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
*inet;test-inet;input
*bridge;test-bridge;input
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
ip saddr . ip daddr . ether saddr { 1.1.1.1 . 2.2.2.2 . ca:fe:ca:fe:ca:fe };ok
+ip saddr vmap { 10.0.1.0-10.0.1.255 : accept, 10.0.1.1-10.0.2.255 : drop };fail
+ip saddr vmap { 3.3.3.3-3.3.3.4 : accept, 1.1.1.1-1.1.1.255 : accept, 1.1.1.0-1.1.2.1 : drop};fail
diff --git a/tests/py/inet/ip.t.payload.bridge b/tests/py/inet/ip.t.payload.bridge
index a422ed76..57dbc9eb 100644
--- a/tests/py/inet/ip.t.payload.bridge
+++ b/tests/py/inet/ip.t.payload.bridge
@@ -3,7 +3,7 @@ __set%d test-bridge 3
__set%d test-bridge 0
element 01010101 02020202 fecafeca 0000feca : 0 [end]
bridge test-bridge input
- [ payload load 2b @ link header + 12 => reg 1 ]
+ [ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
[ payload load 4b @ network header + 16 => reg 9 ]
diff --git a/tests/py/inet/ip_tcp.t b/tests/py/inet/ip_tcp.t
index f2a28ebd..03bafc09 100644
--- a/tests/py/inet/ip_tcp.t
+++ b/tests/py/inet/ip_tcp.t
@@ -1,15 +1,16 @@
: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
*bridge;test-bridge;input
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
# must not remove ip dependency -- ONLY ipv4 packets should be matched
ip protocol tcp tcp dport 22;ok;ip protocol 6 tcp dport 22
-# can remove it here, ip protocol is implied via saddr.
-ip protocol tcp ip saddr 1.2.3.4 tcp dport 22;ok;ip saddr 1.2.3.4 tcp dport 22
+# could in principle remove it here since ipv4 is implied via saddr.
+ip protocol tcp ip saddr 1.2.3.4 tcp dport 22;ok;ip protocol 6 ip saddr 1.2.3.4 tcp dport 22
# but not here.
ip protocol tcp counter ip saddr 1.2.3.4 tcp dport 22;ok;ip protocol 6 counter ip saddr 1.2.3.4 tcp dport 22
diff --git a/tests/py/inet/ip_tcp.t.json.output b/tests/py/inet/ip_tcp.t.json.output
index 4a6a05d7..acad8b1f 100644
--- a/tests/py/inet/ip_tcp.t.json.output
+++ b/tests/py/inet/ip_tcp.t.json.output
@@ -32,6 +32,18 @@
"match": {
"left": {
"payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
"field": "saddr",
"protocol": "ip"
}
diff --git a/tests/py/inet/ipsec.t b/tests/py/inet/ipsec.t
index e924e9bc..b18df395 100644
--- a/tests/py/inet/ipsec.t
+++ b/tests/py/inet/ipsec.t
@@ -19,3 +19,5 @@ ipsec in ip6 daddr dead::beef;ok
ipsec out ip6 saddr dead::feed;ok
ipsec in spnum 256 reqid 1;fail
+
+counter ipsec out ip daddr 192.168.1.2;ok
diff --git a/tests/py/inet/ipsec.t.json b/tests/py/inet/ipsec.t.json
index d7d3a03c..18a64f35 100644
--- a/tests/py/inet/ipsec.t.json
+++ b/tests/py/inet/ipsec.t.json
@@ -134,3 +134,24 @@
}
}
]
+
+# counter ipsec out ip daddr 192.168.1.2
+[
+ {
+ "counter": null
+ },
+ {
+ "match": {
+ "left": {
+ "ipsec": {
+ "dir": "out",
+ "family": "ip",
+ "key": "daddr",
+ "spnum": 0
+ }
+ },
+ "op": "==",
+ "right": "192.168.1.2"
+ }
+ }
+]
diff --git a/tests/py/inet/ipsec.t.payload b/tests/py/inet/ipsec.t.payload
index 6049c664..9648255d 100644
--- a/tests/py/inet/ipsec.t.payload
+++ b/tests/py/inet/ipsec.t.payload
@@ -16,7 +16,6 @@ ip ipsec-ip4 ipsec-input
# ipsec out spi 1-561
inet ipsec-inet ipsec-post
[ xfrm load out 0 spi => reg 1 ]
- [ byteorder reg 1 = hton(reg 1, 4, 4) ]
[ cmp gte reg 1 0x01000000 ]
[ cmp lte reg 1 0x31020000 ]
@@ -38,3 +37,9 @@ ip ipsec-ip4 ipsec-forw
[ xfrm load out 0 saddr6 => reg 1 ]
[ cmp eq reg 1 0x0000adde 0x00000000 0x00000000 0xedfe0000 ]
+# counter ipsec out ip daddr 192.168.1.2
+ip ipsec-ip4 ipsec-forw
+ [ counter pkts 0 bytes 0 ]
+ [ xfrm load out 0 daddr4 => reg 1 ]
+ [ cmp eq reg 1 0x0201a8c0 ]
+
diff --git a/tests/py/inet/map.t b/tests/py/inet/map.t
index e83490a8..5a7161b7 100644
--- a/tests/py/inet/map.t
+++ b/tests/py/inet/map.t
@@ -1,9 +1,10 @@
: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
*inet;test-inet;input
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
mark set ip saddr map { 10.2.3.2 : 0x0000002a, 10.2.3.1 : 0x00000017};ok;meta mark set ip saddr map { 10.2.3.1 : 0x00000017, 10.2.3.2 : 0x0000002a}
mark set ip hdrlength map { 5 : 0x00000017, 4 : 0x00000001};ok;meta mark set ip hdrlength map { 4 : 0x00000001, 5 : 0x00000017}
diff --git a/tests/py/inet/map.t.payload b/tests/py/inet/map.t.payload
index 16225cbd..50344ada 100644
--- a/tests/py/inet/map.t.payload
+++ b/tests/py/inet/map.t.payload
@@ -17,7 +17,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 1 ]
[ meta set mark with reg 1 ]
diff --git a/tests/py/inet/map.t.payload.ip b/tests/py/inet/map.t.payload.ip
index 59575749..3e456675 100644
--- a/tests/py/inet/map.t.payload.ip
+++ b/tests/py/inet/map.t.payload.ip
@@ -13,7 +13,7 @@ __map%d test-ip4 0
element 00000005 : 00000017 0 [end] element 00000004 : 00000001 0 [end]
ip test-ip4 input
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 1 ]
[ meta set mark with reg 1 ]
diff --git a/tests/py/inet/map.t.payload.netdev b/tests/py/inet/map.t.payload.netdev
index 501fb8ee..2e60f09d 100644
--- a/tests/py/inet/map.t.payload.netdev
+++ b/tests/py/inet/map.t.payload.netdev
@@ -17,7 +17,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 1 ]
[ meta set mark with reg 1 ]
diff --git a/tests/py/inet/meta.t b/tests/py/inet/meta.t
index df32332f..7d2515c9 100644
--- a/tests/py/inet/meta.t
+++ b/tests/py/inet/meta.t
@@ -12,7 +12,22 @@ meta nfproto ipv4 tcp dport 22;ok
meta nfproto ipv4 ip saddr 1.2.3.4;ok;ip saddr 1.2.3.4
meta nfproto ipv6 meta l4proto tcp;ok;meta nfproto ipv6 meta l4proto 6
meta nfproto ipv4 counter ip saddr 1.2.3.4;ok
+
+meta protocol ip udp dport 67;ok
+meta protocol ip6 udp dport 67;ok
+
meta ipsec exists;ok
meta secpath missing;ok;meta ipsec missing
meta ibrname "br0";fail
meta obrname "br0";fail
+meta mark set ct mark >> 8;ok
+
+meta mark . tcp dport { 0x0000000a-0x00000014 . 80-90, 0x00100000-0x00100123 . 100-120 };ok
+ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 1.2.3.6-1.2.3.8 . 0x00000200-0x00000300 };ok
+ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 5.6.7.8 . 0x00000200 };ok
+ip saddr . ether saddr . meta l4proto { 1.2.3.4 . aa:bb:cc:dd:ee:ff . 6 };ok
+
+meta mark set ip dscp;ok
+meta mark set ip dscp | 0x40;ok
+meta mark set ip6 dscp;ok
+meta mark set ip6 dscp | 0x40;ok
diff --git a/tests/py/inet/meta.t.json b/tests/py/inet/meta.t.json
index 5501f0be..0fee165f 100644
--- a/tests/py/inet/meta.t.json
+++ b/tests/py/inet/meta.t.json
@@ -213,3 +213,357 @@
}
]
+# meta mark set ct mark >> 8
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ ">>": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 8
+ ]
+ }
+ }
+ }
+]
+
+# meta protocol ip udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
+# meta protocol ip6 udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
+# meta mark . tcp dport { 0x0000000a-0x00000014 . 80-90, 0x00100000-0x00100123 . 100-120 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ {
+ "range": [
+ 10,
+ 20
+ ]
+ },
+ {
+ "range": [
+ 80,
+ 90
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "range": [
+ 1048576,
+ 1048867
+ ]
+ },
+ {
+ "range": [
+ 100,
+ 120
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 1.2.3.6-1.2.3.8 . 0x00000200-0x00000300 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "meta": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.2.3.4",
+ 256
+ ]
+ },
+ {
+ "concat": [
+ {
+ "range": [
+ "1.2.3.6",
+ "1.2.3.8"
+ ]
+ },
+ {
+ "range": [
+ 512,
+ 768
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 5.6.7.8 . 0x00000200 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "meta": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.2.3.4",
+ 256
+ ]
+ },
+ {
+ "concat": [
+ "5.6.7.8",
+ 512
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# meta mark set ip dscp
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ }
+ }
+ }
+]
+
+# meta mark set ip dscp | 0x40
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 64
+ ]
+ }
+ }
+ }
+]
+
+# meta mark set ip6 dscp
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ }
+ }
+ }
+]
+
+# meta mark set ip6 dscp | 0x40
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 64
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr . ether saddr . meta l4proto { 1.2.3.4 . aa:bb:cc:dd:ee:ff . 6 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ {
+ "meta": {
+ "key": "l4proto"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.2.3.4",
+ "aa:bb:cc:dd:ee:ff",
+ "tcp"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/meta.t.json.output b/tests/py/inet/meta.t.json.output
index 3e7dd214..8697d5a2 100644
--- a/tests/py/inet/meta.t.json.output
+++ b/tests/py/inet/meta.t.json.output
@@ -51,3 +51,44 @@
}
]
+# ip saddr . ether saddr . meta l4proto { 1.2.3.4 . aa:bb:cc:dd:ee:ff . 6 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ {
+ "meta": {
+ "key": "l4proto"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.2.3.4",
+ "aa:bb:cc:dd:ee:ff",
+ 6
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/meta.t.payload b/tests/py/inet/meta.t.payload
index d7ff7e2d..7184fa0c 100644
--- a/tests/py/inet/meta.t.payload
+++ b/tests/py/inet/meta.t.payload
@@ -73,3 +73,117 @@ inet test-inet input
inet test-inet input
[ meta load secpath => reg 1 ]
[ cmp eq reg 1 0x00000000 ]
+
+# meta mark set ct mark >> 8
+inet test-inet input
+ [ ct load mark => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000008 ) ]
+ [ meta set mark with reg 1 ]
+
+# meta protocol ip udp dport 67
+inet test-inet input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
+
+# meta protocol ip6 udp dport 67
+inet test-inet input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
+
+# meta mark . tcp dport { 0x0000000a-0x00000014 . 80-90, 0x00100000-0x00100123 . 100-120 }
+__set%d test-inet 87 size 1
+__set%d test-inet 0
+ element 0a000000 00005000 - 14000000 00005a00 : 0 [end] element 00001000 00006400 - 23011000 00007800 : 0 [end]
+ip test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ meta load mark => reg 1 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 1.2.3.6-1.2.3.8 . 0x00000200-0x00000300 }
+__set%d test-inet 87 size 2
+__set%d test-inet 0
+ element 04030201 00010000 - 04030201 00010000 : 0 [end] element 06030201 00020000 - 08030201 00030000 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ meta load mark => reg 9 ]
+ [ byteorder reg 9 = hton(reg 9, 4, 4) ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr . meta mark { 1.2.3.4 . 0x00000100 , 5.6.7.8 . 0x00000200 }
+__set%d test-inet 3 size 2
+__set%d test-inet 0
+ element 04030201 00000100 : 0 [end] element 08070605 00000200 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ meta load mark => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# meta mark set ip dscp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip dscp | 0x40
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffbf ) ^ 0x00000040 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip6 dscp
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip6 dscp | 0x40
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffbf ) ^ 0x00000040 ]
+ [ meta set mark with reg 1 ]
+
+# ip saddr . ether saddr . meta l4proto { 1.2.3.4 . aa:bb:cc:dd:ee:ff . 6 }
+__set%d test-inet 3 size 1
+__set%d test-inet 0
+ element 04030201 ddccbbaa 0000ffee 00000006 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 6b @ link header + 6 => reg 9 ]
+ [ meta load l4proto => reg 11 ]
+ [ lookup reg 1 set __set%d ]
+
diff --git a/tests/py/inet/osf.t.payload b/tests/py/inet/osf.t.payload
index 6f5fba34..6ddab976 100644
--- a/tests/py/inet/osf.t.payload
+++ b/tests/py/inet/osf.t.payload
@@ -1,80 +1,24 @@
# osf name "Linux"
-ip osfip osfchain
- [ osf dreg 1 ]
- [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ]
-
-# osf name "Linux"
-ip6 osfip6 osfchain
- [ osf dreg 1 ]
- [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ]
-
-# osf name "Linux"
inet osfinet osfchain
[ osf dreg 1 ]
[ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ]
# osf ttl loose name "Linux"
-ip osfip osfchain
- [ osf dreg 1 ]
- [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ]
-
-# osf ttl loose name "Linux"
-ip6 osfip6 osfchain
- [ osf dreg 1 ]
- [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ]
-
-# osf ttl loose name "Linux"
inet osfinet osfchain
[ osf dreg 1 ]
[ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ]
# osf ttl skip name "Linux"
-ip osfip osfchain
- [ osf dreg 1 ]
- [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ]
-
-# osf ttl skip name "Linux"
-ip6 osfip6 osfchain
- [ osf dreg 1 ]
- [ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ]
-
-# osf ttl skip name "Linux"
inet osfinet osfchain
[ osf dreg 1 ]
[ cmp eq reg 1 0x756e694c 0x00000078 0x00000000 0x00000000 ]
# osf ttl skip version "Linux:3.0"
-ip osfip osfchain
- [ osf dreg 1 ]
- [ cmp eq reg 1 0x756e694c 0x2e333a78 0x00000030 0x00000000 ]
-
-# osf ttl skip version "Linux:3.0"
-ip6 osfip6 osfchain
- [ osf dreg 1 ]
- [ cmp eq reg 1 0x756e694c 0x2e333a78 0x00000030 0x00000000 ]
-
-# osf ttl skip version "Linux:3.0"
inet osfinet osfchain
[ osf dreg 1 ]
[ cmp eq reg 1 0x756e694c 0x2e333a78 0x00000030 0x00000000 ]
# osf name { "Windows", "MacOs" }
-__set%d osfip 3 size 2
-__set%d osfip 0
- element 646e6957 0073776f 00000000 00000000 : 0 [end] element 4f63614d 00000073 00000000 00000000 : 0 [end]
-ip osfip osfchain
- [ osf dreg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# osf name { "Windows", "MacOs" }
-__set%d osfip6 3 size 2
-__set%d osfip6 0
- element 646e6957 0073776f 00000000 00000000 : 0 [end] element 4f63614d 00000073 00000000 00000000 : 0 [end]
-ip6 osfip6 osfchain
- [ osf dreg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# osf name { "Windows", "MacOs" }
__set%d osfinet 3 size 2
__set%d osfinet 0
element 646e6957 0073776f 00000000 00000000 : 0 [end] element 4f63614d 00000073 00000000 00000000 : 0 [end]
@@ -83,22 +27,6 @@ inet osfinet osfchain
[ lookup reg 1 set __set%d ]
# osf version { "Windows:XP", "MacOs:Sierra" }
-__set%d osfip 3 size 2
-__set%d osfip 0
- element 646e6957 3a73776f 00005058 00000000 : 0 [end] element 4f63614d 69533a73 61727265 00000000 : 0 [end]
-ip osfip osfchain
- [ osf dreg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# osf version { "Windows:XP", "MacOs:Sierra" }
-__set%d osfip6 3 size 2
-__set%d osfip6 0
- element 646e6957 3a73776f 00005058 00000000 : 0 [end] element 4f63614d 69533a73 61727265 00000000 : 0 [end]
-ip6 osfip6 osfchain
- [ osf dreg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# osf version { "Windows:XP", "MacOs:Sierra" }
__set%d osfinet 3 size 2
__set%d osfinet 0
element 646e6957 3a73776f 00005058 00000000 : 0 [end] element 4f63614d 69533a73 61727265 00000000 : 0 [end]
@@ -107,24 +35,6 @@ inet osfinet osfchain
[ lookup reg 1 set __set%d ]
# ct mark set osf name map { "Windows" : 0x00000001, "MacOs" : 0x00000002 }
-__map%d osfip b size 2
-__map%d osfip 0
- element 646e6957 0073776f 00000000 00000000 : 00000001 0 [end] element 4f63614d 00000073 00000000 00000000 : 00000002 0 [end]
-ip osfip osfchain
- [ osf dreg 1 ]
- [ lookup reg 1 set __map%d dreg 1 ]
- [ ct set mark with reg 1 ]
-
-# ct mark set osf name map { "Windows" : 0x00000001, "MacOs" : 0x00000002 }
-__map%d osfip6 b size 2
-__map%d osfip6 0
- element 646e6957 0073776f 00000000 00000000 : 00000001 0 [end] element 4f63614d 00000073 00000000 00000000 : 00000002 0 [end]
-ip6 osfip6 osfchain
- [ osf dreg 1 ]
- [ lookup reg 1 set __map%d dreg 1 ]
- [ ct set mark with reg 1 ]
-
-# ct mark set osf name map { "Windows" : 0x00000001, "MacOs" : 0x00000002 }
__map%d osfinet b size 2
__map%d osfinet 0
element 646e6957 0073776f 00000000 00000000 : 00000001 0 [end] element 4f63614d 00000073 00000000 00000000 : 00000002 0 [end]
@@ -134,24 +44,6 @@ inet osfinet osfchain
[ ct set mark with reg 1 ]
# ct mark set osf version map { "Windows:XP" : 0x00000003, "MacOs:Sierra" : 0x00000004 }
-__map%d osfip b size 2
-__map%d osfip 0
- element 646e6957 3a73776f 00005058 00000000 : 00000003 0 [end] element 4f63614d 69533a73 61727265 00000000 : 00000004 0 [end]
-ip osfip osfchain
- [ osf dreg 1 ]
- [ lookup reg 1 set __map%d dreg 1 ]
- [ ct set mark with reg 1 ]
-
-# ct mark set osf version map { "Windows:XP" : 0x00000003, "MacOs:Sierra" : 0x00000004 }
-__map%d osfip6 b size 2
-__map%d osfip6 0
- element 646e6957 3a73776f 00005058 00000000 : 00000003 0 [end] element 4f63614d 69533a73 61727265 00000000 : 00000004 0 [end]
-ip6 osfip6 osfchain
- [ osf dreg 1 ]
- [ lookup reg 1 set __map%d dreg 1 ]
- [ ct set mark with reg 1 ]
-
-# ct mark set osf version map { "Windows:XP" : 0x00000003, "MacOs:Sierra" : 0x00000004 }
__map%d osfinet b size 2
__map%d osfinet 0
element 646e6957 3a73776f 00005058 00000000 : 00000003 0 [end] element 4f63614d 69533a73 61727265 00000000 : 00000004 0 [end]
diff --git a/tests/py/inet/payloadmerge.t b/tests/py/inet/payloadmerge.t
new file mode 100644
index 00000000..04ba1ce6
--- /dev/null
+++ b/tests/py/inet/payloadmerge.t
@@ -0,0 +1,14 @@
+:input;type filter hook input priority 0
+
+*ip;test-ip4;input
+*ip6;test-ip6;input
+*inet;test-inet;input
+
+tcp sport 1 tcp dport 2;ok
+tcp sport != 1 tcp dport != 2;ok
+tcp sport 1 tcp dport != 2;ok
+tcp sport != 1 tcp dport 2;ok
+meta l4proto != 6 th dport 2;ok
+meta l4proto 6 tcp dport 22;ok;tcp dport 22
+tcp sport > 1 tcp dport > 2;ok
+tcp sport 1 tcp dport > 2;ok
diff --git a/tests/py/inet/payloadmerge.t.json b/tests/py/inet/payloadmerge.t.json
new file mode 100644
index 00000000..e5b66cf9
--- /dev/null
+++ b/tests/py/inet/payloadmerge.t.json
@@ -0,0 +1,211 @@
+# tcp sport 1 tcp dport 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# tcp sport != 1 tcp dport != 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": 2
+ }
+ }
+]
+
+# tcp sport 1 tcp dport != 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": 2
+ }
+ }
+]
+
+# tcp sport != 1 tcp dport 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!=",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# meta l4proto != 6 th dport 2
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "!=",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "th"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# meta l4proto 6 tcp dport 22
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
+ }
+]
+
+# tcp sport > 1 tcp dport > 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": ">",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": ">",
+ "right": 2
+ }
+ }
+]
+
+# tcp sport 1 tcp dport > 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": ">",
+ "right": 2
+ }
+ }
+]
+
diff --git a/tests/py/inet/payloadmerge.t.payload b/tests/py/inet/payloadmerge.t.payload
new file mode 100644
index 00000000..a0465cdd
--- /dev/null
+++ b/tests/py/inet/payloadmerge.t.payload
@@ -0,0 +1,66 @@
+# tcp sport 1 tcp dport 2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x02000100 ]
+
+# tcp sport != 1 tcp dport != 2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000100 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x00000200 ]
+
+# tcp sport 1 tcp dport != 2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp neq reg 1 0x00000200 ]
+
+# tcp sport != 1 tcp dport 2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000100 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# meta l4proto != 6 th dport 2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp neq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000200 ]
+
+# meta l4proto 6 tcp dport 22
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00001600 ]
+
+# tcp sport > 1 tcp dport > 2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp gt reg 1 0x00000100 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gt reg 1 0x00000200 ]
+
+# tcp sport 1 tcp dport > 2
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gt reg 1 0x00000200 ]
+
diff --git a/tests/py/inet/reject.t b/tests/py/inet/reject.t
index 0e8966c9..61a6d556 100644
--- a/tests/py/inet/reject.t
+++ b/tests/py/inet/reject.t
@@ -2,38 +2,40 @@
*inet;test-inet;input
-# The output is specific for inet family
-reject with icmp type host-unreachable;ok;meta nfproto ipv4 reject with icmp type host-unreachable
-reject with icmp type net-unreachable;ok;meta nfproto ipv4 reject with icmp type net-unreachable
-reject with icmp type prot-unreachable;ok;meta nfproto ipv4 reject with icmp type prot-unreachable
-reject with icmp type port-unreachable;ok;meta nfproto ipv4 reject
-reject with icmp type net-prohibited;ok;meta nfproto ipv4 reject with icmp type net-prohibited
-reject with icmp type host-prohibited;ok;meta nfproto ipv4 reject with icmp type host-prohibited
-reject with icmp type admin-prohibited;ok;meta nfproto ipv4 reject with icmp type admin-prohibited
-
-reject with icmpv6 type no-route;ok;meta nfproto ipv6 reject with icmpv6 type no-route
-reject with icmpv6 type admin-prohibited;ok;meta nfproto ipv6 reject with icmpv6 type admin-prohibited
-reject with icmpv6 type addr-unreachable;ok;meta nfproto ipv6 reject with icmpv6 type addr-unreachable
-reject with icmpv6 type port-unreachable;ok;meta nfproto ipv6 reject
+reject with icmp host-unreachable;ok
+reject with icmp net-unreachable;ok
+reject with icmp prot-unreachable;ok
+reject with icmp port-unreachable;ok
+reject with icmp net-prohibited;ok
+reject with icmp host-prohibited;ok
+reject with icmp admin-prohibited;ok
+
+reject with icmpv6 no-route;ok
+reject with icmpv6 admin-prohibited;ok
+reject with icmpv6 addr-unreachable;ok
+reject with icmpv6 port-unreachable;ok
mark 12345 reject with tcp reset;ok;meta l4proto 6 meta mark 0x00003039 reject with tcp reset
reject;ok
-meta nfproto ipv4 reject;ok
-meta nfproto ipv6 reject;ok
+meta nfproto ipv4 reject;ok;reject with icmp port-unreachable
+meta nfproto ipv6 reject;ok;reject with icmpv6 port-unreachable
-reject with icmpx type host-unreachable;ok
-reject with icmpx type no-route;ok
-reject with icmpx type admin-prohibited;ok
-reject with icmpx type port-unreachable;ok;reject
+reject with icmpx host-unreachable;ok
+reject with icmpx no-route;ok
+reject with icmpx admin-prohibited;ok
+reject with icmpx port-unreachable;ok;reject
+reject with icmpx 3;ok;reject with icmpx admin-prohibited
-meta nfproto ipv4 reject with icmp type host-unreachable;ok
-meta nfproto ipv6 reject with icmpv6 type no-route;ok
+meta nfproto ipv4 reject with icmp host-unreachable;ok;reject with icmp host-unreachable
+meta nfproto ipv6 reject with icmpv6 no-route;ok;reject with icmpv6 no-route
-meta nfproto ipv6 reject with icmp type host-unreachable;fail
-meta nfproto ipv4 ip protocol icmp reject with icmpv6 type no-route;fail
-meta nfproto ipv6 ip protocol icmp reject with icmp type host-unreachable;fail
+meta nfproto ipv6 reject with icmp host-unreachable;fail
+meta nfproto ipv4 ip protocol icmp reject with icmpv6 no-route;fail
+meta nfproto ipv6 ip protocol icmp reject with icmp host-unreachable;fail
meta l4proto udp reject with tcp reset;fail
-meta nfproto ipv4 reject with icmpx type admin-prohibited;ok
-meta nfproto ipv6 reject with icmpx type admin-prohibited;ok
+meta nfproto ipv4 reject with icmpx admin-prohibited;ok
+meta nfproto ipv6 reject with icmpx admin-prohibited;ok
+
+ether saddr aa:bb:cc:dd:ee:ff ip daddr 192.168.0.1 reject;ok;ether saddr aa:bb:cc:dd:ee:ff ip daddr 192.168.0.1 reject with icmp port-unreachable
diff --git a/tests/py/inet/reject.t.json b/tests/py/inet/reject.t.json
index bfa94f84..02ac9007 100644
--- a/tests/py/inet/reject.t.json
+++ b/tests/py/inet/reject.t.json
@@ -1,4 +1,4 @@
-# reject with icmp type host-unreachable
+# reject with icmp host-unreachable
[
{
"reject": {
@@ -8,7 +8,7 @@
}
]
-# reject with icmp type net-unreachable
+# reject with icmp net-unreachable
[
{
"reject": {
@@ -18,7 +18,7 @@
}
]
-# reject with icmp type prot-unreachable
+# reject with icmp prot-unreachable
[
{
"reject": {
@@ -28,7 +28,7 @@
}
]
-# reject with icmp type port-unreachable
+# reject with icmp port-unreachable
[
{
"reject": {
@@ -38,7 +38,7 @@
}
]
-# reject with icmp type net-prohibited
+# reject with icmp net-prohibited
[
{
"reject": {
@@ -48,7 +48,7 @@
}
]
-# reject with icmp type host-prohibited
+# reject with icmp host-prohibited
[
{
"reject": {
@@ -58,7 +58,7 @@
}
]
-# reject with icmp type admin-prohibited
+# reject with icmp admin-prohibited
[
{
"reject": {
@@ -68,7 +68,7 @@
}
]
-# reject with icmpv6 type no-route
+# reject with icmpv6 no-route
[
{
"reject": {
@@ -78,7 +78,7 @@
}
]
-# reject with icmpv6 type admin-prohibited
+# reject with icmpv6 admin-prohibited
[
{
"reject": {
@@ -88,7 +88,7 @@
}
]
-# reject with icmpv6 type addr-unreachable
+# reject with icmpv6 addr-unreachable
[
{
"reject": {
@@ -98,7 +98,7 @@
}
]
-# reject with icmpv6 type port-unreachable
+# reject with icmpv6 port-unreachable
[
{
"reject": {
@@ -165,7 +165,7 @@
}
]
-# reject with icmpx type host-unreachable
+# reject with icmpx host-unreachable
[
{
"reject": {
@@ -175,7 +175,7 @@
}
]
-# reject with icmpx type no-route
+# reject with icmpx no-route
[
{
"reject": {
@@ -185,7 +185,7 @@
}
]
-# reject with icmpx type admin-prohibited
+# reject with icmpx admin-prohibited
[
{
"reject": {
@@ -195,7 +195,7 @@
}
]
-# reject with icmpx type port-unreachable
+# reject with icmpx port-unreachable
[
{
"reject": {
@@ -205,7 +205,17 @@
}
]
-# meta nfproto ipv4 reject with icmp type host-unreachable
+# reject with icmpx 3
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
+# meta nfproto ipv4 reject with icmp host-unreachable
[
{
"match": {
@@ -224,7 +234,7 @@
}
]
-# meta nfproto ipv6 reject with icmpv6 type no-route
+# meta nfproto ipv6 reject with icmpv6 no-route
[
{
"match": {
@@ -243,7 +253,7 @@
}
]
-# meta nfproto ipv4 reject with icmpx type admin-prohibited
+# meta nfproto ipv4 reject with icmpx admin-prohibited
[
{
"match": {
@@ -264,7 +274,7 @@
}
]
-# meta nfproto ipv6 reject with icmpx type admin-prohibited
+# meta nfproto ipv6 reject with icmpx admin-prohibited
[
{
"match": {
@@ -285,3 +295,37 @@
}
]
+# ether saddr aa:bb:cc:dd:ee:ff ip daddr 192.168.0.1 reject
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether"
+ }
+ },
+ "op": "==",
+ "right": "aa:bb:cc:dd:ee:ff"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ },
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
diff --git a/tests/py/inet/reject.t.json.output b/tests/py/inet/reject.t.json.output
index 73846fb0..496ce557 100644
--- a/tests/py/inet/reject.t.json.output
+++ b/tests/py/inet/reject.t.json.output
@@ -1,145 +1,73 @@
-# reject with icmp type host-unreachable
+# mark 12345 reject with tcp reset
[
{
"match": {
"left": {
- "meta": { "key": "nfproto" }
+ "meta": { "key": "l4proto" }
},
"op": "==",
- "right": "ipv4"
+ "right": 6
}
},
{
- "reject": {
- "expr": "host-unreachable",
- "type": "icmp"
- }
- }
-]
-
-# reject with icmp type net-unreachable
-[
- {
"match": {
"left": {
- "meta": { "key": "nfproto" }
+ "meta": { "key": "mark" }
},
"op": "==",
- "right": "ipv4"
+ "right": 12345
}
},
{
"reject": {
- "expr": "net-unreachable",
- "type": "icmp"
+ "type": "tcp reset"
}
}
]
-# reject with icmp type prot-unreachable
+# reject
[
{
- "match": {
- "left": {
- "meta": { "key": "nfproto" }
- },
- "op": "==",
- "right": "ipv4"
- }
- },
- {
"reject": {
- "expr": "prot-unreachable",
- "type": "icmp"
- }
- }
-]
-
-# reject with icmp type port-unreachable
-[
- {
- "match": {
- "left": {
- "meta": { "key": "nfproto" }
- },
- "op": "==",
- "right": "ipv4"
+ "expr": "port-unreachable",
+ "type": "icmpx"
}
- },
- {
- "reject": null
}
]
-# reject with icmp type net-prohibited
+# meta nfproto ipv4 reject
[
{
- "match": {
- "left": {
- "meta": { "key": "nfproto" }
- },
- "op": "==",
- "right": "ipv4"
- }
- },
- {
"reject": {
- "expr": "net-prohibited",
+ "expr": "port-unreachable",
"type": "icmp"
}
}
]
-# reject with icmp type host-prohibited
+# meta nfproto ipv6 reject
[
{
- "match": {
- "left": {
- "meta": { "key": "nfproto" }
- },
- "op": "==",
- "right": "ipv4"
- }
- },
- {
"reject": {
- "expr": "host-prohibited",
- "type": "icmp"
+ "expr": "port-unreachable",
+ "type": "icmpv6"
}
}
]
-# reject with icmp type admin-prohibited
+# meta nfproto ipv4 reject with icmp host-unreachable
[
{
- "match": {
- "left": {
- "meta": { "key": "nfproto" }
- },
- "op": "==",
- "right": "ipv4"
- }
- },
- {
"reject": {
- "expr": "admin-prohibited",
+ "expr": "host-unreachable",
"type": "icmp"
}
}
]
-# reject with icmpv6 type no-route
+# meta nfproto ipv6 reject with icmpv6 no-route
[
{
- "match": {
- "left": {
- "meta": { "key": "nfproto" }
- },
- "op": "==",
- "right": "ipv6"
- }
- },
- {
"reject": {
"expr": "no-route",
"type": "icmpv6"
@@ -147,91 +75,3 @@
}
]
-# reject with icmpv6 type admin-prohibited
-[
- {
- "match": {
- "left": {
- "meta": { "key": "nfproto" }
- },
- "op": "==",
- "right": "ipv6"
- }
- },
- {
- "reject": {
- "expr": "admin-prohibited",
- "type": "icmpv6"
- }
- }
-]
-
-# reject with icmpv6 type addr-unreachable
-[
- {
- "match": {
- "left": {
- "meta": { "key": "nfproto" }
- },
- "op": "==",
- "right": "ipv6"
- }
- },
- {
- "reject": {
- "expr": "addr-unreachable",
- "type": "icmpv6"
- }
- }
-]
-
-# reject with icmpv6 type port-unreachable
-[
- {
- "match": {
- "left": {
- "meta": { "key": "nfproto" }
- },
- "op": "==",
- "right": "ipv6"
- }
- },
- {
- "reject": null
- }
-]
-
-# mark 12345 reject with tcp reset
-[
- {
- "match": {
- "left": {
- "meta": { "key": "l4proto" }
- },
- "op": "==",
- "right": 6
- }
- },
- {
- "match": {
- "left": {
- "meta": { "key": "mark" }
- },
- "op": "==",
- "right": 12345
- }
- },
- {
- "reject": {
- "type": "tcp reset"
- }
- }
-]
-
-# reject with icmpx type port-unreachable
-[
- {
- "reject": null
- }
-]
-
diff --git a/tests/py/inet/reject.t.payload.inet b/tests/py/inet/reject.t.payload.inet
index ee1aae02..828cb839 100644
--- a/tests/py/inet/reject.t.payload.inet
+++ b/tests/py/inet/reject.t.payload.inet
@@ -1,64 +1,64 @@
-# reject with icmp type host-unreachable
+# reject with icmp host-unreachable
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ reject type 0 code 1 ]
-# reject with icmp type net-unreachable
+# reject with icmp net-unreachable
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ reject type 0 code 0 ]
-# reject with icmp type prot-unreachable
+# reject with icmp prot-unreachable
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ reject type 0 code 2 ]
-# reject with icmp type port-unreachable
+# reject with icmp port-unreachable
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ reject type 0 code 3 ]
-# reject with icmp type net-prohibited
+# reject with icmp net-prohibited
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ reject type 0 code 9 ]
-# reject with icmp type host-prohibited
+# reject with icmp host-prohibited
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ reject type 0 code 10 ]
-# reject with icmp type admin-prohibited
+# reject with icmp admin-prohibited
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ reject type 0 code 13 ]
-# reject with icmpv6 type no-route
+# reject with icmpv6 no-route
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ reject type 0 code 0 ]
-# reject with icmpv6 type admin-prohibited
+# reject with icmpv6 admin-prohibited
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ reject type 0 code 1 ]
-# reject with icmpv6 type addr-unreachable
+# reject with icmpv6 addr-unreachable
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ reject type 0 code 3 ]
-# reject with icmpv6 type port-unreachable
+# reject with icmpv6 port-unreachable
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -88,147 +88,57 @@ inet test-inet input
[ cmp eq reg 1 0x0000000a ]
[ reject type 0 code 4 ]
-# reject with icmpx type host-unreachable
+# reject with icmpx host-unreachable
inet test-inet input
[ reject type 2 code 2 ]
-# reject with icmpx type no-route
+# reject with icmpx no-route
inet test-inet input
[ reject type 2 code 0 ]
-# reject with icmpx type admin-prohibited
+# reject with icmpx admin-prohibited
inet test-inet input
[ reject type 2 code 3 ]
-# reject with icmpx type port-unreachable
+# reject with icmpx port-unreachable
inet test-inet input
[ reject type 2 code 1 ]
-# meta nfproto ipv4 reject with icmp type host-unreachable
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ reject type 0 code 1 ]
-
-# meta nfproto ipv6 reject with icmpv6 type no-route
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ reject type 0 code 0 ]
-
-# reject with icmp type prot-unreachable
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ reject type 0 code 2 ]
-
-# reject with icmp type port-unreachable
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ reject type 0 code 3 ]
-
-# reject with icmp type net-prohibited
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ reject type 0 code 9 ]
-
-# reject with icmp type host-prohibited
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ reject type 0 code 10 ]
-
-# reject with icmp type admin-prohibited
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ reject type 0 code 13 ]
-
-# reject with icmpv6 type no-route
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ reject type 0 code 0 ]
-
-# reject with icmpv6 type admin-prohibited
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ reject type 0 code 1 ]
-
-# reject with icmpv6 type addr-unreachable
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ reject type 0 code 3 ]
-
-# reject with icmpv6 type port-unreachable
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ reject type 0 code 4 ]
-
-# reject with tcp reset
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ reject type 1 code 0 ]
-
-# reject
-inet test-inet input
- [ reject type 2 code 1 ]
-
-# meta nfproto ipv4 reject
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ reject type 0 code 3 ]
-
-# meta nfproto ipv6 reject
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ reject type 0 code 4 ]
-
-# reject with icmpx type host-unreachable
-inet test-inet input
- [ reject type 2 code 2 ]
-
-# reject with icmpx type no-route
-inet test-inet input
- [ reject type 2 code 0 ]
-
-# reject with icmpx type admin-prohibited
+# reject with icmpx 3
inet test-inet input
[ reject type 2 code 3 ]
-# reject with icmpx type port-unreachable
-inet test-inet input
- [ reject type 2 code 1 ]
-
-# meta nfproto ipv4 reject with icmp type host-unreachable
+# meta nfproto ipv4 reject with icmp host-unreachable
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ reject type 0 code 1 ]
-# meta nfproto ipv6 reject with icmpv6 type no-route
+# meta nfproto ipv6 reject with icmpv6 no-route
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ reject type 0 code 0 ]
-# meta nfproto ipv4 reject with icmpx type admin-prohibited
+# meta nfproto ipv4 reject with icmpx admin-prohibited
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ reject type 2 code 3 ]
-# meta nfproto ipv6 reject with icmpx type admin-prohibited
+# meta nfproto ipv6 reject with icmpx admin-prohibited
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ reject type 2 code 3 ]
+# ether saddr aa:bb:cc:dd:ee:ff ip daddr 192.168.0.1 reject
+inet test-inet input
+ [ meta load iiftype => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 8b @ link header + 6 => reg 1 ]
+ [ cmp eq reg 1 0xddccbbaa 0x0008ffee ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+ [ reject type 0 code 3 ]
+
diff --git a/tests/py/inet/rt.t b/tests/py/inet/rt.t
index 23608ab2..a0e0d003 100644
--- a/tests/py/inet/rt.t
+++ b/tests/py/inet/rt.t
@@ -2,14 +2,13 @@
*inet;test-inet;output
-rt nexthop 192.168.0.1;fail
-rt nexthop fd00::1;fail
-
meta nfproto ipv4 rt nexthop 192.168.0.1;ok;meta nfproto ipv4 rt ip nexthop 192.168.0.1
rt ip6 nexthop fd00::1;ok
# missing context
+rt nexthop 192.168.0.1;fail
rt nexthop fd00::1;fail
+
# wrong context
rt ip nexthop fd00::1;fail
diff --git a/tests/py/inet/sctp.t b/tests/py/inet/sctp.t
index 5188b57e..016173b9 100644
--- a/tests/py/inet/sctp.t
+++ b/tests/py/inet/sctp.t
@@ -1,10 +1,11 @@
: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
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
sctp sport 23;ok
sctp sport != 23;ok
@@ -12,8 +13,6 @@ sctp sport 23-44;ok
sctp sport != 23-44;ok
sctp sport { 23, 24, 25};ok
sctp sport != { 23, 24, 25};ok
-sctp sport { 23-44};ok
-sctp sport != { 23-44};ok
sctp dport 23;ok
sctp dport != 23;ok
@@ -21,8 +20,6 @@ sctp dport 23-44;ok
sctp dport != 23-44;ok
sctp dport { 23, 24, 25};ok
sctp dport != { 23, 24, 25};ok
-sctp dport { 23-44};ok
-sctp dport != { 23-44};ok
sctp checksum 1111;ok
sctp checksum != 11;ok
@@ -30,8 +27,6 @@ sctp checksum 21-333;ok
sctp checksum != 32-111;ok
sctp checksum { 22, 33, 44};ok
sctp checksum != { 22, 33, 44};ok
-sctp checksum { 22-44};ok
-sctp checksum != { 22-44};ok
sctp vtag 22;ok
sctp vtag != 233;ok
@@ -39,5 +34,40 @@ sctp vtag 33-45;ok
sctp vtag != 33-45;ok
sctp vtag {33, 55, 67, 88};ok
sctp vtag != {33, 55, 67, 88};ok
-sctp vtag { 33-55};ok
-sctp vtag != { 33-55};ok
+
+# assert all chunk types are recognized
+sctp chunk data exists;ok
+sctp chunk init exists;ok
+sctp chunk init-ack exists;ok
+sctp chunk sack exists;ok
+sctp chunk heartbeat exists;ok
+sctp chunk heartbeat-ack exists;ok
+sctp chunk abort exists;ok
+sctp chunk shutdown exists;ok
+sctp chunk shutdown-ack exists;ok
+sctp chunk error exists;ok
+sctp chunk cookie-echo exists;ok
+sctp chunk cookie-ack exists;ok
+sctp chunk ecne exists;ok
+sctp chunk cwr exists;ok
+sctp chunk shutdown-complete exists;ok
+sctp chunk asconf-ack exists;ok
+sctp chunk forward-tsn exists;ok
+sctp chunk asconf exists;ok
+
+# test common header fields in random chunk types
+sctp chunk data type 0;ok
+sctp chunk init flags 23;ok
+sctp chunk init-ack length 42;ok
+
+# test one custom field in every applicable chunk type
+sctp chunk data stream 1337;ok
+sctp chunk init initial-tsn 5;ok
+sctp chunk init-ack num-outbound-streams 3;ok
+sctp chunk sack a-rwnd 1;ok
+sctp chunk shutdown cum-tsn-ack 65535;ok
+sctp chunk ecne lowest-tsn 5;ok
+sctp chunk cwr lowest-tsn 8;ok
+sctp chunk asconf-ack seqno 12345;ok
+sctp chunk forward-tsn new-cum-tsn 31337;ok
+sctp chunk asconf seqno 12345;ok
diff --git a/tests/py/inet/sctp.t.json b/tests/py/inet/sctp.t.json
index 2684b034..75a9b01c 100644
--- a/tests/py/inet/sctp.t.json
+++ b/tests/py/inet/sctp.t.json
@@ -110,46 +110,6 @@
}
]
-# sctp sport { 23-44}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sport",
- "protocol": "sctp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 23, 44 ] }
- ]
- }
- }
- }
-]
-
-# sctp sport != { 23-44}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sport",
- "protocol": "sctp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 23, 44 ] }
- ]
- }
- }
- }
-]
-
# sctp dport 23
[
{
@@ -262,46 +222,6 @@
}
]
-# sctp dport { 23-44}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "dport",
- "protocol": "sctp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 23, 44 ] }
- ]
- }
- }
- }
-]
-
-# sctp dport != { 23-44}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "dport",
- "protocol": "sctp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 23, 44 ] }
- ]
- }
- }
- }
-]
-
# sctp checksum 1111
[
{
@@ -414,46 +334,6 @@
}
]
-# sctp checksum { 22-44}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "sctp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 22, 44 ] }
- ]
- }
- }
- }
-]
-
-# sctp checksum != { 22-44}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "sctp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 22, 44 ] }
- ]
- }
- }
- }
-]
-
# sctp vtag 22
[
{
@@ -568,42 +448,480 @@
}
]
-# sctp vtag { 33-55}
+# sctp chunk data exists
[
{
"match": {
"left": {
- "payload": {
- "field": "vtag",
- "protocol": "sctp"
+ "sctp chunk": {
+ "name": "data"
}
},
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
+ "op": "==",
+ "right": true
}
}
]
-# sctp vtag != { 33-55}
+# sctp chunk init exists
[
{
"match": {
"left": {
- "payload": {
- "field": "vtag",
- "protocol": "sctp"
+ "sctp chunk": {
+ "name": "init"
}
},
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk init-ack exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "init-ack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk sack exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk heartbeat exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "heartbeat"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk heartbeat-ack exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "heartbeat-ack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk abort exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "abort"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk shutdown exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "shutdown"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk shutdown-ack exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "shutdown-ack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk error exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "error"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk cookie-echo exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "cookie-echo"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk cookie-ack exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "cookie-ack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk ecne exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "ecne"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk cwr exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "cwr"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk shutdown-complete exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "shutdown-complete"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk asconf-ack exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "asconf-ack"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk forward-tsn exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "forward-tsn"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk asconf exists
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "name": "asconf"
+ }
+ },
+ "op": "==",
+ "right": true
+ }
+ }
+]
+
+# sctp chunk data type 0
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "type",
+ "name": "data"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# sctp chunk init flags 23
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "flags",
+ "name": "init"
+ }
+ },
+ "op": "==",
+ "right": 23
+ }
+ }
+]
+
+# sctp chunk init-ack length 42
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "length",
+ "name": "init-ack"
+ }
+ },
+ "op": "==",
+ "right": 42
+ }
+ }
+]
+
+# sctp chunk data stream 1337
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "stream",
+ "name": "data"
+ }
+ },
+ "op": "==",
+ "right": 1337
+ }
+ }
+]
+
+# sctp chunk init initial-tsn 5
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "initial-tsn",
+ "name": "init"
+ }
+ },
+ "op": "==",
+ "right": 5
+ }
+ }
+]
+
+# sctp chunk init-ack num-outbound-streams 3
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "num-outbound-streams",
+ "name": "init-ack"
+ }
+ },
+ "op": "==",
+ "right": 3
+ }
+ }
+]
+
+# sctp chunk sack a-rwnd 1
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "a-rwnd",
+ "name": "sack"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# sctp chunk shutdown cum-tsn-ack 65535
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "cum-tsn-ack",
+ "name": "shutdown"
+ }
+ },
+ "op": "==",
+ "right": 65535
+ }
+ }
+]
+
+# sctp chunk ecne lowest-tsn 5
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "lowest-tsn",
+ "name": "ecne"
+ }
+ },
+ "op": "==",
+ "right": 5
+ }
+ }
+]
+
+# sctp chunk cwr lowest-tsn 8
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "lowest-tsn",
+ "name": "cwr"
+ }
+ },
+ "op": "==",
+ "right": 8
+ }
+ }
+]
+
+# sctp chunk asconf-ack seqno 12345
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "seqno",
+ "name": "asconf-ack"
+ }
+ },
+ "op": "==",
+ "right": 12345
+ }
+ }
+]
+
+# sctp chunk forward-tsn new-cum-tsn 31337
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "new-cum-tsn",
+ "name": "forward-tsn"
+ }
+ },
+ "op": "==",
+ "right": 31337
+ }
+ }
+]
+
+# sctp chunk asconf seqno 12345
+[
+ {
+ "match": {
+ "left": {
+ "sctp chunk": {
+ "field": "seqno",
+ "name": "asconf"
+ }
+ },
+ "op": "==",
+ "right": 12345
}
}
]
diff --git a/tests/py/inet/sctp.t.payload b/tests/py/inet/sctp.t.payload
index ecfcc725..7337e2ea 100644
--- a/tests/py/inet/sctp.t.payload
+++ b/tests/py/inet/sctp.t.payload
@@ -47,26 +47,6 @@ inet test-inet input
[ payload load 2b @ transport header + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# sctp sport { 23-44}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00001700 : 0 [end] element 00002d00 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000084 ]
- [ payload load 2b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# sctp sport != { 23-44}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00001700 : 0 [end] element 00002d00 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000084 ]
- [ payload load 2b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# sctp dport 23
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -116,26 +96,6 @@ inet test-inet input
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# sctp dport { 23-44}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00001700 : 0 [end] element 00002d00 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000084 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# sctp dport != { 23-44}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00001700 : 0 [end] element 00002d00 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000084 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# sctp checksum 1111
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -185,26 +145,6 @@ inet test-inet input
[ payload load 4b @ transport header + 8 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# sctp checksum { 22-44}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 16000000 : 0 [end] element 2d000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000084 ]
- [ payload load 4b @ transport header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# sctp checksum != { 22-44}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 16000000 : 0 [end] element 2d000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000084 ]
- [ payload load 4b @ transport header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# sctp vtag 22
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -254,23 +194,158 @@ inet test-inet input
[ payload load 4b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# sctp vtag { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000084 ]
- [ payload load 4b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# sctp vtag != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000084 ]
- [ payload load 4b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+# sctp chunk data exists
+ip
+ [ exthdr load 1b @ 0 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk init exists
+ip
+ [ exthdr load 1b @ 1 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk init-ack exists
+ip
+ [ exthdr load 1b @ 2 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk sack exists
+ip
+ [ exthdr load 1b @ 3 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk heartbeat exists
+ip
+ [ exthdr load 1b @ 4 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk heartbeat-ack exists
+ip
+ [ exthdr load 1b @ 5 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk abort exists
+ip
+ [ exthdr load 1b @ 6 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk shutdown exists
+ip
+ [ exthdr load 1b @ 7 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk shutdown-ack exists
+ip
+ [ exthdr load 1b @ 8 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk error exists
+ip
+ [ exthdr load 1b @ 9 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk cookie-echo exists
+ip
+ [ exthdr load 1b @ 10 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk cookie-ack exists
+ip
+ [ exthdr load 1b @ 11 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk ecne exists
+ip
+ [ exthdr load 1b @ 12 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk cwr exists
+ip
+ [ exthdr load 1b @ 13 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk shutdown-complete exists
+ip
+ [ exthdr load 1b @ 14 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk asconf-ack exists
+ip
+ [ exthdr load 1b @ 128 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk forward-tsn exists
+ip
+ [ exthdr load 1b @ 192 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk asconf exists
+ip
+ [ exthdr load 1b @ 193 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# sctp chunk data type 0
+ip
+ [ exthdr load 1b @ 0 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# sctp chunk init flags 23
+ip
+ [ exthdr load 1b @ 1 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000017 ]
+
+# sctp chunk init-ack length 42
+ip
+ [ exthdr load 2b @ 2 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00002a00 ]
+
+# sctp chunk data stream 1337
+ip
+ [ exthdr load 2b @ 0 + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00003905 ]
+
+# sctp chunk init initial-tsn 5
+ip
+ [ exthdr load 4b @ 1 + 16 => reg 1 ]
+ [ cmp eq reg 1 0x05000000 ]
+
+# sctp chunk init-ack num-outbound-streams 3
+ip
+ [ exthdr load 2b @ 2 + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000300 ]
+
+# sctp chunk sack a-rwnd 1
+ip
+ [ exthdr load 4b @ 3 + 8 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# sctp chunk shutdown cum-tsn-ack 65535
+ip
+ [ exthdr load 4b @ 7 + 4 => reg 1 ]
+ [ cmp eq reg 1 0xffff0000 ]
+
+# sctp chunk ecne lowest-tsn 5
+ip
+ [ exthdr load 4b @ 12 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x05000000 ]
+
+# sctp chunk cwr lowest-tsn 8
+ip
+ [ exthdr load 4b @ 13 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x08000000 ]
+
+# sctp chunk asconf-ack seqno 12345
+ip
+ [ exthdr load 4b @ 128 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x39300000 ]
+
+# sctp chunk forward-tsn new-cum-tsn 31337
+ip
+ [ exthdr load 4b @ 192 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x697a0000 ]
+
+# sctp chunk asconf seqno 12345
+ip
+ [ exthdr load 4b @ 193 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x39300000 ]
diff --git a/tests/py/inet/sets.t b/tests/py/inet/sets.t
index daf8f2d6..5b22e1fe 100644
--- a/tests/py/inet/sets.t
+++ b/tests/py/inet/sets.t
@@ -1,9 +1,10 @@
: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
*bridge;test-inet;input
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
!set1 type ipv4_addr timeout 60s;ok
?set1 192.168.3.4 timeout 30s, 10.2.1.1;ok
@@ -16,3 +17,9 @@ ip saddr != @set2 drop;fail
ip6 daddr != @set2 accept;ok
ip6 daddr @set1 drop;fail
+
+!set3 type ipv4_addr . ipv4_addr . inet_service flags interval;ok
+?set3 10.0.0.0/8 . 192.168.1.3-192.168.1.9 . 1024-65535;ok
+
+ip saddr . ip daddr . tcp dport @set3 accept;ok
+ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept;ok
diff --git a/tests/py/inet/sets.t.json b/tests/py/inet/sets.t.json
index bcb638f2..b44ffc20 100644
--- a/tests/py/inet/sets.t.json
+++ b/tests/py/inet/sets.t.json
@@ -36,3 +36,101 @@
}
]
+# ip saddr . ip daddr . tcp dport @set3 accept
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": "@set3"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "10.0.0.0",
+ "len": 8
+ }
+ },
+ {
+ "range": [
+ 10,
+ 23
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "range": [
+ "192.168.1.1",
+ "192.168.3.8"
+ ]
+ },
+ {
+ "range": [
+ 80,
+ 443
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
diff --git a/tests/py/inet/sets.t.payload.bridge b/tests/py/inet/sets.t.payload.bridge
index f5aaab1d..3dd9d57b 100644
--- a/tests/py/inet/sets.t.payload.bridge
+++ b/tests/py/inet/sets.t.payload.bridge
@@ -13,3 +13,30 @@ bridge test-inet input
[ payload load 16b @ network header + 24 => reg 1 ]
[ lookup reg 1 set set2 0x1 ]
[ immediate reg 0 accept ]
+
+# ip saddr . ip daddr . tcp dport @set3 accept
+bridge
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ payload load 2b @ transport header + 2 => reg 10 ]
+ [ lookup reg 1 set set3 ]
+ [ immediate reg 0 accept ]
+
+# ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept
+__set%d test-inet 87
+__set%d test-inet 0
+ element 0000000a 00000a00 - ffffff0a 00001700 : 0 [end] element 0101a8c0 00005000 - 0803a8c0 0000bb01 : 0 [end]
+bridge
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
diff --git a/tests/py/inet/sets.t.payload.inet b/tests/py/inet/sets.t.payload.inet
index 1584fc07..53c6b182 100644
--- a/tests/py/inet/sets.t.payload.inet
+++ b/tests/py/inet/sets.t.payload.inet
@@ -14,4 +14,28 @@ inet test-inet input
[ lookup reg 1 set set2 0x1 ]
[ immediate reg 0 accept ]
+# ip saddr . ip daddr . tcp dport @set3 accept
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ payload load 2b @ transport header + 2 => reg 10 ]
+ [ lookup reg 1 set set3 ]
+ [ immediate reg 0 accept ]
+# ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept
+__set%d test-inet 87
+__set%d test-inet 0
+ element 0000000a 00000a00 - ffffff0a 00001700 : 0 [end] element 0101a8c0 00005000 - 0803a8c0 0000bb01 : 0 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
diff --git a/tests/py/inet/sets.t.payload.netdev b/tests/py/inet/sets.t.payload.netdev
index 9c94e384..e31aeb92 100644
--- a/tests/py/inet/sets.t.payload.netdev
+++ b/tests/py/inet/sets.t.payload.netdev
@@ -14,3 +14,28 @@ netdev test-netdev ingress
[ lookup reg 1 set set2 0x1 ]
[ immediate reg 0 accept ]
+# ip saddr . ip daddr . tcp dport @set3 accept
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ payload load 2b @ transport header + 2 => reg 10 ]
+ [ lookup reg 1 set set3 ]
+ [ immediate reg 0 accept ]
+
+# ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept
+__set%d test-netdev 87
+__set%d test-netdev 0
+ element 0000000a 00000a00 - ffffff0a 00001700 : 0 [end] element 0101a8c0 00005000 - 0803a8c0 0000bb01 : 0 [end]
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
diff --git a/tests/py/inet/snat.t.payload b/tests/py/inet/snat.t.payload
index 00bb937f..50519c6b 100644
--- a/tests/py/inet/snat.t.payload
+++ b/tests/py/inet/snat.t.payload
@@ -7,7 +7,7 @@ inet test-inet postrouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00005100 ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat snat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat snat ip addr_min reg 1 ]
# iifname "eth0" tcp dport 81 ip saddr 10.1.1.1 snat to 192.168.3.2
inet test-inet postrouting
@@ -22,7 +22,7 @@ inet test-inet postrouting
[ payload load 4b @ network header + 12 => reg 1 ]
[ cmp eq reg 1 0x0101010a ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat snat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat snat ip addr_min reg 1 ]
# iifname "eth0" tcp dport 81 snat ip6 to dead::beef
inet test-inet postrouting
@@ -33,7 +33,7 @@ inet test-inet postrouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00005100 ]
[ immediate reg 1 0x0000adde 0x00000000 0x00000000 0xefbe0000 ]
- [ nat snat ip6 addr_min reg 1 addr_max reg 0 ]
+ [ nat snat ip6 addr_min reg 1 ]
# iifname "foo" masquerade random
inet test-inet postrouting
diff --git a/tests/py/inet/socket.t b/tests/py/inet/socket.t
index 91846e8e..05e9ebb4 100644
--- a/tests/py/inet/socket.t
+++ b/tests/py/inet/socket.t
@@ -9,3 +9,7 @@ socket transparent 1;ok
socket transparent 2;fail
socket mark 0x00000005;ok
+
+socket wildcard 0;ok
+socket wildcard 1;ok
+socket wildcard 2;fail
diff --git a/tests/py/inet/socket.t.json b/tests/py/inet/socket.t.json
index 99d6e248..fa48e79d 100644
--- a/tests/py/inet/socket.t.json
+++ b/tests/py/inet/socket.t.json
@@ -43,3 +43,32 @@
}
]
+# socket wildcard 0
+[
+ {
+ "match": {
+ "left": {
+ "socket": {
+ "key": "wildcard"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# socket wildcard 1
+[
+ {
+ "match": {
+ "left": {
+ "socket": {
+ "key": "wildcard"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
diff --git a/tests/py/inet/socket.t.payload b/tests/py/inet/socket.t.payload
index 687b7a45..e66ccbf7 100644
--- a/tests/py/inet/socket.t.payload
+++ b/tests/py/inet/socket.t.payload
@@ -1,45 +1,24 @@
# socket transparent 0
-ip sockip4 sockchain
- [ socket load transparent => reg 1 ]
- [ cmp eq reg 1 0x00000000 ]
-
-# socket transparent 0
-ip6 sockip6 sockchain
- [ socket load transparent => reg 1 ]
- [ cmp eq reg 1 0x00000000 ]
-
-# socket transparent 0
inet sockin sockchain
[ socket load transparent => reg 1 ]
[ cmp eq reg 1 0x00000000 ]
# socket transparent 1
-ip sockip4 sockchain
- [ socket load transparent => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# socket transparent 1
-ip6 sockip6 sockchain
- [ socket load transparent => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# socket transparent 1
inet sockin sockchain
[ socket load transparent => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
# socket mark 0x00000005
-ip sockip4 sockchain
- [ socket load mark => reg 1 ]
- [ cmp eq reg 1 0x00000005 ]
-
-# socket mark 0x00000005
-ip6 sockip6 sockchain
- [ socket load mark => reg 1 ]
- [ cmp eq reg 1 0x00000005 ]
-
-# socket mark 0x00000005
inet sockin sockchain
[ socket load mark => reg 1 ]
[ cmp eq reg 1 0x00000005 ]
+# socket wildcard 0
+inet sockin sockchain
+ [ socket load wildcard => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# socket wildcard 1
+inet sockin sockchain
+ [ socket load wildcard => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
diff --git a/tests/py/inet/synproxy.t.json b/tests/py/inet/synproxy.t.json
index 92c69d75..1dd85a61 100644
--- a/tests/py/inet/synproxy.t.json
+++ b/tests/py/inet/synproxy.t.json
@@ -5,24 +5,6 @@
}
]
-# synproxy mss 1460
-[
- {
- "synproxy": {
- "mss": 1460
- }
- }
-]
-
-# synproxy wscale 7
-[
- {
- "synproxy": {
- "wscale": 7
- }
- }
-]
-
# synproxy mss 1460 wscale 7
[
{
@@ -56,20 +38,6 @@
}
]
-# synproxy mss 1460 wscale 7 timestamp sack-perm
-[
- {
- "synproxy": {
- "mss": 1460,
- "wscale": 7,
- "flags": [
- "timestamp",
- "sack-perm"
- ]
- }
- }
-]
-
# synproxy mss 1460 wscale 5 timestamp sack-perm
[
{
diff --git a/tests/py/inet/synproxy.t.payload b/tests/py/inet/synproxy.t.payload
index 2e6feaaf..dd318b9a 100644
--- a/tests/py/inet/synproxy.t.payload
+++ b/tests/py/inet/synproxy.t.payload
@@ -1,72 +1,24 @@
# synproxy
-ip synproxyip synproxychain
- [ synproxy mss 0 wscale 0 ]
-
-# synproxy
-ip6 synproxyip6 synproxychain
- [ synproxy mss 0 wscale 0 ]
-
-# synproxy
inet synproxyinet synproxychain
[ synproxy mss 0 wscale 0 ]
# synproxy mss 1460 wscale 7
-ip synproxyip synproxychain
- [ synproxy mss 1460 wscale 7 ]
-
-# synproxy mss 1460 wscale 7
-ip6 synproxyip6 synproxychain
- [ synproxy mss 1460 wscale 7 ]
-
-# synproxy mss 1460 wscale 7
inet synproxyinet synproxychain
[ synproxy mss 1460 wscale 7 ]
# synproxy mss 1460 wscale 5 timestamp sack-perm
-ip synproxyip synproxychain
- [ synproxy mss 1460 wscale 5 ]
-
-# synproxy mss 1460 wscale 5 timestamp sack-perm
-ip6 synproxyip6 synproxychain
- [ synproxy mss 1460 wscale 5 ]
-
-# synproxy mss 1460 wscale 5 timestamp sack-perm
inet synproxyinet synproxychain
[ synproxy mss 1460 wscale 5 ]
# synproxy timestamp sack-perm
-ip synproxyip synproxychain
- [ synproxy mss 0 wscale 0 ]
-
-# synproxy timestamp sack-perm
-ip6 synproxyip6 synproxychain
- [ synproxy mss 0 wscale 0 ]
-
-# synproxy timestamp sack-perm
inet synproxyinet synproxychain
[ synproxy mss 0 wscale 0 ]
# synproxy timestamp
-ip synproxyip synproxychain
- [ synproxy mss 0 wscale 0 ]
-
-# synproxy timestamp
-ip6 synproxyip6 synproxychain
- [ synproxy mss 0 wscale 0 ]
-
-# synproxy timestamp
inet synproxyinet synproxychain
[ synproxy mss 0 wscale 0 ]
# synproxy sack-perm
-ip synproxyip synproxychain
- [ synproxy mss 0 wscale 0 ]
-
-# synproxy sack-perm
-ip6 synproxyip6 synproxychain
- [ synproxy mss 0 wscale 0 ]
-
-# synproxy sack-perm
inet synproxyinet synproxychain
[ synproxy mss 0 wscale 0 ]
diff --git a/tests/py/inet/tcp.t b/tests/py/inet/tcp.t
index e0a83e2b..f4bdac17 100644
--- a/tests/py/inet/tcp.t
+++ b/tests/py/inet/tcp.t
@@ -1,10 +1,11 @@
: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
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
tcp dport set {1, 2, 3};fail
@@ -14,8 +15,6 @@ tcp dport 33-45;ok
tcp dport != 33-45;ok
tcp dport { 33, 55, 67, 88};ok
tcp dport != { 33, 55, 67, 88};ok
-tcp dport { 33-55};ok
-tcp dport != { 33-55};ok
tcp dport {telnet, http, https} accept;ok;tcp dport { 443, 23, 80} accept
tcp dport vmap { 22 : accept, 23 : drop };ok
tcp dport vmap { 25:accept, 28:drop };ok
@@ -30,8 +29,6 @@ tcp sport 33-45;ok
tcp sport != 33-45;ok
tcp sport { 33, 55, 67, 88};ok
tcp sport != { 33, 55, 67, 88};ok
-tcp sport { 33-55};ok
-tcp sport != { 33-55};ok
tcp sport vmap { 25:accept, 28:drop };ok
tcp sport 8080 drop;ok
@@ -47,8 +44,6 @@ tcp sequence 33-45;ok
tcp sequence != 33-45;ok
tcp sequence { 33, 55, 67, 88};ok
tcp sequence != { 33, 55, 67, 88};ok
-tcp sequence { 33-55};ok
-tcp sequence != { 33-55};ok
tcp ackseq 42949672 drop;ok
tcp ackseq 22;ok
@@ -57,8 +52,6 @@ tcp ackseq 33-45;ok
tcp ackseq != 33-45;ok
tcp ackseq { 33, 55, 67, 88};ok
tcp ackseq != { 33, 55, 67, 88};ok
-tcp ackseq { 33-55};ok
-tcp ackseq != { 33-55};ok
- tcp doff 22;ok
- tcp doff != 233;ok
@@ -66,8 +59,6 @@ tcp ackseq != { 33-55};ok
- tcp doff != 33-45;ok
- tcp doff { 33, 55, 67, 88};ok
- tcp doff != { 33, 55, 67, 88};ok
-- tcp doff { 33-55};ok
-- tcp doff != { 33-55};ok
# BUG reserved
# BUG: It is accepted but it is not shown then. tcp reserver
@@ -77,8 +68,26 @@ tcp flags != { fin, urg, ecn, cwr} drop;ok
tcp flags cwr;ok
tcp flags != cwr;ok
tcp flags == syn;ok
-tcp flags & (syn|fin) == (syn|fin);ok;tcp flags & (fin | syn) == fin | syn
+tcp flags fin,syn / fin,syn;ok;tcp flags & (fin | syn) == fin | syn
+tcp flags != syn / fin,syn;ok;tcp flags & (fin | syn) != syn
+tcp flags & syn != 0;ok;tcp flags syn
+tcp flags & syn == 0;ok;tcp flags ! syn
+tcp flags & (syn | ack) != 0;ok;tcp flags syn,ack
+tcp flags & (syn | ack) == 0;ok;tcp flags ! syn,ack
+# it should be possible to transform this to: tcp flags syn
+tcp flags & syn == syn;ok
+tcp flags & syn != syn;ok
+tcp flags & (fin | syn | rst | ack) syn;ok;tcp flags & (fin | syn | rst | ack) == syn
+tcp flags & (fin | syn | rst | ack) == syn;ok
+tcp flags & (fin | syn | rst | ack) != syn;ok
+tcp flags & (fin | syn | rst | ack) == syn | ack;ok
+tcp flags & (fin | syn | rst | ack) != syn | ack;ok
+tcp flags & (syn | ack) == syn | ack;ok
tcp flags & (fin | syn | rst | psh | ack | urg | ecn | cwr) == fin | syn | rst | psh | ack | urg | ecn | cwr;ok;tcp flags == 0xff
+tcp flags { syn, syn | ack };ok
+tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack };ok
+tcp flags ! fin,rst;ok
+tcp flags & (fin | syn | rst | ack) ! syn;fail
tcp window 22222;ok
tcp window 22;ok
@@ -87,8 +96,6 @@ tcp window 33-45;ok
tcp window != 33-45;ok
tcp window { 33, 55, 67, 88};ok
tcp window != { 33, 55, 67, 88};ok
-tcp window { 33-55};ok
-tcp window != { 33-55};ok
tcp checksum 22;ok
tcp checksum != 233;ok
@@ -96,8 +103,6 @@ tcp checksum 33-45;ok
tcp checksum != 33-45;ok
tcp checksum { 33, 55, 67, 88};ok
tcp checksum != { 33, 55, 67, 88};ok
-tcp checksum { 33-55};ok
-tcp checksum != { 33-55};ok
tcp urgptr 1234 accept;ok
tcp urgptr 22;ok
@@ -106,7 +111,5 @@ tcp urgptr 33-45;ok
tcp urgptr != 33-45;ok
tcp urgptr { 33, 55, 67, 88};ok
tcp urgptr != { 33, 55, 67, 88};ok
-tcp urgptr { 33-55};ok
-tcp urgptr != { 33-55};ok
tcp doff 8;ok
diff --git a/tests/py/inet/tcp.t.json b/tests/py/inet/tcp.t.json
index babe5920..28dd4341 100644
--- a/tests/py/inet/tcp.t.json
+++ b/tests/py/inet/tcp.t.json
@@ -112,46 +112,6 @@
}
]
-# tcp dport { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "dport",
- "protocol": "tcp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# tcp dport != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "dport",
- "protocol": "tcp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# tcp dport {telnet, http, https} accept
[
{
@@ -397,46 +357,6 @@
}
]
-# tcp sport { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sport",
- "protocol": "tcp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# tcp sport != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sport",
- "protocol": "tcp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# tcp sport vmap { 25:accept, 28:drop }
[
{
@@ -753,46 +673,6 @@
}
]
-# tcp sequence { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sequence",
- "protocol": "tcp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# tcp sequence != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sequence",
- "protocol": "tcp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# tcp ackseq 42949672 drop
[
{
@@ -926,46 +806,6 @@
}
]
-# tcp ackseq { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "ackseq",
- "protocol": "tcp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# tcp ackseq != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "ackseq",
- "protocol": "tcp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# tcp flags { fin, syn, rst, psh, ack, urg, ecn, cwr} drop
[
{
@@ -1114,12 +954,12 @@
}
},
{
- "|": [ "fin", { "|": [ "syn", { "|": [ "rst", { "|": [ "psh", { "|": [ "ack", { "|": [ "urg", { "|": [ "ecn", "cwr" ] } ] } ] } ] } ] } ] } ]
+ "|": [ "fin", "syn", "rst", "psh", "ack", "urg", "ecn", "cwr" ]
}
]
},
"op": "==",
- "right": { "|": [ "fin", { "|": [ "syn", { "|": [ "rst", { "|": [ "psh", { "|": [ "ack", { "|": [ "urg", { "|": [ "ecn", "cwr" ] } ] } ] } ] } ] } ] } ] }
+ "right": { "|": [ "fin", "syn", "rst", "psh", "ack", "urg", "ecn", "cwr" ] }
}
}
]
@@ -1254,46 +1094,6 @@
}
]
-# tcp window { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "window",
- "protocol": "tcp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# tcp window != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "window",
- "protocol": "tcp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# tcp checksum 22
[
{
@@ -1408,46 +1208,6 @@
}
]
-# tcp checksum { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "tcp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# tcp checksum != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "tcp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# tcp urgptr 1234 accept
[
{
@@ -1581,58 +1341,435 @@
}
]
-# tcp urgptr { 33-55}
+# tcp doff 8
[
{
"match": {
"left": {
"payload": {
- "field": "urgptr",
+ "field": "doff",
"protocol": "tcp"
}
},
"op": "==",
+ "right": 8
+ }
+ }
+]
+
+# tcp flags { syn, syn | ack }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
"right": {
"set": [
- { "range": [ 33, 55 ] }
+ "syn",
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ }
]
}
}
}
]
-# tcp urgptr != { 33-55}
+# tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack }
[
{
"match": {
"left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ { "|": [ "fin", "syn", "rst", "psh", "ack", "urg" ] }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "fin",
+ "ack",
+ { "|": [ "psh", "ack" ] },
+ { "|": [ "fin", "psh", "ack" ] }
+ ]
+ }
+ }
+ }
+]
+
+# tcp flags ! fin,rst
+[
+ {
+ "match": {
+ "op": "!",
+ "left": {
"payload": {
- "field": "urgptr",
- "protocol": "tcp"
+ "protocol": "tcp",
+ "field": "flags"
}
},
- "op": "!=",
+ "right": [
+ "fin",
+ "rst"
+ ]
+ }
+ }
+]
+
+# tcp flags fin,syn / fin,syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ "fin",
+ "syn"
+ ]
+ }
+ ]
+ },
+ "op": "==",
"right": {
- "set": [
- { "range": [ 33, 55 ] }
+ "|": [
+ "fin",
+ "syn"
]
}
}
}
]
-# tcp doff 8
+# tcp flags != syn / fin,syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ "fin",
+ "syn"
+ ]
+ }
+ ]
+ },
+ "op": "!=",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & syn == 0
[
{
"match": {
"left": {
"payload": {
- "field": "doff",
+ "field": "flags",
"protocol": "tcp"
}
},
- "op": "==",
- "right": 8
+ "op": "!",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & syn != 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "in",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & (syn | ack) != 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "in",
+ "right": [
+ "syn",
+ "ack"
+ ]
+ }
+ }
+]
+
+# tcp flags & (syn | ack) == 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "op": "!",
+ "right": [
+ "syn",
+ "ack"
+ ]
+ }
+ }
+]
+
+# tcp flags & syn == syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "syn"
+ ]
+ },
+ "op": "==",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & syn != syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ "syn"
+ ]
+ },
+ "op": "!=",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & (fin | syn | rst | ack) syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ "fin",
+ "syn",
+ "rst",
+ "ack"
+ ]
+ }
+ ]
+ },
+ "op": "==",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & (fin | syn | rst | ack) == syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ "fin",
+ "syn",
+ "rst",
+ "ack"
+ ]
+ }
+ ]
+ },
+ "op": "==",
+ "right": "syn"
+ }
+ }
+]
+
+
+# tcp flags & (fin | syn | rst | ack) != syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ "fin",
+ "syn",
+ "rst",
+ "ack"
+ ]
+ }
+ ]
+ },
+ "op": "!=",
+ "right": "syn"
+ }
+ }
+]
+
+# tcp flags & (fin | syn | rst | ack) == syn | ack
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ "fin",
+ "syn",
+ "rst",
+ "ack"
+ ]
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ }
+ }
+ }
+]
+
+# tcp flags & (syn | ack) == syn | ack
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ }
+ }
+ }
+]
+
+# tcp flags & (fin | syn | rst | ack) != syn | ack
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ { "|": [ "fin", "syn", "rst", "ack" ] }
+ ]
+ },
+ "op": "!=",
+ "right": {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ }
}
}
]
diff --git a/tests/py/inet/tcp.t.json.output b/tests/py/inet/tcp.t.json.output
index 0f7a593b..d487a8f1 100644
--- a/tests/py/inet/tcp.t.json.output
+++ b/tests/py/inet/tcp.t.json.output
@@ -115,3 +115,50 @@
}
]
+# tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack }
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ "fin",
+ "syn",
+ "rst",
+ "psh",
+ "ack",
+ "urg"
+ ]
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "fin",
+ {
+ "|": [
+ "fin",
+ "psh",
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ "psh",
+ "ack"
+ ]
+ },
+ "ack"
+ ]
+ }
+ }
+ }
+]
diff --git a/tests/py/inet/tcp.t.payload b/tests/py/inet/tcp.t.payload
index 55f1bc2e..bc6bb989 100644
--- a/tests/py/inet/tcp.t.payload
+++ b/tests/py/inet/tcp.t.payload
@@ -47,26 +47,6 @@ inet test-inet input
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# tcp dport { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [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 ]
-
-# tcp dport != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [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 0x1 ]
-
# tcp dport {telnet, http, https} accept
__set%d test-inet 3
__set%d test-inet 0
@@ -81,7 +61,7 @@ inet test-inet input
# tcp dport vmap { 22 : accept, 23 : drop }
__map%d test-inet b
__map%d test-inet 0
- element 00001600 : 0 [end] element 00001700 : 0 [end]
+ element 00001600 : accept 0 [end] element 00001700 : drop 0 [end]
inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -91,7 +71,7 @@ inet test-inet input
# tcp dport vmap { 25:accept, 28:drop }
__map%d test-inet b
__map%d test-inet 0
- element 00001900 : 0 [end] element 00001c00 : 0 [end]
+ element 00001900 : accept 0 [end] element 00001c00 : drop 0 [end]
inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -167,30 +147,10 @@ inet test-inet input
[ payload load 2b @ transport header + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# tcp sport { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 2b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# tcp sport != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 2b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# tcp sport vmap { 25:accept, 28:drop }
__map%d test-inet b
__map%d test-inet 0
- element 00001900 : 0 [end] element 00001c00 : 0 [end]
+ element 00001900 : accept 0 [end] element 00001c00 : drop 0 [end]
inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -293,26 +253,6 @@ inet test-inet input
[ payload load 4b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# tcp sequence { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 4b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# tcp sequence != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 4b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# tcp ackseq 42949672 drop
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -370,26 +310,6 @@ inet test-inet input
[ payload load 4b @ transport header + 8 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# tcp ackseq { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 4b @ transport header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# tcp ackseq != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 4b @ transport header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# tcp flags { fin, syn, rst, psh, ack, urg, ecn, cwr} drop
__set%d test-inet 3
__set%d test-inet 0
@@ -417,7 +337,7 @@ inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ transport header + 13 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000080 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000080 ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000000 ]
# tcp flags != cwr
@@ -434,20 +354,124 @@ inet test-inet input
[ payload load 1b @ transport header + 13 => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
-# tcp flags & (syn|fin) == (syn|fin)
+# tcp flags fin,syn / fin,syn
inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ transport header + 13 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000003 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000003 ]
+# tcp flags != syn / fin,syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000003 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# tcp flags & syn != 0
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# tcp flags & syn == 0
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp flags & (syn | ack) != 0
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000012 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# tcp flags & (syn | ack) == 0
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000012 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp flags & syn == syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# tcp flags & syn != syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000002 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# tcp flags & (fin | syn | rst | ack) syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# tcp flags & (fin | syn | rst | ack) == syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# tcp flags & (fin | syn | rst | ack) != syn
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000002 ]
+
+# tcp flags & (fin | syn | rst | ack) == syn | ack
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000012 ]
+
+# tcp flags & (fin | syn | rst | ack) != syn | ack
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000012 ]
+
+# tcp flags & (syn | ack) == syn | ack
+inet test-inet input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000012 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000012 ]
+
# tcp flags & (fin | syn | rst | psh | ack | urg | ecn | cwr) == fin | syn | rst | psh | ack | urg | ecn | cwr
inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 1b @ transport header + 13 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000ff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x000000ff ]
# tcp window 22222
@@ -506,26 +530,6 @@ inet test-inet input
[ payload load 2b @ transport header + 14 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# tcp window { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 2b @ transport header + 14 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# tcp window != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 2b @ transport header + 14 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# tcp checksum 22
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -575,26 +579,6 @@ inet test-inet input
[ payload load 2b @ transport header + 16 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# tcp checksum { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 2b @ transport header + 16 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# tcp checksum != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ payload load 2b @ transport header + 16 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# tcp urgptr 1234 accept
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -652,31 +636,39 @@ inet test-inet input
[ payload load 2b @ transport header + 18 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# tcp urgptr { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
+# tcp doff 8
inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
- [ payload load 2b @ transport header + 18 => reg 1 ]
- [ lookup reg 1 set __set%d ]
+ [ payload load 1b @ transport header + 12 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000080 ]
-# tcp urgptr != { 33-55}
-__set%d test-inet 7
+# tcp flags & (fin | syn | rst | psh | ack | urg) == { fin, ack, psh | ack, fin | psh | ack }
+__set%d test-inet 3
__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
+ element 00000001 : 0 [end] element 00000010 : 0 [end] element 00000018 : 0 [end] element 00000019 : 0 [end]
+ip
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
- [ payload load 2b @ transport header + 18 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000003f ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
-# tcp doff 8
-inet test-inet input
+# tcp flags { syn, syn | ack }
+__set%d test-inet 3
+__set%d test-inet 0
+ element 00000002 : 0 [end] element 00000012 : 0 [end]
+inet
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
- [ payload load 1b @ transport header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00000000 ]
- [ cmp eq reg 1 0x00000080 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+# tcp flags ! fin,rst
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 1b @ transport header + 13 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000005 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
diff --git a/tests/py/inet/tcpopt.t.payload b/tests/py/inet/tcpopt.t.payload
deleted file mode 100644
index 7e254ed3..00000000
--- a/tests/py/inet/tcpopt.t.payload
+++ /dev/null
@@ -1,200 +0,0 @@
-# tcp option eol kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option noop kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg length 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg size 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]
- [ cmp eq reg 1 0x00000100 ]
-
-# tcp option window kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window length 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window count 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack-permitted kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack-permitted length 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack length 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack left 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack0 left 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack1 left 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack2 left 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack3 left 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack right 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack0 right 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack1 right 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack2 right 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack3 right 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option timestamp length 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option timestamp tsval 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp tsecr 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option window exists
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window missing
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
- [ cmp eq reg 1 0x00000000 ]
-
-# tcp option maxseg size set 1360
-inet test-inet input
- [ immediate reg 1 0x00005005 ]
- [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
diff --git a/tests/py/inet/tproxy.t b/tests/py/inet/tproxy.t
index d23bbcb5..9901df75 100644
--- a/tests/py/inet/tproxy.t
+++ b/tests/py/inet/tproxy.t
@@ -19,3 +19,5 @@ meta l4proto 17 tproxy ip to :50080;ok
meta l4proto 17 tproxy ip6 to :50080;ok
meta l4proto 17 tproxy to :50080;ok
ip daddr 0.0.0.0/0 meta l4proto 6 tproxy ip to :2000;ok
+
+meta l4proto 6 tproxy ip to 127.0.0.1:symhash mod 2 map { 0 : 23, 1 : 42 };ok
diff --git a/tests/py/inet/tproxy.t.json b/tests/py/inet/tproxy.t.json
index 7b3b11c4..71b6fd2f 100644
--- a/tests/py/inet/tproxy.t.json
+++ b/tests/py/inet/tproxy.t.json
@@ -183,3 +183,38 @@
}
}
]
+
+# meta l4proto 6 tproxy ip to 127.0.0.1:symhash mod 2 map { 0 : 23, 1 : 42 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "tproxy": {
+ "addr": "127.0.0.1",
+ "family": "ip",
+ "port": {
+ "map": {
+ "data": {
+ "set": [
+ [ 0, 23 ],
+ [ 1, 42 ]
+ ]
+ },
+ "key": {
+ "symhash": { "mod": 2 }
+ }
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/tproxy.t.payload b/tests/py/inet/tproxy.t.payload
index 82ff928d..2f419042 100644
--- a/tests/py/inet/tproxy.t.payload
+++ b/tests/py/inet/tproxy.t.payload
@@ -54,10 +54,22 @@ inet x y
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 4b @ network header + 16 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000000 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000000 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x0000d007 ]
[ tproxy ip port reg 1 ]
+# meta l4proto 6 tproxy ip to 127.0.0.1:symhash mod 2 map { 0 : 23, 1 : 42 }
+__map%d x b size 2
+__map%d x 0
+ element 00000000 : 00001700 0 [end] element 00000001 : 00002a00 0 [end]
+inet x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ immediate reg 1 0x0100007f ]
+ [ hash reg 2 = symhash() % mod 2 ]
+ [ lookup reg 2 set __map%d dreg 2 ]
+ [ tproxy ip addr reg 1 port reg 2 ]
+
diff --git a/tests/py/inet/udp.t b/tests/py/inet/udp.t
index 4e3eaa51..7f21c8ed 100644
--- a/tests/py/inet/udp.t
+++ b/tests/py/inet/udp.t
@@ -1,10 +1,11 @@
: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
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
udp sport 80 accept;ok
udp sport != 60 accept;ok
@@ -12,8 +13,6 @@ udp sport 50-70 accept;ok
udp sport != 50-60 accept;ok
udp sport { 49, 50} drop;ok
udp sport != { 50, 60} accept;ok
-udp sport { 12-40};ok
-udp sport != { 13-24};ok
udp dport set {1, 2, 3};fail
@@ -23,8 +22,6 @@ udp dport 70-75 accept;ok
udp dport != 50-60 accept;ok
udp dport { 49, 50} drop;ok
udp dport != { 50, 60} accept;ok
-udp dport { 70-75} accept;ok
-udp dport != { 50-60} accept;ok
udp length 6666;ok
udp length != 6666;ok
@@ -32,8 +29,6 @@ udp length 50-65 accept;ok
udp length != 50-65 accept;ok
udp length { 50, 65} accept;ok
udp length != { 50, 65} accept;ok
-udp length { 35-50};ok
-udp length != { 35-50};ok
udp checksum 6666 drop;ok
udp checksum != { 444, 555} accept;ok
@@ -44,8 +39,6 @@ udp checksum 33-45;ok
udp checksum != 33-45;ok
udp checksum { 33, 55, 67, 88};ok
udp checksum != { 33, 55, 67, 88};ok
-udp checksum { 33-55};ok
-udp checksum != { 33-55};ok
# limit impact to lo
iif "lo" udp checksum set 0;ok
diff --git a/tests/py/inet/udp.t.json b/tests/py/inet/udp.t.json
index f8826640..665998ec 100644
--- a/tests/py/inet/udp.t.json
+++ b/tests/py/inet/udp.t.json
@@ -126,46 +126,6 @@
}
]
-# udp sport { 12-40}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sport",
- "protocol": "udp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 12, 40 ] }
- ]
- }
- }
- }
-]
-
-# udp sport != { 13-24}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sport",
- "protocol": "udp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 13, 24 ] }
- ]
- }
- }
- }
-]
-
# udp dport 80 accept
[
{
@@ -294,52 +254,6 @@
}
]
-# udp dport { 70-75} accept
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "dport",
- "protocol": "udp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 70, 75 ] }
- ]
- }
- }
- },
- {
- "accept": null
- }
-]
-
-# udp dport != { 50-60} accept
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "dport",
- "protocol": "udp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 50, 60 ] }
- ]
- }
- }
- },
- {
- "accept": null
- }
-]
-
# udp length 6666
[
{
@@ -462,46 +376,6 @@
}
]
-# udp length { 35-50}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "length",
- "protocol": "udp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 35, 50 ] }
- ]
- }
- }
- }
-]
-
-# udp length != { 35-50}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "length",
- "protocol": "udp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 35, 50 ] }
- ]
- }
- }
- }
-]
-
# udp checksum 6666 drop
[
{
@@ -659,46 +533,6 @@
}
]
-# udp checksum { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "udp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# udp checksum != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "udp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# iif "lo" udp checksum set 0
[
{
diff --git a/tests/py/inet/udp.t.payload b/tests/py/inet/udp.t.payload
index d91eb784..e6beda7f 100644
--- a/tests/py/inet/udp.t.payload
+++ b/tests/py/inet/udp.t.payload
@@ -53,26 +53,6 @@ inet test-inet input
[ lookup reg 1 set __set%d 0x1 ]
[ immediate reg 0 accept ]
-# udp sport { 12-40}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000c00 : 0 [end] element 00002900 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000011 ]
- [ payload load 2b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# udp sport != { 13-24}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000d00 : 0 [end] element 00001900 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000011 ]
- [ payload load 2b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# udp dport 80 accept
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -128,28 +108,6 @@ inet test-inet input
[ lookup reg 1 set __set%d 0x1 ]
[ immediate reg 0 accept ]
-# udp dport { 70-75} accept
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00004600 : 0 [end] element 00004c00 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000011 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
- [ immediate reg 0 accept ]
-
-# udp dport != { 50-60} accept
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00003200 : 0 [end] element 00003d00 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000011 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
- [ immediate reg 0 accept ]
-
# udp length 6666
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -203,26 +161,6 @@ inet test-inet input
[ lookup reg 1 set __set%d 0x1 ]
[ immediate reg 0 accept ]
-# udp length { 35-50}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002300 : 0 [end] element 00003300 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000011 ]
- [ payload load 2b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# udp length != { 35-50}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002300 : 0 [end] element 00003300 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000011 ]
- [ payload load 2b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# udp checksum 6666 drop
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -291,26 +229,6 @@ inet test-inet input
[ payload load 2b @ transport header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# udp checksum { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000011 ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# udp checksum != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000011 ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# iif "lo" udp checksum set 0
inet test-inet input
[ meta load iif => reg 1 ]
diff --git a/tests/py/inet/udplite.t b/tests/py/inet/udplite.t
index 7c22acb9..6a54709c 100644
--- a/tests/py/inet/udplite.t
+++ b/tests/py/inet/udplite.t
@@ -1,10 +1,11 @@
: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
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
udplite sport 80 accept;ok
udplite sport != 60 accept;ok
@@ -12,8 +13,6 @@ udplite sport 50-70 accept;ok
udplite sport != 50-60 accept;ok
udplite sport { 49, 50} drop;ok
udplite sport != { 49, 50} accept;ok
-udplite sport { 12-40};ok
-udplite sport != { 12-40};ok
udplite dport 80 accept;ok
udplite dport != 60 accept;ok
@@ -21,8 +20,6 @@ udplite dport 70-75 accept;ok
udplite dport != 50-60 accept;ok
udplite dport { 49, 50} drop;ok
udplite dport != { 49, 50} accept;ok
-udplite dport { 70-75} accept;ok
-udplite dport != { 70-75} accept;ok
- udplite csumcov 6666;ok
- udplite csumcov != 6666;ok
@@ -30,8 +27,6 @@ udplite dport != { 70-75} accept;ok
- udplite csumcov != 50-65 accept;ok
- udplite csumcov { 50, 65} accept;ok
- udplite csumcov != { 50, 65} accept;ok
-- udplite csumcov { 35-50};ok
-- udplite csumcov != { 35-50};ok
udplite checksum 6666 drop;ok
udplite checksum != { 444, 555} accept;ok
@@ -41,5 +36,3 @@ udplite checksum 33-45;ok
udplite checksum != 33-45;ok
udplite checksum { 33, 55, 67, 88};ok
udplite checksum != { 33, 55, 67, 88};ok
-udplite checksum { 33-55};ok
-udplite checksum != { 33-55};ok
diff --git a/tests/py/inet/udplite.t.json b/tests/py/inet/udplite.t.json
index f56bee47..713a534f 100644
--- a/tests/py/inet/udplite.t.json
+++ b/tests/py/inet/udplite.t.json
@@ -126,46 +126,6 @@
}
]
-# udplite sport { 12-40}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sport",
- "protocol": "udplite"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 12, 40 ] }
- ]
- }
- }
- }
-]
-
-# udplite sport != { 12-40}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "sport",
- "protocol": "udplite"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 12, 40 ] }
- ]
- }
- }
- }
-]
-
# udplite dport 80 accept
[
{
@@ -294,52 +254,6 @@
}
]
-# udplite dport { 70-75} accept
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "dport",
- "protocol": "udplite"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 70, 75 ] }
- ]
- }
- }
- },
- {
- "accept": null
- }
-]
-
-# udplite dport != { 70-75} accept
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "dport",
- "protocol": "udplite"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 70, 75 ] }
- ]
- }
- }
- },
- {
- "accept": null
- }
-]
-
# udplite checksum 6666 drop
[
{
@@ -497,43 +411,3 @@
}
]
-# udplite checksum { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "udplite"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# udplite checksum != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "udplite"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
diff --git a/tests/py/inet/udplite.t.payload b/tests/py/inet/udplite.t.payload
index eb3dc075..de9d09ed 100644
--- a/tests/py/inet/udplite.t.payload
+++ b/tests/py/inet/udplite.t.payload
@@ -53,26 +53,6 @@ inet test-inet input
[ lookup reg 1 set __set%d 0x1 ]
[ immediate reg 0 accept ]
-# udplite sport { 12-40}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000c00 : 0 [end] element 00002900 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000088 ]
- [ payload load 2b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# udplite sport != { 12-40}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000c00 : 0 [end] element 00002900 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000088 ]
- [ payload load 2b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# udplite dport 80 accept
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -128,28 +108,6 @@ inet test-inet input
[ lookup reg 1 set __set%d 0x1 ]
[ immediate reg 0 accept ]
-# udplite dport { 70-75} accept
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00004600 : 0 [end] element 00004c00 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000088 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
- [ immediate reg 0 accept ]
-
-# udplite dport != { 70-75} accept
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00004600 : 0 [end] element 00004c00 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000088 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
- [ immediate reg 0 accept ]
-
# udplite checksum 6666 drop
inet test-inet input
[ meta load l4proto => reg 1 ]
@@ -218,23 +176,3 @@ inet test-inet input
[ payload load 2b @ transport header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# udplite checksum { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000088 ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# udplite checksum != { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000088 ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
diff --git a/tests/py/inet/vmap.t b/tests/py/inet/vmap.t
new file mode 100644
index 00000000..0ac6e561
--- /dev/null
+++ b/tests/py/inet/vmap.t
@@ -0,0 +1,10 @@
+: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
+
+iifname . ip protocol . th dport vmap { "eth0" . tcp . 22 : accept, "eth1" . udp . 67 : drop };ok;iifname . ip protocol . th dport vmap { "eth0" . 6 . 22 : accept, "eth1" . 17 . 67 : drop }
+ip saddr . @ih,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e };ok
+udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept };ok
diff --git a/tests/py/inet/vmap.t.json b/tests/py/inet/vmap.t.json
new file mode 100644
index 00000000..37472cc6
--- /dev/null
+++ b/tests/py/inet/vmap.t.json
@@ -0,0 +1,144 @@
+# iifname . ip protocol . th dport vmap { "eth0" . tcp . 22 : accept, "eth1" . udp . 67 : drop }
+[
+ {
+ "vmap": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "eth0",
+ 6,
+ 22
+ ]
+ },
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "eth1",
+ 17,
+ 67
+ ]
+ },
+ {
+ "drop": null
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "th"
+ }
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr . @ih,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "base": "ih",
+ "len": 32,
+ "offset": 32
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.1.1.1",
+ 20
+ ]
+ },
+ {
+ "concat": [
+ "2.2.2.2",
+ 30
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }
+[
+ {
+ "vmap": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ {
+ "range": [
+ 47,
+ 63
+ ]
+ },
+ "0xe373135363130333131303735353203"
+ ]
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "length",
+ "protocol": "udp"
+ }
+ },
+ {
+ "payload": {
+ "base": "th",
+ "len": 128,
+ "offset": 160
+ }
+ }
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/vmap.t.payload b/tests/py/inet/vmap.t.payload
new file mode 100644
index 00000000..29ec846d
--- /dev/null
+++ b/tests/py/inet/vmap.t.payload
@@ -0,0 +1,34 @@
+# iifname . ip protocol . th dport vmap { "eth0" . tcp . 22 : accept, "eth1" . udp . 67 : drop }
+__map%d test-inet b size 2
+__map%d test-inet 0
+ element 30687465 00000000 00000000 00000000 00000006 00001600 : accept 0 [end] element 31687465 00000000 00000000 00000000 00000011 00004300 : drop 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load iifname => reg 1 ]
+ [ payload load 1b @ network header + 9 => reg 2 ]
+ [ payload load 2b @ transport header + 2 => reg 13 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip saddr . @ih,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }
+__set%d test-inet 3 size 2
+__set%d test-inet 0
+ element 01010101 14000000 : 0 [end] element 02020202 1e000000 : 0 [end]
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ inner header + 4 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }
+__map%d x 8f size 1
+__map%d x 0
+ element 00002f00 3531370e 33303136 37303131 03323535 - 00003f00 3531370e 33303136 37303131 03323535 : accept 0 [end]
+inet x y
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ payload load 16b @ transport header + 20 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
diff --git a/tests/py/inet/vmap.t.payload.netdev b/tests/py/inet/vmap.t.payload.netdev
new file mode 100644
index 00000000..3f51bb33
--- /dev/null
+++ b/tests/py/inet/vmap.t.payload.netdev
@@ -0,0 +1,34 @@
+# iifname . ip protocol . th dport vmap { "eth0" . tcp . 22 : accept, "eth1" . udp . 67 : drop }
+__map%d test-netdev b size 2
+__map%d test-netdev 0
+ element 30687465 00000000 00000000 00000000 00000006 00001600 : accept 0 [end] element 31687465 00000000 00000000 00000000 00000011 00004300 : drop 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load iifname => reg 1 ]
+ [ payload load 1b @ network header + 9 => reg 2 ]
+ [ payload load 2b @ transport header + 2 => reg 13 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip saddr . @ih,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }
+__set%d test-netdev 3 size 2
+__set%d test-netdev 0
+ element 01010101 14000000 : 0 [end] element 02020202 1e000000 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ inner header + 4 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }
+__map%d test-netdev 8f size 1
+__map%d test-netdev 0
+ element 00002f00 3531370e 33303136 37303131 03323535 - 00003f00 3531370e 33303136 37303131 03323535 : accept 0 [end]
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ payload load 16b @ transport header + 20 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
diff --git a/tests/py/inet/vxlan.t b/tests/py/inet/vxlan.t
new file mode 100644
index 00000000..10cdb7a4
--- /dev/null
+++ b/tests/py/inet/vxlan.t
@@ -0,0 +1,23 @@
+: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
+*netdev;test-netdev;ingress,egress
+
+vxlan vni 10;fail
+udp dport 4789 vxlan vni 10;ok
+udp dport 4789 vxlan ip saddr 10.141.11.2;ok
+udp dport 4789 vxlan ip saddr 10.141.11.0/24;ok
+udp dport 4789 vxlan ip protocol 1;ok
+udp dport 4789 vxlan udp sport 8888;ok
+udp dport 4789 vxlan icmp type echo-reply;ok
+udp dport 4789 vxlan ether saddr 62:87:4d:d6:19:05;ok
+udp dport 4789 vxlan vlan id 10;ok
+udp dport 4789 vxlan ip dscp 0x02;ok
+udp dport 4789 vxlan ip dscp 0x02;ok
+udp dport 4789 vxlan ip saddr . vxlan ip daddr { 1.2.3.4 . 4.3.2.1 };ok
+
+udp dport 4789 vxlan ip saddr set 1.2.3.4;fail
diff --git a/tests/py/inet/vxlan.t.json b/tests/py/inet/vxlan.t.json
new file mode 100644
index 00000000..91b3d294
--- /dev/null
+++ b/tests/py/inet/vxlan.t.json
@@ -0,0 +1,344 @@
+# udp dport 4789 vxlan vni 10
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "vni",
+ "protocol": "vxlan",
+ "tunnel": "vxlan"
+ }
+ },
+ "op": "==",
+ "right": 10
+ }
+ }
+]
+
+# udp dport 4789 vxlan ip saddr 10.141.11.2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip",
+ "tunnel": "vxlan"
+ }
+ },
+ "op": "==",
+ "right": "10.141.11.2"
+ }
+ }
+]
+
+# udp dport 4789 vxlan ip saddr 10.141.11.0/24
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip",
+ "tunnel": "vxlan"
+ }
+ },
+ "op": "==",
+ "right": {
+ "prefix": {
+ "addr": "10.141.11.0",
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# udp dport 4789 vxlan ip protocol 1
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "protocol",
+ "protocol": "ip",
+ "tunnel": "vxlan"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# udp dport 4789 vxlan udp sport 8888
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sport",
+ "protocol": "udp",
+ "tunnel": "vxlan"
+ }
+ },
+ "op": "==",
+ "right": 8888
+ }
+ }
+]
+
+# udp dport 4789 vxlan icmp type echo-reply
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmp",
+ "tunnel": "vxlan"
+ }
+ },
+ "op": "==",
+ "right": "echo-reply"
+ }
+ }
+]
+
+# udp dport 4789 vxlan ether saddr 62:87:4d:d6:19:05
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ether",
+ "tunnel": "vxlan"
+ }
+ },
+ "op": "==",
+ "right": "62:87:4d:d6:19:05"
+ }
+ }
+]
+
+# udp dport 4789 vxlan vlan id 10
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "vlan",
+ "tunnel": "vxlan"
+ }
+ },
+ "op": "==",
+ "right": 10
+ }
+ }
+]
+
+# udp dport 4789 vxlan ip dscp 0x02
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip",
+ "tunnel": "vxlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# udp dport 4789 vxlan ip dscp 0x02
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip",
+ "tunnel": "vxlan"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# udp dport 4789 vxlan ip saddr . vxlan ip daddr { 1.2.3.4 . 4.3.2.1 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip",
+ "tunnel": "vxlan"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip",
+ "tunnel": "vxlan"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.2.3.4",
+ "4.3.2.1"
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/vxlan.t.payload b/tests/py/inet/vxlan.t.payload
new file mode 100644
index 00000000..cde8e56f
--- /dev/null
+++ b/tests/py/inet/vxlan.t.payload
@@ -0,0 +1,114 @@
+# udp dport 4789 vxlan vni 10
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000b512 ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 3b @ unknown header + 4 => reg 1 ] ]
+ [ cmp eq reg 1 0x000a0000 ]
+
+# udp dport 4789 vxlan ip saddr 10.141.11.2
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000b512 ]
+ [ inner type 1 hdrsize 8 flags f [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 4b @ network header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x020b8d0a ]
+
+# udp dport 4789 vxlan ip saddr 10.141.11.0/24
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000b512 ]
+ [ inner type 1 hdrsize 8 flags f [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 3b @ network header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x000b8d0a ]
+
+# udp dport 4789 vxlan ip protocol 1
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000b512 ]
+ [ inner type 1 hdrsize 8 flags f [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 1b @ network header + 9 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# udp dport 4789 vxlan udp sport 8888
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000b512 ]
+ [ inner type 1 hdrsize 8 flags f [ meta load l4proto => reg 1 ] ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 2b @ transport header + 0 => reg 1 ] ]
+ [ cmp eq reg 1 0x0000b822 ]
+
+# udp dport 4789 vxlan icmp type echo-reply
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000b512 ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 2b @ link header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 1 hdrsize 8 flags f [ meta load l4proto => reg 1 ] ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 1b @ transport header + 0 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# udp dport 4789 vxlan ether saddr 62:87:4d:d6:19:05
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000b512 ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 6b @ link header + 6 => reg 1 ] ]
+ [ cmp eq reg 1 0xd64d8762 0x00000519 ]
+
+# udp dport 4789 vxlan vlan id 10
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000b512 ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 2b @ link header + 12 => reg 1 ] ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 2b @ link header + 14 => reg 1 ] ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000a00 ]
+
+# udp dport 4789 vxlan ip dscp 0x02
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000b512 ]
+ [ inner type 1 hdrsize 8 flags f [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 1b @ network header + 1 => reg 1 ] ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000008 ]
+
+# udp dport 4789 vxlan ip saddr . vxlan ip daddr { 1.2.3.4 . 4.3.2.1 }
+__set%d test-netdev 3 size 1
+__set%d test-netdev 0
+ element 04030201 01020304 : 0 [end]
+netdev test-netdev ingress
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x0000b512 ]
+ [ inner type 1 hdrsize 8 flags f [ meta load protocol => reg 1 ] ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 4b @ network header + 12 => reg 1 ] ]
+ [ inner type 1 hdrsize 8 flags f [ payload load 4b @ network header + 16 => reg 9 ] ]
+ [ lookup reg 1 set __set%d ]
+
diff --git a/tests/py/ip/ct.t b/tests/py/ip/ct.t
index d3247f79..a0a22289 100644
--- a/tests/py/ip/ct.t
+++ b/tests/py/ip/ct.t
@@ -21,3 +21,16 @@ ct original protocol 17 ct reply proto-src 53;ok;ct protocol 17 ct reply proto-s
# wrong address family
ct reply ip daddr dead::beef;fail
+
+meta mark set ct original daddr map { 1.1.1.1 : 0x00000011 };fail
+meta mark set ct original ip daddr map { 1.1.1.1 : 0x00000011 };ok
+meta mark set ct original saddr . meta mark map { 1.1.1.1 . 0x00000014 : 0x0000001e };fail
+meta mark set ct original ip saddr . meta mark map { 1.1.1.1 . 0x00000014 : 0x0000001e };ok
+ct original saddr . meta mark { 1.1.1.1 . 0x00000014 };fail
+ct original ip saddr . meta mark { 1.1.1.1 . 0x00000014 };ok
+ct mark set ip dscp << 2 | 0x10;ok
+ct mark set ip dscp << 26 | 0x10;ok
+ct mark set ip dscp & 0x0f << 1;ok;ct mark set ip dscp & af33
+ct mark set ip dscp & 0x0f << 2;ok;ct mark set ip dscp & 0x3c
+ct mark set ip dscp | 0x04;ok
+ct mark set ip dscp | 1 << 20;ok;ct mark set ip dscp | 0x100000
diff --git a/tests/py/ip/ct.t.json b/tests/py/ip/ct.t.json
index 881cd4c9..915632ae 100644
--- a/tests/py/ip/ct.t.json
+++ b/tests/py/ip/ct.t.json
@@ -216,3 +216,266 @@
}
]
+# meta mark set ct original ip daddr map { 1.1.1.1 : 0x00000011 }
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ 17
+ ]
+ ]
+ },
+ "key": {
+ "ct": {
+ "dir": "original",
+ "key": "ip daddr"
+ }
+ }
+ }
+ }
+ }
+ }
+]
+
+# meta mark set ct original ip saddr . meta mark map { 1.1.1.1 . 0x00000014 : 0x0000001e }
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "1.1.1.1",
+ 20
+ ]
+ },
+ 30
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "ct": {
+ "dir": "original",
+ "key": "ip saddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "mark"
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# ct original ip saddr . meta mark { 1.1.1.1 . 0x00000014 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "ct": {
+ "dir": "original",
+ "key": "ip saddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.1.1.1",
+ 20
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip dscp << 2 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip dscp << 26 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip dscp & 0x0f << 1
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "&": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ "af33"
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip dscp & 0x0f << 2
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "&": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 60
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip dscp | 0x04
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip dscp | 1 << 20
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 1048576
+ ]
+ }
+ }
+ }
+]
diff --git a/tests/py/ip/ct.t.payload b/tests/py/ip/ct.t.payload
index d5faed4c..692011d0 100644
--- a/tests/py/ip/ct.t.payload
+++ b/tests/py/ip/ct.t.payload
@@ -21,25 +21,21 @@ ip test-ip4 output
# ct original ip saddr 192.168.1.0/24
ip test-ip4 output
[ ct load src_ip => reg 1 , dir original ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0001a8c0 ]
# ct reply ip saddr 192.168.1.0/24
ip test-ip4 output
[ ct load src_ip => reg 1 , dir reply ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0001a8c0 ]
# ct original ip daddr 192.168.1.0/24
ip test-ip4 output
[ ct load dst_ip => reg 1 , dir original ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0001a8c0 ]
# ct reply ip daddr 192.168.1.0/24
ip test-ip4 output
[ ct load dst_ip => reg 1 , dir reply ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0001a8c0 ]
# ct l3proto ipv4
@@ -60,3 +56,81 @@ ip test-ip4 output
[ cmp eq reg 1 0x00000011 ]
[ ct load proto_src => reg 1 , dir reply ]
[ cmp eq reg 1 0x00003500 ]
+
+# meta mark set ct original ip daddr map { 1.1.1.1 : 0x00000011 }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 01010101 : 00000011 0 [end]
+ip
+ [ ct load dst_ip => reg 1 , dir original ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ct original ip saddr . meta mark map { 1.1.1.1 . 0x00000014 : 0x0000001e }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 01010101 00000014 : 0000001e 0 [end]
+ip
+ [ ct load src_ip => reg 1 , dir original ]
+ [ meta load mark => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# ct original ip saddr . meta mark { 1.1.1.1 . 0x00000014 }
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 01010101 00000014 : 0 [end]
+ip
+ [ ct load src_ip => reg 1 , dir original ]
+ [ meta load mark => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ct mark set ip dscp << 2 | 0x10
+ip test-ip4 output
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip dscp << 26 | 0x10
+ip
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x0000001a ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip dscp & 0x0f << 1
+ip test-ip4 output
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000001e ) ^ 0x00000000 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip dscp & 0x0f << 2
+ip test-ip4 output
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000003c ) ^ 0x00000000 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip dscp | 0x04
+ip test-ip4 output
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffb ) ^ 0x00000004 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip dscp | 1 << 20
+ip test-ip4 output
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffefffff ) ^ 0x00100000 ]
+ [ ct set mark with reg 1 ]
diff --git a/tests/py/ip/dnat.t b/tests/py/ip/dnat.t
index 089017c8..881571db 100644
--- a/tests/py/ip/dnat.t
+++ b/tests/py/ip/dnat.t
@@ -8,6 +8,16 @@ iifname "eth0" tcp dport {80, 90, 23} dnat to 192.168.3.2;ok
iifname "eth0" tcp dport != {80, 90, 23} dnat to 192.168.3.2;ok
iifname "eth0" tcp dport != 23-34 dnat to 192.168.3.2;ok
iifname "eth0" tcp dport 81 dnat to 192.168.3.2:8080;ok
+iifname "eth0" tcp dport 81 dnat to 192.168.3.2:8080-8999;ok
+iifname "eth0" tcp dport 81 dnat to 192.168.3.2-192.168.3.4:8080;ok
+iifname "eth0" tcp dport 81 dnat to 192.168.3.2-192.168.3.4:8080-8999;ok
dnat to ct mark map { 0x00000014 : 1.2.3.4};ok
dnat to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4};ok
+
+dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 8888 - 8999 };ok
+dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 80 };ok
+dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.2 . 8888 - 8999 };ok
+ip daddr 192.168.0.1 dnat ip to tcp dport map { 443 : 10.141.10.4 . 8443, 80 : 10.141.10.4 . 8080 };ok
+meta l4proto 6 dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69 . 22, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 };ok
+dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69/32, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 };ok
diff --git a/tests/py/ip/dnat.t.json b/tests/py/ip/dnat.t.json
index 0481a368..fe15d072 100644
--- a/tests/py/ip/dnat.t.json
+++ b/tests/py/ip/dnat.t.json
@@ -262,3 +262,482 @@
}
]
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2:8080-8999
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 81
+ }
+ },
+ {
+ "dnat": {
+ "addr": "192.168.3.2",
+ "port": {
+ "range": [
+ 8080,
+ 8999
+ ]
+ }
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2-192.168.3.4:8080-8999
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 81
+ }
+ },
+ {
+ "dnat": {
+ "addr": {
+ "range": [
+ "192.168.3.2",
+ "192.168.3.4"
+ ]
+ },
+ "port": {
+ "range": [
+ 8080,
+ 8999
+ ]
+ }
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2-192.168.3.4:8080
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": 81
+ }
+ },
+ {
+ "dnat": {
+ "addr": {
+ "range": [
+ "192.168.3.2",
+ "192.168.3.4"
+ ]
+ },
+ "port": 8080
+ }
+ }
+]
+
+# dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.2 . 8888 - 8999 }
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "192.168.1.2",
+ 80
+ ]
+ },
+ {
+ "concat": [
+ "10.141.10.2",
+ {
+ "range": [
+ 8888,
+ 8999
+ ]
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 8888 - 8999 }
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "192.168.1.2",
+ 80
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "10.141.10.0",
+ "len": 24
+ }
+ },
+ {
+ "range": [
+ 8888,
+ 8999
+ ]
+ }
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 80 }
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "192.168.1.2",
+ 80
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "10.141.10.0",
+ "len": 24
+ }
+ },
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# ip daddr 192.168.0.1 dnat ip to tcp dport map { 443 : 10.141.10.4 . 8443, 80 : 10.141.10.4 . 8080 }
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "192.168.0.1"
+ }
+ },
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ 80,
+ {
+ "concat": [
+ "10.141.10.4",
+ 8080
+ ]
+ }
+ ],
+ [
+ 443,
+ {
+ "concat": [
+ "10.141.10.4",
+ 8443
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# meta l4proto 6 dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69 . 22, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "enp2s0",
+ "10.1.1.136"
+ ]
+ },
+ {
+ "concat": [
+ "1.1.2.69",
+ 22
+ ]
+ }
+ ],
+ [
+ {
+ "concat": [
+ "enp2s0",
+ {
+ "range": [
+ "10.1.1.1",
+ "10.1.1.135"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "range": [
+ "1.1.2.66",
+ "1.84.236.78"
+ ]
+ },
+ 22
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69/32, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 }
+[
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "enp2s0",
+ "10.1.1.136"
+ ]
+ },
+ {
+ "prefix": {
+ "addr": "1.1.2.69",
+ "len": 32
+ }
+ }
+ ],
+ [
+ {
+ "concat": [
+ "enp2s0",
+ {
+ "range": [
+ "10.1.1.1",
+ "10.1.1.135"
+ ]
+ }
+ ]
+ },
+ {
+ "range": [
+ "1.1.2.66",
+ "1.84.236.78"
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
diff --git a/tests/py/ip/dnat.t.payload.ip b/tests/py/ip/dnat.t.payload.ip
index 1b869d0a..439c6abe 100644
--- a/tests/py/ip/dnat.t.payload.ip
+++ b/tests/py/ip/dnat.t.payload.ip
@@ -8,7 +8,7 @@ ip test-ip4 prerouting
[ cmp gte reg 1 0x00005000 ]
[ cmp lte reg 1 0x00005a00 ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
# iifname "eth0" tcp dport != 80-90 dnat to 192.168.3.2
ip test-ip4 prerouting
@@ -19,7 +19,7 @@ ip test-ip4 prerouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ range neq reg 1 0x00005000 0x00005a00 ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
# iifname "eth0" tcp dport {80, 90, 23} dnat to 192.168.3.2
__set%d test-ip4 3
@@ -33,7 +33,7 @@ ip test-ip4 prerouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
# iifname "eth0" tcp dport != {80, 90, 23} dnat to 192.168.3.2
__set%d test-ip4 3
@@ -47,7 +47,7 @@ ip test-ip4 prerouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
# iifname "eth0" tcp dport != 23-34 dnat to 192.168.3.2
ip test-ip4 prerouting
@@ -58,7 +58,7 @@ ip test-ip4 prerouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ range neq reg 1 0x00001700 0x00002200 ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
# iifname "eth0" tcp dport 81 dnat to 192.168.3.2:8080
ip test-ip4 prerouting
@@ -70,7 +70,7 @@ ip test-ip4 prerouting
[ cmp eq reg 1 0x00005100 ]
[ immediate reg 1 0x0203a8c0 ]
[ immediate reg 2 0x0000901f ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 proto_min reg 2 flags 0x2 ]
# dnat to ct mark map { 0x00000014 : 1.2.3.4}
__map%d test-ip4 b
@@ -79,7 +79,7 @@ __map%d test-ip4 0
ip test-ip4 prerouting
[ ct load mark => reg 1 ]
[ lookup reg 1 set __map%d dreg 1 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
# dnat to ct mark . ip daddr map { 0x00000014 . 1.1.1.1 : 1.2.3.4}
__map%d test-ip4 b
@@ -89,5 +89,116 @@ ip test-ip4 output
[ ct load mark => reg 1 ]
[ payload load 4b @ network header + 16 => reg 9 ]
[ lookup reg 1 set __map%d dreg 1 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 8888 - 8999 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 0201a8c0 00005000 : 000a8d0a 0000b822 ff0a8d0a 00002723 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 10 proto_min reg 9 proto_max reg 11 ]
+
+# dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 80 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 0201a8c0 00005000 : 000a8d0a 00005000 ff0a8d0a 00005000 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 10 proto_min reg 9 proto_max reg 11 ]
+
+# dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.2 . 8888 - 8999 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 0201a8c0 00005000 : 020a8d0a 0000b822 020a8d0a 00002723 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 10 proto_min reg 9 proto_max reg 11 ]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2:8080-8999
+ip
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005100 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ immediate reg 2 0x0000901f ]
+ [ immediate reg 3 0x00002723 ]
+ [ nat dnat ip addr_min reg 1 proto_min reg 2 proto_max reg 3 flags 0x2 ]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2-192.168.3.4:8080
+ip
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005100 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ immediate reg 2 0x0403a8c0 ]
+ [ immediate reg 3 0x0000901f ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 2 proto_min reg 3 flags 0x2 ]
+
+# iifname "eth0" tcp dport 81 dnat to 192.168.3.2-192.168.3.4:8080-8999
+ip
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00005100 ]
+ [ immediate reg 1 0x0203a8c0 ]
+ [ immediate reg 2 0x0403a8c0 ]
+ [ immediate reg 3 0x0000901f ]
+ [ immediate reg 4 0x00002723 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 4 flags 0x2 ]
+
+# ip daddr 192.168.0.1 dnat ip to tcp dport map { 443 : 10.141.10.4 . 8443, 80 : 10.141.10.4 . 8080 }
+__map%d test-ip4 b size 2
+__map%d test-ip4 0
+ element 0000bb01 : 040a8d0a 0000fb20 0 [end] element 00005000 : 040a8d0a 0000901f 0 [end]
+ip
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 proto_min reg 9 ]
+
+# meta l4proto 6 dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69 . 22, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 }
+__map%d test-ip4 8f size 2
+__map%d test-ip4 0
+ element 32706e65 00003073 00000000 00000000 8801010a - 32706e65 00003073 00000000 00000000 8801010a : 45020101 00001600 45020101 00001600 0 [end] element 32706e65 00003073 00000000 00000000 0101010a - 32706e65 00003073 00000000 00000000 8701010a : 42020101 00001600 4eec5401 00001600 0 [end]
+ip test-ip4 prerouting
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ meta load iifname => reg 1 ]
+ [ payload load 4b @ network header + 12 => reg 2 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 10 proto_min reg 9 proto_max reg 11 ]
+
+# dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69/32, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 }
+__map%d test-ip4 8f size 2
+__map%d test-ip4 0
+ element 32706e65 00003073 00000000 00000000 8801010a - 32706e65 00003073 00000000 00000000 8801010a : 45020101 45020101 0 [end] element 32706e65 00003073 00000000 00000000 0101010a - 32706e65 00003073 00000000 00000000 8701010a : 42020101 4eec5401 0 [end]
+ip test-ip4 prerouting
+ [ meta load iifname => reg 1 ]
+ [ payload load 4b @ network header + 12 => reg 2 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 9 ]
diff --git a/tests/py/ip/flowtable.t b/tests/py/ip/flowtable.t
deleted file mode 100644
index 086c6cf6..00000000
--- a/tests/py/ip/flowtable.t
+++ /dev/null
@@ -1,5 +0,0 @@
-:input;type filter hook input priority 0
-
-*ip;test-ip;input
-
-meter xyz size 8192 { ip saddr timeout 30s counter};ok
diff --git a/tests/py/ip/flowtable.t.json b/tests/py/ip/flowtable.t.json
deleted file mode 100644
index a03cc9d7..00000000
--- a/tests/py/ip/flowtable.t.json
+++ /dev/null
@@ -1,24 +0,0 @@
-# meter xyz size 8192 { ip saddr timeout 30s counter}
-[
- {
- "meter": {
- "key": {
- "elem": {
- "timeout": 30,
- "val": {
- "payload": {
- "field": "saddr",
- "protocol": "ip"
- }
- }
- }
- },
- "name": "xyz",
- "size": 8192,
- "stmt": {
- "counter": null
- }
- }
- }
-]
-
diff --git a/tests/py/ip/flowtable.t.payload b/tests/py/ip/flowtable.t.payload
deleted file mode 100644
index c0aad39e..00000000
--- a/tests/py/ip/flowtable.t.payload
+++ /dev/null
@@ -1,7 +0,0 @@
-# meter xyz size 8192 { ip saddr timeout 30s counter}
-xyz test-ip 31
-xyz test-ip 0
-ip test-ip input
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ dynset update reg_key 1 set xyz timeout 30000ms expr [ counter pkts 0 bytes 0 ] ]
-
diff --git a/tests/py/ip/hash.t.payload b/tests/py/ip/hash.t.payload
index 71ab0652..fefe492d 100644
--- a/tests/py/ip/hash.t.payload
+++ b/tests/py/ip/hash.t.payload
@@ -41,7 +41,7 @@ ip test-ip4 pre
[ payload load 4b @ network header + 12 => reg 2 ]
[ hash reg 1 = jhash(reg 2, 4, 0xdeadbeef) % mod 2 ]
[ lookup reg 1 set __map%d dreg 1 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
# ct mark set symhash mod 2 offset 100
ip test-ip4 pre
diff --git a/tests/py/ip/icmp.t b/tests/py/ip/icmp.t
index 6c05fb9d..226c339b 100644
--- a/tests/py/ip/icmp.t
+++ b/tests/py/ip/icmp.t
@@ -26,51 +26,43 @@ icmp code 111 accept;ok
icmp code != 111 accept;ok
icmp code 33-55;ok
icmp code != 33-55;ok
-icmp code { 33-55};ok
-icmp code != { 33-55};ok
-icmp code { 2, 4, 54, 33, 56};ok;icmp code { prot-unreachable, 4, 33, 54, 56}
-icmp code != { prot-unreachable, 4, 33, 54, 56};ok
+icmp code { 2, 4, 54, 33, 56};ok
+icmp code != { prot-unreachable, frag-needed, 33, 54, 56};ok;icmp code != { 2, 4, 33, 54, 56}
icmp checksum 12343 accept;ok
icmp checksum != 12343 accept;ok
icmp checksum 11-343 accept;ok
icmp checksum != 11-343 accept;ok
-icmp checksum { 11-343} accept;ok
-icmp checksum != { 11-343} accept;ok
icmp checksum { 1111, 222, 343} accept;ok
icmp checksum != { 1111, 222, 343} accept;ok
-icmp id 1245 log;ok
-icmp id 22;ok
-icmp id != 233;ok
-icmp id 33-45;ok
-icmp id != 33-45;ok
-icmp id { 33-55};ok
-icmp id != { 33-55};ok
-icmp id { 22, 34, 333};ok
-icmp id != { 22, 34, 333};ok
+icmp id 1245 log;ok;icmp type { echo-reply, echo-request} icmp id 1245 log
+icmp id 22;ok;icmp type { echo-reply, echo-request} icmp id 22
+icmp id != 233;ok;icmp type { echo-reply, echo-request} icmp id != 233
+icmp id 33-45;ok;icmp type { echo-reply, echo-request} icmp id 33-45
+icmp id != 33-45;ok;icmp type { echo-reply, echo-request} icmp id != 33-45
-icmp sequence 22;ok
-icmp sequence != 233;ok
-icmp sequence 33-45;ok
-icmp sequence != 33-45;ok
-icmp sequence { 33, 55, 67, 88};ok
-icmp sequence != { 33, 55, 67, 88};ok
-icmp sequence { 33-55};ok
-icmp sequence != { 33-55};ok
+icmp id { 22, 34, 333};ok;icmp type { echo-request, echo-reply} icmp id { 22, 34, 333}
+icmp id != { 22, 34, 333};ok;icmp type { echo-request, echo-reply} icmp id != { 22, 34, 333}
+
+icmp sequence 22;ok;icmp type { echo-reply, echo-request} icmp sequence 22
+icmp sequence != 233;ok;icmp type { echo-reply, echo-request} icmp sequence != 233
+icmp sequence 33-45;ok;icmp type { echo-reply, echo-request} icmp sequence 33-45
+icmp sequence != 33-45;ok;icmp type { echo-reply, echo-request} icmp sequence != 33-45
+icmp sequence { 33, 55, 67, 88};ok;icmp type { echo-request, echo-reply} icmp sequence { 33, 55, 67, 88}
+icmp sequence != { 33, 55, 67, 88};ok;icmp type { echo-request, echo-reply} icmp sequence != { 33, 55, 67, 88}
+icmp id 1 icmp sequence 2;ok;icmp type { echo-reply, echo-request} icmp id 1 icmp sequence 2
+icmp type { echo-reply, echo-request} icmp id 1 icmp sequence 2;ok
+icmp type echo-reply icmp id 1;ok
icmp mtu 33;ok
icmp mtu 22-33;ok
-icmp mtu { 22-33};ok
-icmp mtu != { 22-33};ok
icmp mtu 22;ok
icmp mtu != 233;ok
icmp mtu 33-45;ok
icmp mtu != 33-45;ok
icmp mtu { 33, 55, 67, 88};ok
icmp mtu != { 33, 55, 67, 88};ok
-icmp mtu { 33-55};ok
-icmp mtu != { 33-55};ok
icmp gateway 22;ok
icmp gateway != 233;ok
@@ -78,7 +70,8 @@ icmp gateway 33-45;ok
icmp gateway != 33-45;ok
icmp gateway { 33, 55, 67, 88};ok
icmp gateway != { 33, 55, 67, 88};ok
-icmp gateway { 33-55};ok
-icmp gateway != { 33-55};ok
icmp gateway != 34;ok
icmp gateway != { 333, 334};ok
+
+icmp code 1 icmp type 2;ok;icmp type 2 icmp code 1
+icmp code != 1 icmp type 2 icmp mtu 5;fail
diff --git a/tests/py/ip/icmp.t.json b/tests/py/ip/icmp.t.json
index 4e172745..45e04c78 100644
--- a/tests/py/ip/icmp.t.json
+++ b/tests/py/ip/icmp.t.json
@@ -8,7 +8,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "echo-reply"
}
},
@@ -27,7 +27,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "destination-unreachable"
}
},
@@ -46,7 +46,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "source-quench"
}
},
@@ -65,7 +65,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "redirect"
}
},
@@ -84,7 +84,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "echo-request"
}
},
@@ -103,7 +103,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "time-exceeded"
}
},
@@ -122,7 +122,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "parameter-problem"
}
},
@@ -141,7 +141,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "timestamp-request"
}
},
@@ -160,7 +160,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "timestamp-reply"
}
},
@@ -179,7 +179,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "info-request"
}
},
@@ -198,7 +198,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "info-reply"
}
},
@@ -217,7 +217,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "address-mask-request"
}
},
@@ -236,7 +236,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "address-mask-reply"
}
},
@@ -255,7 +255,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "router-advertisement"
}
},
@@ -274,7 +274,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": "router-solicitation"
}
},
@@ -293,7 +293,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
"echo-reply",
@@ -301,6 +301,8 @@
"source-quench",
"redirect",
"echo-request",
+ "router-advertisement",
+ "router-solicitation",
"time-exceeded",
"parameter-problem",
"timestamp-request",
@@ -308,9 +310,7 @@
"info-request",
"info-reply",
"address-mask-request",
- "address-mask-reply",
- "router-advertisement",
- "router-solicitation"
+ "address-mask-reply"
]
}
}
@@ -352,7 +352,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": 111
}
},
@@ -390,53 +390,18 @@
"protocol": "icmp"
}
},
- "op": "==",
- "right": {
- "range": [ 33, 55 ]
- }
- }
- }
-]
-
-# icmp code != 33-55
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "code",
- "protocol": "icmp"
- }
- },
- "op": "!=",
- "right": {
- "range": [ 33, 55 ]
- }
- }
- }
-]
-
-# icmp code { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "code",
- "protocol": "icmp"
- }
- },
- "op": "==",
+ "op": "==",
"right": {
- "set": [
- { "range": [ 33, 55 ] }
+ "range": [
+ 33,
+ 55
]
}
}
}
]
-# icmp code != { 33-55}
+# icmp code != 33-55
[
{
"match": {
@@ -448,8 +413,9 @@
},
"op": "!=",
"right": {
- "set": [
- { "range": [ 33, 55 ] }
+ "range": [
+ 33,
+ 55
]
}
}
@@ -466,7 +432,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
2,
@@ -480,7 +446,7 @@
}
]
-# icmp code != { prot-unreachable, 4, 33, 54, 56}
+# icmp code != { prot-unreachable, frag-needed, 33, 54, 56}
[
{
"match": {
@@ -493,7 +459,7 @@
"op": "!=",
"right": {
"set": [
- "prot-unreachable",
+ 2,
4,
33,
54,
@@ -514,7 +480,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": 12343
}
},
@@ -552,52 +518,11 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
- "range": [ 11, 343 ]
- }
- }
- },
- {
- "accept": null
- }
-]
-
-# icmp checksum != 11-343 accept
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "icmp"
- }
- },
- "op": "!=",
- "right": {
- "range": [ 11, 343 ]
- }
- }
- },
- {
- "accept": null
- }
-]
-
-# icmp checksum { 11-343} accept
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "icmp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 11, 343 ] }
+ "range": [
+ 11,
+ 343
]
}
}
@@ -607,7 +532,7 @@
}
]
-# icmp checksum != { 11-343} accept
+# icmp checksum != 11-343 accept
[
{
"match": {
@@ -619,8 +544,9 @@
},
"op": "!=",
"right": {
- "set": [
- { "range": [ 11, 343 ] }
+ "range": [
+ 11,
+ 343
]
}
}
@@ -640,12 +566,12 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
- 1111,
222,
- 343
+ 343,
+ 1111
]
}
}
@@ -668,9 +594,9 @@
"op": "!=",
"right": {
"set": [
- 1111,
222,
- 343
+ 343,
+ 1111
]
}
}
@@ -690,7 +616,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": 1245
}
},
@@ -709,7 +635,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": 22
}
}
@@ -737,20 +663,19 @@
"match": {
"left": {
"payload": {
- "field": "id",
+ "field": "type",
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
- "range": [ 33, 45 ]
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
}
}
- }
-]
-
-# icmp id != 33-45
-[
+ },
{
"match": {
"left": {
@@ -759,36 +684,36 @@
"protocol": "icmp"
}
},
- "op": "!=",
+ "op": "==",
"right": {
- "range": [ 33, 45 ]
+ "range": [
+ 33,
+ 45
+ ]
}
}
}
]
-# icmp id { 33-55}
+# icmp id != 33-45
[
{
"match": {
"left": {
"payload": {
- "field": "id",
+ "field": "type",
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
- { "range": [ 33, 55 ] }
+ "echo-reply",
+ "echo-request"
]
}
}
- }
-]
-
-# icmp id != { 33-55}
-[
+ },
{
"match": {
"left": {
@@ -799,8 +724,9 @@
},
"op": "!=",
"right": {
- "set": [
- { "range": [ 33, 55 ] }
+ "range": [
+ 33,
+ 45
]
}
}
@@ -813,11 +739,28 @@
"match": {
"left": {
"payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
"field": "id",
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
22,
@@ -835,6 +778,23 @@
"match": {
"left": {
"payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
"field": "id",
"protocol": "icmp"
}
@@ -857,11 +817,28 @@
"match": {
"left": {
"payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
"field": "sequence",
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": 22
}
}
@@ -873,6 +850,23 @@
"match": {
"left": {
"payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
"field": "sequence",
"protocol": "icmp"
}
@@ -889,13 +883,33 @@
"match": {
"left": {
"payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
"field": "sequence",
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
- "range": [ 33, 45 ]
+ "range": [
+ 33,
+ 45
+ ]
}
}
}
@@ -907,13 +921,33 @@
"match": {
"left": {
"payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
"field": "sequence",
"protocol": "icmp"
}
},
"op": "!=",
"right": {
- "range": [ 33, 45 ]
+ "range": [
+ 33,
+ 45
+ ]
}
}
}
@@ -925,11 +959,28 @@
"match": {
"left": {
"payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
"field": "sequence",
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
33,
@@ -948,6 +999,23 @@
"match": {
"left": {
"payload": {
+ "field": "type",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
"field": "sequence",
"protocol": "icmp"
}
@@ -965,121 +1033,125 @@
}
]
-# icmp sequence { 33-55}
+# icmp id 1 icmp sequence 2
[
{
"match": {
"left": {
"payload": {
- "field": "sequence",
+ "field": "type",
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
- { "range": [ 33, 55 ] }
+ "echo-reply",
+ "echo-request"
]
}
}
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
}
]
-# icmp sequence != { 33-55}
+# icmp type { echo-reply, echo-request} icmp id 1 icmp sequence 2
[
{
"match": {
"left": {
"payload": {
- "field": "sequence",
+ "field": "type",
"protocol": "icmp"
}
},
- "op": "!=",
+ "op": "==",
"right": {
"set": [
- { "range": [ 33, 55 ] }
+ "echo-reply",
+ "echo-request"
]
}
}
- }
-]
-
-# icmp mtu 33
-[
+ },
{
"match": {
"left": {
"payload": {
- "field": "mtu",
+ "field": "id",
"protocol": "icmp"
}
},
- "op": "==",
- "right": 33
+ "op": "==",
+ "right": 1
}
- }
-]
-
-# icmp mtu 22-33
-[
+ },
{
"match": {
"left": {
"payload": {
- "field": "mtu",
+ "field": "sequence",
"protocol": "icmp"
}
},
- "op": "==",
- "right": {
- "range": [ 22, 33 ]
- }
+ "op": "==",
+ "right": 2
}
}
]
-# icmp mtu { 22-33}
+# icmp type echo-reply icmp id 1
[
{
"match": {
"left": {
"payload": {
- "field": "mtu",
+ "field": "type",
"protocol": "icmp"
}
},
- "op": "==",
- "right": {
- "set": [
- { "range": [ 22, 33 ] }
- ]
- }
+ "op": "==",
+ "right": "echo-reply"
}
- }
-]
-
-# icmp mtu != { 22-33}
-[
+ },
{
"match": {
"left": {
"payload": {
- "field": "mtu",
+ "field": "id",
"protocol": "icmp"
}
},
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 22, 33 ] }
- ]
- }
+ "op": "==",
+ "right": 1
}
}
]
-# icmp mtu 22
+# icmp mtu 33
[
{
"match": {
@@ -1089,13 +1161,13 @@
"protocol": "icmp"
}
},
- "op": "==",
- "right": 22
+ "op": "==",
+ "right": 33
}
}
]
-# icmp mtu != 233
+# icmp mtu 22-33
[
{
"match": {
@@ -1105,13 +1177,18 @@
"protocol": "icmp"
}
},
- "op": "!=",
- "right": 233
+ "op": "==",
+ "right": {
+ "range": [
+ 22,
+ 33
+ ]
+ }
}
}
]
-# icmp mtu 33-45
+# icmp mtu 22
[
{
"match": {
@@ -1121,15 +1198,13 @@
"protocol": "icmp"
}
},
- "op": "==",
- "right": {
- "range": [ 33, 45 ]
- }
+ "op": "==",
+ "right": 22
}
}
]
-# icmp mtu != 33-45
+# icmp mtu != 233
[
{
"match": {
@@ -1140,14 +1215,12 @@
}
},
"op": "!=",
- "right": {
- "range": [ 33, 45 ]
- }
+ "right": 233
}
}
]
-# icmp mtu { 33, 55, 67, 88}
+# icmp mtu 33-45
[
{
"match": {
@@ -1157,20 +1230,18 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
- "set": [
+ "range": [
33,
- 55,
- 67,
- 88
+ 45
]
}
}
}
]
-# icmp mtu != { 33, 55, 67, 88}
+# icmp mtu != 33-45
[
{
"match": {
@@ -1182,18 +1253,16 @@
},
"op": "!=",
"right": {
- "set": [
+ "range": [
33,
- 55,
- 67,
- 88
+ 45
]
}
}
}
]
-# icmp mtu { 33-55}
+# icmp mtu { 33, 55, 67, 88}
[
{
"match": {
@@ -1203,17 +1272,20 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
- { "range": [ 33, 55 ] }
+ 33,
+ 55,
+ 67,
+ 88
]
}
}
}
]
-# icmp mtu != { 33-55}
+# icmp mtu != { 33, 55, 67, 88}
[
{
"match": {
@@ -1226,7 +1298,10 @@
"op": "!=",
"right": {
"set": [
- { "range": [ 33, 55 ] }
+ 33,
+ 55,
+ 67,
+ 88
]
}
}
@@ -1243,7 +1318,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": 22
}
}
@@ -1275,9 +1350,12 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
- "range": [ 33, 45 ]
+ "range": [
+ 33,
+ 45
+ ]
}
}
}
@@ -1295,7 +1373,10 @@
},
"op": "!=",
"right": {
- "range": [ 33, 45 ]
+ "range": [
+ 33,
+ 45
+ ]
}
}
}
@@ -1311,7 +1392,7 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
33,
@@ -1347,7 +1428,7 @@
}
]
-# icmp gateway { 33-55}
+# icmp gateway != 34
[
{
"match": {
@@ -1357,17 +1438,13 @@
"protocol": "icmp"
}
},
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
+ "op": "!=",
+ "right": 34
}
}
]
-# icmp gateway != { 33-55}
+# icmp gateway != { 333, 334}
[
{
"match": {
@@ -1380,47 +1457,38 @@
"op": "!=",
"right": {
"set": [
- { "range": [ 33, 55 ] }
+ 333,
+ 334
]
}
}
}
]
-# icmp gateway != 34
+# icmp code 1 icmp type 2
[
{
"match": {
"left": {
"payload": {
- "field": "gateway",
+ "field": "type",
"protocol": "icmp"
}
},
- "op": "!=",
- "right": 34
+ "op": "==",
+ "right": 2
}
- }
-]
-
-# icmp gateway != { 333, 334}
-[
+ },
{
"match": {
"left": {
"payload": {
- "field": "gateway",
+ "field": "code",
"protocol": "icmp"
}
},
- "op": "!=",
- "right": {
- "set": [
- 333,
- 334
- ]
- }
+ "op": "==",
+ "right": 1
}
}
]
-
diff --git a/tests/py/ip/icmp.t.json.output b/tests/py/ip/icmp.t.json.output
index e8045bb8..52fd6016 100644
--- a/tests/py/ip/icmp.t.json.output
+++ b/tests/py/ip/icmp.t.json.output
@@ -1,4 +1,28 @@
-# icmp type {echo-reply, destination-unreachable, source-quench, redirect, echo-request, time-exceeded, parameter-problem, timestamp-request, timestamp-reply, info-request, info-reply, address-mask-request, address-mask-reply, router-advertisement, router-solicitation} accept
+# icmp code { 2, 4, 54, 33, 56}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 2,
+ 4,
+ 33,
+ 54,
+ 56
+ ]
+ }
+ }
+ }
+]
+
+# icmp id 1245 log
[
{
"match": {
@@ -8,104 +32,138 @@
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
"echo-reply",
- "destination-unreachable",
- "source-quench",
- "redirect",
- "echo-request",
- "router-advertisement",
- "router-solicitation",
- "time-exceeded",
- "parameter-problem",
- "timestamp-request",
- "timestamp-reply",
- "info-request",
- "info-reply",
- "address-mask-request",
- "address-mask-reply"
+ "echo-request"
]
}
}
},
{
- "accept": null
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 1245
+ }
+ },
+ {
+ "log": null
}
]
-# icmp code { 2, 4, 54, 33, 56}
+# icmp id 22
[
{
"match": {
"left": {
"payload": {
- "field": "code",
+ "field": "type",
"protocol": "icmp"
}
},
"op": "==",
"right": {
"set": [
- "prot-unreachable",
- 4,
- 33,
- 54,
- 56
+ "echo-reply",
+ "echo-request"
]
}
}
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": 22
+ }
}
]
-# icmp checksum { 1111, 222, 343} accept
+# icmp id != 233
[
{
"match": {
"left": {
"payload": {
- "field": "checksum",
+ "field": "type",
"protocol": "icmp"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
- 222,
- 343,
- 1111
+ "echo-reply",
+ "echo-request"
]
}
}
},
{
- "accept": null
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "!=",
+ "right": 233
+ }
}
]
-# icmp checksum != { 1111, 222, 343} accept
+# icmp id { 33-55}
[
{
"match": {
"left": {
"payload": {
- "field": "checksum",
+ "field": "type",
"protocol": "icmp"
}
},
- "op": "!=",
+ "op": "==",
"right": {
"set": [
- 222,
- 343,
- 1111
+ "echo-reply",
+ "echo-request"
]
}
}
},
{
- "accept": null
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "range": [
+ 33,
+ 55
+ ]
+ }
+ ]
+ }
+ }
}
]
+
diff --git a/tests/py/ip/icmp.t.payload.ip b/tests/py/ip/icmp.t.payload.ip
index 27f22207..3bc6de3c 100644
--- a/tests/py/ip/icmp.t.payload.ip
+++ b/tests/py/ip/icmp.t.payload.ip
@@ -102,17 +102,6 @@ ip test-ip4 input
[ cmp eq reg 1 0x00000012 ]
[ immediate reg 0 accept ]
-# icmp type {echo-reply, destination-unreachable, source-quench, redirect, echo-request, time-exceeded, parameter-problem, timestamp-request, timestamp-reply, info-request, info-reply, address-mask-request, address-mask-reply} accept
-__set%d test-ip4 3
-__set%d test-ip4 0
- element 00000000 : 0 [end] element 00000003 : 0 [end] element 00000004 : 0 [end] element 00000005 : 0 [end] element 00000008 : 0 [end] element 0000000b : 0 [end] element 0000000c : 0 [end] element 0000000d : 0 [end] element 0000000e : 0 [end] element 0000000f : 0 [end] element 00000010 : 0 [end] element 00000011 : 0 [end] element 00000012 : 0 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
- [ immediate reg 0 accept ]
-
# icmp type != {echo-reply, destination-unreachable, source-quench}
__set%d test-ip4 3
__set%d test-ip4 0
@@ -154,26 +143,6 @@ ip test-ip4 input
[ payload load 1b @ transport header + 1 => reg 1 ]
[ range neq reg 1 0x00000021 0x00000037 ]
-# icmp code { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
- [ payload load 1b @ transport header + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# icmp code != { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
- [ payload load 1b @ transport header + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# icmp code { 2, 4, 54, 33, 56}
__set%d test-ip4 3
__set%d test-ip4 0
@@ -184,7 +153,7 @@ ip test-ip4 input
[ payload load 1b @ transport header + 1 => reg 1 ]
[ lookup reg 1 set __set%d ]
-# icmp code != { prot-unreachable, 4, 33, 54, 56}
+# icmp code != { prot-unreachable, frag-needed, 33, 54, 56}
__set%d test-ip4 3
__set%d test-ip4 0
element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000036 : 0 [end] element 00000021 : 0 [end] element 00000038 : 0 [end]
@@ -227,28 +196,6 @@ ip test-ip4 input
[ range neq reg 1 0x00000b00 0x00005701 ]
[ immediate reg 0 accept ]
-# icmp checksum { 11-343} accept
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
- [ immediate reg 0 accept ]
-
-# icmp checksum != { 11-343} accept
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
- [ immediate reg 0 accept ]
-
# icmp checksum { 1111, 222, 343} accept
__set%d test-ip4 3
__set%d test-ip4 0
@@ -272,155 +219,215 @@ ip test-ip4 input
[ immediate reg 0 accept ]
# icmp id 1245 log
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ cmp eq reg 1 0x0000dd04 ]
[ log ]
# icmp id 22
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ cmp eq reg 1 0x00001600 ]
# icmp id != 233
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ cmp neq reg 1 0x0000e900 ]
# icmp id 33-45
+__set%d test-ip4 3
+__set%d test-ip4 input
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ cmp gte reg 1 0x00002100 ]
[ cmp lte reg 1 0x00002d00 ]
# icmp id != 33-45
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
- [ payload load 2b @ transport header + 4 => reg 1 ]
- [ range neq reg 1 0x00002100 0x00002d00 ]
-
-# icmp id { 33-55}
-__set%d test-ip4 7
+__set%d test-ip4 3
__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
- [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
[ lookup reg 1 set __set%d ]
-
-# icmp id != { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+ [ range neq reg 1 0x00002100 0x00002d00 ]
# icmp id { 22, 34, 333}
__set%d test-ip4 3
__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+__set%d test-ip4 3
+__set%d test-ip4 0
element 00001600 : 0 [end] element 00002200 : 0 [end] element 00004d01 : 0 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d ]
# icmp id != { 22, 34, 333}
__set%d test-ip4 3
__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+__set%d test-ip4 3
+__set%d test-ip4 0
element 00001600 : 0 [end] element 00002200 : 0 [end] element 00004d01 : 0 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
# icmp sequence 22
-ip test-ip4 input
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+ip
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ cmp eq reg 1 0x00001600 ]
# icmp sequence != 233
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ cmp neq reg 1 0x0000e900 ]
# icmp sequence 33-45
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ cmp gte reg 1 0x00002100 ]
[ cmp lte reg 1 0x00002d00 ]
# icmp sequence != 33-45
+__set%d test-ip4 3
+__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ range neq reg 1 0x00002100 0x00002d00 ]
# icmp sequence { 33, 55, 67, 88}
__set%d test-ip4 3
__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+__set%d test-ip4 3
+__set%d test-ip4 0
element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ lookup reg 1 set __set%d ]
# icmp sequence != { 33, 55, 67, 88}
__set%d test-ip4 3
__set%d test-ip4 0
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+__set%d test-ip4 3
+__set%d test-ip4 0
element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# icmp sequence { 33-55}
-__set%d test-ip4 7
+# icmp id 1 icmp sequence 2
+__set%d test-ip4 3
__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip test-ip4 input
+ element 00000008 : 0 [end] element 00000000 : 0 [end]
+ip
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
[ lookup reg 1 set __set%d ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x02000100 ]
-# icmp sequence != { 33-55}
-__set%d test-ip4 7
+# icmp type { echo-reply, echo-request} icmp id 1 icmp sequence 2
+__set%d test-ip4 3
__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip test-ip4 input
+ element 00000000 : 0 [end] element 00000008 : 0 [end]
+ip
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 4b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x02000100 ]
+
+# icmp type echo-reply icmp id 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
# icmp mtu 33
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ cmp eq reg 1 0x00002100 ]
@@ -428,34 +435,18 @@ ip test-ip4 input
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ cmp gte reg 1 0x00001600 ]
[ cmp lte reg 1 0x00002100 ]
-# icmp mtu { 22-33}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00001600 : 0 [end] element 00002200 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# icmp mtu != { 22-33}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00001600 : 0 [end] element 00002200 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# icmp mtu 22
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ cmp eq reg 1 0x00001600 ]
@@ -463,6 +454,8 @@ ip test-ip4 input
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ cmp neq reg 1 0x0000e900 ]
@@ -470,6 +463,8 @@ ip test-ip4 input
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ cmp gte reg 1 0x00002100 ]
[ cmp lte reg 1 0x00002d00 ]
@@ -478,6 +473,8 @@ ip test-ip4 input
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ range neq reg 1 0x00002100 0x00002d00 ]
@@ -488,6 +485,8 @@ __set%d test-ip4 0
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ lookup reg 1 set __set%d ]
@@ -498,26 +497,8 @@ __set%d test-ip4 0
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# icmp mtu { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# icmp mtu != { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000003 ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
@@ -525,6 +506,8 @@ ip test-ip4 input
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ cmp eq reg 1 0x16000000 ]
@@ -532,6 +515,8 @@ ip test-ip4 input
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ cmp neq reg 1 0xe9000000 ]
@@ -539,6 +524,8 @@ ip test-ip4 input
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ cmp gte reg 1 0x21000000 ]
[ cmp lte reg 1 0x2d000000 ]
@@ -547,6 +534,8 @@ ip test-ip4 input
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ range neq reg 1 0x21000000 0x2d000000 ]
@@ -557,6 +546,8 @@ __set%d test-ip4 0
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d ]
@@ -567,26 +558,8 @@ __set%d test-ip4 0
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
- [ payload load 4b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# icmp gateway { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
- [ payload load 4b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# icmp gateway != { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
@@ -594,6 +567,8 @@ ip test-ip4 input
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ cmp neq reg 1 0x22000000 ]
@@ -604,6 +579,8 @@ __set%d test-ip4 0
ip test-ip4 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000005 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
@@ -634,3 +611,9 @@ ip test-ip4 input
[ lookup reg 1 set __set%d ]
[ immediate reg 0 accept ]
+# icmp code 1 icmp type 2
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000102 ]
diff --git a/tests/py/ip/igmp.t b/tests/py/ip/igmp.t
index 939dcc32..a556e475 100644
--- a/tests/py/ip/igmp.t
+++ b/tests/py/ip/igmp.t
@@ -16,8 +16,6 @@ igmp checksum 12343;ok
igmp checksum != 12343;ok
igmp checksum 11-343;ok
igmp checksum != 11-343;ok
-igmp checksum { 11-343};ok
-igmp checksum != { 11-343};ok
igmp checksum { 1111, 222, 343};ok
igmp checksum != { 1111, 222, 343};ok
diff --git a/tests/py/ip/igmp.t.json b/tests/py/ip/igmp.t.json
index 66dd3bb7..0e2a43f3 100644
--- a/tests/py/ip/igmp.t.json
+++ b/tests/py/ip/igmp.t.json
@@ -196,56 +196,6 @@
}
]
-# igmp checksum { 11-343}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "igmp"
- }
- },
- "op": "==",
- "right": {
- "set": [
- {
- "range": [
- 11,
- 343
- ]
- }
- ]
- }
- }
- }
-]
-
-# igmp checksum != { 11-343}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "igmp"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- {
- "range": [
- 11,
- 343
- ]
- }
- ]
- }
- }
- }
-]
-
# igmp checksum { 1111, 222, 343}
[
{
diff --git a/tests/py/ip/igmp.t.payload b/tests/py/ip/igmp.t.payload
index 1319c324..940fe2cd 100644
--- a/tests/py/ip/igmp.t.payload
+++ b/tests/py/ip/igmp.t.payload
@@ -62,150 +62,6 @@ ip test-ip4 input
[ payload load 2b @ transport header + 2 => reg 1 ]
[ range neq reg 1 0x00000b00 0x00005701 ]
-# igmp checksum { 11-343}
-__set%d test-ip4 7 size 3
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# igmp checksum != { 11-343}
-__set%d test-ip4 7 size 3
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# igmp checksum { 1111, 222, 343}
-__set%d test-ip4 3 size 3
-__set%d test-ip4 0
- element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# igmp checksum != { 1111, 222, 343}
-__set%d test-ip4 3 size 3
-__set%d test-ip4 0
- element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# igmp type membership-query
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000011 ]
-
-# igmp type membership-report-v1
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000012 ]
-
-# igmp type membership-report-v2
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000016 ]
-
-# igmp type membership-report-v3
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000022 ]
-
-# igmp type leave-group
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000017 ]
-
-# igmp type { membership-report-v1, membership-report-v2, membership-report-v3}
-__set%d test-ip4 3 size 3
-__set%d test-ip4 0
- element 00000012 : 0 [end] element 00000016 : 0 [end] element 00000022 : 0 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# igmp type != { membership-report-v1, membership-report-v2, membership-report-v3}
-__set%d test-ip4 3 size 3
-__set%d test-ip4 0
- element 00000012 : 0 [end] element 00000016 : 0 [end] element 00000022 : 0 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# igmp checksum 12343
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ cmp eq reg 1 0x00003730 ]
-
-# igmp checksum != 12343
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ cmp neq reg 1 0x00003730 ]
-
-# igmp checksum 11-343
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ cmp gte reg 1 0x00000b00 ]
- [ cmp lte reg 1 0x00005701 ]
-
-# igmp checksum != 11-343
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ range neq reg 1 0x00000b00 0x00005701 ]
-
-# igmp checksum { 11-343}
-__set%d test-ip4 7 size 3
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# igmp checksum != { 11-343}
-__set%d test-ip4 7 size 3
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# igmp checksum { 1111, 222, 343}
__set%d test-ip4 3 size 3
__set%d test-ip4 0
@@ -226,41 +82,6 @@ ip test-ip4 input
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# igmp type membership-query
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000011 ]
-
-# igmp type membership-report-v1
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000012 ]
-
-# igmp type membership-report-v2
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000016 ]
-
-# igmp type membership-report-v3
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000022 ]
-
-# igmp type leave-group
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ transport header + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000017 ]
-
# igmp type { membership-report-v1, membership-report-v2, membership-report-v3}
__set%d test-ip4 3 size 3
__set%d test-ip4 0
@@ -281,75 +102,6 @@ ip test-ip4 input
[ payload load 1b @ transport header + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# igmp checksum 12343
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ cmp eq reg 1 0x00003730 ]
-
-# igmp checksum != 12343
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ cmp neq reg 1 0x00003730 ]
-
-# igmp checksum 11-343
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ cmp gte reg 1 0x00000b00 ]
- [ cmp lte reg 1 0x00005701 ]
-
-# igmp checksum != 11-343
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ range neq reg 1 0x00000b00 0x00005701 ]
-
-# igmp checksum { 11-343}
-__set%d test-ip4 7 size 3
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# igmp checksum != { 11-343}
-__set%d test-ip4 7 size 3
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000b00 : 0 [end] element 00005801 : 1 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# igmp checksum { 1111, 222, 343}
-__set%d test-ip4 3 size 3
-__set%d test-ip4 0
- element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# igmp checksum != { 1111, 222, 343}
-__set%d test-ip4 3 size 3
-__set%d test-ip4 0
- element 00005704 : 0 [end] element 0000de00 : 0 [end] element 00005701 : 0 [end]
-ip test-ip4 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# igmp mrt 10
ip test-ip4 input
[ meta load l4proto => reg 1 ]
diff --git a/tests/py/ip/ip.t b/tests/py/ip/ip.t
index 0421d01b..e6999c29 100644
--- a/tests/py/ip/ip.t
+++ b/tests/py/ip/ip.t
@@ -1,10 +1,11 @@
: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
*inet;test-inet;input
*bridge;test-bridge;input
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
- ip version 2;ok
@@ -39,8 +40,6 @@ ip length 333-435;ok
ip length != 333-453;ok
ip length { 333, 553, 673, 838};ok
ip length != { 333, 553, 673, 838};ok
-ip length { 333-535};ok
-ip length != { 333-535};ok
ip id 22;ok
ip id != 233;ok
@@ -48,17 +47,16 @@ ip id 33-45;ok
ip id != 33-45;ok
ip id { 33, 55, 67, 88};ok
ip id != { 33, 55, 67, 88};ok
-ip id { 33-55};ok
-ip id != { 33-55};ok
-
-ip frag-off 222 accept;ok
-ip frag-off != 233;ok
-ip frag-off 33-45;ok
-ip frag-off != 33-45;ok
-ip frag-off { 33, 55, 67, 88};ok
-ip frag-off != { 33, 55, 67, 88};ok
-ip frag-off { 33-55};ok
-ip frag-off != { 33-55};ok
+
+ip frag-off 0xde accept;ok
+ip frag-off != 0xe9;ok
+ip frag-off 0x21-0x2d;ok
+ip frag-off != 0x21-0x2d;ok
+ip frag-off { 0x21, 0x37, 0x43, 0x58};ok
+ip frag-off != { 0x21, 0x37, 0x43, 0x58};ok
+ip frag-off & 0x1fff != 0x0;ok
+ip frag-off & 0x2000 != 0x0;ok
+ip frag-off & 0x4000 != 0x0;ok
ip ttl 0 drop;ok
ip ttl 233;ok
@@ -66,8 +64,6 @@ ip ttl 33-55;ok
ip ttl != 45-50;ok
ip ttl {43, 53, 45 };ok
ip ttl != {43, 53, 45 };ok
-ip ttl { 33-55};ok
-ip ttl != { 33-55};ok
ip protocol tcp;ok;ip protocol 6
ip protocol != tcp;ok;ip protocol != 6
@@ -84,23 +80,19 @@ ip checksum 33-45;ok
ip checksum != 33-45;ok
ip checksum { 33, 55, 67, 88};ok
ip checksum != { 33, 55, 67, 88};ok
-ip checksum { 33-55};ok
-ip checksum != { 33-55};ok
ip saddr set {192.19.1.2, 191.1.22.1};fail
ip saddr 192.168.2.0/24;ok
ip saddr != 192.168.2.0/24;ok
ip saddr 192.168.3.1 ip daddr 192.168.3.100;ok
-ip saddr != 1.1.1.1;ok;ip saddr != 1.1.1.1
-ip saddr 1.1.1.1;ok;ip saddr 1.1.1.1
+ip saddr != 1.1.1.1;ok
+ip saddr 1.1.1.1;ok
ip daddr 192.168.0.1-192.168.0.250;ok
ip daddr 10.0.0.0-10.255.255.255;ok
ip daddr 172.16.0.0-172.31.255.255;ok
ip daddr 192.168.3.1-192.168.4.250;ok
ip daddr != 192.168.0.1-192.168.0.250;ok
-ip daddr { 192.168.0.1-192.168.0.250};ok
-ip daddr != { 192.168.0.1-192.168.0.250};ok
ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept;ok
ip daddr != { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept;ok
@@ -135,3 +127,11 @@ iif "lo" ip protocol set 1;ok
iif "lo" ip dscp set af23;ok
iif "lo" ip dscp set cs0;ok
+
+ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 };ok
+ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept };ok
+
+ip saddr 1.2.3.4 ip daddr 3.4.5.6;ok
+ip saddr 1.2.3.4 counter ip daddr 3.4.5.6;ok
+
+ip dscp 1/6;ok;ip dscp & 0x3f == lephb
diff --git a/tests/py/ip/ip.t.json b/tests/py/ip/ip.t.json
index 3131ab79..a170e5c1 100644
--- a/tests/py/ip/ip.t.json
+++ b/tests/py/ip/ip.t.json
@@ -270,46 +270,6 @@
}
]
-# ip length { 333-535}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "length",
- "protocol": "ip"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 333, 535 ] }
- ]
- }
- }
- }
-]
-
-# ip length != { 333-535}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "length",
- "protocol": "ip"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 333, 535 ] }
- ]
- }
- }
- }
-]
-
# ip id 22
[
{
@@ -424,47 +384,7 @@
}
]
-# ip id { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "id",
- "protocol": "ip"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# ip id != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "id",
- "protocol": "ip"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# ip frag-off 222 accept
+# ip frag-off 0xde accept
[
{
"match": {
@@ -483,7 +403,7 @@
}
]
-# ip frag-off != 233
+# ip frag-off != 0xe9
[
{
"match": {
@@ -499,7 +419,7 @@
}
]
-# ip frag-off 33-45
+# ip frag-off 0x21-0x2d
[
{
"match": {
@@ -517,7 +437,7 @@
}
]
-# ip frag-off != 33-45
+# ip frag-off != 0x21-0x2d
[
{
"match": {
@@ -535,7 +455,7 @@
}
]
-# ip frag-off { 33, 55, 67, 88}
+# ip frag-off { 0x21, 0x37, 0x43, 0x58}
[
{
"match": {
@@ -558,7 +478,7 @@
}
]
-# ip frag-off != { 33, 55, 67, 88}
+# ip frag-off != { 0x21, 0x37, 0x43, 0x58}
[
{
"match": {
@@ -581,42 +501,65 @@
}
]
-# ip frag-off { 33-55}
+# ip frag-off & 0x1fff != 0x0
[
{
"match": {
"left": {
- "payload": {
- "field": "frag-off",
- "protocol": "ip"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
+ "&": [
+ {
+ "payload": {
+ "field": "frag-off",
+ "protocol": "ip"
+ }
+ },
+ 8191
]
- }
+ },
+ "op": "!=",
+ "right": 0
}
}
]
-# ip frag-off != { 33-55}
+# ip frag-off & 0x2000 != 0x0
[
{
"match": {
"left": {
- "payload": {
- "field": "frag-off",
- "protocol": "ip"
- }
+ "&": [
+ {
+ "payload": {
+ "field": "frag-off",
+ "protocol": "ip"
+ }
+ },
+ 8192
+ ]
},
"op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
+ "right": 0
+ }
+ }
+]
+
+# ip frag-off & 0x4000 != 0x0
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "frag-off",
+ "protocol": "ip"
+ }
+ },
+ 16384
]
- }
+ },
+ "op": "!=",
+ "right": 0
}
}
]
@@ -736,46 +679,6 @@
}
]
-# ip ttl { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "ttl",
- "protocol": "ip"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# ip ttl != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "ttl",
- "protocol": "ip"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# ip protocol tcp
[
{
@@ -1019,46 +922,6 @@
}
]
-# ip checksum { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "ip"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# ip checksum != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "ip"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# ip saddr 192.168.2.0/24
[
{
@@ -1251,46 +1114,6 @@
}
]
-# ip daddr { 192.168.0.1-192.168.0.250}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "daddr",
- "protocol": "ip"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ "192.168.0.1", "192.168.0.250" ] }
- ]
- }
- }
- }
-]
-
-# ip daddr != { 192.168.0.1-192.168.0.250}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "daddr",
- "protocol": "ip"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ "192.168.0.1", "192.168.0.250" ] }
- ]
- }
- }
- }
-]
-
# ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
[
{
@@ -1836,3 +1659,174 @@
}
]
+# ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 }
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "192.0.2.1",
+ {
+ "range": [
+ "10.0.0.1",
+ "10.0.0.2"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept }
+[
+ {
+ "vmap": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ {
+ "range": [
+ "192.168.5.1",
+ "192.168.5.128"
+ ]
+ },
+ {
+ "range": [
+ "192.168.6.1",
+ "192.168.6.128"
+ ]
+ }
+ ]
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ }
+ }
+ }
+]
+
+# ip saddr 1.2.3.4 ip daddr 3.4.5.6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "3.4.5.6"
+ }
+ }
+]
+
+# ip saddr 1.2.3.4 counter ip daddr 3.4.5.6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "counter": {
+ "bytes": 0,
+ "packets": 0
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "3.4.5.6"
+ }
+ }
+]
+
+# ip dscp 1/6
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 63
+ ]
+ },
+ "op": "==",
+ "right": "lephb"
+ }
+ }
+]
diff --git a/tests/py/ip/ip.t.json.output b/tests/py/ip/ip.t.json.output
index b201cdaa..351ae935 100644
--- a/tests/py/ip/ip.t.json.output
+++ b/tests/py/ip/ip.t.json.output
@@ -230,3 +230,34 @@
}
]
+# ip saddr 1.2.3.4 counter ip daddr 3.4.5.6
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "counter": null
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "3.4.5.6"
+ }
+ }
+]
+
diff --git a/tests/py/ip/ip.t.payload b/tests/py/ip/ip.t.payload
index d627b22f..d7ddf7be 100644
--- a/tests/py/ip/ip.t.payload
+++ b/tests/py/ip/ip.t.payload
@@ -1,25 +1,25 @@
# ip dscp cs1
ip test-ip4 input
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000020 ]
# ip dscp != cs1
ip test-ip4 input
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000020 ]
# ip dscp 0x38
ip test-ip4 input
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp eq reg 1 0x000000e0 ]
# ip dscp != 0x20
ip test-ip4 input
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000080 ]
# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
@@ -28,7 +28,7 @@ __set%d test-ip4 0
element 00000020 : 0 [end] element 00000040 : 0 [end] element 00000060 : 0 [end] element 00000080 : 0 [end] element 000000a0 : 0 [end] element 000000c0 : 0 [end] element 000000e0 : 0 [end] element 00000000 : 0 [end] element 00000028 : 0 [end] element 00000030 : 0 [end] element 00000038 : 0 [end] element 00000048 : 0 [end] element 00000050 : 0 [end] element 00000058 : 0 [end] element 00000068 : 0 [end] element 00000070 : 0 [end] element 00000078 : 0 [end] element 00000088 : 0 [end] element 00000090 : 0 [end] element 00000098 : 0 [end] element 000000b8 : 0 [end]
ip test-ip4 input
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
# ip dscp != {cs0, cs3}
@@ -37,16 +37,16 @@ __set%d test-ip4 0
element 00000000 : 0 [end] element 00000060 : 0 [end]
ip test-ip4 input
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d 0x1 ]
# ip dscp vmap { cs1 : continue , cs4 : accept } counter
__map%d test-ip4 b size 2
__map%d test-ip4 0
- element 00000020 : 0 [end] element 00000080 : 0 [end]
+ element 00000020 : continue 0 [end] element 00000080 : accept 0 [end]
ip test-ip4 input
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 0 ]
[ counter pkts 0 bytes 0 ]
@@ -87,22 +87,6 @@ ip test-ip4 input
[ payload load 2b @ network header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip length { 333-535}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00004d01 : 0 [end] element 00001802 : 1 [end]
-ip test-ip4 input
- [ payload load 2b @ network header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip length != { 333-535}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00004d01 : 0 [end] element 00001802 : 1 [end]
-ip test-ip4 input
- [ payload load 2b @ network header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip id 22
ip test-ip4 input
[ payload load 2b @ network header + 4 => reg 1 ]
@@ -140,45 +124,29 @@ ip test-ip4 input
[ payload load 2b @ network header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip id { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip test-ip4 input
- [ payload load 2b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip id != { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip test-ip4 input
- [ payload load 2b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# ip frag-off 222 accept
+# ip frag-off 0xde accept
ip test-ip4 input
[ payload load 2b @ network header + 6 => reg 1 ]
[ cmp eq reg 1 0x0000de00 ]
[ immediate reg 0 accept ]
-# ip frag-off != 233
+# ip frag-off != 0xe9
ip test-ip4 input
[ payload load 2b @ network header + 6 => reg 1 ]
[ cmp neq reg 1 0x0000e900 ]
-# ip frag-off 33-45
+# ip frag-off 0x21-0x2d
ip test-ip4 input
[ payload load 2b @ network header + 6 => reg 1 ]
[ cmp gte reg 1 0x00002100 ]
[ cmp lte reg 1 0x00002d00 ]
-# ip frag-off != 33-45
+# ip frag-off != 0x21-0x2d
ip test-ip4 input
[ payload load 2b @ network header + 6 => reg 1 ]
[ range neq reg 1 0x00002100 0x00002d00 ]
-# ip frag-off { 33, 55, 67, 88}
+# ip frag-off { 0x21, 0x37, 0x43, 0x58}
__set%d test-ip4 3
__set%d test-ip4 0
element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
@@ -186,7 +154,7 @@ ip test-ip4 input
[ payload load 2b @ network header + 6 => reg 1 ]
[ lookup reg 1 set __set%d ]
-# ip frag-off != { 33, 55, 67, 88}
+# ip frag-off != { 0x21, 0x37, 0x43, 0x58}
__set%d test-ip4 3
__set%d test-ip4 0
element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
@@ -194,21 +162,23 @@ ip test-ip4 input
[ payload load 2b @ network header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip frag-off { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
+# ip frag-off & 0x1fff != 0x0
ip test-ip4 input
[ payload load 2b @ network header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff1f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
-# ip frag-off != { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
+# ip frag-off & 0x2000 != 0x0
ip test-ip4 input
[ payload load 2b @ network header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000020 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ip frag-off & 0x4000 != 0x0
+ip test-ip4 input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000040 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
# ip ttl 0 drop
ip test-ip4 input
@@ -248,22 +218,6 @@ ip test-ip4 input
[ payload load 1b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip ttl { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip test-ip4 input
- [ payload load 1b @ network header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip ttl != { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip test-ip4 input
- [ payload load 1b @ network header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip protocol tcp
ip test-ip4 input
[ payload load 1b @ network header + 9 => reg 1 ]
@@ -340,32 +294,14 @@ ip test-ip4 input
[ payload load 2b @ network header + 10 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip checksum { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip test-ip4 input
- [ payload load 2b @ network header + 10 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip checksum != { 33-55}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip test-ip4 input
- [ payload load 2b @ network header + 10 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip saddr 192.168.2.0/24
ip test-ip4 input
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp eq reg 1 0x0002a8c0 ]
# ip saddr != 192.168.2.0/24
ip test-ip4 input
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp neq reg 1 0x0002a8c0 ]
# ip saddr 192.168.3.1 ip daddr 192.168.3.100
@@ -414,22 +350,6 @@ ip test-ip4 input
[ payload load 4b @ network header + 16 => reg 1 ]
[ range neq reg 1 0x0100a8c0 0xfa00a8c0 ]
-# ip daddr { 192.168.0.1-192.168.0.250}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 0100a8c0 : 0 [end] element fb00a8c0 : 1 [end]
-ip test-ip4 input
- [ payload load 4b @ network header + 16 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip daddr != { 192.168.0.1-192.168.0.250}
-__set%d test-ip4 7
-__set%d test-ip4 0
- element 00000000 : 1 [end] element 0100a8c0 : 0 [end] element fb00a8c0 : 1 [end]
-ip test-ip4 input
- [ payload load 4b @ network header + 16 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
__set%d test-ip4 3
__set%d test-ip4 0
@@ -489,59 +409,49 @@ ip test-ip4 input
# ip saddr & 0xff == 1
ip test-ip4 input
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xff000000 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x01000000 ]
# ip saddr & 0.0.0.255 < 0.0.0.127
ip test-ip4 input
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xff000000 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
[ cmp lt reg 1 0x7f000000 ]
# ip saddr & 0xffff0000 == 0xffff0000
ip test-ip4 input
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ffff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000ffff ]
-# ip saddr . ip daddr . ip protocol { 1.1.1.1 . 2.2.2.2 . tcp, 1.1.1.1 . 3.3.3.3 . udp}
-__set%d test-ip 3
-__set%d test-ip 0
- element 01010101 02020202 00000006 : 0 [end] element 01010101 03030303 00000011 : 0 [end]
-ip test-ip input
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ payload load 4b @ network header + 16 => reg 9 ]
- [ payload load 1b @ network header + 9 => reg 10 ]
- [ lookup reg 1 set __set%d ]
-
# ip version 4 ip hdrlength 5
ip test-ip4 input
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000040 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000005 ]
# ip hdrlength 0
ip test-ip4 input
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
# ip hdrlength 15
ip test-ip4 input
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000000f ]
# ip hdrlength vmap { 0-4 : drop, 5 : accept, 6 : continue } counter
__map%d test-ip4 f size 4
__map%d test-ip4 0
- element 00000000 : 0 [end] element 00000005 : 0 [end] element 00000006 : 0 [end] element 00000007 : 1 [end]
+ element 00000000 : drop 0 [end] element 00000005 : accept 0 [end] element 00000006 : continue 0 [end] element 00000007 : 1 [end]
ip test-ip4 input
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 0 ]
[ counter pkts 0 bytes 0 ]
@@ -571,7 +481,7 @@ ip test-ip4 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000fcff ) ^ 0x00000100 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000100 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip ecn set ce
@@ -579,7 +489,7 @@ ip test-ip4 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000fcff ) ^ 0x00000300 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000300 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip dscp set af23
@@ -587,7 +497,7 @@ ip test-ip4 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000003ff ) ^ 0x00005800 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00005800 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip dscp set cs0
@@ -595,7 +505,7 @@ ip test-ip4 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000003ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00000000 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip ttl set 23
@@ -603,7 +513,7 @@ ip test-ip4 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff00 ) ^ 0x00000017 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff00 ) ^ 0x00000017 ]
[ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip protocol set 1
@@ -611,6 +521,46 @@ ip test-ip4 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000ff ) ^ 0x00000100 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000ff ) ^ 0x00000100 ]
[ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x1 ]
+# ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 }
+__set%d test-ip4 87 size 1
+__set%d test-ip4 0
+ element 010200c0 0100000a - 010200c0 0200000a : 0 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept }
+__map%d test-ip4 8f size 1
+__map%d test-ip4 0
+ element 0105a8c0 0106a8c0 - 8005a8c0 8006a8c0 : accept 0 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip saddr 1.2.3.4 ip daddr 3.4.5.6
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
+
+# ip saddr 1.2.3.4 counter ip daddr 3.4.5.6
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
+
+# ip dscp 1/6
+ip test-ip4 input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000003f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000001 ]
diff --git a/tests/py/ip/ip.t.payload.bridge b/tests/py/ip/ip.t.payload.bridge
index 91a4fde3..53f881d3 100644
--- a/tests/py/ip/ip.t.payload.bridge
+++ b/tests/py/ip/ip.t.payload.bridge
@@ -3,7 +3,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000020 ]
# ip dscp != cs1
@@ -11,7 +11,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000020 ]
# ip dscp 0x38
@@ -19,7 +19,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp eq reg 1 0x000000e0 ]
# ip dscp != 0x20
@@ -27,7 +27,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000080 ]
# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
@@ -38,7 +38,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
# ip dscp != {cs0, cs3}
@@ -49,18 +49,18 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d 0x1 ]
# ip dscp vmap { cs1 : continue , cs4 : accept } counter
__map%d test-bridge b size 2
__map%d test-bridge 0
- element 00000020 : 0 [end] element 00000080 : 0 [end]
+ element 00000020 : continue 0 [end] element 00000080 : accept 0 [end]
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 0 ]
[ counter pkts 0 bytes 0 ]
@@ -113,26 +113,6 @@ bridge test-bridge input
[ payload load 2b @ network header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip length { 333-535}
-__set%d test-bridge 7 size 3
-__set%d test-bridge 0
- element 00000000 : 1 [end] element 00004d01 : 0 [end] element 00001802 : 1 [end]
-bridge test-bridge input
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 2b @ network header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip length != { 333-535}
-__set%d test-bridge 7 size 3
-__set%d test-bridge 0
- element 00000000 : 1 [end] element 00004d01 : 0 [end] element 00001802 : 1 [end]
-bridge test-bridge input
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 2b @ network header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip id 22
bridge test-bridge input
[ meta load protocol => reg 1 ]
@@ -182,27 +162,7 @@ bridge test-bridge input
[ payload load 2b @ network header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip id { 33-55}
-__set%d test-bridge 7 size 3
-__set%d test-bridge 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-bridge test-bridge input
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 2b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip id != { 33-55}
-__set%d test-bridge 7 size 3
-__set%d test-bridge 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-bridge test-bridge input
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 2b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# ip frag-off 222 accept
+# ip frag-off 0xde accept
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
@@ -210,14 +170,14 @@ bridge test-bridge input
[ cmp eq reg 1 0x0000de00 ]
[ immediate reg 0 accept ]
-# ip frag-off != 233
+# ip frag-off != 0xe9
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 6 => reg 1 ]
[ cmp neq reg 1 0x0000e900 ]
-# ip frag-off 33-45
+# ip frag-off 0x21-0x2d
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
@@ -225,14 +185,14 @@ bridge test-bridge input
[ cmp gte reg 1 0x00002100 ]
[ cmp lte reg 1 0x00002d00 ]
-# ip frag-off != 33-45
+# ip frag-off != 0x21-0x2d
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 6 => reg 1 ]
[ range neq reg 1 0x00002100 0x00002d00 ]
-# ip frag-off { 33, 55, 67, 88}
+# ip frag-off { 0x21, 0x37, 0x43, 0x58}
__set%d test-bridge 3 size 4
__set%d test-bridge 0
element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
@@ -242,7 +202,7 @@ bridge test-bridge input
[ payload load 2b @ network header + 6 => reg 1 ]
[ lookup reg 1 set __set%d ]
-# ip frag-off != { 33, 55, 67, 88}
+# ip frag-off != { 0x21, 0x37, 0x43, 0x58}
__set%d test-bridge 3 size 4
__set%d test-bridge 0
element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
@@ -252,25 +212,29 @@ bridge test-bridge input
[ payload load 2b @ network header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip frag-off { 33-55}
-__set%d test-bridge 7 size 3
-__set%d test-bridge 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
+# ip frag-off & 0x1fff != 0x0
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff1f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
-# ip frag-off != { 33-55}
-__set%d test-bridge 7 size 3
-__set%d test-bridge 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
+# ip frag-off & 0x2000 != 0x0
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000020 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ip frag-off & 0x4000 != 0x0
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000040 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
# ip ttl 0 drop
bridge test-bridge input
@@ -322,26 +286,6 @@ bridge test-bridge input
[ payload load 1b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip ttl { 33-55}
-__set%d test-bridge 7 size 3
-__set%d test-bridge 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-bridge test-bridge input
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 1b @ network header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip ttl != { 33-55}
-__set%d test-bridge 7 size 3
-__set%d test-bridge 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-bridge test-bridge input
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 1b @ network header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip protocol tcp
bridge test-bridge input
[ meta load protocol => reg 1 ]
@@ -442,40 +386,18 @@ bridge test-bridge input
[ payload load 2b @ network header + 10 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip checksum { 33-55}
-__set%d test-bridge 7 size 3
-__set%d test-bridge 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-bridge test-bridge input
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 2b @ network header + 10 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip checksum != { 33-55}
-__set%d test-bridge 7 size 3
-__set%d test-bridge 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-bridge test-bridge input
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 2b @ network header + 10 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip saddr 192.168.2.0/24
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp eq reg 1 0x0002a8c0 ]
# ip saddr != 192.168.2.0/24
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp neq reg 1 0x0002a8c0 ]
# ip saddr 192.168.3.1 ip daddr 192.168.3.100
@@ -540,26 +462,6 @@ bridge test-bridge input
[ payload load 4b @ network header + 16 => reg 1 ]
[ range neq reg 1 0x0100a8c0 0xfa00a8c0 ]
-# ip daddr { 192.168.0.1-192.168.0.250}
-__set%d test-bridge 7 size 3
-__set%d test-bridge 0
- element 00000000 : 1 [end] element 0100a8c0 : 0 [end] element fb00a8c0 : 1 [end]
-bridge test-bridge input
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 16 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip daddr != { 192.168.0.1-192.168.0.250}
-__set%d test-bridge 7 size 3
-__set%d test-bridge 0
- element 00000000 : 1 [end] element 0100a8c0 : 0 [end] element fb00a8c0 : 1 [end]
-bridge test-bridge input
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 16 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
__set%d test-bridge 3 size 3
__set%d test-bridge 0
@@ -639,7 +541,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xff000000 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x01000000 ]
# ip saddr & 0.0.0.255 < 0.0.0.127
@@ -647,7 +549,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xff000000 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
[ cmp lt reg 1 0x7f000000 ]
# ip saddr & 0xffff0000 == 0xffff0000
@@ -655,7 +557,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ffff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000ffff ]
# ip version 4 ip hdrlength 5
@@ -663,10 +565,10 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000040 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000005 ]
# ip hdrlength 0
@@ -674,7 +576,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
# ip hdrlength 15
@@ -682,18 +584,18 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000000f ]
# ip hdrlength vmap { 0-4 : drop, 5 : accept, 6 : continue } counter
__map%d test-bridge f size 4
__map%d test-bridge 0
- element 00000000 : 0 [end] element 00000005 : 0 [end] element 00000006 : 0 [end] element 00000007 : 1 [end]
+ element 00000000 : drop 0 [end] element 00000005 : accept 0 [end] element 00000006 : continue 0 [end] element 00000007 : 1 [end]
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 0 ]
[ counter pkts 0 bytes 0 ]
@@ -731,7 +633,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000fcff ) ^ 0x00000100 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000100 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip ecn set ce
@@ -741,7 +643,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000fcff ) ^ 0x00000300 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000300 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip ttl set 23
@@ -751,7 +653,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff00 ) ^ 0x00000017 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff00 ) ^ 0x00000017 ]
[ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip protocol set 1
@@ -761,7 +663,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000ff ) ^ 0x00000100 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000ff ) ^ 0x00000100 ]
[ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x1 ]
# iif "lo" ip dscp set af23
@@ -771,7 +673,7 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000003ff ) ^ 0x00005800 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00005800 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip dscp set cs0
@@ -781,6 +683,56 @@ bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000003ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00000000 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
+# ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 }
+__set%d test-bridge 87 size 1
+__set%d test-bridge 0
+ element 010200c0 0100000a - 010200c0 0200000a : 0 [end]
+bridge
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept }
+__map%d test-bridge 8f size 1
+__map%d test-bridge 0
+ element 0105a8c0 0106a8c0 - 8005a8c0 8006a8c0 : accept 0 [end]
+bridge
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip saddr 1.2.3.4 ip daddr 3.4.5.6
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
+
+# ip saddr 1.2.3.4 counter ip daddr 3.4.5.6
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
+
+# ip dscp 1/6
+bridge test-bridge input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000003f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000001 ]
diff --git a/tests/py/ip/ip.t.payload.inet b/tests/py/ip/ip.t.payload.inet
index b9cb28a2..08674c98 100644
--- a/tests/py/ip/ip.t.payload.inet
+++ b/tests/py/ip/ip.t.payload.inet
@@ -3,7 +3,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000020 ]
# ip dscp != cs1
@@ -11,7 +11,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000020 ]
# ip dscp 0x38
@@ -19,7 +19,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp eq reg 1 0x000000e0 ]
# ip dscp != 0x20
@@ -27,7 +27,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000080 ]
# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
@@ -38,7 +38,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
# ip dscp != {cs0, cs3}
@@ -49,18 +49,18 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d 0x1 ]
# ip dscp vmap { cs1 : continue , cs4 : accept } counter
__map%d test-inet b size 2
__map%d test-inet 0
- element 00000020 : 0 [end] element 00000080 : 0 [end]
+ element 00000020 : continue 0 [end] element 00000080 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 0 ]
[ counter pkts 0 bytes 0 ]
@@ -113,26 +113,6 @@ inet test-inet input
[ payload load 2b @ network header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip length { 333-535}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00004d01 : 0 [end] element 00001802 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ network header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip length != { 333-535}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00004d01 : 0 [end] element 00001802 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ network header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip id 22
inet test-inet input
[ meta load nfproto => reg 1 ]
@@ -182,27 +162,7 @@ inet test-inet input
[ payload load 2b @ network header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip id { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip id != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# ip frag-off 222 accept
+# ip frag-off 0xde accept
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
@@ -210,14 +170,14 @@ inet test-inet input
[ cmp eq reg 1 0x0000de00 ]
[ immediate reg 0 accept ]
-# ip frag-off != 233
+# ip frag-off != 0xe9
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 2b @ network header + 6 => reg 1 ]
[ cmp neq reg 1 0x0000e900 ]
-# ip frag-off 33-45
+# ip frag-off 0x21-0x2d
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
@@ -225,14 +185,14 @@ inet test-inet input
[ cmp gte reg 1 0x00002100 ]
[ cmp lte reg 1 0x00002d00 ]
-# ip frag-off != 33-45
+# ip frag-off != 0x21-0x2d
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 2b @ network header + 6 => reg 1 ]
[ range neq reg 1 0x00002100 0x00002d00 ]
-# ip frag-off { 33, 55, 67, 88}
+# ip frag-off { 0x21, 0x37, 0x43, 0x58}
__set%d test-inet 3
__set%d test-inet 0
element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
@@ -242,7 +202,7 @@ inet test-inet input
[ payload load 2b @ network header + 6 => reg 1 ]
[ lookup reg 1 set __set%d ]
-# ip frag-off != { 33, 55, 67, 88}
+# ip frag-off != { 0x21, 0x37, 0x43, 0x58}
__set%d test-inet 3
__set%d test-inet 0
element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
@@ -252,25 +212,29 @@ inet test-inet input
[ payload load 2b @ network header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip frag-off { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
+# ip frag-off & 0x1fff != 0x0
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 2b @ network header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff1f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
-# ip frag-off != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
+# ip frag-off & 0x2000 != 0x0
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 2b @ network header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000020 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ip frag-off & 0x4000 != 0x0
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000040 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
# ip ttl 0 drop
inet test-inet input
@@ -322,26 +286,6 @@ inet test-inet input
[ payload load 1b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip ttl { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ network header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip ttl != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 1b @ network header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip protocol tcp
inet test-inet input
[ meta load nfproto => reg 1 ]
@@ -442,40 +386,18 @@ inet test-inet input
[ payload load 2b @ network header + 10 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip checksum { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ network header + 10 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip checksum != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 2b @ network header + 10 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip saddr 192.168.2.0/24
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp eq reg 1 0x0002a8c0 ]
# ip saddr != 192.168.2.0/24
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp neq reg 1 0x0002a8c0 ]
# ip saddr 192.168.3.1 ip daddr 192.168.3.100
@@ -540,26 +462,6 @@ inet test-inet input
[ payload load 4b @ network header + 16 => reg 1 ]
[ range neq reg 1 0x0100a8c0 0xfa00a8c0 ]
-# ip daddr { 192.168.0.1-192.168.0.250}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 0100a8c0 : 0 [end] element fb00a8c0 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 4b @ network header + 16 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip daddr != { 192.168.0.1-192.168.0.250}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 0100a8c0 : 0 [end] element fb00a8c0 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 4b @ network header + 16 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
__set%d test-inet 3
__set%d test-inet 0
@@ -639,7 +541,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xff000000 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x01000000 ]
# ip saddr & 0.0.0.255 < 0.0.0.127
@@ -647,7 +549,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xff000000 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
[ cmp lt reg 1 0x7f000000 ]
# ip saddr & 0xffff0000 == 0xffff0000
@@ -655,30 +557,18 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ffff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000ffff ]
-# ip saddr . ip daddr . ip protocol { 1.1.1.1 . 2.2.2.2 . tcp, 1.1.1.1 . 3.3.3.3 . udp}
-__set%d test-ip 3
-__set%d test-ip 0
- element 01010101 02020202 00000006 : 0 [end] element 01010101 03030303 00000011 : 0 [end]
-inet test-ip input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x00000002 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ payload load 4b @ network header + 16 => reg 9 ]
- [ payload load 1b @ network header + 9 => reg 10 ]
- [ lookup reg 1 set __set%d ]
-
# ip version 4 ip hdrlength 5
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000040 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000005 ]
# ip hdrlength 0
@@ -686,7 +576,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
# ip hdrlength 15
@@ -694,18 +584,18 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000000f ]
# ip hdrlength vmap { 0-4 : drop, 5 : accept, 6 : continue } counter
__map%d test-inet f size 4
__map%d test-inet 0
- element 00000000 : 0 [end] element 00000005 : 0 [end] element 00000006 : 0 [end] element 00000007 : 1 [end]
+ element 00000000 : drop 0 [end] element 00000005 : accept 0 [end] element 00000006 : continue 0 [end] element 00000007 : 1 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 0 ]
[ counter pkts 0 bytes 0 ]
@@ -743,7 +633,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000fcff ) ^ 0x00000100 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000100 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip ecn set ce
@@ -753,7 +643,7 @@ inet test-netdev ingress
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000fcff ) ^ 0x00000300 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000300 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip dscp set af23
@@ -763,7 +653,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000003ff ) ^ 0x00005800 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00005800 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip dscp set cs0
@@ -773,7 +663,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000003ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00000000 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip ttl set 23
@@ -783,7 +673,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 2b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff00 ) ^ 0x00000017 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff00 ) ^ 0x00000017 ]
[ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip protocol set 1
@@ -793,6 +683,56 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
[ payload load 2b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000ff ) ^ 0x00000100 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000ff ) ^ 0x00000100 ]
[ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x1 ]
+# ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 }
+__set%d test-inet 87 size 1
+__set%d test-inet 0
+ element 010200c0 0100000a - 010200c0 0200000a : 0 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept }
+__map%d test-inet 8f size 1
+__map%d test-inet 0
+ element 0105a8c0 0106a8c0 - 8005a8c0 8006a8c0 : accept 0 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip saddr 1.2.3.4 ip daddr 3.4.5.6
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
+
+# ip saddr 1.2.3.4 counter ip daddr 3.4.5.6
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
+
+# ip dscp 1/6
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000003f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000001 ]
diff --git a/tests/py/ip/ip.t.payload.netdev b/tests/py/ip/ip.t.payload.netdev
index 588e5ca2..8220b05d 100644
--- a/tests/py/ip/ip.t.payload.netdev
+++ b/tests/py/ip/ip.t.payload.netdev
@@ -47,26 +47,6 @@ netdev test-netdev ingress
[ payload load 2b @ network header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip length { 333-535}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00004d01 : 0 [end] element 00001802 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 2b @ network header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip length != { 333-535}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00004d01 : 0 [end] element 00001802 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 2b @ network header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip id 22
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
@@ -116,27 +96,7 @@ netdev test-netdev ingress
[ payload load 2b @ network header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip id { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 2b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip id != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 2b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# ip frag-off 222 accept
+# ip frag-off 0xde accept
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
@@ -144,14 +104,14 @@ netdev test-netdev ingress
[ cmp eq reg 1 0x0000de00 ]
[ immediate reg 0 accept ]
-# ip frag-off != 233
+# ip frag-off != 0xe9
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 6 => reg 1 ]
[ cmp neq reg 1 0x0000e900 ]
-# ip frag-off 33-45
+# ip frag-off 0x21-0x2d
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
@@ -159,14 +119,14 @@ netdev test-netdev ingress
[ cmp gte reg 1 0x00002100 ]
[ cmp lte reg 1 0x00002d00 ]
-# ip frag-off != 33-45
+# ip frag-off != 0x21-0x2d
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 6 => reg 1 ]
[ range neq reg 1 0x00002100 0x00002d00 ]
-# ip frag-off { 33, 55, 67, 88}
+# ip frag-off { 0x21, 0x37, 0x43, 0x58}
__set%d test-netdev 3
__set%d test-netdev 0
element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
@@ -176,7 +136,7 @@ netdev test-netdev ingress
[ payload load 2b @ network header + 6 => reg 1 ]
[ lookup reg 1 set __set%d ]
-# ip frag-off != { 33, 55, 67, 88}
+# ip frag-off != { 0x21, 0x37, 0x43, 0x58}
__set%d test-netdev 3
__set%d test-netdev 0
element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
@@ -186,25 +146,29 @@ netdev test-netdev ingress
[ payload load 2b @ network header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip frag-off { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-netdev test-netdev ingress
+# ip frag-off & 0x1fff != 0x0
+netdev x y
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff1f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
-# ip frag-off != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-netdev test-netdev ingress
+# ip frag-off & 0x2000 != 0x0
+netdev x y
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000020 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ip frag-off & 0x4000 != 0x0
+netdev x y
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000040 ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
# ip ttl 0 drop
netdev test-netdev ingress
@@ -249,26 +213,6 @@ netdev test-netdev ingress
[ payload load 1b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip ttl { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 1b @ network header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip ttl != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 1b @ network header + 8 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip protocol { icmp, esp, ah, comp, udp, udplite, tcp, dccp, sctp} accept
__set%d test-netdev 3
__set%d test-netdev 0
@@ -355,40 +299,18 @@ netdev test-netdev ingress
[ payload load 2b @ network header + 10 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip checksum { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 2b @ network header + 10 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip checksum != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 2b @ network header + 10 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip saddr 192.168.2.0/24
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp eq reg 1 0x0002a8c0 ]
# ip saddr != 192.168.2.0/24
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
+ [ payload load 3b @ network header + 12 => reg 1 ]
[ cmp neq reg 1 0x0002a8c0 ]
# ip saddr 192.168.3.1 ip daddr 192.168.3.100
@@ -446,26 +368,6 @@ netdev test-netdev ingress
[ payload load 4b @ network header + 16 => reg 1 ]
[ range neq reg 1 0x0100a8c0 0xfa00a8c0 ]
-# ip daddr { 192.168.0.1-192.168.0.250}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 0100a8c0 : 0 [end] element fb00a8c0 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 16 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip daddr != { 192.168.0.1-192.168.0.250}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 0100a8c0 : 0 [end] element fb00a8c0 : 1 [end]
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 16 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip daddr { 192.168.5.1, 192.168.5.2, 192.168.5.3 } accept
__set%d test-netdev 3
__set%d test-netdev 0
@@ -538,7 +440,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xff000000 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x01000000 ]
# ip saddr & 0.0.0.255 < 0.0.0.127
@@ -546,7 +448,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xff000000 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0xff000000 ) ^ 0x00000000 ]
[ cmp lt reg 1 0x7f000000 ]
# ip saddr & 0xffff0000 == 0xffff0000
@@ -554,7 +456,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ffff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000ffff ]
# ip version 4 ip hdrlength 5
@@ -562,10 +464,10 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000040 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000005 ]
# ip hdrlength 0
@@ -573,7 +475,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
# ip hdrlength 15
@@ -581,18 +483,18 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000000f ]
# ip hdrlength vmap { 0-4 : drop, 5 : accept, 6 : continue } counter
__map%d test-netdev f size 4
__map%d test-netdev 0
- element 00000000 : 0 [end] element 00000005 : 0 [end] element 00000006 : 0 [end] element 00000007 : 1 [end]
+ element 00000000 : drop 0 [end] element 00000005 : accept 0 [end] element 00000006 : continue 0 [end] element 00000007 : 1 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000f ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 0 ]
[ counter pkts 0 bytes 0 ]
@@ -631,124 +533,12 @@ netdev test-netdev ingress
[ payload load 4b @ network header + 16 => reg 1 ]
[ cmp eq reg 1 0x0200a8c0 ]
-# ip ttl 233
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 1b @ network header + 8 => reg 1 ]
- [ cmp eq reg 1 0x000000e9 ]
-
-# ip protocol tcp
-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 0x00000006 ]
-
-# ip protocol != tcp
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 1b @ network header + 9 => reg 1 ]
- [ cmp neq reg 1 0x00000006 ]
-
-# ip saddr != 1.1.1.1
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ cmp neq reg 1 0x01010101 ]
-
-# ip daddr 192.168.0.2
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 16 => reg 1 ]
- [ cmp eq reg 1 0x0200a8c0 ]
-
-# ip ttl 233
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 1b @ network header + 8 => reg 1 ]
- [ cmp eq reg 1 0x000000e9 ]
-
-# ip protocol tcp
-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 0x00000006 ]
-
-# ip protocol != tcp
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 1b @ network header + 9 => reg 1 ]
- [ cmp neq reg 1 0x00000006 ]
-
-# ip saddr != 1.1.1.1
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 12 => reg 1 ]
- [ cmp neq reg 1 0x01010101 ]
-
-# ip daddr 192.168.0.2
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 4b @ network header + 16 => reg 1 ]
- [ cmp eq reg 1 0x0200a8c0 ]
-
-# ip ttl 233
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 1b @ network header + 8 => reg 1 ]
- [ cmp eq reg 1 0x000000e9 ]
-
-# ip protocol tcp
-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 0x00000006 ]
-
-# ip protocol != tcp
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 1b @ network header + 9 => reg 1 ]
- [ cmp neq reg 1 0x00000006 ]
-
-# ip ttl 233
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 1b @ network header + 8 => reg 1 ]
- [ cmp eq reg 1 0x000000e9 ]
-
-# ip protocol tcp
-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 0x00000006 ]
-
-# ip protocol != tcp
-netdev test-netdev ingress
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x00000008 ]
- [ payload load 1b @ network header + 9 => reg 1 ]
- [ cmp neq reg 1 0x00000006 ]
-
# ip dscp cs1
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000020 ]
# ip dscp != cs1
@@ -756,7 +546,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000020 ]
# ip dscp 0x38
@@ -764,7 +554,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp eq reg 1 0x000000e0 ]
# ip dscp != 0x20
@@ -772,7 +562,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000080 ]
# ip dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
@@ -783,7 +573,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
# ip dscp != {cs0, cs3}
@@ -794,18 +584,18 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d 0x1 ]
# ip dscp vmap { cs1 : continue , cs4 : accept } counter
__map%d test-netdev b size 2
__map%d test-netdev 0
- element 00000020 : 0 [end] element 00000080 : 0 [end]
+ element 00000020 : continue 0 [end] element 00000080 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 0 ]
[ counter pkts 0 bytes 0 ]
@@ -843,7 +633,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000fcff ) ^ 0x00000100 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000100 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip ecn set ce
@@ -853,7 +643,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000fcff ) ^ 0x00000300 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000fcff ) ^ 0x00000300 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip dscp set af23
@@ -863,7 +653,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000003ff ) ^ 0x00005800 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00005800 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip dscp set cs0
@@ -873,7 +663,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000003ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000003ff ) ^ 0x00000000 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip ttl set 23
@@ -883,7 +673,7 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000ff00 ) ^ 0x00000017 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff00 ) ^ 0x00000017 ]
[ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x0 ]
# iif "lo" ip protocol set 1
@@ -893,6 +683,56 @@ netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
[ payload load 2b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000ff ) ^ 0x00000100 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000ff ) ^ 0x00000100 ]
[ payload write reg 1 => 2b @ network header + 8 csum_type 1 csum_off 10 csum_flags 0x1 ]
+# ip saddr . ip daddr { 192.0.2.1 . 10.0.0.1-10.0.0.2 }
+__set%d test-netdev 87 size 1
+__set%d test-netdev 0
+ element 010200c0 0100000a - 010200c0 0200000a : 0 [end]
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+
+# ip saddr . ip daddr vmap { 192.168.5.1-192.168.5.128 . 192.168.6.1-192.168.6.128 : accept }
+__map%d test-netdev 8f size 1
+__map%d test-netdev 0
+ element 0105a8c0 0106a8c0 - 8005a8c0 8006a8c0 : accept 0 [end]
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# ip saddr 1.2.3.4 ip daddr 3.4.5.6
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
+
+# ip saddr 1.2.3.4 counter ip daddr 3.4.5.6
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x04030201 ]
+ [ counter pkts 0 bytes 0 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x06050403 ]
+
+# ip dscp 1/6
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000003f ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000001 ]
diff --git a/tests/py/ip/ip_tcp.t b/tests/py/ip/ip_tcp.t
index 467da3ef..ff398aa6 100644
--- a/tests/py/ip/ip_tcp.t
+++ b/tests/py/ip/ip_tcp.t
@@ -1,5 +1,4 @@
:input;type filter hook input priority 0
-:ingress;type filter hook ingress device lo priority 0
*ip;test-ip;input
diff --git a/tests/py/ip/masquerade.t.payload b/tests/py/ip/masquerade.t.payload
index 83351526..79e52856 100644
--- a/tests/py/ip/masquerade.t.payload
+++ b/tests/py/ip/masquerade.t.payload
@@ -112,12 +112,12 @@ ip test-ip4 postrouting
# iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } masquerade
__map%d test-ip4 b
__map%d test-ip4 0
- element 00001600 : 0 [end] element 0000de00 : 0 [end]
+ element 00001600 : drop 0 [end] element 0000de00 : drop 0 [end]
ip test-ip4 postrouting
[ meta load iifname => reg 1 ]
[ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
[ ct load state => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000a ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000a ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000000 ]
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -130,7 +130,7 @@ ip test-ip4 postrouting
[ payload load 1b @ network header + 9 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x00000004 ]
- [ masq proto_min reg 1 proto_max reg 0 ]
+ [ masq proto_min reg 1 flags 0x2 ]
# ip protocol 6 masquerade to :1024-2048
ip test-ip4 postrouting
@@ -138,5 +138,5 @@ ip test-ip4 postrouting
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x00000004 ]
[ immediate reg 2 0x00000008 ]
- [ masq proto_min reg 1 proto_max reg 2 ]
+ [ masq proto_min reg 1 proto_max reg 2 flags 0x2 ]
diff --git a/tests/py/ip/meta.t b/tests/py/ip/meta.t
index 4db88354..a88a6145 100644
--- a/tests/py/ip/meta.t
+++ b/tests/py/ip/meta.t
@@ -8,5 +8,15 @@ meta l4proto ipv6-icmp icmpv6 type nd-router-advert;ok;icmpv6 type nd-router-adv
meta l4proto 58 icmpv6 type nd-router-advert;ok;icmpv6 type nd-router-advert
icmpv6 type nd-router-advert;ok
+meta protocol ip udp dport 67;ok;udp dport 67
+
meta ibrname "br0";fail
meta obrname "br0";fail
+
+meta sdif "lo" accept;ok
+meta sdifname != "vrf1" accept;ok
+
+meta mark set ip dscp;ok
+
+meta mark set ip dscp << 2 | 0x10;ok
+meta mark set ip dscp << 26 | 0x10;ok
diff --git a/tests/py/ip/meta.t.json b/tests/py/ip/meta.t.json
index f873aa88..25936dba 100644
--- a/tests/py/ip/meta.t.json
+++ b/tests/py/ip/meta.t.json
@@ -105,3 +105,132 @@
}
]
+# meta sdif "lo" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "sdif"
+ }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta sdifname != "vrf1" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "sdifname"
+ }
+ },
+ "op": "!=",
+ "right": "vrf1"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta protocol ip udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
+# meta mark set ip dscp
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ }
+ }
+ }
+]
+
+# meta mark set ip dscp << 2 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+
+# meta mark set ip dscp << 26 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
diff --git a/tests/py/ip/meta.t.payload b/tests/py/ip/meta.t.payload
index 322c0878..880ac5d6 100644
--- a/tests/py/ip/meta.t.payload
+++ b/tests/py/ip/meta.t.payload
@@ -33,3 +33,46 @@ ip test-ip4 input
[ payload load 1b @ transport header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000086 ]
+# meta sdif "lo" accept
+ip6 test-ip4 input
+ [ meta load sdif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# meta sdifname != "vrf1" accept
+ip6 test-ip4 input
+ [ meta load sdifname => reg 1 ]
+ [ cmp neq reg 1 0x31667276 0x00000000 0x00000000 0x00000000 ]
+ [ immediate reg 0 accept ]
+
+# meta protocol ip udp dport 67
+ip test-ip4 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
+
+# meta mark set ip dscp
+ip test-ip4 input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip dscp << 2 | 0x10
+ip test-ip4 input
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip dscp << 26 | 0x10
+ip
+ [ payload load 1b @ network header + 1 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x0000001a ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ meta set mark with reg 1 ]
diff --git a/tests/py/ip/numgen.t b/tests/py/ip/numgen.t
index 29a6a105..2a881460 100644
--- a/tests/py/ip/numgen.t
+++ b/tests/py/ip/numgen.t
@@ -5,3 +5,5 @@ ct mark set numgen inc mod 2;ok
ct mark set numgen inc mod 2 offset 100;ok
dnat to numgen inc mod 2 map { 0 : 192.168.10.100, 1 : 192.168.20.200 };ok
dnat to numgen inc mod 10 map { 0-5 : 192.168.10.100, 6-9 : 192.168.20.200};ok
+dnat to numgen inc mod 7 offset 167772161;ok
+dnat to numgen inc mod 255 offset 167772161;ok
diff --git a/tests/py/ip/numgen.t.json b/tests/py/ip/numgen.t.json
index 9902c2cf..6cf66041 100644
--- a/tests/py/ip/numgen.t.json
+++ b/tests/py/ip/numgen.t.json
@@ -97,3 +97,33 @@
}
]
+# dnat to numgen inc mod 7 offset 167772161
+[
+ {
+ "dnat": {
+ "addr": {
+ "numgen": {
+ "mod": 7,
+ "mode": "inc",
+ "offset": 167772161
+ }
+ }
+ }
+ }
+]
+
+# dnat to numgen inc mod 255 offset 167772161
+[
+ {
+ "dnat": {
+ "addr": {
+ "numgen": {
+ "mod": 255,
+ "mode": "inc",
+ "offset": 167772161
+ }
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip/numgen.t.payload b/tests/py/ip/numgen.t.payload
index 04088b75..b4eadf85 100644
--- a/tests/py/ip/numgen.t.payload
+++ b/tests/py/ip/numgen.t.payload
@@ -10,7 +10,7 @@ __map%d x 0
ip test-ip4 pre
[ numgen reg 1 = inc mod 2 ]
[ lookup reg 1 set __map%d dreg 1 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
# dnat to numgen inc mod 10 map { 0-5 : 192.168.10.100, 6-9 : 192.168.20.200}
__map%d test-ip4 f
@@ -20,10 +20,21 @@ ip test-ip4 pre
[ numgen reg 1 = inc mod 10 ]
[ byteorder reg 1 = hton(reg 1, 4, 4) ]
[ lookup reg 1 set __map%d dreg 1 ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 ]
# ct mark set numgen inc mod 2 offset 100
ip test-ip4 pre
[ numgen reg 1 = inc mod 2 offset 100 ]
[ ct set mark with reg 1 ]
+# dnat to numgen inc mod 7 offset 167772161
+ip test-ip4 pre
+ [ numgen reg 1 = inc mod 7 offset 167772161 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ nat dnat ip addr_min reg 1 ]
+
+# dnat to numgen inc mod 255 offset 167772161
+ip test-ip4 pre
+ [ numgen reg 1 = inc mod 255 offset 167772161 ]
+ [ byteorder reg 1 = hton(reg 1, 4, 4) ]
+ [ nat dnat ip addr_min reg 1 ]
diff --git a/tests/py/ip/redirect.t b/tests/py/ip/redirect.t
index d2991ce2..8c2b52f0 100644
--- a/tests/py/ip/redirect.t
+++ b/tests/py/ip/redirect.t
@@ -47,5 +47,5 @@ ip daddr 10.0.0.0-10.2.3.4 udp dport 53 counter redirect;ok
iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } redirect;ok
# redirect with maps
-ip protocol 6 redirect to :tcp dport map { 22 : 8000, 80 : 8080};ok
+redirect to :tcp dport map { 22 : 8000, 80 : 8080};ok
diff --git a/tests/py/ip/redirect.t.json b/tests/py/ip/redirect.t.json
index 3544e7f1..2afdf9b1 100644
--- a/tests/py/ip/redirect.t.json
+++ b/tests/py/ip/redirect.t.json
@@ -593,21 +593,9 @@
}
]
-# ip protocol 6 redirect to :tcp dport map { 22 : 8000, 80 : 8080}
+# redirect to :tcp dport map { 22 : 8000, 80 : 8080}
[
{
- "match": {
- "left": {
- "payload": {
- "field": "protocol",
- "protocol": "ip"
- }
- },
- "op": "==",
- "right": 6
- }
- },
- {
"redirect": {
"port": {
"map": {
diff --git a/tests/py/ip/redirect.t.payload b/tests/py/ip/redirect.t.payload
index f208aacb..4bed47c1 100644
--- a/tests/py/ip/redirect.t.payload
+++ b/tests/py/ip/redirect.t.payload
@@ -93,7 +93,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00001600 ]
[ immediate reg 1 0x00001600 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# udp dport 1234 redirect to :4321
ip test-ip4 output
@@ -102,7 +102,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000d204 ]
[ immediate reg 1 0x0000e110 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# ip daddr 172.16.0.1 udp dport 9998 redirect to :6515
ip test-ip4 output
@@ -113,7 +113,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00000e27 ]
[ immediate reg 1 0x00007319 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# tcp dport 39128 redirect to :993
ip test-ip4 output
@@ -122,7 +122,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000d898 ]
[ immediate reg 1 0x0000e103 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# ip protocol tcp redirect to :100-200
ip test-ip4 output
@@ -130,7 +130,7 @@ ip test-ip4 output
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x00006400 ]
[ immediate reg 2 0x0000c800 ]
- [ redir proto_min reg 1 proto_max reg 2 ]
+ [ redir proto_min reg 1 proto_max reg 2 flags 0x2 ]
# tcp dport 9128 redirect to :993 random
ip test-ip4 output
@@ -139,7 +139,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000a823 ]
[ immediate reg 1 0x0000e103 ]
- [ redir proto_min reg 1 flags 0x4 ]
+ [ redir proto_min reg 1 flags 0x6 ]
# tcp dport 9128 redirect to :993 fully-random
ip test-ip4 output
@@ -148,7 +148,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000a823 ]
[ immediate reg 1 0x0000e103 ]
- [ redir proto_min reg 1 flags 0x10 ]
+ [ redir proto_min reg 1 flags 0x12 ]
# tcp dport 9128 redirect to :123 persistent
ip test-ip4 output
@@ -157,7 +157,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000a823 ]
[ immediate reg 1 0x00007b00 ]
- [ redir proto_min reg 1 flags 0x8 ]
+ [ redir proto_min reg 1 flags 0xa ]
# tcp dport 9128 redirect to :123 random,persistent
ip test-ip4 output
@@ -166,7 +166,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000a823 ]
[ immediate reg 1 0x00007b00 ]
- [ redir proto_min reg 1 flags 0xc ]
+ [ redir proto_min reg 1 flags 0xe ]
# tcp dport { 1, 2, 3, 4, 5, 6, 7, 8, 101, 202, 303, 1001, 2002, 3003} redirect
__set%d test-ip4 3
@@ -194,12 +194,12 @@ ip test-ip4 output
# iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } redirect
__map%d test-ip4 b
__map%d test-ip4 0
- element 00001600 : 0 [end] element 0000de00 : 0 [end]
+ element 00001600 : drop 0 [end] element 0000de00 : drop 0 [end]
ip test-ip4 output
[ meta load iifname => reg 1 ]
[ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
[ ct load state => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000a ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000a ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000000 ]
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -207,14 +207,14 @@ ip test-ip4 output
[ lookup reg 1 set __map%d dreg 0 ]
[ redir ]
-# ip protocol 6 redirect to :tcp dport map { 22 : 8000, 80 : 8080}
+# redirect to :tcp dport map { 22 : 8000, 80 : 8080}
__map%d test-ip4 b
__map%d test-ip4 0
element 00001600 : 0000401f 0 [end] element 00005000 : 0000901f 0 [end]
ip test-ip4 output
- [ payload load 1b @ network header + 9 => reg 1 ]
+ [ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __map%d dreg 1 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
diff --git a/tests/py/ip/reject.t b/tests/py/ip/reject.t
index cc5561a0..ad009944 100644
--- a/tests/py/ip/reject.t
+++ b/tests/py/ip/reject.t
@@ -3,14 +3,15 @@
*ip;test-ip4;output
reject;ok
-reject with icmp type host-unreachable;ok
-reject with icmp type net-unreachable;ok
-reject with icmp type prot-unreachable;ok
-reject with icmp type port-unreachable;ok;reject
-reject with icmp type net-prohibited;ok
-reject with icmp type host-prohibited;ok
-reject with icmp type admin-prohibited;ok
+reject with icmp host-unreachable;ok
+reject with icmp net-unreachable;ok
+reject with icmp prot-unreachable;ok
+reject with icmp port-unreachable;ok;reject
+reject with icmp net-prohibited;ok
+reject with icmp host-prohibited;ok
+reject with icmp admin-prohibited;ok
+reject with icmp 3;ok;reject
mark 0x80000000 reject with tcp reset;ok;meta mark 0x80000000 reject with tcp reset
-reject with icmp type no-route;fail
-reject with icmpv6 type no-route;fail
+reject with icmp no-route;fail
+reject with icmpv6 no-route;fail
diff --git a/tests/py/ip/reject.t.json b/tests/py/ip/reject.t.json
index d120b9f1..3e1d28de 100644
--- a/tests/py/ip/reject.t.json
+++ b/tests/py/ip/reject.t.json
@@ -5,7 +5,7 @@
}
]
-# reject with icmp type host-unreachable
+# reject with icmp host-unreachable
[
{
"reject": {
@@ -15,7 +15,7 @@
}
]
-# reject with icmp type net-unreachable
+# reject with icmp net-unreachable
[
{
"reject": {
@@ -25,7 +25,7 @@
}
]
-# reject with icmp type prot-unreachable
+# reject with icmp prot-unreachable
[
{
"reject": {
@@ -35,7 +35,7 @@
}
]
-# reject with icmp type port-unreachable
+# reject with icmp port-unreachable
[
{
"reject": {
@@ -45,7 +45,7 @@
}
]
-# reject with icmp type net-prohibited
+# reject with icmp net-prohibited
[
{
"reject": {
@@ -55,7 +55,7 @@
}
]
-# reject with icmp type host-prohibited
+# reject with icmp host-prohibited
[
{
"reject": {
@@ -65,7 +65,7 @@
}
]
-# reject with icmp type admin-prohibited
+# reject with icmp admin-prohibited
[
{
"reject": {
@@ -75,6 +75,16 @@
}
]
+# reject with icmp 3
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
# mark 0x80000000 reject with tcp reset
[
{
diff --git a/tests/py/ip/reject.t.json.output b/tests/py/ip/reject.t.json.output
index b2529dd7..3917413d 100644
--- a/tests/py/ip/reject.t.json.output
+++ b/tests/py/ip/reject.t.json.output
@@ -1,7 +1,10 @@
-# reject with icmp type port-unreachable
+# reject
[
{
- "reject": null
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
}
]
diff --git a/tests/py/ip/reject.t.payload b/tests/py/ip/reject.t.payload
index 07e4cc8d..5829065a 100644
--- a/tests/py/ip/reject.t.payload
+++ b/tests/py/ip/reject.t.payload
@@ -2,34 +2,38 @@
ip test-ip4 output
[ reject type 0 code 3 ]
-# reject with icmp type host-unreachable
+# reject with icmp host-unreachable
ip test-ip4 output
[ reject type 0 code 1 ]
-# reject with icmp type net-unreachable
+# reject with icmp net-unreachable
ip test-ip4 output
[ reject type 0 code 0 ]
-# reject with icmp type prot-unreachable
+# reject with icmp prot-unreachable
ip test-ip4 output
[ reject type 0 code 2 ]
-# reject with icmp type port-unreachable
+# reject with icmp port-unreachable
ip test-ip4 output
[ reject type 0 code 3 ]
-# reject with icmp type net-prohibited
+# reject with icmp net-prohibited
ip test-ip4 output
[ reject type 0 code 9 ]
-# reject with icmp type host-prohibited
+# reject with icmp host-prohibited
ip test-ip4 output
[ reject type 0 code 10 ]
-# reject with icmp type admin-prohibited
+# reject with icmp admin-prohibited
ip test-ip4 output
[ reject type 0 code 13 ]
+# reject with icmp 3
+ip test-ip4 output
+ [ reject type 0 code 3 ]
+
# mark 0x80000000 reject with tcp reset
ip test-ip4 output
[ meta load l4proto => reg 1 ]
diff --git a/tests/py/ip/sets.t b/tests/py/ip/sets.t
index 7b7e0722..46d9686b 100644
--- a/tests/py/ip/sets.t
+++ b/tests/py/ip/sets.t
@@ -1,9 +1,10 @@
: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
*inet;test-inet;input
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
!w type ipv4_addr;ok
!x type inet_proto;ok
@@ -51,6 +52,17 @@ ip saddr != @set33 drop;fail
ip saddr . ip daddr @set5 drop;ok
add @set5 { ip saddr . ip daddr };ok
+!map1 type ipv4_addr . ipv4_addr : mark;ok
+add @map1 { ip saddr . ip daddr : meta mark };ok
+
# test nested anonymous sets
ip saddr { { 1.1.1.0, 3.3.3.0 }, 2.2.2.0 };ok;ip saddr { 1.1.1.0, 2.2.2.0, 3.3.3.0 }
ip saddr { { 1.1.1.0/24, 3.3.3.0/24 }, 2.2.2.0/24 };ok;ip saddr { 1.1.1.0/24, 2.2.2.0/24, 3.3.3.0/24 }
+
+!set6 type ipv4_addr;ok
+?set6 192.168.3.5, *;ok
+ip saddr @set6 drop;ok
+
+ip saddr vmap { 1.1.1.1 : drop, * : accept };ok
+meta mark set ip saddr map { 1.1.1.1 : 0x00000001, * : 0x00000002 };ok
+
diff --git a/tests/py/ip/sets.t.json b/tests/py/ip/sets.t.json
index 65d2df87..44ca1528 100644
--- a/tests/py/ip/sets.t.json
+++ b/tests/py/ip/sets.t.json
@@ -188,3 +188,118 @@
}
]
+# ip saddr @set6 drop
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ "op": "==",
+ "right": "@set6"
+ }
+ },
+ {
+ "drop": null
+ }
+]
+
+# ip saddr vmap { 1.1.1.1 : drop, * : accept }
+[
+ {
+ "vmap": {
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "*",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ }
+]
+
+# meta mark set ip saddr map { 1.1.1.1 : 0x00000001, * : 0x00000002 }
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ 1
+ ],
+ [
+ "*",
+ 2
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ }
+ }
+ }
+]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+[
+ {
+ "map": {
+ "data": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "elem": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ }
+ ]
+ },
+ "map": "@map1",
+ "op": "add"
+ }
+ }
+]
+
diff --git a/tests/py/ip/sets.t.payload.inet b/tests/py/ip/sets.t.payload.inet
index fa956c0c..fd6517a5 100644
--- a/tests/py/ip/sets.t.payload.inet
+++ b/tests/py/ip/sets.t.payload.inet
@@ -66,3 +66,41 @@ inet test-inet input
[ cmp eq reg 1 0x00000002 ]
[ payload load 4b @ network header + 12 => reg 1 ]
[ lookup reg 1 set __set%d ]
+
+# ip saddr @set6 drop
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set6 ]
+ [ immediate reg 0 drop ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ meta load mark => reg 10 ]
+ [ dynset add reg_key 1 set map1 sreg_data 10 ]
+
+# ip saddr vmap { 1.1.1.1 : drop, * : accept }
+__map%d test-inet b
+__map%d test-inet 0
+ element 01010101 : drop 0 [end] element : accept 2 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# meta mark set ip saddr map { 1.1.1.1 : 0x00000001, * : 0x00000002 }
+__map%d test-inet b
+__map%d test-inet 0
+ element 01010101 : 00000001 0 [end] element : 00000002 2 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
diff --git a/tests/py/ip/sets.t.payload.ip b/tests/py/ip/sets.t.payload.ip
index ca3b5ade..d9cc32b6 100644
--- a/tests/py/ip/sets.t.payload.ip
+++ b/tests/py/ip/sets.t.payload.ip
@@ -50,3 +50,34 @@ __set%d test-ip4 0
ip test-ip4 input
[ payload load 4b @ network header + 12 => reg 1 ]
[ lookup reg 1 set __set%d ]
+
+# ip saddr @set6 drop
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set6 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr vmap { 1.1.1.1 : drop, * : accept }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 01010101 : drop 0 [end] element : accept 2 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# meta mark set ip saddr map { 1.1.1.1 : 0x00000001, * : 0x00000002 }
+__map%d test-ip4 b
+__map%d test-ip4 0
+ element 01010101 : 00000001 0 [end] element : 00000002 2 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+ip test-ip4 input
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ meta load mark => reg 10 ]
+ [ dynset add reg_key 1 set map1 sreg_data 10 ]
+
diff --git a/tests/py/ip/sets.t.payload.netdev b/tests/py/ip/sets.t.payload.netdev
index 9772d756..d41b9e8b 100644
--- a/tests/py/ip/sets.t.payload.netdev
+++ b/tests/py/ip/sets.t.payload.netdev
@@ -66,3 +66,42 @@ netdev test-netdev ingress
[ cmp eq reg 1 0x00000008 ]
[ payload load 4b @ network header + 12 => reg 1 ]
[ lookup reg 1 set __set%d ]
+
+# ip saddr @set6 drop
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set set6 ]
+ [ immediate reg 0 drop ]
+
+# ip saddr vmap { 1.1.1.1 : drop, * : accept }
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 01010101 : drop 0 [end] element : accept 2 [end]
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 0 ]
+
+# meta mark set ip saddr map { 1.1.1.1 : 0x00000001, * : 0x00000002 }
+__map%d test-netdev b
+__map%d test-netdev 0
+ element 01010101 : 00000001 0 [end] element : 00000002 2 [end]
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# add @map1 { ip saddr . ip daddr : meta mark }
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ meta load mark => reg 10 ]
+ [ dynset add reg_key 1 set map1 sreg_data 10 ]
+
diff --git a/tests/py/ip/snat.t b/tests/py/ip/snat.t
index 7281bf5f..d4b0d2cb 100644
--- a/tests/py/ip/snat.t
+++ b/tests/py/ip/snat.t
@@ -6,5 +6,16 @@ iifname "eth0" tcp dport 80-90 snat to 192.168.3.2;ok
iifname "eth0" tcp dport != 80-90 snat to 192.168.3.2;ok
iifname "eth0" tcp dport {80, 90, 23} snat to 192.168.3.2;ok
iifname "eth0" tcp dport != {80, 90, 23} snat to 192.168.3.2;ok
+iifname "eth0" tcp dport 80-90 snat to 192.168.3.0-192.168.3.255;ok;iifname "eth0" tcp dport 80-90 snat to 192.168.3.0/24
+iifname "eth0" tcp dport 80-90 snat to 192.168.3.15-192.168.3.240;ok
iifname "eth0" tcp dport != 23-34 snat to 192.168.3.2;ok
+
+meta l4proto 17 snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 };ok
+snat ip to ip saddr map { 10.141.11.4 : 192.168.2.2-192.168.2.4 };ok
+snat ip to ip saddr map { 10.141.12.14 : 192.168.2.0/24 };ok
+snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 };ok
+
+meta l4proto { 6, 17} snat ip to ip saddr . th dport map { 10.141.11.4 . 20 : 192.168.2.3 . 80};ok
+snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 };fail
+snat ip to ip saddr . th dport map { 10.141.11.4 . 20 : 192.168.2.3 . 80 };fail
diff --git a/tests/py/ip/snat.t.json b/tests/py/ip/snat.t.json
index e87b524e..967560e6 100644
--- a/tests/py/ip/snat.t.json
+++ b/tests/py/ip/snat.t.json
@@ -166,3 +166,365 @@
}
]
+# iifname "eth0" tcp dport 80-90 snat to 192.168.3.0-192.168.3.255
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 80,
+ 90
+ ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "prefix": {
+ "addr": "192.168.3.0",
+ "len": 24
+ }
+ }
+ }
+ }
+]
+
+# iifname "eth0" tcp dport 80-90 snat to 192.168.3.15-192.168.3.240
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "op": "==",
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 80,
+ 90
+ ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "range": [
+ "192.168.3.15",
+ "192.168.3.240"
+ ]
+ }
+ }
+ }
+]
+
+# snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.11.4",
+ {
+ "concat": [
+ "192.168.2.3",
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip",
+ "type_flags": "concat"
+ }
+ }
+]
+
+# snat ip interval to ip saddr map { 10.141.11.4 : 192.168.2.2-192.168.2.4 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.11.4",
+ {
+ "range": [
+ "192.168.2.2",
+ "192.168.2.4"
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip",
+ "type_flags": "interval"
+ }
+ }
+]
+
+# snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "prefix": {
+ "addr": "10.141.11.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "192.168.2.0",
+ "len": 24
+ }
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip",
+ "flags": "netmap",
+ "type_flags": [
+ "interval",
+ "prefix"
+ ]
+ }
+ }
+]
+
+# meta l4proto 17 snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": "udp"
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.11.4",
+ {
+ "concat": [
+ "192.168.2.3",
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# snat ip to ip saddr map { 10.141.11.4 : 192.168.2.2-192.168.2.4 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.11.4",
+ {
+ "range": [
+ "192.168.2.2",
+ "192.168.2.4"
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# snat ip to ip saddr map { 10.141.12.14 : 192.168.2.0/24 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.12.14",
+ {
+ "prefix": {
+ "addr": "192.168.2.0",
+ "len": 24
+ }
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# meta l4proto { 6, 17} snat ip to ip saddr . th dport map { 10.141.11.4 . 20 : 192.168.2.3 . 80}
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "tcp",
+ "udp"
+ ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "10.141.11.4",
+ 20
+ ]
+ },
+ {
+ "concat": [
+ "192.168.2.3",
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "th"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
diff --git a/tests/py/ip/snat.t.json.output b/tests/py/ip/snat.t.json.output
index 1365316c..2a997801 100644
--- a/tests/py/ip/snat.t.json.output
+++ b/tests/py/ip/snat.t.json.output
@@ -70,3 +70,180 @@
}
]
+# snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.11.4",
+ {
+ "concat": [
+ "192.168.2.3",
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# meta l4proto 17 snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 }
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 17
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ "10.141.11.4",
+ {
+ "concat": [
+ "192.168.2.3",
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# meta l4proto { 6, 17} snat ip to ip saddr . th dport map { 10.141.11.4 . 20 : 192.168.2.3 . 80}
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 6,
+ 17
+ ]
+ }
+ }
+ },
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "10.141.11.4",
+ 20
+ ]
+ },
+ {
+ "concat": [
+ "192.168.2.3",
+ 80
+ ]
+ }
+ ]
+ ]
+ },
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "th"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "family": "ip"
+ }
+ }
+]
+
+# snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 }
+[
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "data": {
+ "set": [
+ [
+ {
+ "prefix": {
+ "addr": "10.141.11.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "192.168.2.0",
+ "len": 24
+ }
+ }
+ ]
+ ]
+ },
+ "key": {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ }
+ }
+ },
+ "family": "ip",
+ "flags": "netmap",
+ "type_flags": "prefix"
+ }
+ }
+]
+
diff --git a/tests/py/ip/snat.t.payload b/tests/py/ip/snat.t.payload
index 789933ff..71a5e2f1 100644
--- a/tests/py/ip/snat.t.payload
+++ b/tests/py/ip/snat.t.payload
@@ -8,7 +8,7 @@ ip test-ip4 postrouting
[ cmp gte reg 1 0x00005000 ]
[ cmp lte reg 1 0x00005a00 ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat snat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat snat ip addr_min reg 1 ]
# iifname "eth0" tcp dport != 80-90 snat to 192.168.3.2
ip test-ip4 postrouting
@@ -19,7 +19,7 @@ ip test-ip4 postrouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ range neq reg 1 0x00005000 0x00005a00 ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat snat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat snat ip addr_min reg 1 ]
# iifname "eth0" tcp dport {80, 90, 23} snat to 192.168.3.2
__set%d test-ip4 3
@@ -33,7 +33,7 @@ ip test-ip4 postrouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat snat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat snat ip addr_min reg 1 ]
# iifname "eth0" tcp dport != {80, 90, 23} snat to 192.168.3.2
__set%d test-ip4 3
@@ -47,7 +47,7 @@ ip test-ip4 postrouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat snat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat snat ip addr_min reg 1 ]
# iifname "eth0" tcp dport != 23-34 snat to 192.168.3.2
ip test-ip4 postrouting
@@ -58,5 +58,97 @@ ip test-ip4 postrouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ range neq reg 1 0x00001700 0x00002200 ]
[ immediate reg 1 0x0203a8c0 ]
- [ nat snat ip addr_min reg 1 addr_max reg 0 ]
+ [ nat snat ip addr_min reg 1 ]
+
+# iifname "eth0" tcp dport 80-90 snat to 192.168.3.0-192.168.3.255
+ip
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00005000 ]
+ [ cmp lte reg 1 0x00005a00 ]
+ [ immediate reg 1 0x0003a8c0 ]
+ [ immediate reg 2 0xff03a8c0 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 2 ]
+
+# iifname "eth0" tcp dport 80-90 snat to 192.168.3.15-192.168.3.240
+ip
+ [ meta load iifname => reg 1 ]
+ [ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp gte reg 1 0x00005000 ]
+ [ cmp lte reg 1 0x00005a00 ]
+ [ immediate reg 1 0x0f03a8c0 ]
+ [ immediate reg 2 0xf003a8c0 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 2 ]
+
+# meta l4proto 17 snat ip to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 040b8d0a : 0302a8c0 00005000 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 proto_min reg 9 ]
+
+# snat ip to ip saddr map { 10.141.11.4 : 192.168.2.2-192.168.2.4 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 040b8d0a : 0202a8c0 0402a8c0 0 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 9 ]
+
+# snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 }
+__map%d test-ip4 f size 3
+__map%d test-ip4 0
+ element 00000000 : 1 [end] element 000b8d0a : 0002a8c0 ff02a8c0 0 [end] element 000c8d0a : 1 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 9 flags 0x40 ]
+
+# snat ip to ip saddr map { 10.141.12.14 : 192.168.2.0/24 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 0e0c8d0a : 0002a8c0 ff02a8c0 0 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 9 ]
+
+# meta l4proto { 6, 17} snat ip to ip saddr . th dport map { 10.141.11.4 . 20 : 192.168.2.3 . 80}
+__set%d test-ip4 3 size 2
+__set%d test-ip4 0
+ element 00000006 : 0 [end] element 00000011 : 0 [end]
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 040b8d0a 00001400 : 0302a8c0 00005000 0 [end]
+ip
+ [ meta load l4proto => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 proto_min reg 9 ]
+
+# ip daddr 192.168.0.1 dnat to tcp dport map { 443 : 10.141.10.4 . 8443, 80 : 10.141.10.4 . 8080 }
+__map%d x b size 2
+__map%d x 0
+ element 0000bb01 : 040a8d0a 0000fb20 0 [end] element 00005000 : 040a8d0a 0000901f 0 [end]
+ip
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ cmp eq reg 1 0x0100a8c0 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat dnat ip addr_min reg 1 proto_min reg 9 ]
diff --git a/tests/py/ip/tcpopt.t b/tests/py/ip/tcpopt.t
deleted file mode 100644
index 7ee50a89..00000000
--- a/tests/py/ip/tcpopt.t
+++ /dev/null
@@ -1,38 +0,0 @@
-:input;type filter hook input priority 0
-
-*ip;test-ip;input
-
-tcp option eol kind 1;ok
-tcp option noop kind 1;ok
-tcp option maxseg kind 1;ok
-tcp option maxseg length 1;ok
-tcp option maxseg size 1;ok
-tcp option window kind 1;ok
-tcp option window length 1;ok
-tcp option window count 1;ok
-tcp option sack-permitted kind 1;ok
-tcp option sack-permitted length 1;ok
-tcp option sack kind 1;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 kind 1;ok
-tcp option timestamp length 1;ok
-tcp option timestamp tsval 1;ok
-tcp option timestamp tsecr 1;ok
-
-tcp option foobar;fail
-tcp option foo bar;fail
-tcp option eol left;fail
-tcp option eol left 1;fail
-tcp option eol left 1;fail
-tcp option sack window;fail
-tcp option sack window 1;fail
diff --git a/tests/py/ip/tcpopt.t.json b/tests/py/ip/tcpopt.t.json
deleted file mode 100644
index d573dd1c..00000000
--- a/tests/py/ip/tcpopt.t.json
+++ /dev/null
@@ -1,416 +0,0 @@
-# tcp option eol kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "eol"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option noop kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "noop"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option maxseg kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "maxseg"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# 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 kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "window"
- }
- },
- "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-permitted kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "sack-permitted"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack-permitted length 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "length",
- "name": "sack-permitted"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# 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": "sack0"
- }
- },
- "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 kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "timestamp"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# 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
- }
- }
-]
-
diff --git a/tests/py/ip/tcpopt.t.json.output b/tests/py/ip/tcpopt.t.json.output
deleted file mode 100644
index 81dd8ad8..00000000
--- a/tests/py/ip/tcpopt.t.json.output
+++ /dev/null
@@ -1,16 +0,0 @@
-# tcp option sack0 right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
diff --git a/tests/py/ip/tcpopt.t.payload b/tests/py/ip/tcpopt.t.payload
deleted file mode 100644
index b2e5bdb2..00000000
--- a/tests/py/ip/tcpopt.t.payload
+++ /dev/null
@@ -1,181 +0,0 @@
-# tcp option eol kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option noop kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg length 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg size 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]
- [ cmp eq reg 1 0x00000100 ]
-
-# tcp option window kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window length 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window count 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack-permitted kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack-permitted length 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack length 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack left 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack0 left 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack1 left 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack2 left 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack3 left 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack right 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack0 right 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack1 right 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack2 right 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack3 right 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option timestamp length 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option timestamp tsval 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp tsecr 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
diff --git a/tests/py/ip6/ct.t b/tests/py/ip6/ct.t
new file mode 100644
index 00000000..c06fd6a0
--- /dev/null
+++ b/tests/py/ip6/ct.t
@@ -0,0 +1,9 @@
+:output;type filter hook output priority 0
+
+*ip6;test-ip6;output
+
+ct mark set ip6 dscp << 2 | 0x10;ok
+ct mark set ip6 dscp << 26 | 0x10;ok
+ct mark set ip6 dscp | 0x04;ok
+ct mark set ip6 dscp | 0xff000000;ok
+ct mark set ip6 dscp & 0x0f << 2;ok;ct mark set ip6 dscp & 0x3c
diff --git a/tests/py/ip6/ct.t.json b/tests/py/ip6/ct.t.json
new file mode 100644
index 00000000..7d8c88bb
--- /dev/null
+++ b/tests/py/ip6/ct.t.json
@@ -0,0 +1,293 @@
+# ct mark set ip6 dscp lshift 2 or 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip6 dscp lshift 26 or 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip6 dscp << 2 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip6 dscp << 26 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip6 dscp | 0x04
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip6 dscp | 0xff000000
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 4278190080
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip6 dscp << 2 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip6 dscp << 26 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip6 dscp | 0x04
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip6 dscp | 0xff000000
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 4278190080
+ ]
+ }
+ }
+ }
+]
+
+# ct mark set ip6 dscp & 0x0f << 2
+[
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "&": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 60
+ ]
+ }
+ }
+ }
+]
diff --git a/tests/py/ip6/ct.t.payload b/tests/py/ip6/ct.t.payload
new file mode 100644
index 00000000..944208f2
--- /dev/null
+++ b/tests/py/ip6/ct.t.payload
@@ -0,0 +1,46 @@
+# ct mark set ip6 dscp << 2 | 0x10
+ip6 test-ip6 output
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip6 dscp << 26 | 0x10
+ip6 test-ip6 output
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x0000001a ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip6 dscp | 0x04
+ip6 test-ip6 output
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xfffffffb ) ^ 0x00000004 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip6 dscp | 0xff000000
+ip6 test-ip6 output
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffffff ) ^ 0xff000000 ]
+ [ ct set mark with reg 1 ]
+
+# ct mark set ip6 dscp & 0x0f << 2
+ip6 test-ip6 output
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000003c ) ^ 0x00000000 ]
+ [ ct set mark with reg 1 ]
diff --git a/tests/py/ip6/dnat.t b/tests/py/ip6/dnat.t
index db5fde58..89d5a5f9 100644
--- a/tests/py/ip6/dnat.t
+++ b/tests/py/ip6/dnat.t
@@ -3,7 +3,7 @@
*ip6;test-ip6;prerouting
tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:80-100;ok
-tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:100;ok;tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:100
+tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:100;ok
tcp dport 80-90 dnat to [2001:838:35f:1::]:80;ok
-dnat to [2001:838:35f:1::]/64;ok;dnat to 2001:838:35f:1::-2001:838:35f:1:ffff:ffff:ffff:ffff
-dnat to 2001:838:35f:1::-2001:838:35f:1:ffff:ffff:ffff:ffff;ok
+dnat to [2001:838:35f:1::]/64;ok;dnat to 2001:838:35f:1::/64
+dnat to 2001:838:35f:1::-2001:838:35f:1:ffff:ffff:ffff:ffff;ok;dnat to 2001:838:35f:1::/64
diff --git a/tests/py/ip6/dnat.t.json b/tests/py/ip6/dnat.t.json
index 3419b60f..cbfdb68b 100644
--- a/tests/py/ip6/dnat.t.json
+++ b/tests/py/ip6/dnat.t.json
@@ -81,10 +81,10 @@
{
"dnat": {
"addr": {
- "range": [
- "2001:838:35f:1::",
- "2001:838:35f:1:ffff:ffff:ffff:ffff"
- ]
+ "prefix": {
+ "addr": "2001:838:35f:1::",
+ "len": 64
+ }
}
}
}
@@ -95,11 +95,12 @@
{
"dnat": {
"addr": {
- "range": [
- "2001:838:35f:1::",
- "2001:838:35f:1:ffff:ffff:ffff:ffff"
- ]
+ "prefix": {
+ "addr": "2001:838:35f:1::",
+ "len": 64
+ }
}
}
}
]
+
diff --git a/tests/py/ip6/dnat.t.payload.ip6 b/tests/py/ip6/dnat.t.payload.ip6
index 985159e2..004ffdeb 100644
--- a/tests/py/ip6/dnat.t.payload.ip6
+++ b/tests/py/ip6/dnat.t.payload.ip6
@@ -9,7 +9,7 @@ ip6 test-ip6 prerouting
[ immediate reg 2 0x38080120 0x02005f03 0x00000000 0x00000000 ]
[ immediate reg 3 0x00005000 ]
[ immediate reg 4 0x00006400 ]
- [ nat dnat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 4 ]
+ [ nat dnat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 4 flags 0x2 ]
# tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:100
ip6 test-ip6 prerouting
@@ -21,7 +21,7 @@ ip6 test-ip6 prerouting
[ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
[ immediate reg 2 0x38080120 0x02005f03 0x00000000 0x00000000 ]
[ immediate reg 3 0x00006400 ]
- [ nat dnat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 0 ]
+ [ nat dnat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 flags 0x2 ]
# tcp dport 80-90 dnat to [2001:838:35f:1::]:80
ip6 test-ip6 prerouting
@@ -32,7 +32,7 @@ ip6 test-ip6 prerouting
[ cmp lte reg 1 0x00005a00 ]
[ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
[ immediate reg 2 0x00005000 ]
- [ nat dnat ip6 addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 ]
+ [ nat dnat ip6 addr_min reg 1 proto_min reg 2 flags 0x2 ]
# dnat to [2001:838:35f:1::]/64
ip6 test-ip6 prerouting
diff --git a/tests/py/ip6/dst.t b/tests/py/ip6/dst.t
index 9e7c554f..cd1fd3b2 100644
--- a/tests/py/ip6/dst.t
+++ b/tests/py/ip6/dst.t
@@ -9,8 +9,6 @@ dst nexthdr 33-45;ok
dst nexthdr != 33-45;ok
dst nexthdr { 33, 55, 67, 88};ok
dst nexthdr != { 33, 55, 67, 88};ok
-dst nexthdr { 33-55};ok
-dst nexthdr != { 33-55};ok
dst nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp};ok;dst nexthdr { 51, 50, 17, 136, 58, 6, 33, 132, 108}
dst nexthdr != { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp};ok;dst nexthdr != { 51, 50, 17, 136, 58, 6, 33, 132, 108}
dst nexthdr icmp;ok;dst nexthdr 1
@@ -21,6 +19,3 @@ dst hdrlength != 233;ok
dst hdrlength 33-45;ok
dst hdrlength != 33-45;ok
dst hdrlength { 33, 55, 67, 88};ok
-dst hdrlength != { 33, 55, 67, 88};ok
-dst hdrlength { 33-55};ok
-dst hdrlength != { 33-55};ok
diff --git a/tests/py/ip6/dst.t.json b/tests/py/ip6/dst.t.json
index 1373e177..e947a76f 100644
--- a/tests/py/ip6/dst.t.json
+++ b/tests/py/ip6/dst.t.json
@@ -112,46 +112,6 @@
}
]
-# dst nexthdr { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "nexthdr",
- "name": "dst"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# dst nexthdr != { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "nexthdr",
- "name": "dst"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# dst nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
[
{
@@ -353,44 +313,3 @@
}
}
]
-
-# dst hdrlength { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "hdrlength",
- "name": "dst"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# dst hdrlength != { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "hdrlength",
- "name": "dst"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
diff --git a/tests/py/ip6/dst.t.payload.inet b/tests/py/ip6/dst.t.payload.inet
index ff22237e..90d6bda1 100644
--- a/tests/py/ip6/dst.t.payload.inet
+++ b/tests/py/ip6/dst.t.payload.inet
@@ -47,26 +47,6 @@ inet test-inet input
[ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# dst nexthdr { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# dst nexthdr != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# dst nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
__set%d test-inet 3
__set%d test-inet 0
@@ -149,24 +129,3 @@ ip6 test-ip6 input
[ cmp eq reg 1 0x0000000a ]
[ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-
-# dst hdrlength { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# dst hdrlength != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
diff --git a/tests/py/ip6/dst.t.payload.ip6 b/tests/py/ip6/dst.t.payload.ip6
index 9bf564cb..941140d0 100644
--- a/tests/py/ip6/dst.t.payload.ip6
+++ b/tests/py/ip6/dst.t.payload.ip6
@@ -35,22 +35,6 @@ ip6 test-ip6 input
[ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# dst nexthdr { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# dst nexthdr != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 60 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# dst nexthdr { udplite, ipcomp, udp, ah, sctp, esp, dccp, tcp, ipv6-icmp}
__set%d test-ip6 3
__set%d test-ip6 0
@@ -113,21 +97,3 @@ __set%d test-ip6 0
ip6 test-ip6 input
[ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-
-# dst hdrlength { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# dst hdrlength != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 60 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-
diff --git a/tests/py/ip6/ether.t b/tests/py/ip6/ether.t
index d94a0d21..49d7d063 100644
--- a/tests/py/ip6/ether.t
+++ b/tests/py/ip6/ether.t
@@ -3,6 +3,6 @@
*ip6;test-ip6;input
tcp dport 22 iiftype ether ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:4 accept;ok;tcp dport 22 ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:04 accept
-tcp dport 22 ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:04;ok;tcp dport 22 ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:04
+tcp dport 22 ip6 daddr 1::2 ether saddr 00:0f:54:0c:11:04;ok
tcp dport 22 ether saddr 00:0f:54:0c:11:04 ip6 daddr 1::2;ok
ether saddr 00:0f:54:0c:11:04 ip6 daddr 1::2 accept;ok
diff --git a/tests/py/ip6/exthdr.t.json.output b/tests/py/ip6/exthdr.t.json.output
index c9f5b49b..813402a2 100644
--- a/tests/py/ip6/exthdr.t.json.output
+++ b/tests/py/ip6/exthdr.t.json.output
@@ -1,33 +1,3 @@
-# exthdr hbh == exists
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "name": "hbh"
- }
- },
- "op": "==",
- "right": true
- }
- }
-]
-
-# exthdr hbh == missing
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "name": "hbh"
- }
- },
- "op": "==",
- "right": false
- }
- }
-]
-
# exthdr hbh 1
[
{
diff --git a/tests/py/ip6/flowtable.t b/tests/py/ip6/flowtable.t
deleted file mode 100644
index e58d51bb..00000000
--- a/tests/py/ip6/flowtable.t
+++ /dev/null
@@ -1,6 +0,0 @@
-:input;type filter hook input priority 0
-
-*ip6;test-ip6;input
-
-meter acct_out size 4096 { meta iif . ip6 saddr timeout 600s counter };ok;meter acct_out size 4096 { iif . ip6 saddr timeout 10m counter }
-meter acct_out size 12345 { ip6 saddr . meta iif timeout 600s counter };ok;meter acct_out size 12345 { ip6 saddr . iif timeout 10m counter }
diff --git a/tests/py/ip6/flowtable.t.json b/tests/py/ip6/flowtable.t.json
deleted file mode 100644
index d0b3a957..00000000
--- a/tests/py/ip6/flowtable.t.json
+++ /dev/null
@@ -1,62 +0,0 @@
-# meter acct_out size 4096 { meta iif . ip6 saddr timeout 600s counter }
-[
- {
- "meter": {
- "key": {
- "elem": {
- "timeout": 600,
- "val": {
- "concat": [
- {
- "meta": { "key": "iif" }
- },
- {
- "payload": {
- "field": "saddr",
- "protocol": "ip6"
- }
- }
- ]
- }
- }
- },
- "name": "acct_out",
- "size": 4096,
- "stmt": {
- "counter": null
- }
- }
- }
-]
-
-# meter acct_out size 12345 { ip6 saddr . meta iif timeout 600s counter }
-[
- {
- "meter": {
- "key": {
- "elem": {
- "timeout": 600,
- "val": {
- "concat": [
- {
- "payload": {
- "field": "saddr",
- "protocol": "ip6"
- }
- },
- {
- "meta": { "key": "iif" }
- }
- ]
- }
- }
- },
- "name": "acct_out",
- "size": 12345,
- "stmt": {
- "counter": null
- }
- }
- }
-]
-
diff --git a/tests/py/ip6/flowtable.t.json.output b/tests/py/ip6/flowtable.t.json.output
deleted file mode 100644
index d0b3a957..00000000
--- a/tests/py/ip6/flowtable.t.json.output
+++ /dev/null
@@ -1,62 +0,0 @@
-# meter acct_out size 4096 { meta iif . ip6 saddr timeout 600s counter }
-[
- {
- "meter": {
- "key": {
- "elem": {
- "timeout": 600,
- "val": {
- "concat": [
- {
- "meta": { "key": "iif" }
- },
- {
- "payload": {
- "field": "saddr",
- "protocol": "ip6"
- }
- }
- ]
- }
- }
- },
- "name": "acct_out",
- "size": 4096,
- "stmt": {
- "counter": null
- }
- }
- }
-]
-
-# meter acct_out size 12345 { ip6 saddr . meta iif timeout 600s counter }
-[
- {
- "meter": {
- "key": {
- "elem": {
- "timeout": 600,
- "val": {
- "concat": [
- {
- "payload": {
- "field": "saddr",
- "protocol": "ip6"
- }
- },
- {
- "meta": { "key": "iif" }
- }
- ]
- }
- }
- },
- "name": "acct_out",
- "size": 12345,
- "stmt": {
- "counter": null
- }
- }
- }
-]
-
diff --git a/tests/py/ip6/flowtable.t.payload b/tests/py/ip6/flowtable.t.payload
deleted file mode 100644
index 559475f6..00000000
--- a/tests/py/ip6/flowtable.t.payload
+++ /dev/null
@@ -1,16 +0,0 @@
-# meter acct_out size 4096 { meta iif . ip6 saddr timeout 600s counter }
-acct_out test-ip6 31
-acct_out test-ip6 0
-ip6 test-ip6 input
- [ meta load iif => reg 1 ]
- [ payload load 16b @ network header + 8 => reg 9 ]
- [ dynset update reg_key 1 set acct_out timeout 600000ms expr [ counter pkts 0 bytes 0 ] ]
-
-# meter acct_out size 12345 { ip6 saddr . meta iif timeout 600s counter }
-acct_out test-ip6 31
-acct_out test-ip6 0
-ip6 test-ip6 input
- [ payload load 16b @ network header + 8 => reg 1 ]
- [ meta load iif => reg 2 ]
- [ dynset update reg_key 1 set acct_out timeout 600000ms expr [ counter pkts 0 bytes 0 ] ]
-
diff --git a/tests/py/ip6/frag.t b/tests/py/ip6/frag.t
index e16529ad..6bbd6ac0 100644
--- a/tests/py/ip6/frag.t
+++ b/tests/py/ip6/frag.t
@@ -1,8 +1,10 @@
: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
*ip6;test-ip6;output
*inet;test-inet;output
+*netdev;test-netdev;ingress,egress
frag nexthdr tcp;ok;frag nexthdr 6
frag nexthdr != icmp;ok;frag nexthdr != 1
@@ -17,8 +19,6 @@ frag reserved 33-45;ok
frag reserved != 33-45;ok
frag reserved { 33, 55, 67, 88};ok
frag reserved != { 33, 55, 67, 88};ok
-frag reserved { 33-55};ok
-frag reserved != { 33-55};ok
frag frag-off 22;ok
frag frag-off != 233;ok
@@ -26,8 +26,6 @@ frag frag-off 33-45;ok
frag frag-off != 33-45;ok
frag frag-off { 33, 55, 67, 88};ok
frag frag-off != { 33, 55, 67, 88};ok
-frag frag-off { 33-55};ok
-frag frag-off != { 33-55};ok
frag reserved2 1;ok
frag more-fragments 0;ok
@@ -40,5 +38,3 @@ frag id 33-45;ok
frag id != 33-45;ok
frag id { 33, 55, 67, 88};ok
frag id != { 33, 55, 67, 88};ok
-frag id { 33-55};ok
-frag id != { 33-55};ok
diff --git a/tests/py/ip6/frag.t.payload.inet b/tests/py/ip6/frag.t.payload.inet
index ef44f1ae..20334f44 100644
--- a/tests/py/ip6/frag.t.payload.inet
+++ b/tests/py/ip6/frag.t.payload.inet
@@ -95,32 +95,12 @@ inet test-inet output
[ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# frag reserved { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet output
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# frag reserved != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet output
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# frag frag-off 22
inet test-inet output
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000b000 ]
# frag frag-off != 233
@@ -128,7 +108,7 @@ inet test-inet output
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00004807 ]
# frag frag-off 33-45
@@ -136,7 +116,7 @@ inet test-inet output
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
[ cmp gte reg 1 0x00000801 ]
[ cmp lte reg 1 0x00006801 ]
@@ -145,7 +125,7 @@ inet test-inet output
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
[ range neq reg 1 0x00000801 0x00006801 ]
# frag frag-off { 33, 55, 67, 88}
@@ -156,7 +136,7 @@ inet test-inet output
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
# frag frag-off != { 33, 55, 67, 88}
@@ -167,39 +147,9 @@ inet test-inet output
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d 0x1 ]
-# frag frag-off { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-inet test-inet output
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
- [ lookup reg 1 set __set%d ]
-
-# frag frag-off != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-inet test-inet output
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# frag more-fragments 1
-inet test-inet output
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000001 ) ^ 0x00000000 ]
- [ cmp eq reg 1 0x00000001 ]
-
# frag id 1
inet test-inet output
[ meta load nfproto => reg 1 ]
@@ -256,32 +206,12 @@ inet test-inet output
[ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# frag id { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-inet test-inet output
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# frag id != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-inet test-inet output
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# frag reserved2 1
inet test-inet output
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000006 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000006 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000002 ]
# frag more-fragments 0
@@ -289,7 +219,7 @@ inet test-inet output
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000001 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
# frag more-fragments 1
@@ -297,6 +227,6 @@ inet test-inet output
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000001 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000001 ]
diff --git a/tests/py/ip6/frag.t.payload.ip6 b/tests/py/ip6/frag.t.payload.ip6
index 940fb9f0..7c3e7a4e 100644
--- a/tests/py/ip6/frag.t.payload.ip6
+++ b/tests/py/ip6/frag.t.payload.ip6
@@ -71,45 +71,29 @@ ip6 test-ip6 output
[ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# frag reserved { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 output
- [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# frag reserved != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 output
- [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# frag frag-off 22
ip6 test-ip6 output
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000b000 ]
# frag frag-off != 233
ip6 test-ip6 output
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00004807 ]
# frag frag-off 33-45
ip6 test-ip6 output
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
[ cmp gte reg 1 0x00000801 ]
[ cmp lte reg 1 0x00006801 ]
# frag frag-off != 33-45
ip6 test-ip6 output
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
[ range neq reg 1 0x00000801 0x00006801 ]
# frag frag-off { 33, 55, 67, 88}
@@ -118,7 +102,7 @@ __set%d test-ip6 0
element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
ip6 test-ip6 output
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
# frag frag-off != { 33, 55, 67, 88}
@@ -127,33 +111,9 @@ __set%d test-ip6 0
element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
ip6 test-ip6 output
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d 0x1 ]
-# frag frag-off { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-ip6 test-ip6 output
- [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
- [ lookup reg 1 set __set%d ]
-
-# frag frag-off != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-ip6 test-ip6 output
- [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000f8ff ) ^ 0x00000000 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# frag more-fragments 1
-ip6 test-ip6 output
- [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000001 ) ^ 0x00000000 ]
- [ cmp eq reg 1 0x00000001 ]
-
# frag id 1
ip6 test-ip6 output
[ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
@@ -196,37 +156,21 @@ ip6 test-ip6 output
[ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# frag id { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-ip6 test-ip6 output
- [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# frag id != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-ip6 test-ip6 output
- [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# frag reserved2 1
ip6 test-ip6 output
[ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000006 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000006 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000002 ]
# frag more-fragments 0
ip6 test-ip6 output
[ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000001 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000000 ]
# frag more-fragments 1
ip6 test-ip6 output
[ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000001 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000001 ]
diff --git a/tests/py/ip6/frag.t.payload.netdev b/tests/py/ip6/frag.t.payload.netdev
new file mode 100644
index 00000000..05620754
--- /dev/null
+++ b/tests/py/ip6/frag.t.payload.netdev
@@ -0,0 +1,232 @@
+# frag nexthdr tcp
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+
+# frag nexthdr != icmp
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp neq reg 1 0x00000001 ]
+
+# frag nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp}
+__set%d test-netdev 3 size 8
+__set%d test-netdev 0
+ element 00000032 : 0 [end] element 00000033 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000088 : 0 [end] element 00000006 : 0 [end] element 00000021 : 0 [end] element 00000084 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp}
+__set%d test-netdev 3 size 8
+__set%d test-netdev 0
+ element 00000032 : 0 [end] element 00000033 : 0 [end] element 0000006c : 0 [end] element 00000011 : 0 [end] element 00000088 : 0 [end] element 00000006 : 0 [end] element 00000021 : 0 [end] element 00000084 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag nexthdr esp
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000032 ]
+
+# frag nexthdr ah
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000033 ]
+
+# frag reserved 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000016 ]
+
+# frag reserved != 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp neq reg 1 0x000000e9 ]
+
+# frag reserved 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ cmp gte reg 1 0x00000021 ]
+ [ cmp lte reg 1 0x0000002d ]
+
+# frag reserved != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ range neq reg 1 0x00000021 0x0000002d ]
+
+# frag reserved { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag reserved != { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 1 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag frag-off 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x0000b000 ]
+
+# frag frag-off != 233
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00004807 ]
+
+# frag frag-off 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ cmp gte reg 1 0x00000801 ]
+ [ cmp lte reg 1 0x00006801 ]
+
+# frag frag-off != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ range neq reg 1 0x00000801 0x00006801 ]
+
+# frag frag-off { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag frag-off != { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000f8ff ) ^ 0x00000000 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
+# frag reserved2 1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000006 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000002 ]
+
+# frag more-fragments 0
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# frag more-fragments 1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000001 ) ^ 0x00000000 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# frag id 1
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# frag id 22
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp eq reg 1 0x16000000 ]
+
+# frag id != 33
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp neq reg 1 0x21000000 ]
+
+# frag id 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ cmp gte reg 1 0x21000000 ]
+ [ cmp lte reg 1 0x2d000000 ]
+
+# frag id != 33-45
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ range neq reg 1 0x21000000 0x2d000000 ]
+
+# frag id { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+
+# frag id != { 33, 55, 67, 88}
+__set%d test-netdev 3 size 4
+__set%d test-netdev 0
+ element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ exthdr load ipv6 4b @ 44 + 4 => reg 1 ]
+ [ lookup reg 1 set __set%d 0x1 ]
+
diff --git a/tests/py/ip6/hbh.t b/tests/py/ip6/hbh.t
index f367a384..fce5feae 100644
--- a/tests/py/ip6/hbh.t
+++ b/tests/py/ip6/hbh.t
@@ -9,8 +9,6 @@ hbh hdrlength 33-45;ok
hbh hdrlength != 33-45;ok
hbh hdrlength {33, 55, 67, 88};ok
hbh hdrlength != {33, 55, 67, 88};ok
-hbh hdrlength { 33-55};ok
-hbh hdrlength != { 33-55};ok
hbh nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6};ok;hbh nexthdr { 58, 136, 51, 50, 6, 17, 132, 33, 108}
hbh nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6};ok;hbh nexthdr != { 58, 136, 51, 50, 6, 17, 132, 33, 108}
@@ -20,7 +18,5 @@ hbh nexthdr 33-45;ok
hbh nexthdr != 33-45;ok
hbh nexthdr {33, 55, 67, 88};ok
hbh nexthdr != {33, 55, 67, 88};ok
-hbh nexthdr { 33-55};ok
-hbh nexthdr != { 33-55};ok
hbh nexthdr ip;ok;hbh nexthdr 0
hbh nexthdr != ip;ok;hbh nexthdr != 0
diff --git a/tests/py/ip6/hbh.t.json b/tests/py/ip6/hbh.t.json
index 441d3bfe..68670a3b 100644
--- a/tests/py/ip6/hbh.t.json
+++ b/tests/py/ip6/hbh.t.json
@@ -112,46 +112,6 @@
}
]
-# hbh hdrlength { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "hdrlength",
- "name": "hbh"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# hbh hdrlength != { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "hdrlength",
- "name": "hbh"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# hbh nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
[
{
@@ -322,46 +282,6 @@
}
]
-# hbh nexthdr { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "nexthdr",
- "name": "hbh"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# hbh nexthdr != { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "nexthdr",
- "name": "hbh"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# hbh nexthdr ip
[
{
diff --git a/tests/py/ip6/hbh.t.payload.inet b/tests/py/ip6/hbh.t.payload.inet
index e358351d..63afd832 100644
--- a/tests/py/ip6/hbh.t.payload.inet
+++ b/tests/py/ip6/hbh.t.payload.inet
@@ -47,26 +47,6 @@ inet test-inet filter-input
[ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# hbh hdrlength { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet filter-input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# hbh hdrlength != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet filter-input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# hbh nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
__set%d test-inet 3
__set%d test-inet 0
@@ -136,26 +116,6 @@ inet test-inet filter-input
[ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# hbh nexthdr { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet filter-input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# hbh nexthdr != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet filter-input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# hbh nexthdr ip
inet test-inet filter-input
[ meta load nfproto => reg 1 ]
diff --git a/tests/py/ip6/hbh.t.payload.ip6 b/tests/py/ip6/hbh.t.payload.ip6
index a4b131a5..913505a5 100644
--- a/tests/py/ip6/hbh.t.payload.ip6
+++ b/tests/py/ip6/hbh.t.payload.ip6
@@ -35,22 +35,6 @@ ip6 test-ip6 filter-input
[ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# hbh hdrlength { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 filter-input
- [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# hbh hdrlength != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 filter-input
- [ exthdr load ipv6 1b @ 0 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# hbh nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6}
__set%d test-ip6 3
__set%d test-ip6 0
@@ -104,22 +88,6 @@ ip6 test-ip6 filter-input
[ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# hbh nexthdr { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 filter-input
- [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# hbh nexthdr != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 filter-input
- [ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# hbh nexthdr ip
ip6 test-ip6 filter-input
[ exthdr load ipv6 1b @ 0 + 0 => reg 1 ]
diff --git a/tests/py/ip6/icmpv6.t b/tests/py/ip6/icmpv6.t
index 8d794115..7632bfd8 100644
--- a/tests/py/ip6/icmpv6.t
+++ b/tests/py/ip6/icmpv6.t
@@ -28,25 +28,20 @@ icmpv6 type {router-renumbering, mld-listener-done, time-exceeded, nd-router-sol
icmpv6 type {mld-listener-query, time-exceeded, nd-router-advert} accept;ok
icmpv6 type != {mld-listener-query, time-exceeded, nd-router-advert} accept;ok
-icmpv6 code 4;ok;icmpv6 code port-unreachable
+icmpv6 code 4;ok
icmpv6 code 3-66;ok
-icmpv6 code {5, 6, 7} accept;ok;icmpv6 code {policy-fail, reject-route, 7} accept
-icmpv6 code != {policy-fail, reject-route, 7} accept;ok
-icmpv6 code { 3-66};ok
-icmpv6 code != { 3-66};ok
+icmpv6 code {5, 6, 7} accept;ok
+icmpv6 code != {policy-fail, reject-route, 7} accept;ok;icmpv6 code != {5, 6, 7} accept
icmpv6 checksum 2222 log;ok
icmpv6 checksum != 2222 log;ok
icmpv6 checksum 222-226;ok
-icmpv6 checksum != 2222 log;ok
+icmpv6 checksum != 222-226;ok
icmpv6 checksum { 222, 226};ok
icmpv6 checksum != { 222, 226};ok
-icmpv6 checksum { 222-226};ok
-icmpv6 checksum != { 222-226};ok
-# BUG: icmpv6 parameter-problem, pptr, mtu, packet-too-big
+# BUG: icmpv6 parameter-problem, pptr
# [ICMP6HDR_PPTR] = ICMP6HDR_FIELD("parameter-problem", icmp6_pptr),
-# [ICMP6HDR_MTU] = ICMP6HDR_FIELD("packet-too-big", icmp6_mtu),
# $ sudo nft add rule ip6 test6 input icmpv6 parameter-problem 35
# <cmdline>:1:53-53: Error: syntax error, unexpected end of file
# add rule ip6 test6 input icmpv6 parameter-problem 35
@@ -59,44 +54,46 @@ icmpv6 checksum != { 222-226};ok
# <cmdline>:1:54-54: Error: syntax error, unexpected end of file
# add rule ip6 test6 input icmpv6 parameter-problem 2-4
-# BUG: packet-too-big
-# $ sudo nft add rule ip6 test6 input icmpv6 packet-too-big 34
-# <cmdline>:1:50-50: Error: syntax error, unexpected end of file
-# add rule ip6 test6 input icmpv6 packet-too-big 34
-
icmpv6 mtu 22;ok
icmpv6 mtu != 233;ok
icmpv6 mtu 33-45;ok
icmpv6 mtu != 33-45;ok
icmpv6 mtu {33, 55, 67, 88};ok
icmpv6 mtu != {33, 55, 67, 88};ok
-icmpv6 mtu {33-55};ok
-icmpv6 mtu != {33-55};ok
-
-- icmpv6 id 2;ok
-- icmpv6 id != 233;ok
-icmpv6 id 33-45;ok
-icmpv6 id != 33-45;ok
-icmpv6 id {33, 55, 67, 88};ok
-icmpv6 id != {33, 55, 67, 88};ok
-icmpv6 id {33-55};ok
-icmpv6 id != {33-55};ok
-
-icmpv6 sequence 2;ok
-icmpv6 sequence {3, 4, 5, 6, 7} accept;ok
-
-icmpv6 sequence {2, 4};ok
-icmpv6 sequence != {2, 4};ok
-icmpv6 sequence 2-4;ok
-icmpv6 sequence != 2-4;ok
-icmpv6 sequence { 2-4};ok
-icmpv6 sequence != { 2-4};ok
-
-- icmpv6 max-delay 22;ok
-- icmpv6 max-delay != 233;ok
+icmpv6 type packet-too-big icmpv6 mtu 1280;ok;icmpv6 mtu 1280
+
+icmpv6 id 33-45;ok;icmpv6 type { echo-request, echo-reply} icmpv6 id 33-45
+icmpv6 id != 33-45;ok;icmpv6 type { echo-request, echo-reply} icmpv6 id != 33-45
+icmpv6 id {33, 55, 67, 88};ok;icmpv6 type { echo-request, echo-reply} icmpv6 id { 33, 55, 67, 88}
+icmpv6 id != {33, 55, 67, 88};ok;icmpv6 type { echo-request, echo-reply} icmpv6 id != { 33, 55, 67, 88}
+
+icmpv6 id 1;ok;icmpv6 type { echo-request, echo-reply} icmpv6 id 1
+icmpv6 type echo-reply icmpv6 id 65534;ok
+
+icmpv6 sequence 2;ok;icmpv6 type { echo-request, echo-reply} icmpv6 sequence 2
+icmpv6 sequence {3, 4, 5, 6, 7} accept;ok;icmpv6 type { echo-request, echo-reply} icmpv6 sequence { 3, 4, 5, 6, 7} accept
+
+
+icmpv6 sequence {2, 4};ok;icmpv6 type { echo-request, echo-reply} icmpv6 sequence { 2, 4}
+icmpv6 sequence != {2, 4};ok;icmpv6 type { echo-request, echo-reply} icmpv6 sequence != { 2, 4}
+icmpv6 sequence 2-4;ok;icmpv6 type { echo-request, echo-reply} icmpv6 sequence 2-4
+icmpv6 sequence != 2-4;ok;icmpv6 type { echo-request, echo-reply} icmpv6 sequence != 2-4
+
icmpv6 max-delay 33-45;ok
icmpv6 max-delay != 33-45;ok
icmpv6 max-delay {33, 55, 67, 88};ok
icmpv6 max-delay != {33, 55, 67, 88};ok
-icmpv6 max-delay {33-55};ok
-icmpv6 max-delay != {33-55};ok
+
+icmpv6 type parameter-problem icmpv6 code 0;ok
+
+icmpv6 type mld-listener-query icmpv6 taddr 2001:db8::133;ok
+icmpv6 type nd-neighbor-solicit icmpv6 taddr 2001:db8::133;ok
+icmpv6 type nd-neighbor-advert icmpv6 taddr 2001:db8::133;ok
+icmpv6 taddr 2001:db8::133;ok;icmpv6 type { mld-listener-query, mld-listener-report, mld-listener-done, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect} icmpv6 taddr 2001:db8::133
+
+icmpv6 taddr 2001:db8::133;ok;icmpv6 type { mld-listener-query, mld-listener-report, mld-listener-done, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect} icmpv6 taddr 2001:db8::133
+
+icmpv6 type { mld-listener-query, mld-listener-report, mld-listener-done, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect} icmpv6 taddr 2001:db8::133;ok
+icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert } icmpv6 taddr 2001:db8::133;ok
+icmpv6 daddr 2001:db8::133;ok
+icmpv6 type nd-redirect icmpv6 daddr 2001:db8::133;ok;icmpv6 daddr 2001:db8::133
diff --git a/tests/py/ip6/icmpv6.t.json b/tests/py/ip6/icmpv6.t.json
index f6cfbf17..9df886dd 100644
--- a/tests/py/ip6/icmpv6.t.json
+++ b/tests/py/ip6/icmpv6.t.json
@@ -532,8 +532,8 @@
"op": "!=",
"right": {
"set": [
- "policy-fail",
- "reject-route",
+ 5,
+ 6,
7
]
}
@@ -544,46 +544,6 @@
}
]
-# icmpv6 code { 3-66}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "code",
- "protocol": "icmpv6"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 3, 66 ] }
- ]
- }
- }
- }
-]
-
-# icmpv6 code != { 3-66}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "code",
- "protocol": "icmpv6"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 3, 66 ] }
- ]
- }
- }
- }
-]
-
# icmpv6 checksum 2222 log
[
{
@@ -640,7 +600,7 @@
}
]
-# icmpv6 checksum != 2222 log
+# icmpv6 checksum != 222-226
[
{
"match": {
@@ -650,12 +610,11 @@
"protocol": "icmpv6"
}
},
- "op": "!=",
- "right": 2222
+ "op": "!=",
+ "right": {
+ "range": [ 222, 226 ]
+ }
}
- },
- {
- "log": null
}
]
@@ -701,46 +660,6 @@
}
]
-# icmpv6 checksum { 222-226}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "icmpv6"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 222, 226 ] }
- ]
- }
- }
- }
-]
-
-# icmpv6 checksum != { 222-226}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "checksum",
- "protocol": "icmpv6"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 222, 226 ] }
- ]
- }
- }
- }
-]
-
# icmpv6 mtu 22
[
{
@@ -855,46 +774,6 @@
}
]
-# icmpv6 mtu {33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "mtu",
- "protocol": "icmpv6"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# icmpv6 mtu != {33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "mtu",
- "protocol": "icmpv6"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# icmpv6 id 33-45
[
{
@@ -977,42 +856,63 @@
}
]
-# icmpv6 id {33-55}
+# icmpv6 id 1
[
{
"match": {
"left": {
"payload": {
- "field": "id",
+ "field": "type",
"protocol": "icmpv6"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
- { "range": [ 33, 55 ] }
+ "echo-request",
+ "echo-reply"
]
}
}
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": 1
+ }
}
]
-# icmpv6 id != {33-55}
+# icmpv6 type echo-reply icmpv6 id 65534
[
{
"match": {
"left": {
"payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "echo-reply"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
"field": "id",
"protocol": "icmpv6"
}
},
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
+ "op": "==",
+ "right": 65534
}
}
]
@@ -1138,165 +1038,388 @@
}
]
-# icmpv6 sequence { 2-4}
+# icmpv6 max-delay 33-45
[
{
"match": {
"left": {
"payload": {
- "field": "sequence",
+ "field": "max-delay",
"protocol": "icmpv6"
}
},
"op": "==",
"right": {
- "set": [
- { "range": [ 2, 4 ] }
- ]
+ "range": [ 33, 45 ]
}
}
}
]
-# icmpv6 sequence != { 2-4}
+# icmpv6 max-delay != 33-45
[
{
"match": {
"left": {
"payload": {
- "field": "sequence",
+ "field": "max-delay",
"protocol": "icmpv6"
}
},
"op": "!=",
"right": {
- "set": [
- { "range": [ 2, 4 ] }
- ]
+ "range": [ 33, 45 ]
}
}
}
]
-# icmpv6 max-delay 33-45
+# icmpv6 max-delay {33, 55, 67, 88}
[
{
"match": {
"left": {
"payload": {
"field": "max-delay",
- "name": "icmpv6"
+ "protocol": "icmpv6"
}
},
"op": "==",
"right": {
- "range": [ 33, 45 ]
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
}
}
}
]
-# icmpv6 max-delay != 33-45
+# icmpv6 max-delay != {33, 55, 67, 88}
[
{
"match": {
"left": {
"payload": {
"field": "max-delay",
- "name": "icmpv6"
+ "protocol": "icmpv6"
}
},
"op": "!=",
"right": {
- "range": [ 33, 45 ]
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
}
}
}
]
-# icmpv6 max-delay {33, 55, 67, 88}
+# icmpv6 type packet-too-big icmpv6 mtu 1280
[
{
"match": {
"left": {
"payload": {
- "field": "max-delay",
- "name": "icmpv6"
+ "field": "mtu",
+ "protocol": "icmpv6"
}
},
- "op": "==",
+ "op": "==",
+ "right": 1280
+ }
+ }
+]
+
+# icmpv6 type parameter-problem icmpv6 code 0
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "parameter-problem"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "code",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": 0
+ }
+ }
+]
+
+# icmpv6 type mld-listener-query icmpv6 taddr 2001:db8::133
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "mld-listener-query"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "taddr",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "2001:db8::133"
+ }
+ }
+]
+
+# icmpv6 type nd-neighbor-solicit icmpv6 taddr 2001:db8::133
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-neighbor-solicit"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "taddr",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "2001:db8::133"
+ }
+ }
+]
+
+# icmpv6 type nd-neighbor-advert icmpv6 taddr 2001:db8::133
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "nd-neighbor-advert"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "taddr",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "2001:db8::133"
+ }
+ }
+]
+
+# icmpv6 taddr 2001:db8::133
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
"right": {
"set": [
- 33,
- 55,
- 67,
- 88
+ "mld-listener-query",
+ "mld-listener-report",
+ "mld-listener-done",
+ "nd-neighbor-solicit",
+ "nd-neighbor-advert",
+ "nd-redirect"
]
}
}
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "taddr",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "2001:db8::133"
+ }
}
]
-# icmpv6 max-delay != {33, 55, 67, 88}
+# icmpv6 taddr 2001:db8::133
[
{
"match": {
"left": {
"payload": {
- "field": "max-delay",
- "name": "icmpv6"
+ "field": "type",
+ "protocol": "icmpv6"
}
},
- "op": "!=",
+ "op": "==",
"right": {
"set": [
- 33,
- 55,
- 67,
- 88
+ "mld-listener-query",
+ "mld-listener-report",
+ "mld-listener-done",
+ "nd-neighbor-solicit",
+ "nd-neighbor-advert",
+ "nd-redirect"
]
}
}
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "taddr",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "2001:db8::133"
+ }
}
]
-# icmpv6 max-delay {33-55}
+# icmpv6 type { mld-listener-query, mld-listener-report, mld-listener-done, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect} icmpv6 taddr 2001:db8::133
[
{
"match": {
"left": {
"payload": {
- "field": "max-delay",
- "name": "icmpv6"
+ "field": "type",
+ "protocol": "icmpv6"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
- { "range": [ 33, 55 ] }
+ "mld-listener-query",
+ "mld-listener-report",
+ "mld-listener-done",
+ "nd-neighbor-solicit",
+ "nd-neighbor-advert",
+ "nd-redirect"
]
}
}
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "taddr",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "2001:db8::133"
+ }
}
]
-# icmpv6 max-delay != {33-55}
+# icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert } icmpv6 taddr 2001:db8::133
[
{
"match": {
"left": {
"payload": {
- "field": "max-delay",
- "name": "icmpv6"
+ "field": "type",
+ "protocol": "icmpv6"
}
},
- "op": "!=",
+ "op": "==",
"right": {
"set": [
- { "range": [ 33, 55 ] }
+ "nd-neighbor-solicit",
+ "nd-neighbor-advert"
]
}
}
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "taddr",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "2001:db8::133"
+ }
}
]
+# icmpv6 daddr 2001:db8::133
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "2001:db8::133"
+ }
+ }
+]
+
+# icmpv6 type nd-redirect icmpv6 daddr 2001:db8::133
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "daddr",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": "2001:db8::133"
+ }
+ }
+]
diff --git a/tests/py/ip6/icmpv6.t.json.output b/tests/py/ip6/icmpv6.t.json.output
index 3a106621..f29b346c 100644
--- a/tests/py/ip6/icmpv6.t.json.output
+++ b/tests/py/ip6/icmpv6.t.json.output
@@ -8,7 +8,7 @@
"protocol": "icmpv6"
}
},
- "op": "==",
+ "op": "==",
"right": "mld-listener-done"
}
},
@@ -27,7 +27,7 @@
"protocol": "icmpv6"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
"time-exceeded",
@@ -53,7 +53,7 @@
"protocol": "icmpv6"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
"time-exceeded",
@@ -103,8 +103,8 @@
"protocol": "icmpv6"
}
},
- "op": "==",
- "right": "port-unreachable"
+ "op": "==",
+ "right": 4
}
}
]
@@ -119,9 +119,12 @@
"protocol": "icmpv6"
}
},
- "op": "==",
+ "op": "==",
"right": {
- "range": [ "addr-unreachable", 66 ]
+ "range": [
+ 3,
+ 66
+ ]
}
}
}
@@ -137,11 +140,11 @@
"protocol": "icmpv6"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
- "policy-fail",
- "reject-route",
+ 5,
+ 6,
7
]
}
@@ -162,10 +165,15 @@
"protocol": "icmpv6"
}
},
- "op": "==",
+ "op": "==",
"right": {
"set": [
- { "range": [ "addr-unreachable", 66 ] }
+ {
+ "range": [
+ "addr-unreachable",
+ 66
+ ]
+ }
]
}
}
@@ -185,7 +193,565 @@
"op": "!=",
"right": {
"set": [
- { "range": [ "addr-unreachable", 66 ] }
+ {
+ "range": [
+ "addr-unreachable",
+ 66
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 33,
+ 45
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id != 33-45
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [
+ 33,
+ 45
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id != {33, 55, 67, 88}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 33,
+ 55,
+ 67,
+ 88
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id {33-55}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "range": [
+ 33,
+ 55
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 id != {33-55}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "id",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ {
+ "range": [
+ 33,
+ 55
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence 2
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": 2
+ }
+ }
+]
+
+# icmpv6 sequence {3, 4, 5, 6, 7} accept
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 3,
+ 4,
+ 5,
+ 6,
+ 7
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# icmpv6 sequence {2, 4}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ 2,
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence != {2, 4}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ 2,
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence 2-4
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "range": [
+ 2,
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence != 2-4
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "range": [
+ 2,
+ 4
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence { 2-4}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ {
+ "range": [
+ 2,
+ 4
+ ]
+ }
+ ]
+ }
+ }
+ }
+]
+
+# icmpv6 sequence != { 2-4}
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "echo-request",
+ "echo-reply"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "sequence",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "!=",
+ "right": {
+ "set": [
+ {
+ "range": [
+ 2,
+ 4
+ ]
+ }
]
}
}
diff --git a/tests/py/ip6/icmpv6.t.payload.ip6 b/tests/py/ip6/icmpv6.t.payload.ip6
index 51d71f41..5b6035d1 100644
--- a/tests/py/ip6/icmpv6.t.payload.ip6
+++ b/tests/py/ip6/icmpv6.t.payload.ip6
@@ -231,26 +231,6 @@ ip6 test-ip6 input
[ lookup reg 1 set __set%d 0x1 ]
[ immediate reg 0 accept ]
-# icmpv6 code { 3-66}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000003 : 0 [end] element 00000043 : 1 [end]
-ip6 test-ip6 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x0000003a ]
- [ payload load 1b @ transport header + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# icmpv6 code != { 3-66}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000003 : 0 [end] element 00000043 : 1 [end]
-ip6 test-ip6 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x0000003a ]
- [ payload load 1b @ transport header + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# icmpv6 checksum 2222 log
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
@@ -275,13 +255,12 @@ ip6 test-ip6 input
[ cmp gte reg 1 0x0000de00 ]
[ cmp lte reg 1 0x0000e200 ]
-# icmpv6 checksum != 2222 log
-ip6 test-ip6 input
+# icmpv6 checksum != 222-226
+ip6
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
[ payload load 2b @ transport header + 2 => reg 1 ]
- [ cmp neq reg 1 0x0000ae08 ]
- [ log ]
+ [ range neq reg 1 0x0000de00 0x0000e200 ]
# icmpv6 checksum { 222, 226}
__set%d test-ip6 3
@@ -303,30 +282,12 @@ ip6 test-ip6 input
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# icmpv6 checksum { 222-226}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 0000de00 : 0 [end] element 0000e300 : 1 [end]
-ip6 test-ip6 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x0000003a ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# icmpv6 checksum != { 222-226}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 0000de00 : 0 [end] element 0000e300 : 1 [end]
-ip6 test-ip6 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x0000003a ]
- [ payload load 2b @ transport header + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# icmpv6 mtu 22
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ cmp eq reg 1 0x16000000 ]
@@ -334,6 +295,8 @@ ip6 test-ip6 input
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ cmp neq reg 1 0xe9000000 ]
@@ -341,6 +304,8 @@ ip6 test-ip6 input
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ cmp gte reg 1 0x21000000 ]
[ cmp lte reg 1 0x2d000000 ]
@@ -349,6 +314,8 @@ ip6 test-ip6 input
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ range neq reg 1 0x21000000 0x2d000000 ]
@@ -359,6 +326,8 @@ __set%d test-ip6 0
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d ]
@@ -369,172 +338,185 @@ __set%d test-ip6 0
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# icmpv6 mtu {33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-ip6 test-ip6 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x0000003a ]
- [ payload load 4b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# icmpv6 mtu != {33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-ip6 test-ip6 input
+# icmpv6 type packet-too-big icmpv6 mtu 1280
+ip6
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
[ payload load 4b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+ [ cmp eq reg 1 0x00050000 ]
# icmpv6 id 33-45
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ cmp gte reg 1 0x00002100 ]
[ cmp lte reg 1 0x00002d00 ]
# icmpv6 id != 33-45
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ range neq reg 1 0x00002100 0x00002d00 ]
# icmpv6 id {33, 55, 67, 88}
__set%d test-ip6 3
__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+__set%d test-ip6 3
+__set%d test-ip6 0
element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d ]
# icmpv6 id != {33, 55, 67, 88}
__set%d test-ip6 3
__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+__set%d test-ip6 3
+__set%d test-ip6 0
element 00002100 : 0 [end] element 00003700 : 0 [end] element 00004300 : 0 [end] element 00005800 : 0 [end]
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# icmpv6 id {33-55}
-__set%d test-ip6 7
+# icmpv6 id 1
+__set%d test-ip6 3 size 2
__set%d test-ip6 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip6 test-ip6 input
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+ip6
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
- [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
[ lookup reg 1 set __set%d ]
+ [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
-# icmpv6 id != {33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip6 test-ip6 input
+# icmpv6 type echo-reply icmpv6 id 65534
+ip6
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
[ payload load 2b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+ [ cmp eq reg 1 0x0000feff ]
# icmpv6 sequence 2
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ cmp eq reg 1 0x00000200 ]
# icmpv6 sequence {3, 4, 5, 6, 7} accept
__set%d test-ip6 3
__set%d test-ip6 0
- element 00000300 : 0 [end] element 00000400 : 0 [end] element 00000500 : 0 [end] element 00000600 : 0 [end] element 00000700 : 0 [end]
-ip6 test-ip6 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x0000003a ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d ]
- [ immediate reg 0 accept ]
-
-# icmpv6 sequence != {3, 4, 5, 6, 7} accept
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
__set%d test-ip6 3
__set%d test-ip6 0
element 00000300 : 0 [end] element 00000400 : 0 [end] element 00000500 : 0 [end] element 00000600 : 0 [end] element 00000700 : 0 [end]
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+ [ lookup reg 1 set __set%d ]
[ immediate reg 0 accept ]
# icmpv6 sequence {2, 4}
__set%d test-ip6 3
__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+__set%d test-ip6 3
+__set%d test-ip6 0
element 00000200 : 0 [end] element 00000400 : 0 [end]
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ lookup reg 1 set __set%d ]
# icmpv6 sequence != {2, 4}
__set%d test-ip6 3
__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
+__set%d test-ip6 3
+__set%d test-ip6 0
element 00000200 : 0 [end] element 00000400 : 0 [end]
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
# icmpv6 sequence 2-4
+__set%d test-ip6 3
+__set%d test-ip6 0
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
[ payload load 2b @ transport header + 6 => reg 1 ]
[ cmp gte reg 1 0x00000200 ]
[ cmp lte reg 1 0x00000400 ]
# icmpv6 sequence != 2-4
-ip6 test-ip6 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x0000003a ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
- [ range neq reg 1 0x00000200 0x00000400 ]
-
-# icmpv6 sequence { 2-4}
-__set%d test-ip6 7
+__set%d test-ip6 3
__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000200 : 0 [end] element 00000500 : 1 [end]
+ element 00000080 : 0 [end] element 00000081 : 0 [end]
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
- [ payload load 2b @ transport header + 6 => reg 1 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
[ lookup reg 1 set __set%d ]
-
-# icmpv6 sequence != { 2-4}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000200 : 0 [end] element 00000500 : 1 [end]
-ip6 test-ip6 input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x0000003a ]
[ payload load 2b @ transport header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+ [ range neq reg 1 0x00000200 0x00000400 ]
# icmpv6 max-delay 33-45
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000082 ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ cmp gte reg 1 0x00002100 ]
[ cmp lte reg 1 0x00002d00 ]
@@ -543,6 +525,8 @@ ip6 test-ip6 input
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000082 ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ range neq reg 1 0x00002100 0x00002d00 ]
@@ -553,6 +537,8 @@ __set%d test-ip6 0
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000082 ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d ]
@@ -563,26 +549,95 @@ __set%d test-ip6 0
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000082 ]
[ payload load 2b @ transport header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# icmpv6 max-delay {33-55}
-__set%d test-ip6 7
+# icmpv6 type parameter-problem icmpv6 code 0
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 2b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000004 ]
+
+# icmpv6 type mld-listener-query icmpv6 taddr 2001:db8::133
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000082 ]
+ [ payload load 16b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0xb80d0120 0x00000000 0x00000000 0x33010000 ]
+
+# icmpv6 type nd-neighbor-solicit icmpv6 taddr 2001:db8::133
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000087 ]
+ [ payload load 16b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0xb80d0120 0x00000000 0x00000000 0x33010000 ]
+
+# icmpv6 type nd-neighbor-advert icmpv6 taddr 2001:db8::133
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000088 ]
+ [ payload load 16b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0xb80d0120 0x00000000 0x00000000 0x33010000 ]
+
+# icmpv6 taddr 2001:db8::133
+__set%d test-ip6 3 size 6
__set%d test-ip6 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
+ element 00000082 : 0 [end] element 00000083 : 0 [end] element 00000084 : 0 [end] element 00000087 : 0 [end] element 00000088 : 0 [end] element 00000089 : 0 [end]
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
- [ payload load 2b @ transport header + 4 => reg 1 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
[ lookup reg 1 set __set%d ]
+ [ payload load 16b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0xb80d0120 0x00000000 0x00000000 0x33010000 ]
-# icmpv6 max-delay != {33-55}
-__set%d test-ip6 7
+# icmpv6 type { mld-listener-query, mld-listener-report, mld-listener-done, nd-neighbor-solicit, nd-neighbor-advert, nd-redirect} icmpv6 taddr 2001:db8::133
+__set%d test-ip6 3 size 6
__set%d test-ip6 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
+ element 00000082 : 0 [end] element 00000083 : 0 [end] element 00000084 : 0 [end] element 00000087 : 0 [end] element 00000088 : 0 [end] element 00000089 : 0 [end]
ip6 test-ip6 input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x0000003a ]
- [ payload load 2b @ transport header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 16b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0xb80d0120 0x00000000 0x00000000 0x33010000 ]
+
+# icmpv6 type { nd-neighbor-solicit, nd-neighbor-advert } icmpv6 taddr 2001:db8::133
+__set%d test-ip6 3 size 2
+__set%d test-ip6 0
+ element 00000087 : 0 [end] element 00000088 : 0 [end]
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ lookup reg 1 set __set%d ]
+ [ payload load 16b @ transport header + 8 => reg 1 ]
+ [ cmp eq reg 1 0xb80d0120 0x00000000 0x00000000 0x33010000 ]
+# icmpv6 daddr 2001:db8::133
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000089 ]
+ [ payload load 16b @ transport header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xb80d0120 0x00000000 0x00000000 0x33010000 ]
+
+# icmpv6 type nd-redirect icmpv6 daddr 2001:db8::133
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x0000003a ]
+ [ payload load 1b @ transport header + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000089 ]
+ [ payload load 16b @ transport header + 24 => reg 1 ]
+ [ cmp eq reg 1 0xb80d0120 0x00000000 0x00000000 0x33010000 ]
diff --git a/tests/py/ip6/ip6.t b/tests/py/ip6/ip6.t
index 8210d22b..430dd571 100644
--- a/tests/py/ip6/ip6.t
+++ b/tests/py/ip6/ip6.t
@@ -17,6 +17,15 @@ ip6 dscp != 0x20;ok;ip6 dscp != cs4
ip6 dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef};ok
ip6 dscp vmap { 0x04 : accept, 0x3f : continue } counter;ok
+!map1 type dscp : mark;ok
+meta mark set ip6 dscp map @map1;ok
+!map2 type dscp . ipv6_addr : mark;ok
+meta mark set ip6 dscp . ip6 daddr map @map2;ok
+!map3 type dscp : mark;ok
+ip6 dscp @map3;ok
+!map4 type dscp . ipv6_addr : mark;ok
+ip6 dscp . ip6 daddr @map4;ok
+
ip6 flowlabel 22;ok
ip6 flowlabel != 233;ok
- ip6 flowlabel 33-45;ok
@@ -24,9 +33,7 @@ ip6 flowlabel != 233;ok
ip6 flowlabel { 33, 55, 67, 88};ok
# BUG ip6 flowlabel { 5046528, 2883584, 13522432 }
ip6 flowlabel != { 33, 55, 67, 88};ok
-ip6 flowlabel { 33-55};ok
-ip6 flowlabel != { 33-55};ok
-ip6 flowlabel vmap { 0 : accept, 2 : continue } ;ok
+ip6 flowlabel vmap { 0 : accept, 2 : continue };ok
ip6 length 22;ok
ip6 length != 233;ok
@@ -34,16 +41,12 @@ ip6 length 33-45;ok
ip6 length != 33-45;ok
ip6 length { 33, 55, 67, 88};ok
ip6 length != {33, 55, 67, 88};ok
-ip6 length { 33-55};ok
-ip6 length != { 33-55};ok
ip6 nexthdr {udp, ah, comp, udplite, tcp, dccp, sctp};ok;ip6 nexthdr { 132, 51, 108, 136, 17, 33, 6}
ip6 nexthdr {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6};ok;ip6 nexthdr { 6, 136, 108, 33, 50, 17, 132, 58, 51}
ip6 nexthdr != {esp, ah, comp, udp, udplite, tcp, dccp, sctp, icmpv6};ok;ip6 nexthdr != { 6, 136, 108, 33, 50, 17, 132, 58, 51}
ip6 nexthdr esp;ok;ip6 nexthdr 50
ip6 nexthdr != esp;ok;ip6 nexthdr != 50
-ip6 nexthdr { 33-44};ok
-ip6 nexthdr != { 33-44};ok
ip6 nexthdr 33-44;ok
ip6 nexthdr != 33-44;ok
@@ -53,8 +56,6 @@ ip6 hoplimit 33-45;ok
ip6 hoplimit != 33-45;ok
ip6 hoplimit {33, 55, 67, 88};ok
ip6 hoplimit != {33, 55, 67, 88};ok
-ip6 hoplimit {33-55};ok
-ip6 hoplimit != {33-55};ok
# from src/scanner.l
# v680 (({hex4}:){7}{hex4})
diff --git a/tests/py/ip6/ip6.t.json b/tests/py/ip6/ip6.t.json
index f898240f..49e5a2dd 100644
--- a/tests/py/ip6/ip6.t.json
+++ b/tests/py/ip6/ip6.t.json
@@ -135,39 +135,107 @@
}
]
-# ip6 flowlabel 22
+# meta mark set ip6 dscp map @map1
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": "@map1",
+ "key": {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ }
+ }
+ }
+ }
+ }
+]
+
+# meta mark set ip6 dscp . ip6 daddr map @map2
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "data": "@map2",
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+]
+
+# ip6 dscp @map3
[
{
"match": {
"left": {
"payload": {
- "field": "flowlabel",
+ "field": "dscp",
"protocol": "ip6"
}
},
- "op": "==",
- "right": 22
+ "op": "==",
+ "right": "@map3"
}
}
]
-# ip6 flowlabel != 233
+# ip6 dscp . ip6 daddr @map4
[
{
"match": {
"left": {
- "payload": {
- "field": "flowlabel",
- "protocol": "ip6"
- }
+ "concat": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ }
+ ]
},
- "op": "!=",
- "right": 233
+ "op": "==",
+ "right": "@map4"
}
}
]
-# ip6 flowlabel { 33, 55, 67, 88}
+# ip6 flowlabel 22
[
{
"match": {
@@ -178,19 +246,12 @@
}
},
"op": "==",
- "right": {
- "set": [
- 33,
- 55,
- 67,
- 88
- ]
- }
+ "right": 22
}
}
]
-# ip6 flowlabel != { 33, 55, 67, 88}
+# ip6 flowlabel != 233
[
{
"match": {
@@ -201,19 +262,12 @@
}
},
"op": "!=",
- "right": {
- "set": [
- 33,
- 55,
- 67,
- 88
- ]
- }
+ "right": 233
}
}
]
-# ip6 flowlabel { 33-55}
+# ip6 flowlabel { 33, 55, 67, 88}
[
{
"match": {
@@ -226,14 +280,17 @@
"op": "==",
"right": {
"set": [
- { "range": [ 33, 55 ] }
+ 33,
+ 55,
+ 67,
+ 88
]
}
}
}
]
-# ip6 flowlabel != { 33-55}
+# ip6 flowlabel != { 33, 55, 67, 88}
[
{
"match": {
@@ -246,7 +303,10 @@
"op": "!=",
"right": {
"set": [
- { "range": [ 33, 55 ] }
+ 33,
+ 55,
+ 67,
+ 88
]
}
}
@@ -397,48 +457,6 @@
}
]
-# ip6 length { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "length",
- "protocol": "ip6"
- }
- },
- "op": "==",
- "right": {
- "set": [
- {
- "range": [ 33, 55 ]
- }
- ]
- }
- }
- }
-]
-
-# ip6 length != { 33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "length",
- "protocol": "ip6"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# ip6 nexthdr {udp, ah, comp, udplite, tcp, dccp, sctp}
[
{
@@ -743,46 +761,6 @@
}
]
-# ip6 hoplimit {33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "hoplimit",
- "protocol": "ip6"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# ip6 hoplimit != {33-55}
-[
- {
- "match": {
- "left": {
- "payload": {
- "field": "hoplimit",
- "protocol": "ip6"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# ip6 saddr 1234:1234:1234:1234:1234:1234:1234:1234
[
{
diff --git a/tests/py/ip6/ip6.t.payload.inet b/tests/py/ip6/ip6.t.payload.inet
index d015c8ef..dbb430af 100644
--- a/tests/py/ip6/ip6.t.payload.inet
+++ b/tests/py/ip6/ip6.t.payload.inet
@@ -3,7 +3,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000002 ]
# ip6 dscp != cs1
@@ -11,7 +11,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000002 ]
# ip6 dscp 0x38
@@ -19,7 +19,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000000e ]
# ip6 dscp != 0x20
@@ -27,7 +27,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000008 ]
# ip6 dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
@@ -38,27 +38,71 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
# ip6 dscp vmap { 0x04 : accept, 0x3f : continue } counter
__map%d test-inet b size 2
__map%d test-inet 0
- element 00000001 : 0 [end] element 0000c00f : 0 [end]
+ element 00000001 : accept 0 [end] element 0000c00f : continue 0 [end]
ip6 test-ip6 input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 0 ]
[ counter pkts 0 bytes 0 ]
+# meta mark set ip6 dscp map @map1
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ lookup reg 1 set map1 dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip6 dscp . ip6 daddr map @map2
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ payload load 16b @ network header + 24 => reg 9 ]
+ [ lookup reg 1 set map2 dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# ip6 dscp @map3
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ lookup reg 1 set map3 ]
+
+# ip6 dscp . ip6 daddr @map4
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ payload load 16b @ network header + 24 => reg 9 ]
+ [ lookup reg 1 set map4 ]
+
# ip6 flowlabel 22
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00160000 ]
# ip6 flowlabel != 233
@@ -66,7 +110,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00e90000 ]
# ip6 flowlabel { 33, 55, 67, 88}
@@ -77,7 +121,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
# ip6 flowlabel != { 33, 55, 67, 88}
@@ -88,40 +132,18 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip6 flowlabel { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00210000 : 0 [end] element 00380000 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
- [ lookup reg 1 set __set%d ]
-
-# ip6 flowlabel != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00210000 : 0 [end] element 00380000 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# ip6 flowlabel vmap { 0 : accept, 2 : continue }
+# ip6 flowlabel vmap { 0 : accept, 2 : continue }
__map%d test-inet b size 2
__map%d test-inet 0
- element 00000000 : 0 [end] element 00020000 : 0 [end]
+ element 00000000 : accept 0 [end] element 00020000 : continue 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 0 ]
# ip6 length 22
@@ -173,26 +195,6 @@ inet test-inet input
[ payload load 2b @ network header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip6 length { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ payload load 2b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip6 length != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ payload load 2b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip6 nexthdr {udp, ah, comp, udplite, tcp, dccp, sctp}
__set%d test-inet 3
__set%d test-inet 0
@@ -237,26 +239,6 @@ inet test-inet input
[ payload load 1b @ network header + 6 => reg 1 ]
[ cmp neq reg 1 0x00000032 ]
-# ip6 nexthdr { 33-44}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 0000002d : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ payload load 1b @ network header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip6 nexthdr != { 33-44}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 0000002d : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ payload load 1b @ network header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip6 nexthdr 33-44
inet test-inet input
[ meta load nfproto => reg 1 ]
@@ -321,26 +303,6 @@ inet test-inet input
[ payload load 1b @ network header + 7 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip6 hoplimit {33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ payload load 1b @ network header + 7 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip6 hoplimit != {33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ payload load 1b @ network header + 7 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip6 saddr 1234:1234:1234:1234:1234:1234:1234:1234
inet test-inet input
[ meta load nfproto => reg 1 ]
@@ -604,9 +566,8 @@ inet test-inet input
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
- [ payload load 16b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xffffffff 0xffffffff 0x00000000 0x00000000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
- [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x00000000 ]
+ [ payload load 8b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 ]
# ip6 saddr ::1 ip6 daddr ::2
inet test-inet input
@@ -659,7 +620,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00003ff0 ) ^ 0x00000009 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00003ff0 ) ^ 0x00000009 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 0 csum_off 0 csum_flags 0x0 ]
# iif "lo" ip6 dscp set 63
@@ -669,7 +630,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00003ff0 ) ^ 0x0000c00f ]
+ [ bitwise reg 1 = ( reg 1 & 0x00003ff0 ) ^ 0x0000c00f ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 0 csum_off 0 csum_flags 0x0 ]
# iif "lo" ip6 ecn set ect0
@@ -679,7 +640,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000cf ) ^ 0x00000020 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000cf ) ^ 0x00000020 ]
[ payload write reg 1 => 1b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
# iif "lo" ip6 ecn set ce
@@ -689,7 +650,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000cf ) ^ 0x00000030 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000cf ) ^ 0x00000030 ]
[ payload write reg 1 => 1b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
# iif "lo" ip6 flowlabel set 0
@@ -699,7 +660,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
[ payload write reg 1 => 3b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
# iif "lo" ip6 flowlabel set 12345
@@ -709,7 +670,7 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00393000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00393000 ]
[ payload write reg 1 => 3b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
# iif "lo" ip6 flowlabel set 0xfffff
@@ -719,6 +680,6 @@ inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00ffff0f ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00ffff0f ]
[ payload write reg 1 => 3b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
diff --git a/tests/py/ip6/ip6.t.payload.ip6 b/tests/py/ip6/ip6.t.payload.ip6
index b2e8363c..b1289232 100644
--- a/tests/py/ip6/ip6.t.payload.ip6
+++ b/tests/py/ip6/ip6.t.payload.ip6
@@ -1,25 +1,25 @@
# ip6 dscp cs1
ip6 test-ip6 input
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000002 ]
# ip6 dscp != cs1
ip6 test-ip6 input
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000002 ]
# ip6 dscp 0x38
ip6 test-ip6 input
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0000000e ]
# ip6 dscp != 0x20
ip6 test-ip6 input
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000008 ]
# ip6 dscp {cs0, cs1, cs2, cs3, cs4, cs5, cs6, cs7, af11, af12, af13, af21, af22, af23, af31, af32, af33, af41, af42, af43, ef}
@@ -28,29 +28,65 @@ __set%d test-ip6 0
element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000006 : 0 [end] element 00000008 : 0 [end] element 0000000a : 0 [end] element 0000000c : 0 [end] element 0000000e : 0 [end] element 00000000 : 0 [end] element 00008002 : 0 [end] element 00000003 : 0 [end] element 00008003 : 0 [end] element 00008004 : 0 [end] element 00000005 : 0 [end] element 00008005 : 0 [end] element 00008006 : 0 [end] element 00000007 : 0 [end] element 00008007 : 0 [end] element 00008008 : 0 [end] element 00000009 : 0 [end] element 00008009 : 0 [end] element 0000800b : 0 [end]
ip6 test-ip6 input
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
# ip6 dscp vmap { 0x04 : accept, 0x3f : continue } counter
__map%d test-ip6 b size 2
__map%d test-ip6 0
- element 00000001 : 0 [end] element 0000c00f : 0 [end]
+ element 00000001 : accept 0 [end] element 0000c00f : continue 0 [end]
ip6 test-ip6 input
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 0 ]
[ counter pkts 0 bytes 0 ]
+# meta mark set ip6 dscp map @map1
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ lookup reg 1 set map1 dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip6 dscp . ip6 daddr map @map2
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ payload load 16b @ network header + 24 => reg 9 ]
+ [ lookup reg 1 set map2 dreg 1 ]
+ [ meta set mark with reg 1 ]
+
+# ip6 dscp @map3
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ lookup reg 1 set map3 ]
+
+# ip6 dscp . ip6 daddr @map4
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ payload load 16b @ network header + 24 => reg 9 ]
+ [ lookup reg 1 set map4 ]
+
# ip6 flowlabel 22
ip6 test-ip6 input
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00160000 ]
# ip6 flowlabel != 233
ip6 test-ip6 input
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00e90000 ]
# ip6 flowlabel { 33, 55, 67, 88}
@@ -59,7 +95,7 @@ __set%d test-ip6 0
element 00210000 : 0 [end] element 00370000 : 0 [end] element 00430000 : 0 [end] element 00580000 : 0 [end]
ip6 test-ip6 input
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d ]
# ip6 flowlabel != { 33, 55, 67, 88}
@@ -68,34 +104,16 @@ __set%d test-ip6 0
element 00210000 : 0 [end] element 00370000 : 0 [end] element 00430000 : 0 [end] element 00580000 : 0 [end]
ip6 test-ip6 input
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip6 flowlabel { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00210000 : 0 [end] element 00380000 : 1 [end]
-ip6 test-ip6 input
- [ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
- [ lookup reg 1 set __set%d ]
-
-# ip6 flowlabel != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00210000 : 0 [end] element 00380000 : 1 [end]
-ip6 test-ip6 input
- [ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
-# ip6 flowlabel vmap { 0 : accept, 2 : continue }
+# ip6 flowlabel vmap { 0 : accept, 2 : continue }
__map%d test-ip6 b size 2
__map%d test-ip6 0
- element 00000000 : 0 [end] element 00020000 : 0 [end]
+ element 00000000 : accept 0 [end] element 00020000 : continue 0 [end]
ip6 test-ip6 input
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00ffff0f ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00ffff0f ) ^ 0x00000000 ]
[ lookup reg 1 set __map%d dreg 0 ]
# ip6 length 22
@@ -135,22 +153,6 @@ ip6 test-ip6 input
[ payload load 2b @ network header + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip6 length { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip6 test-ip6 input
- [ payload load 2b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip6 length != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip6 test-ip6 input
- [ payload load 2b @ network header + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip6 nexthdr {udp, ah, comp, udplite, tcp, dccp, sctp}
__set%d test-ip6 3
__set%d test-ip6 0
@@ -185,22 +187,6 @@ ip6 test-ip6 input
[ payload load 1b @ network header + 6 => reg 1 ]
[ cmp neq reg 1 0x00000032 ]
-# ip6 nexthdr { 33-44}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 0000002d : 1 [end]
-ip6 test-ip6 input
- [ payload load 1b @ network header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip6 nexthdr != { 33-44}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 0000002d : 1 [end]
-ip6 test-ip6 input
- [ payload load 1b @ network header + 6 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip6 nexthdr 33-44
ip6 test-ip6 input
[ payload load 1b @ network header + 6 => reg 1 ]
@@ -249,22 +235,6 @@ ip6 test-ip6 input
[ payload load 1b @ network header + 7 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# ip6 hoplimit {33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ payload load 1b @ network header + 7 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# ip6 hoplimit != {33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ payload load 1b @ network header + 7 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# ip6 saddr 1234:1234:1234:1234:1234:1234:1234:1234
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
@@ -452,9 +422,8 @@ ip6 test-ip6 input
# ip6 saddr ::/64
ip6 test-ip6 input
- [ payload load 16b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0xffffffff 0xffffffff 0x00000000 0x00000000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
- [ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x00000000 ]
+ [ payload load 8b @ network header + 8 => reg 1 ]
+ [ cmp eq reg 1 0x00000000 0x00000000 ]
# ip6 saddr ::1 ip6 daddr ::2
ip6 test-ip6 input
@@ -495,7 +464,7 @@ ip6 test-ip6 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00003ff0 ) ^ 0x00000009 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00003ff0 ) ^ 0x00000009 ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 0 csum_off 0 csum_flags 0x0 ]
# iif "lo" ip6 dscp set 63
@@ -503,7 +472,7 @@ ip6 test-ip6 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 2b @ network header + 0 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00003ff0 ) ^ 0x0000c00f ]
+ [ bitwise reg 1 = ( reg 1 & 0x00003ff0 ) ^ 0x0000c00f ]
[ payload write reg 1 => 2b @ network header + 0 csum_type 0 csum_off 0 csum_flags 0x0 ]
# iif "lo" ip6 ecn set ect0
@@ -511,7 +480,7 @@ ip6 test-ip6 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000cf ) ^ 0x00000020 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000cf ) ^ 0x00000020 ]
[ payload write reg 1 => 1b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
# iif "lo" ip6 ecn set ce
@@ -519,7 +488,7 @@ ip6 test-ip6 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 1b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000cf ) ^ 0x00000030 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000cf ) ^ 0x00000030 ]
[ payload write reg 1 => 1b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
# iif "lo" ip6 flowlabel set 0
@@ -527,7 +496,7 @@ ip6 test-ip6 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00000000 ]
[ payload write reg 1 => 3b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
# iif "lo" ip6 flowlabel set 12345
@@ -535,7 +504,7 @@ ip6 test-ip6 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00393000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00393000 ]
[ payload write reg 1 => 3b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
# iif "lo" ip6 flowlabel set 0xfffff
@@ -543,6 +512,6 @@ ip6 test-ip6 input
[ meta load iif => reg 1 ]
[ cmp eq reg 1 0x00000001 ]
[ payload load 3b @ network header + 1 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x000000f0 ) ^ 0x00ffff0f ]
+ [ bitwise reg 1 = ( reg 1 & 0x000000f0 ) ^ 0x00ffff0f ]
[ payload write reg 1 => 3b @ network header + 1 csum_type 0 csum_off 0 csum_flags 0x0 ]
diff --git a/tests/py/ip6/map.t.payload b/tests/py/ip6/map.t.payload
index 9b393a60..8e900c18 100644
--- a/tests/py/ip6/map.t.payload
+++ b/tests/py/ip6/map.t.payload
@@ -4,7 +4,7 @@ __map%d test-ip6 0
element 00000000 00000000 00000000 02000000 : 0000002a 0 [end] element 00000000 00000000 00000000 ffff0000 : 00000017 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x00000000 0x00000000 0x00000000 0xffff0000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x00000000 0x00000000 0x00000000 0xffff0000 ) ^ 0x00000000 0x00000000 0x00000000 0x00000000 ]
[ lookup reg 1 set __map%d dreg 1 ]
[ meta set mark with reg 1 ]
diff --git a/tests/py/ip6/masquerade.t.payload.ip6 b/tests/py/ip6/masquerade.t.payload.ip6
index 98657551..43ae2ae4 100644
--- a/tests/py/ip6/masquerade.t.payload.ip6
+++ b/tests/py/ip6/masquerade.t.payload.ip6
@@ -112,12 +112,12 @@ ip6 test-ip6 postrouting
# iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } masquerade
__map%d test-ip6 b
__map%d test-ip6 0
- element 00001600 : 0 [end] element 0000de00 : 0 [end]
+ element 00001600 : drop 0 [end] element 0000de00 : drop 0 [end]
ip6 test-ip6 postrouting
[ meta load iifname => reg 1 ]
[ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
[ ct load state => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000a ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000a ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000000 ]
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -130,7 +130,7 @@ ip6 test-ip6 postrouting
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x00000004 ]
- [ masq proto_min reg 1 proto_max reg 0 ]
+ [ masq proto_min reg 1 flags 0x2 ]
# meta l4proto 6 masquerade to :1024-2048
ip6 test-ip6 postrouting
@@ -138,5 +138,5 @@ ip6 test-ip6 postrouting
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x00000004 ]
[ immediate reg 2 0x00000008 ]
- [ masq proto_min reg 1 proto_max reg 2 ]
+ [ masq proto_min reg 1 proto_max reg 2 flags 0x2 ]
diff --git a/tests/py/ip6/meta.t b/tests/py/ip6/meta.t
index 24445084..c177b081 100644
--- a/tests/py/ip6/meta.t
+++ b/tests/py/ip6/meta.t
@@ -8,3 +8,12 @@ meta l4proto ipv6-icmp icmpv6 type nd-router-advert;ok;icmpv6 type nd-router-adv
meta l4proto icmp icmp type echo-request;ok;icmp type echo-request
meta l4proto 1 icmp type echo-request;ok;icmp type echo-request
icmp type echo-request;ok
+
+meta protocol ip udp dport 67;ok
+meta protocol ip6 udp dport 67;ok;udp dport 67
+
+meta sdif "lo" accept;ok
+meta sdifname != "vrf1" accept;ok
+
+meta mark set ip6 dscp << 2 | 0x10;ok
+meta mark set ip6 dscp << 26 | 0x10;ok
diff --git a/tests/py/ip6/meta.t.json b/tests/py/ip6/meta.t.json
index 29cf9fd2..1a2394d8 100644
--- a/tests/py/ip6/meta.t.json
+++ b/tests/py/ip6/meta.t.json
@@ -105,3 +105,209 @@
}
]
+# meta sdif "lo" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "sdif"
+ }
+ },
+ "op": "==",
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta sdifname != "vrf1" accept
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "sdifname"
+ }
+ },
+ "op": "!=",
+ "right": "vrf1"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
+# meta protocol ip udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
+# meta protocol ip6 udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
+# meta mark set ip6 dscp lshift 2 or 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# meta mark set ip6 dscp lshift 26 or 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# meta mark set ip6 dscp << 2 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
+# meta mark set ip6 dscp << 26 | 0x10
+[
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/ip6/meta.t.json.output b/tests/py/ip6/meta.t.json.output
index dede9b16..61adf184 100644
--- a/tests/py/ip6/meta.t.json.output
+++ b/tests/py/ip6/meta.t.json.output
@@ -46,3 +46,19 @@
}
]
+# meta protocol ip6 udp dport 67
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "dport",
+ "protocol": "udp"
+ }
+ },
+ "op": "==",
+ "right": 67
+ }
+ }
+]
+
diff --git a/tests/py/ip6/meta.t.payload b/tests/py/ip6/meta.t.payload
index f203baab..6a37f1de 100644
--- a/tests/py/ip6/meta.t.payload
+++ b/tests/py/ip6/meta.t.payload
@@ -32,3 +32,51 @@ ip6 test-ip6 input
[ cmp eq reg 1 0x00000001 ]
[ payload load 1b @ transport header + 0 => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
+
+# meta sdif "lo" accept
+ip6 test-ip6 input
+ [ meta load sdif => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+ [ immediate reg 0 accept ]
+
+# meta sdifname != "vrf1" accept
+ip6 test-ip6 input
+ [ meta load sdifname => reg 1 ]
+ [ cmp neq reg 1 0x31667276 0x00000000 0x00000000 0x00000000 ]
+ [ immediate reg 0 accept ]
+
+# meta protocol ip udp dport 67
+ip6 test-ip6 input
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
+
+# meta protocol ip6 udp dport 67
+ip6 test-ip6 input
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000011 ]
+ [ payload load 2b @ transport header + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00004300 ]
+
+# meta mark set ip6 dscp << 2 | 0x10
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x00000002 ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ meta set mark with reg 1 ]
+
+# meta mark set ip6 dscp << 26 | 0x10
+ip6 test-ip6 input
+ [ payload load 2b @ network header + 0 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000c00f ) ^ 0x00000000 ]
+ [ byteorder reg 1 = ntoh(reg 1, 2, 2) ]
+ [ bitwise reg 1 = ( reg 1 >> 0x00000006 ) ]
+ [ bitwise reg 1 = ( reg 1 << 0x0000001a ) ]
+ [ bitwise reg 1 = ( reg 1 & 0xffffffef ) ^ 0x00000010 ]
+ [ meta set mark with reg 1 ]
diff --git a/tests/py/ip6/mh.t b/tests/py/ip6/mh.t
index 2f90372e..46f4ba05 100644
--- a/tests/py/ip6/mh.t
+++ b/tests/py/ip6/mh.t
@@ -15,8 +15,6 @@ mh nexthdr 33-45;ok
mh nexthdr != 33-45;ok
mh nexthdr { 33, 55, 67, 88 };ok
mh nexthdr != { 33, 55, 67, 88 };ok
-mh nexthdr { 33-55 };ok
-mh nexthdr != { 33-55 };ok
mh hdrlength 22;ok
mh hdrlength != 233;ok
@@ -24,8 +22,6 @@ mh hdrlength 33-45;ok
mh hdrlength != 33-45;ok
mh hdrlength { 33, 55, 67, 88 };ok
mh hdrlength != { 33, 55, 67, 88 };ok
-mh hdrlength { 33-55 };ok
-mh hdrlength != { 33-55 };ok
mh type {binding-refresh-request, home-test-init, careof-test-init, home-test, careof-test, binding-update, binding-acknowledgement, binding-error, fast-binding-update, fast-binding-acknowledgement, fast-binding-advertisement, experimental-mobility-header, home-agent-switch-message};ok
mh type home-agent-switch-message;ok
@@ -37,8 +33,6 @@ mh reserved 33-45;ok
mh reserved != 33-45;ok
mh reserved { 33, 55, 67, 88};ok
mh reserved != { 33, 55, 67, 88};ok
-mh reserved { 33-55};ok
-mh reserved != { 33-55};ok
mh checksum 22;ok
mh checksum != 233;ok
@@ -46,5 +40,3 @@ mh checksum 33-45;ok
mh checksum != 33-45;ok
mh checksum { 33, 55, 67, 88};ok
mh checksum != { 33, 55, 67, 88};ok
-mh checksum { 33-55};ok
-mh checksum != { 33-55};ok
diff --git a/tests/py/ip6/mh.t.json b/tests/py/ip6/mh.t.json
index 211477d3..3159b14b 100644
--- a/tests/py/ip6/mh.t.json
+++ b/tests/py/ip6/mh.t.json
@@ -232,48 +232,6 @@
}
]
-# mh nexthdr { 33-55 }
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "nexthdr",
- "name": "mh"
- }
- },
- "op": "==",
- "right": {
- "set": [
- {
- "range": [ 33, 55 ]
- }
- ]
- }
- }
- }
-]
-
-# mh nexthdr != { 33-55 }
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "nexthdr",
- "name": "mh"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# mh hdrlength 22
[
{
@@ -388,46 +346,6 @@
}
]
-# mh hdrlength { 33-55 }
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "hdrlength",
- "name": "mh"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# mh hdrlength != { 33-55 }
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "hdrlength",
- "name": "mh"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# mh type {binding-refresh-request, home-test-init, careof-test-init, home-test, careof-test, binding-update, binding-acknowledgement, binding-error, fast-binding-update, fast-binding-acknowledgement, fast-binding-advertisement, experimental-mobility-header, home-agent-switch-message}
[
{
@@ -606,46 +524,6 @@
}
]
-# mh reserved { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "reserved",
- "name": "mh"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# mh reserved != { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "reserved",
- "name": "mh"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# mh checksum 22
[
{
@@ -760,43 +638,3 @@
}
]
-# mh checksum { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "checksum",
- "name": "mh"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# mh checksum != { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "checksum",
- "name": "mh"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
diff --git a/tests/py/ip6/mh.t.payload.inet b/tests/py/ip6/mh.t.payload.inet
index 2c473fbd..54eaa70e 100644
--- a/tests/py/ip6/mh.t.payload.inet
+++ b/tests/py/ip6/mh.t.payload.inet
@@ -95,26 +95,6 @@ inet test-inet input
[ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# mh nexthdr { 33-55 }
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# mh nexthdr != { 33-55 }
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# mh hdrlength 22
inet test-inet input
[ meta load nfproto => reg 1 ]
@@ -164,26 +144,6 @@ inet test-inet input
[ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# mh hdrlength { 33-55 }
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# mh hdrlength != { 33-55 }
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# mh type {binding-refresh-request, home-test-init, careof-test-init, home-test, careof-test, binding-update, binding-acknowledgement, binding-error, fast-binding-update, fast-binding-acknowledgement, fast-binding-advertisement, experimental-mobility-header, home-agent-switch-message}
__set%d test-inet 3
__set%d test-inet 0
@@ -257,26 +217,6 @@ inet test-inet input
[ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# mh reserved { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# mh reserved != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# mh checksum 22
inet test-inet input
[ meta load nfproto => reg 1 ]
@@ -325,24 +265,3 @@ inet test-inet input
[ cmp eq reg 1 0x0000000a ]
[ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-
-# mh checksum { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# mh checksum != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
diff --git a/tests/py/ip6/mh.t.payload.ip6 b/tests/py/ip6/mh.t.payload.ip6
index 93744dac..73bd4226 100644
--- a/tests/py/ip6/mh.t.payload.ip6
+++ b/tests/py/ip6/mh.t.payload.ip6
@@ -71,22 +71,6 @@ ip6 test-ip6 input
[ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# mh nexthdr { 33-55 }
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# mh nexthdr != { 33-55 }
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 135 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# mh hdrlength 22
ip6 test-ip6 input
[ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
@@ -124,22 +108,6 @@ ip6 test-ip6 input
[ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# mh hdrlength { 33-55 }
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# mh hdrlength != { 33-55 }
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 135 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# mh type {binding-refresh-request, home-test-init, careof-test-init, home-test, careof-test, binding-update, binding-acknowledgement, binding-error, fast-binding-update, fast-binding-acknowledgement, fast-binding-advertisement, experimental-mobility-header, home-agent-switch-message}
__set%d test-ip6 3
__set%d test-ip6 0
@@ -195,22 +163,6 @@ ip6 test-ip6 input
[ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# mh reserved { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# mh reserved != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 135 + 3 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# mh checksum 22
ip6 test-ip6 input
[ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
@@ -247,20 +199,3 @@ __set%d test-ip6 0
ip6 test-ip6 input
[ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-
-# mh checksum { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# mh checksum != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00002100 : 0 [end] element 00003800 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 2b @ 135 + 4 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
diff --git a/tests/py/ip6/redirect.t b/tests/py/ip6/redirect.t
index 778d53f3..70ef7f9f 100644
--- a/tests/py/ip6/redirect.t
+++ b/tests/py/ip6/redirect.t
@@ -46,4 +46,4 @@ ip6 daddr fe00::1-fe00::200 udp dport 53 counter redirect;ok
iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } redirect;ok
# redirect with maps
-ip6 nexthdr 6 redirect to :tcp dport map { 22 : 8000, 80 : 8080};ok
+redirect to :tcp dport map { 22 : 8000, 80 : 8080};ok
diff --git a/tests/py/ip6/redirect.t.json b/tests/py/ip6/redirect.t.json
index 0059c7ac..c18223fa 100644
--- a/tests/py/ip6/redirect.t.json
+++ b/tests/py/ip6/redirect.t.json
@@ -557,21 +557,9 @@
}
]
-# ip6 nexthdr 6 redirect to :tcp dport map { 22 : 8000, 80 : 8080}
+# redirect to :tcp dport map { 22 : 8000, 80 : 8080}
[
{
- "match": {
- "left": {
- "payload": {
- "field": "nexthdr",
- "protocol": "ip6"
- }
- },
- "op": "==",
- "right": 6
- }
- },
- {
"redirect": {
"port": {
"map": {
diff --git a/tests/py/ip6/redirect.t.payload.ip6 b/tests/py/ip6/redirect.t.payload.ip6
index 8f85a570..cfc29013 100644
--- a/tests/py/ip6/redirect.t.payload.ip6
+++ b/tests/py/ip6/redirect.t.payload.ip6
@@ -104,7 +104,7 @@ ip6 test-ip6 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000d204 ]
[ immediate reg 1 0x0000d204 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# ip6 daddr fe00::cafe udp dport 9998 redirect to :6515
ip6 test-ip6 output
@@ -115,7 +115,7 @@ ip6 test-ip6 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00000e27 ]
[ immediate reg 1 0x00007319 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# ip6 nexthdr tcp redirect to :100-200
ip6 test-ip6 output
@@ -123,7 +123,7 @@ ip6 test-ip6 output
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x00006400 ]
[ immediate reg 2 0x0000c800 ]
- [ redir proto_min reg 1 proto_max reg 2 ]
+ [ redir proto_min reg 1 proto_max reg 2 flags 0x2 ]
# tcp dport 39128 redirect to :993
ip6 test-ip6 output
@@ -132,7 +132,7 @@ ip6 test-ip6 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000d898 ]
[ immediate reg 1 0x0000e103 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# tcp dport 9128 redirect to :993 random
ip6 test-ip6 output
@@ -141,7 +141,7 @@ ip6 test-ip6 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000a823 ]
[ immediate reg 1 0x0000e103 ]
- [ redir proto_min reg 1 flags 0x4 ]
+ [ redir proto_min reg 1 flags 0x6 ]
# tcp dport 9128 redirect to :993 fully-random,persistent
ip6 test-ip6 output
@@ -150,7 +150,7 @@ ip6 test-ip6 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000a823 ]
[ immediate reg 1 0x0000e103 ]
- [ redir proto_min reg 1 flags 0x18 ]
+ [ redir proto_min reg 1 flags 0x1a ]
# tcp dport { 1, 2, 3, 4, 5, 6, 7, 8, 101, 202, 303, 1001, 2002, 3003} redirect
__set%d test-ip6 3
@@ -178,12 +178,12 @@ ip6 test-ip6 output
# iifname "eth0" ct state established,new tcp dport vmap {22 : drop, 222 : drop } redirect
__map%d test-ip6 b
__map%d test-ip6 0
- element 00001600 : 0 [end] element 0000de00 : 0 [end]
+ element 00001600 : drop 0 [end] element 0000de00 : drop 0 [end]
ip6 test-ip6 output
[ meta load iifname => reg 1 ]
[ cmp eq reg 1 0x30687465 0x00000000 0x00000000 0x00000000 ]
[ ct load state => reg 1 ]
- [ bitwise reg 1 = (reg=1 & 0x0000000a ) ^ 0x00000000 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000000a ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000000 ]
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -191,14 +191,14 @@ ip6 test-ip6 output
[ lookup reg 1 set __map%d dreg 0 ]
[ redir ]
-# ip6 nexthdr 6 redirect to :tcp dport map { 22 : 8000, 80 : 8080}
+# redirect to :tcp dport map { 22 : 8000, 80 : 8080}
__map%d test-ip6 b
__map%d test-ip6 0
element 00001600 : 0000401f 0 [end] element 00005000 : 0000901f 0 [end]
ip6 test-ip6 output
- [ payload load 1b @ network header + 6 => reg 1 ]
+ [ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __map%d dreg 1 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
diff --git a/tests/py/ip6/reject.t b/tests/py/ip6/reject.t
index 7fa04eec..bfdd094e 100644
--- a/tests/py/ip6/reject.t
+++ b/tests/py/ip6/reject.t
@@ -3,13 +3,14 @@
*ip6;test-ip6;output
reject;ok
-reject with icmpv6 type no-route;ok
-reject with icmpv6 type admin-prohibited;ok
-reject with icmpv6 type addr-unreachable;ok
-reject with icmpv6 type port-unreachable;ok;reject
-reject with icmpv6 type policy-fail;ok
-reject with icmpv6 type reject-route;ok
+reject with icmpv6 no-route;ok
+reject with icmpv6 admin-prohibited;ok
+reject with icmpv6 addr-unreachable;ok
+reject with icmpv6 port-unreachable;ok;reject
+reject with icmpv6 policy-fail;ok
+reject with icmpv6 reject-route;ok
+reject with icmpv6 3;ok;reject with icmpv6 addr-unreachable
mark 0x80000000 reject with tcp reset;ok;meta mark 0x80000000 reject with tcp reset
-reject with icmpv6 type host-unreachable;fail
-reject with icmp type host-unreachable;fail
+reject with icmpv6 host-unreachable;fail
+reject with icmp host-unreachable;fail
diff --git a/tests/py/ip6/reject.t.json b/tests/py/ip6/reject.t.json
index ae57c333..312a7dab 100644
--- a/tests/py/ip6/reject.t.json
+++ b/tests/py/ip6/reject.t.json
@@ -5,7 +5,7 @@
}
]
-# reject with icmpv6 type no-route
+# reject with icmpv6 no-route
[
{
"reject": {
@@ -15,7 +15,7 @@
}
]
-# reject with icmpv6 type admin-prohibited
+# reject with icmpv6 admin-prohibited
[
{
"reject": {
@@ -25,7 +25,7 @@
}
]
-# reject with icmpv6 type addr-unreachable
+# reject with icmpv6 addr-unreachable
[
{
"reject": {
@@ -35,7 +35,7 @@
}
]
-# reject with icmpv6 type port-unreachable
+# reject with icmpv6 port-unreachable
[
{
"reject": {
@@ -45,7 +45,7 @@
}
]
-# reject with icmpv6 type policy-fail
+# reject with icmpv6 policy-fail
[
{
"reject": {
@@ -55,7 +55,7 @@
}
]
-# reject with icmpv6 type reject-route
+# reject with icmpv6 reject-route
[
{
"reject": {
@@ -65,6 +65,16 @@
}
]
+# reject with icmpv6 3
+[
+ {
+ "reject": {
+ "expr": "addr-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
# mark 0x80000000 reject with tcp reset
[
{
diff --git a/tests/py/ip6/reject.t.json.output b/tests/py/ip6/reject.t.json.output
index 4e2058fe..04f12f56 100644
--- a/tests/py/ip6/reject.t.json.output
+++ b/tests/py/ip6/reject.t.json.output
@@ -1,7 +1,10 @@
-# reject with icmpv6 type port-unreachable
+# reject
[
{
- "reject": null
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpv6"
+ }
}
]
diff --git a/tests/py/ip6/reject.t.payload.ip6 b/tests/py/ip6/reject.t.payload.ip6
index dd4491ae..3d4321b0 100644
--- a/tests/py/ip6/reject.t.payload.ip6
+++ b/tests/py/ip6/reject.t.payload.ip6
@@ -2,30 +2,34 @@
ip6 test-ip6 output
[ reject type 0 code 4 ]
-# reject with icmpv6 type no-route
+# reject with icmpv6 no-route
ip6 test-ip6 output
[ reject type 0 code 0 ]
-# reject with icmpv6 type admin-prohibited
+# reject with icmpv6 admin-prohibited
ip6 test-ip6 output
[ reject type 0 code 1 ]
-# reject with icmpv6 type addr-unreachable
+# reject with icmpv6 addr-unreachable
ip6 test-ip6 output
[ reject type 0 code 3 ]
-# reject with icmpv6 type port-unreachable
+# reject with icmpv6 port-unreachable
ip6 test-ip6 output
[ reject type 0 code 4 ]
-# reject with icmpv6 type policy-fail
+# reject with icmpv6 policy-fail
ip6 test-ip6 output
[ reject type 0 code 5 ]
-# reject with icmpv6 type reject-route
+# reject with icmpv6 reject-route
ip6 test-ip6 output
[ reject type 0 code 6 ]
+# reject with icmpv6 3
+ip6 test-ip6 output
+ [ reject type 0 code 3 ]
+
# mark 0x80000000 reject with tcp reset
ip6 test-ip6 output
[ meta load l4proto => reg 1 ]
diff --git a/tests/py/ip6/rt.t b/tests/py/ip6/rt.t
index c3feaabe..c33d38a5 100644
--- a/tests/py/ip6/rt.t
+++ b/tests/py/ip6/rt.t
@@ -15,8 +15,6 @@ rt nexthdr 33-45;ok
rt nexthdr != 33-45;ok
rt nexthdr { 33, 55, 67, 88};ok
rt nexthdr != { 33, 55, 67, 88};ok
-rt nexthdr { 33-55};ok
-rt nexthdr != { 33-55};ok
rt hdrlength 22;ok
rt hdrlength != 233;ok
@@ -24,8 +22,6 @@ rt hdrlength 33-45;ok
rt hdrlength != 33-45;ok
rt hdrlength { 33, 55, 67, 88};ok
rt hdrlength != { 33, 55, 67, 88};ok
-rt hdrlength { 33-55};ok
-rt hdrlength != { 33-55};ok
rt type 22;ok
rt type != 233;ok
@@ -33,8 +29,6 @@ rt type 33-45;ok
rt type != 33-45;ok
rt type { 33, 55, 67, 88};ok
rt type != { 33, 55, 67, 88};ok
-rt type { 33-55};ok
-rt type != { 33-55};ok
rt seg-left 22;ok
rt seg-left != 233;ok
@@ -42,5 +36,3 @@ rt seg-left 33-45;ok
rt seg-left != 33-45;ok
rt seg-left { 33, 55, 67, 88};ok
rt seg-left != { 33, 55, 67, 88};ok
-rt seg-left { 33-55};ok
-rt seg-left != { 33-55};ok
diff --git a/tests/py/ip6/rt.t.json b/tests/py/ip6/rt.t.json
index 86a46402..b12873d6 100644
--- a/tests/py/ip6/rt.t.json
+++ b/tests/py/ip6/rt.t.json
@@ -232,46 +232,6 @@
}
]
-# rt nexthdr { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "nexthdr",
- "name": "rt"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# rt nexthdr != { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "nexthdr",
- "name": "rt"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# rt hdrlength 22
[
{
@@ -386,46 +346,6 @@
}
]
-# rt hdrlength { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "hdrlength",
- "name": "rt"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# rt hdrlength != { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "hdrlength",
- "name": "rt"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# rt type 22
[
{
@@ -540,46 +460,6 @@
}
]
-# rt type { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "type",
- "name": "rt"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# rt type != { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "type",
- "name": "rt"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
# rt seg-left 22
[
{
@@ -694,43 +574,3 @@
}
]
-# rt seg-left { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "seg-left",
- "name": "rt"
- }
- },
- "op": "==",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
-# rt seg-left != { 33-55}
-[
- {
- "match": {
- "left": {
- "exthdr": {
- "field": "seg-left",
- "name": "rt"
- }
- },
- "op": "!=",
- "right": {
- "set": [
- { "range": [ 33, 55 ] }
- ]
- }
- }
- }
-]
-
diff --git a/tests/py/ip6/rt.t.payload.inet b/tests/py/ip6/rt.t.payload.inet
index eafb4a00..864d3114 100644
--- a/tests/py/ip6/rt.t.payload.inet
+++ b/tests/py/ip6/rt.t.payload.inet
@@ -95,26 +95,6 @@ inet test-inet input
[ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# rt nexthdr { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# rt nexthdr != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# rt hdrlength 22
inet test-inet input
[ meta load nfproto => reg 1 ]
@@ -164,26 +144,6 @@ inet test-inet input
[ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# rt hdrlength { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# rt hdrlength != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# rt type 22
inet test-inet input
[ meta load nfproto => reg 1 ]
@@ -233,26 +193,6 @@ inet test-inet input
[ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# rt type { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# rt type != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# rt seg-left 22
inet test-inet input
[ meta load nfproto => reg 1 ]
@@ -302,23 +242,3 @@ inet test-inet input
[ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# rt seg-left { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# rt seg-left != { 33-55}
-__set%d test-inet 7
-__set%d test-inet 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-inet test-inet input
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
- [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
diff --git a/tests/py/ip6/rt.t.payload.ip6 b/tests/py/ip6/rt.t.payload.ip6
index 929cf9e1..c7b52f82 100644
--- a/tests/py/ip6/rt.t.payload.ip6
+++ b/tests/py/ip6/rt.t.payload.ip6
@@ -71,22 +71,6 @@ ip6 test-ip6 input
[ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# rt nexthdr { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# rt nexthdr != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 43 + 0 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# rt hdrlength 22
ip6 test-ip6 input
[ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
@@ -124,22 +108,6 @@ ip6 test-ip6 input
[ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# rt hdrlength { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# rt hdrlength != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 43 + 1 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# rt type 22
ip6 test-ip6 input
[ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
@@ -177,22 +145,6 @@ ip6 test-ip6 input
[ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# rt type { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# rt type != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 43 + 2 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
# rt seg-left 22
ip6 test-ip6 input
[ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
@@ -230,19 +182,3 @@ ip6 test-ip6 input
[ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
-# rt seg-left { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
- [ lookup reg 1 set __set%d ]
-
-# rt seg-left != { 33-55}
-__set%d test-ip6 7
-__set%d test-ip6 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-ip6 test-ip6 input
- [ exthdr load ipv6 1b @ 43 + 3 => reg 1 ]
- [ lookup reg 1 set __set%d 0x1 ]
-
diff --git a/tests/py/ip6/sets.t b/tests/py/ip6/sets.t
index add82eb8..17fd62f5 100644
--- a/tests/py/ip6/sets.t
+++ b/tests/py/ip6/sets.t
@@ -1,9 +1,10 @@
: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
*ip6;test-ip6;input
*inet;test-inet;input
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
!w type ipv6_addr;ok
!x type inet_proto;ok
@@ -40,4 +41,8 @@ ip6 saddr != @set33 drop;fail
!set5 type ipv6_addr . ipv6_addr;ok
ip6 saddr . ip6 daddr @set5 drop;ok
add @set5 { ip6 saddr . ip6 daddr };ok
+
+!map1 type ipv6_addr . ipv6_addr : mark;ok
+add @map1 { ip6 saddr . ip6 daddr : meta mark };ok
+
delete @set5 { ip6 saddr . ip6 daddr };ok
diff --git a/tests/py/ip6/sets.t.json b/tests/py/ip6/sets.t.json
index 948c1f16..2029d2b5 100644
--- a/tests/py/ip6/sets.t.json
+++ b/tests/py/ip6/sets.t.json
@@ -116,3 +116,35 @@
}
}
]
+
+# add @map1 { ip6 saddr . ip6 daddr : meta mark }
+[
+ {
+ "map": {
+ "data": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "elem": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip6"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ }
+ ]
+ },
+ "map": "@map1",
+ "op": "add"
+ }
+ }
+]
+
diff --git a/tests/py/ip6/sets.t.payload.inet b/tests/py/ip6/sets.t.payload.inet
index 47ad86a2..2bbd5573 100644
--- a/tests/py/ip6/sets.t.payload.inet
+++ b/tests/py/ip6/sets.t.payload.inet
@@ -31,6 +31,15 @@ inet test-inet input
[ payload load 16b @ network header + 24 => reg 2 ]
[ dynset add reg_key 1 set set5 ]
+# add @map1 { ip6 saddr . ip6 daddr : meta mark }
+inet test-inet input
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x0000000a ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ payload load 16b @ network header + 24 => reg 2 ]
+ [ meta load mark => reg 3 ]
+ [ dynset add reg_key 1 set map1 sreg_data 3 ]
+
# delete @set5 { ip6 saddr . ip6 daddr }
inet test-inet input
[ meta load nfproto => reg 1 ]
diff --git a/tests/py/ip6/sets.t.payload.ip6 b/tests/py/ip6/sets.t.payload.ip6
index a5febb9f..c59f7b5c 100644
--- a/tests/py/ip6/sets.t.payload.ip6
+++ b/tests/py/ip6/sets.t.payload.ip6
@@ -29,3 +29,10 @@ ip6 test-ip6 input
[ payload load 16b @ network header + 24 => reg 2 ]
[ dynset delete reg_key 1 set set5 ]
+# add @map1 { ip6 saddr . ip6 daddr : meta mark }
+ip6 test-ip6 input
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ payload load 16b @ network header + 24 => reg 2 ]
+ [ meta load mark => reg 3 ]
+ [ dynset add reg_key 1 set map1 sreg_data 3 ]
+
diff --git a/tests/py/ip6/sets.t.payload.netdev b/tests/py/ip6/sets.t.payload.netdev
index dab74159..1866d26b 100644
--- a/tests/py/ip6/sets.t.payload.netdev
+++ b/tests/py/ip6/sets.t.payload.netdev
@@ -39,3 +39,12 @@ netdev test-netdev ingress
[ payload load 16b @ network header + 24 => reg 2 ]
[ dynset delete reg_key 1 set set5 ]
+# add @map1 { ip6 saddr . ip6 daddr : meta mark }
+netdev test-netdev ingress
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ payload load 16b @ network header + 8 => reg 1 ]
+ [ payload load 16b @ network header + 24 => reg 2 ]
+ [ meta load mark => reg 3 ]
+ [ dynset add reg_key 1 set map1 sreg_data 3 ]
+
diff --git a/tests/py/ip6/snat.t b/tests/py/ip6/snat.t
index c259f934..564f0894 100644
--- a/tests/py/ip6/snat.t
+++ b/tests/py/ip6/snat.t
@@ -2,5 +2,5 @@
*ip6;test-ip6;postrouting
-tcp dport 80-90 snat to [2001:838:35f:1::]-[2001:838:35f:2::]:80-100;ok;tcp dport 80-90 snat to [2001:838:35f:1::]-[2001:838:35f:2::]:80-100
+tcp dport 80-90 snat to [2001:838:35f:1::]-[2001:838:35f:2::]:80-100;ok
tcp dport 80-90 snat to [2001:838:35f:1::]-[2001:838:35f:2::]:100;ok
diff --git a/tests/py/ip6/snat.t.payload.ip6 b/tests/py/ip6/snat.t.payload.ip6
index 537e6682..66a29672 100644
--- a/tests/py/ip6/snat.t.payload.ip6
+++ b/tests/py/ip6/snat.t.payload.ip6
@@ -9,7 +9,7 @@ ip6 test-ip6 postrouting
[ immediate reg 2 0x38080120 0x02005f03 0x00000000 0x00000000 ]
[ immediate reg 3 0x00005000 ]
[ immediate reg 4 0x00006400 ]
- [ nat snat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 4 ]
+ [ nat snat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 4 flags 0x2 ]
# tcp dport 80-90 snat to [2001:838:35f:1::]-[2001:838:35f:2::]:100
ip6 test-ip6 postrouting
@@ -21,5 +21,5 @@ ip6 test-ip6 postrouting
[ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
[ immediate reg 2 0x38080120 0x02005f03 0x00000000 0x00000000 ]
[ immediate reg 3 0x00006400 ]
- [ nat snat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 0 ]
+ [ nat snat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 flags 0x2 ]
diff --git a/tests/py/ip6/srh.t.payload b/tests/py/ip6/srh.t.payload
index b6247456..364940a9 100644
--- a/tests/py/ip6/srh.t.payload
+++ b/tests/py/ip6/srh.t.payload
@@ -11,7 +11,7 @@ ip6 test-ip6 input
# srh last-entry { 0, 4-127, 255 }
__set%d test-ip6 7 size 5
__set%d test-ip6 0
- element 00000000 : 0 [end] element 00000001 : 1 [end] element 00000004 : 0 [end] element 00000080 : 1 [end] element 000000ff : 0 [end] userdata = {
+ element 00000000 : 0 [end] element 00000001 : 1 [end] element 00000004 : 0 [end] element 00000080 : 1 [end] element 000000ff : 0 [end] userdata = { \x01\x04\x01\x00\x00\x00 }
ip6 test-ip6 input
[ exthdr load ipv6 1b @ 43 + 4 => reg 1 ]
[ lookup reg 1 set __set%d ]
@@ -29,7 +29,7 @@ ip6 test-ip6 input
# srh flags { 0, 4-127, 255 }
__set%d test-ip6 7 size 5
__set%d test-ip6 0
- element 00000000 : 0 [end] element 00000001 : 1 [end] element 00000004 : 0 [end] element 00000080 : 1 [end] element 000000ff : 0 [end] userdata = {
+ element 00000000 : 0 [end] element 00000001 : 1 [end] element 00000004 : 0 [end] element 00000080 : 1 [end] element 000000ff : 0 [end] userdata = { \x01\x04\x01\x00\x00\x00 }
ip6 test-ip6 input
[ exthdr load ipv6 1b @ 43 + 5 => reg 1 ]
[ lookup reg 1 set __set%d ]
@@ -47,7 +47,7 @@ ip6 test-ip6 input
# srh tag { 0, 4-127, 0xffff }
__set%d test-ip6 7 size 5
__set%d test-ip6 0
- element 00000000 : 0 [end] element 00000100 : 1 [end] element 00000400 : 0 [end] element 00008000 : 1 [end] element 0000ffff : 0 [end] userdata = {
+ element 00000000 : 0 [end] element 00000100 : 1 [end] element 00000400 : 0 [end] element 00008000 : 1 [end] element 0000ffff : 0 [end] userdata = { \x01\x04\x01\x00\x00\x00 }
ip6 test-ip6 input
[ exthdr load ipv6 2b @ 43 + 6 => reg 1 ]
[ lookup reg 1 set __set%d ]
diff --git a/tests/py/ip6/tcpopt.t b/tests/py/ip6/tcpopt.t
deleted file mode 100644
index 497f69fc..00000000
--- a/tests/py/ip6/tcpopt.t
+++ /dev/null
@@ -1,37 +0,0 @@
-:input;type filter hook input priority 0
-*ip6;test-ip6;input
-
-tcp option eol kind 1;ok
-tcp option noop kind 1;ok
-tcp option maxseg kind 1;ok
-tcp option maxseg length 1;ok
-tcp option maxseg size 1;ok
-tcp option window kind 1;ok
-tcp option window length 1;ok
-tcp option window count 1;ok
-tcp option sack-permitted kind 1;ok
-tcp option sack-permitted length 1;ok
-tcp option sack kind 1;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 kind 1;ok
-tcp option timestamp length 1;ok
-tcp option timestamp tsval 1;ok
-tcp option timestamp tsecr 1;ok
-
-tcp option foobar;fail
-tcp option foo bar;fail
-tcp option eol left;fail
-tcp option eol left 1;fail
-tcp option eol left 1;fail
-tcp option sack window;fail
-tcp option sack window 1;fail
diff --git a/tests/py/ip6/tcpopt.t.json b/tests/py/ip6/tcpopt.t.json
deleted file mode 100644
index d573dd1c..00000000
--- a/tests/py/ip6/tcpopt.t.json
+++ /dev/null
@@ -1,416 +0,0 @@
-# tcp option eol kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "eol"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option noop kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "noop"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option maxseg kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "maxseg"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# 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 kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "window"
- }
- },
- "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-permitted kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "sack-permitted"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack-permitted length 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "length",
- "name": "sack-permitted"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# 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": "sack0"
- }
- },
- "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 kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "timestamp"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# 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
- }
- }
-]
-
diff --git a/tests/py/ip6/tcpopt.t.json.output b/tests/py/ip6/tcpopt.t.json.output
deleted file mode 100644
index 81dd8ad8..00000000
--- a/tests/py/ip6/tcpopt.t.json.output
+++ /dev/null
@@ -1,16 +0,0 @@
-# tcp option sack0 right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
diff --git a/tests/py/ip6/tcpopt.t.payload b/tests/py/ip6/tcpopt.t.payload
deleted file mode 100644
index 4b189197..00000000
--- a/tests/py/ip6/tcpopt.t.payload
+++ /dev/null
@@ -1,181 +0,0 @@
-# tcp option eol kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option noop kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg length 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg size 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]
- [ cmp eq reg 1 0x00000100 ]
-
-# tcp option window kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window length 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window count 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack-permitted kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack-permitted length 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack length 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack left 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack0 left 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack1 left 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack2 left 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack3 left 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack right 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack0 right 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack1 right 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack2 right 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack3 right 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option timestamp length 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option timestamp tsval 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp tsecr 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
diff --git a/tests/py/ip6/vmap.t b/tests/py/ip6/vmap.t
index 434f5d92..2d54b822 100644
--- a/tests/py/ip6/vmap.t
+++ b/tests/py/ip6/vmap.t
@@ -1,9 +1,10 @@
: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
*ip6;test-ip6;input
*inet;test-inet;input
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
ip6 saddr vmap { abcd::3 : accept };ok
ip6 saddr 1234:1234:1234:1234:1234:1234:1234:1234:1234;fail
diff --git a/tests/py/ip6/vmap.t.payload.inet b/tests/py/ip6/vmap.t.payload.inet
index 53f19eb9..931cc6bd 100644
--- a/tests/py/ip6/vmap.t.payload.inet
+++ b/tests/py/ip6/vmap.t.payload.inet
@@ -1,7 +1,7 @@
# ip6 saddr vmap { abcd::3 : accept }
__map%d test-inet b
__map%d test-inet 0
- element 0000cdab 00000000 00000000 03000000 : 0 [end]
+ element 0000cdab 00000000 00000000 03000000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -11,7 +11,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 34123412 34123412 : 0 [end]
+ element 34123412 34123412 34123412 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -21,7 +21,7 @@ inet test-inet input
# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34120000 34123412 34123412 34123412 : 0 [end]
+ element 34120000 34123412 34123412 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -31,7 +31,7 @@ inet test-inet input
# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00003412 34123412 34123412 34123412 : 0 [end]
+ element 00003412 34123412 34123412 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -41,7 +41,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34120000 34123412 34123412 : 0 [end]
+ element 34123412 34120000 34123412 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -51,7 +51,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 00003412 34123412 34123412 : 0 [end]
+ element 34123412 00003412 34123412 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -61,7 +61,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 34120000 34123412 : 0 [end]
+ element 34123412 34123412 34120000 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -71,7 +71,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 00003412 34123412 : 0 [end]
+ element 34123412 34123412 00003412 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -81,7 +81,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234::1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 34123412 34120000 : 0 [end]
+ element 34123412 34123412 34123412 34120000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -91,7 +91,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:: : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 34123412 00003412 : 0 [end]
+ element 34123412 34123412 34123412 00003412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -101,7 +101,7 @@ inet test-inet input
# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00000000 34123412 34123412 34123412 : 0 [end]
+ element 00000000 34123412 34123412 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -111,7 +111,7 @@ inet test-inet input
# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00003412 34120000 34123412 34123412 : 0 [end]
+ element 00003412 34120000 34123412 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -121,7 +121,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 00000000 34123412 34123412 : 0 [end]
+ element 34123412 00000000 34123412 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -131,7 +131,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 00003412 34120000 34123412 : 0 [end]
+ element 34123412 00003412 34120000 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -141,7 +141,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 00000000 34123412 : 0 [end]
+ element 34123412 34123412 00000000 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -151,7 +151,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 00003412 34120000 : 0 [end]
+ element 34123412 34123412 00003412 34120000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -161,7 +161,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:: : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 34123412 00000000 : 0 [end]
+ element 34123412 34123412 34123412 00000000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -171,7 +171,7 @@ inet test-inet input
# ip6 saddr vmap { ::1234:1234:1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00000000 34120000 34123412 34123412 : 0 [end]
+ element 00000000 34120000 34123412 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -181,7 +181,7 @@ inet test-inet input
# ip6 saddr vmap { 1234::1234:1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00003412 00000000 34123412 34123412 : 0 [end]
+ element 00003412 00000000 34123412 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -191,7 +191,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234::1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 00000000 34120000 34123412 : 0 [end]
+ element 34123412 00000000 34120000 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -201,7 +201,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234::1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 00003412 00000000 34123412 : 0 [end]
+ element 34123412 00003412 00000000 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -211,7 +211,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234:1234::1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 00000000 34120000 : 0 [end]
+ element 34123412 34123412 00000000 34120000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -221,7 +221,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234:1234:1234:: : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 00003412 00000000 : 0 [end]
+ element 34123412 34123412 00003412 00000000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -231,7 +231,7 @@ inet test-inet input
# ip6 saddr vmap { ::1234:1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00000000 00000000 34123412 34123412 : 0 [end]
+ element 00000000 00000000 34123412 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -241,7 +241,7 @@ inet test-inet input
# ip6 saddr vmap { 1234::1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00003412 00000000 34120000 34123412 : 0 [end]
+ element 00003412 00000000 34120000 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -251,7 +251,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234::1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 00000000 00000000 34123412 : 0 [end]
+ element 34123412 00000000 00000000 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -261,7 +261,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234::1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 00003412 00000000 34120000 : 0 [end]
+ element 34123412 00003412 00000000 34120000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -271,7 +271,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234:1234:: : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 00000000 00000000 : 0 [end]
+ element 34123412 34123412 00000000 00000000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -281,7 +281,7 @@ inet test-inet input
# ip6 saddr vmap { ::1234:1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00000000 00000000 34120000 34123412 : 0 [end]
+ element 00000000 00000000 34120000 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -291,7 +291,7 @@ inet test-inet input
# ip6 saddr vmap { 1234::1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00003412 00000000 00000000 34123412 : 0 [end]
+ element 00003412 00000000 00000000 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -301,7 +301,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234::1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 00000000 00000000 34120000 : 0 [end]
+ element 34123412 00000000 00000000 34120000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -311,7 +311,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:1234:: : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 00003412 00000000 00000000 : 0 [end]
+ element 34123412 00003412 00000000 00000000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -321,7 +321,7 @@ inet test-inet input
# ip6 saddr vmap { ::1234:1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00000000 00000000 00000000 34123412 : 0 [end]
+ element 00000000 00000000 00000000 34123412 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -331,7 +331,7 @@ inet test-inet input
# ip6 saddr vmap { 1234::1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00003412 00000000 00000000 34120000 : 0 [end]
+ element 00003412 00000000 00000000 34120000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -341,7 +341,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:1234:: : accept}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 00000000 00000000 00000000 : 0 [end]
+ element 34123412 00000000 00000000 00000000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -351,7 +351,7 @@ inet test-inet input
# ip6 saddr vmap { ::1234 : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00000000 00000000 00000000 34120000 : 0 [end]
+ element 00000000 00000000 00000000 34120000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -361,7 +361,7 @@ inet test-inet input
# ip6 saddr vmap { 1234:: : accept}
__map%d test-inet b
__map%d test-inet 0
- element 00003412 00000000 00000000 00000000 : 0 [end]
+ element 00003412 00000000 00000000 00000000 : accept 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -371,7 +371,7 @@ inet test-inet input
# ip6 saddr vmap { ::/64 : accept}
__map%d test-inet f
__map%d test-inet 0
- element 00000000 00000000 00000000 00000000 : 0 [end] element 00000000 01000000 00000000 00000000 : 1 [end]
+ element 00000000 00000000 00000000 00000000 : accept 0 [end] element 00000000 01000000 00000000 00000000 : 1 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -381,7 +381,7 @@ inet test-inet input
# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:: : accept, ::aaaa : drop}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 34123412 0000aaaa : 0 [end] element 00000000 00000000 00000000 aaaa0000 : 0 [end]
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 aaaa0000 : drop 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -391,7 +391,7 @@ inet test-inet input
# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept, ::bbbb : drop}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 34123412 0000aaaa : 0 [end] element 00000000 00000000 00000000 bbbb0000 : 0 [end]
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 bbbb0000 : drop 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -401,7 +401,7 @@ inet test-inet input
# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::cccc : drop}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 34123412 0000aaaa : 0 [end] element 00000000 00000000 00000000 cccc0000 : 0 [end]
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 cccc0000 : drop 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
@@ -411,7 +411,7 @@ inet test-inet input
# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::dddd: drop}
__map%d test-inet b
__map%d test-inet 0
- element 34123412 34123412 34123412 0000aaaa : 0 [end] element 00000000 00000000 00000000 dddd0000 : 0 [end]
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 dddd0000 : drop 0 [end]
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x0000000a ]
diff --git a/tests/py/ip6/vmap.t.payload.ip6 b/tests/py/ip6/vmap.t.payload.ip6
index 620979f0..6e077b27 100644
--- a/tests/py/ip6/vmap.t.payload.ip6
+++ b/tests/py/ip6/vmap.t.payload.ip6
@@ -1,7 +1,7 @@
# ip6 saddr vmap { abcd::3 : accept }
__map%d test-ip6 b
__map%d test-ip6 0
- element 0000cdab 00000000 00000000 03000000 : 0 [end]
+ element 0000cdab 00000000 00000000 03000000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -9,7 +9,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 34123412 34123412 : 0 [end]
+ element 34123412 34123412 34123412 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -17,7 +17,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34120000 34123412 34123412 34123412 : 0 [end]
+ element 34120000 34123412 34123412 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -25,7 +25,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00003412 34123412 34123412 34123412 : 0 [end]
+ element 00003412 34123412 34123412 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -33,7 +33,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34120000 34123412 34123412 : 0 [end]
+ element 34123412 34120000 34123412 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -41,7 +41,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 00003412 34123412 34123412 : 0 [end]
+ element 34123412 00003412 34123412 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -49,7 +49,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 34120000 34123412 : 0 [end]
+ element 34123412 34123412 34120000 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -57,7 +57,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 00003412 34123412 : 0 [end]
+ element 34123412 34123412 00003412 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -65,7 +65,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234::1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 34123412 34120000 : 0 [end]
+ element 34123412 34123412 34123412 34120000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -73,7 +73,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:: : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 34123412 00003412 : 0 [end]
+ element 34123412 34123412 34123412 00003412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -81,7 +81,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00000000 34123412 34123412 34123412 : 0 [end]
+ element 00000000 34123412 34123412 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -89,7 +89,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00003412 34120000 34123412 34123412 : 0 [end]
+ element 00003412 34120000 34123412 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -97,7 +97,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 00000000 34123412 34123412 : 0 [end]
+ element 34123412 00000000 34123412 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -105,7 +105,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 00003412 34120000 34123412 : 0 [end]
+ element 34123412 00003412 34120000 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -113,7 +113,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 00000000 34123412 : 0 [end]
+ element 34123412 34123412 00000000 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -121,7 +121,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 00003412 34120000 : 0 [end]
+ element 34123412 34123412 00003412 34120000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -129,7 +129,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:: : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 34123412 00000000 : 0 [end]
+ element 34123412 34123412 34123412 00000000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -137,7 +137,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { ::1234:1234:1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00000000 34120000 34123412 34123412 : 0 [end]
+ element 00000000 34120000 34123412 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -145,7 +145,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234::1234:1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00003412 00000000 34123412 34123412 : 0 [end]
+ element 00003412 00000000 34123412 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -153,7 +153,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234::1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 00000000 34120000 34123412 : 0 [end]
+ element 34123412 00000000 34120000 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -161,7 +161,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234::1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 00003412 00000000 34123412 : 0 [end]
+ element 34123412 00003412 00000000 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -169,7 +169,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234:1234::1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 00000000 34120000 : 0 [end]
+ element 34123412 34123412 00000000 34120000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -177,7 +177,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234:1234:1234:: : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 00003412 00000000 : 0 [end]
+ element 34123412 34123412 00003412 00000000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -185,7 +185,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { ::1234:1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00000000 00000000 34123412 34123412 : 0 [end]
+ element 00000000 00000000 34123412 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -193,7 +193,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234::1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00003412 00000000 34120000 34123412 : 0 [end]
+ element 00003412 00000000 34120000 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -201,7 +201,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234::1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 00000000 00000000 34123412 : 0 [end]
+ element 34123412 00000000 00000000 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -209,7 +209,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234::1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 00003412 00000000 34120000 : 0 [end]
+ element 34123412 00003412 00000000 34120000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -217,7 +217,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234:1234:: : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 00000000 00000000 : 0 [end]
+ element 34123412 34123412 00000000 00000000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -225,7 +225,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { ::1234:1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00000000 00000000 34120000 34123412 : 0 [end]
+ element 00000000 00000000 34120000 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -233,7 +233,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234::1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00003412 00000000 00000000 34123412 : 0 [end]
+ element 00003412 00000000 00000000 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -241,7 +241,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234::1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 00000000 00000000 34120000 : 0 [end]
+ element 34123412 00000000 00000000 34120000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -249,7 +249,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:1234:: : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 00003412 00000000 00000000 : 0 [end]
+ element 34123412 00003412 00000000 00000000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -257,7 +257,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { ::1234:1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00000000 00000000 00000000 34123412 : 0 [end]
+ element 00000000 00000000 00000000 34123412 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -265,7 +265,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234::1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00003412 00000000 00000000 34120000 : 0 [end]
+ element 00003412 00000000 00000000 34120000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -273,7 +273,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:1234:: : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 00000000 00000000 00000000 : 0 [end]
+ element 34123412 00000000 00000000 00000000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -281,7 +281,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { ::1234 : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00000000 00000000 00000000 34120000 : 0 [end]
+ element 00000000 00000000 00000000 34120000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -289,7 +289,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { 1234:: : accept}
__map%d test-ip6 b
__map%d test-ip6 0
- element 00003412 00000000 00000000 00000000 : 0 [end]
+ element 00003412 00000000 00000000 00000000 : accept 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -297,7 +297,7 @@ ip6 test-ip6 input
# ip6 saddr vmap { ::/64 : accept}
__map%d test-ip6 f
__map%d test-ip6 0
- element 00000000 00000000 00000000 00000000 : 0 [end] element 00000000 01000000 00000000 00000000 : 1 [end]
+ element 00000000 00000000 00000000 00000000 : accept 0 [end] element 00000000 01000000 00000000 00000000 : 1 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -305,7 +305,7 @@ ip6 test-ip6 input
# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:: : accept, ::aaaa : drop}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 34123412 0000aaaa : 0 [end] element 00000000 00000000 00000000 aaaa0000 : 0 [end]
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 aaaa0000 : drop 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -313,7 +313,7 @@ ip6 test-ip6 input
# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept, ::bbbb : drop}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 34123412 0000aaaa : 0 [end] element 00000000 00000000 00000000 bbbb0000 : 0 [end]
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 bbbb0000 : drop 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -321,7 +321,7 @@ ip6 test-ip6 input
# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::cccc : drop}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 34123412 0000aaaa : 0 [end] element 00000000 00000000 00000000 cccc0000 : 0 [end]
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 cccc0000 : drop 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
@@ -329,7 +329,7 @@ ip6 test-ip6 input
# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::dddd: drop}
__map%d test-ip6 b
__map%d test-ip6 0
- element 34123412 34123412 34123412 0000aaaa : 0 [end] element 00000000 00000000 00000000 dddd0000 : 0 [end]
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 dddd0000 : drop 0 [end]
ip6 test-ip6 input
[ payload load 16b @ network header + 8 => reg 1 ]
[ lookup reg 1 set __map%d dreg 0 ]
diff --git a/tests/py/ip6/vmap.t.payload.netdev b/tests/py/ip6/vmap.t.payload.netdev
index 0ae5d5b0..45f2c0b0 100644
--- a/tests/py/ip6/vmap.t.payload.netdev
+++ b/tests/py/ip6/vmap.t.payload.netdev
@@ -1,7 +1,7 @@
# ip6 saddr vmap { abcd::3 : accept }
__map%d test-netdev b
__map%d test-netdev 0
- element 0000cdab 00000000 00000000 03000000 : 0 [end]
+ element 0000cdab 00000000 00000000 03000000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -11,7 +11,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 34123412 34123412 : 0 [end]
+ element 34123412 34123412 34123412 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -21,7 +21,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34120000 34123412 34123412 34123412 : 0 [end]
+ element 34120000 34123412 34123412 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -31,7 +31,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00003412 34123412 34123412 34123412 : 0 [end]
+ element 00003412 34123412 34123412 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -41,7 +41,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34120000 34123412 34123412 : 0 [end]
+ element 34123412 34120000 34123412 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -51,7 +51,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 00003412 34123412 34123412 : 0 [end]
+ element 34123412 00003412 34123412 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -61,7 +61,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 34120000 34123412 : 0 [end]
+ element 34123412 34123412 34120000 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -71,7 +71,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 00003412 34123412 : 0 [end]
+ element 34123412 34123412 00003412 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -81,7 +81,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234::1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 34123412 34120000 : 0 [end]
+ element 34123412 34123412 34123412 34120000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -91,7 +91,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:1234:: : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 34123412 00003412 : 0 [end]
+ element 34123412 34123412 34123412 00003412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -101,7 +101,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { ::1234:1234:1234:1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00000000 34123412 34123412 34123412 : 0 [end]
+ element 00000000 34123412 34123412 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -111,7 +111,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234::1234:1234:1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00003412 34120000 34123412 34123412 : 0 [end]
+ element 00003412 34120000 34123412 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -121,7 +121,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234::1234:1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 00000000 34123412 34123412 : 0 [end]
+ element 34123412 00000000 34123412 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -131,7 +131,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234::1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 00003412 34120000 34123412 : 0 [end]
+ element 34123412 00003412 34120000 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -141,7 +141,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234:1234::1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 00000000 34123412 : 0 [end]
+ element 34123412 34123412 00000000 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -151,7 +151,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234:1234:1234::1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 00003412 34120000 : 0 [end]
+ element 34123412 34123412 00003412 34120000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -161,7 +161,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234:1234:1234:1234:: : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 34123412 00000000 : 0 [end]
+ element 34123412 34123412 34123412 00000000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -171,7 +171,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { ::1234:1234:1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00000000 34120000 34123412 34123412 : 0 [end]
+ element 00000000 34120000 34123412 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -181,7 +181,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234::1234:1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00003412 00000000 34123412 34123412 : 0 [end]
+ element 00003412 00000000 34123412 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -191,7 +191,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234::1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 00000000 34120000 34123412 : 0 [end]
+ element 34123412 00000000 34120000 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -201,7 +201,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234::1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 00003412 00000000 34123412 : 0 [end]
+ element 34123412 00003412 00000000 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -211,7 +211,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234:1234::1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 00000000 34120000 : 0 [end]
+ element 34123412 34123412 00000000 34120000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -221,7 +221,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234:1234:1234:: : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 00003412 00000000 : 0 [end]
+ element 34123412 34123412 00003412 00000000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -231,7 +231,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { ::1234:1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00000000 00000000 34123412 34123412 : 0 [end]
+ element 00000000 00000000 34123412 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -241,7 +241,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234::1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00003412 00000000 34120000 34123412 : 0 [end]
+ element 00003412 00000000 34120000 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -251,7 +251,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234::1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 00000000 00000000 34123412 : 0 [end]
+ element 34123412 00000000 00000000 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -261,7 +261,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234::1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 00003412 00000000 34120000 : 0 [end]
+ element 34123412 00003412 00000000 34120000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -271,7 +271,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234:1234:: : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 00000000 00000000 : 0 [end]
+ element 34123412 34123412 00000000 00000000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -281,7 +281,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { ::1234:1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00000000 00000000 34120000 34123412 : 0 [end]
+ element 00000000 00000000 34120000 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -291,7 +291,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234::1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00003412 00000000 00000000 34123412 : 0 [end]
+ element 00003412 00000000 00000000 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -301,7 +301,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234::1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 00000000 00000000 34120000 : 0 [end]
+ element 34123412 00000000 00000000 34120000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -311,7 +311,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:1234:: : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 00003412 00000000 00000000 : 0 [end]
+ element 34123412 00003412 00000000 00000000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -321,7 +321,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { ::1234:1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00000000 00000000 00000000 34123412 : 0 [end]
+ element 00000000 00000000 00000000 34123412 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -331,7 +331,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234::1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00003412 00000000 00000000 34120000 : 0 [end]
+ element 00003412 00000000 00000000 34120000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -341,7 +341,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:1234:: : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 00000000 00000000 00000000 : 0 [end]
+ element 34123412 00000000 00000000 00000000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -351,7 +351,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { ::1234 : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00000000 00000000 00000000 34120000 : 0 [end]
+ element 00000000 00000000 00000000 34120000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -361,7 +361,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { 1234:: : accept}
__map%d test-netdev b
__map%d test-netdev 0
- element 00003412 00000000 00000000 00000000 : 0 [end]
+ element 00003412 00000000 00000000 00000000 : accept 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -371,7 +371,7 @@ netdev test-netdev ingress
# ip6 saddr vmap { ::/64 : accept}
__map%d test-netdev f
__map%d test-netdev 0
- element 00000000 00000000 00000000 00000000 : 0 [end] element 00000000 01000000 00000000 00000000 : 1 [end]
+ element 00000000 00000000 00000000 00000000 : accept 0 [end] element 00000000 01000000 00000000 00000000 : 1 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -381,7 +381,7 @@ netdev test-netdev ingress
# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:: : accept, ::aaaa : drop}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 34123412 0000aaaa : 0 [end] element 00000000 00000000 00000000 aaaa0000 : 0 [end]
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 aaaa0000 : drop 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -391,7 +391,7 @@ netdev test-netdev ingress
# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept, ::bbbb : drop}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 34123412 0000aaaa : 0 [end] element 00000000 00000000 00000000 bbbb0000 : 0 [end]
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 bbbb0000 : drop 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -401,7 +401,7 @@ netdev test-netdev ingress
# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::cccc : drop}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 34123412 0000aaaa : 0 [end] element 00000000 00000000 00000000 cccc0000 : 0 [end]
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 cccc0000 : drop 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
@@ -411,7 +411,7 @@ netdev test-netdev ingress
# ip6 saddr vmap {1234:1234:1234:1234:1234:1234:aaaa:::accept,::dddd: drop}
__map%d test-netdev b
__map%d test-netdev 0
- element 34123412 34123412 34123412 0000aaaa : 0 [end] element 00000000 00000000 00000000 dddd0000 : 0 [end]
+ element 34123412 34123412 34123412 0000aaaa : accept 0 [end] element 00000000 00000000 00000000 dddd0000 : drop 0 [end]
netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
diff --git a/tests/py/any/dup.t b/tests/py/netdev/dup.t
index 181b4195..56328022 100644
--- a/tests/py/any/dup.t
+++ b/tests/py/netdev/dup.t
@@ -1,6 +1,7 @@
:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
dup to "lo";ok
dup to meta mark map { 0x00000001 : "lo", 0x00000002 : "lo"};ok
diff --git a/tests/py/any/dup.t.json b/tests/py/netdev/dup.t.json
index dc56f649..dc56f649 100644
--- a/tests/py/any/dup.t.json
+++ b/tests/py/netdev/dup.t.json
diff --git a/tests/py/any/dup.t.payload b/tests/py/netdev/dup.t.payload
index 51ff782c..51ff782c 100644
--- a/tests/py/any/dup.t.payload
+++ b/tests/py/netdev/dup.t.payload
diff --git a/tests/py/any/fwd.t b/tests/py/netdev/fwd.t
index 2e34d55a..6051560a 100644
--- a/tests/py/any/fwd.t
+++ b/tests/py/netdev/fwd.t
@@ -1,6 +1,7 @@
:ingress;type filter hook ingress device lo priority 0
+:egress;type filter hook egress device lo priority 0
-*netdev;test-netdev;ingress
+*netdev;test-netdev;ingress,egress
fwd to "lo";ok
fwd to meta mark map { 0x00000001 : "lo", 0x00000002 : "lo"};ok
diff --git a/tests/py/any/fwd.t.json b/tests/py/netdev/fwd.t.json
index 583606c0..583606c0 100644
--- a/tests/py/any/fwd.t.json
+++ b/tests/py/netdev/fwd.t.json
diff --git a/tests/py/any/fwd.t.json.output b/tests/py/netdev/fwd.t.json.output
index 8433e492..8433e492 100644
--- a/tests/py/any/fwd.t.json.output
+++ b/tests/py/netdev/fwd.t.json.output
diff --git a/tests/py/any/fwd.t.payload b/tests/py/netdev/fwd.t.payload
index f03077a6..f03077a6 100644
--- a/tests/py/any/fwd.t.payload
+++ b/tests/py/netdev/fwd.t.payload
diff --git a/tests/py/netdev/reject.t b/tests/py/netdev/reject.t
new file mode 100644
index 00000000..c66e649c
--- /dev/null
+++ b/tests/py/netdev/reject.t
@@ -0,0 +1,40 @@
+:ingress;type filter hook ingress device lo priority 0
+
+*netdev;test-netdev;ingress
+
+reject with icmp host-unreachable;ok
+reject with icmp net-unreachable;ok
+reject with icmp prot-unreachable;ok
+reject with icmp port-unreachable;ok
+reject with icmp net-prohibited;ok
+reject with icmp host-prohibited;ok
+reject with icmp admin-prohibited;ok
+
+reject with icmpv6 no-route;ok
+reject with icmpv6 admin-prohibited;ok
+reject with icmpv6 addr-unreachable;ok
+reject with icmpv6 port-unreachable;ok
+reject with icmpv6 policy-fail;ok
+reject with icmpv6 reject-route;ok
+
+mark 12345 reject with tcp reset;ok;meta l4proto 6 meta mark 0x00003039 reject with tcp reset
+
+reject;ok
+meta protocol ip reject;ok;reject with icmp port-unreachable
+meta protocol ip6 reject;ok;reject with icmpv6 port-unreachable
+
+reject with icmpx host-unreachable;ok
+reject with icmpx no-route;ok
+reject with icmpx admin-prohibited;ok
+reject with icmpx port-unreachable;ok;reject
+
+meta protocol ip reject with icmp host-unreachable;ok;reject with icmp host-unreachable
+meta protocol ip6 reject with icmpv6 no-route;ok;reject with icmpv6 no-route
+
+meta protocol ip6 reject with icmp host-unreachable;fail
+meta protocol ip ip protocol icmp reject with icmpv6 no-route;fail
+meta protocol ip6 ip protocol icmp reject with icmp host-unreachable;fail
+meta l4proto udp reject with tcp reset;fail
+
+meta protocol ip reject with icmpx admin-prohibited;ok
+meta protocol ip6 reject with icmpx admin-prohibited;ok
diff --git a/tests/py/netdev/reject.t.json b/tests/py/netdev/reject.t.json
new file mode 100644
index 00000000..9968aaf8
--- /dev/null
+++ b/tests/py/netdev/reject.t.json
@@ -0,0 +1,293 @@
+# reject with icmp host-unreachable
+[
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp net-unreachable
+[
+ {
+ "reject": {
+ "expr": "net-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp prot-unreachable
+[
+ {
+ "reject": {
+ "expr": "prot-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp net-prohibited
+[
+ {
+ "reject": {
+ "expr": "net-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp host-prohibited
+[
+ {
+ "reject": {
+ "expr": "host-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmp admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmp"
+ }
+ }
+]
+
+# reject with icmpv6 no-route
+[
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 addr-unreachable
+[
+ {
+ "reject": {
+ "expr": "addr-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 policy-fail
+[
+ {
+ "reject": {
+ "expr": "policy-fail",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpv6 reject-route
+[
+ {
+ "reject": {
+ "expr": "reject-route",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# mark 12345 reject with tcp reset
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "op": "==",
+ "right": 6
+ }
+ },
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "op": "==",
+ "right": 12345
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+]
+
+# reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
+
+# meta protocol ip reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# meta protocol ip6 reject
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# reject with icmpx host-unreachable
+[
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx no-route
+[
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx admin-prohibited
+[
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
+# reject with icmpx port-unreachable
+[
+ {
+ "reject": {
+ "expr": "port-unreachable",
+ "type": "icmpx"
+ }
+ }
+]
+
+# meta protocol ip reject with icmp host-unreachable
+[
+ {
+ "reject": {
+ "expr": "host-unreachable",
+ "type": "icmp"
+ }
+ }
+]
+
+# meta protocol ip6 reject with icmpv6 no-route
+[
+ {
+ "reject": {
+ "expr": "no-route",
+ "type": "icmpv6"
+ }
+ }
+]
+
+# meta protocol ip reject with icmpx admin-prohibited
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip"
+ }
+ },
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
+# meta protocol ip6 reject with icmpx admin-prohibited
+[
+ {
+ "match": {
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "op": "==",
+ "right": "ip6"
+ }
+ },
+ {
+ "reject": {
+ "expr": "admin-prohibited",
+ "type": "icmpx"
+ }
+ }
+]
+
diff --git a/tests/py/netdev/reject.t.payload b/tests/py/netdev/reject.t.payload
new file mode 100644
index 00000000..d014adab
--- /dev/null
+++ b/tests/py/netdev/reject.t.payload
@@ -0,0 +1,142 @@
+# reject with icmp host-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 1 ]
+
+# reject with icmp net-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 0 ]
+
+# reject with icmp prot-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 2 ]
+
+# reject with icmp port-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 3 ]
+
+# reject with icmp net-prohibited
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 9 ]
+
+# reject with icmp host-prohibited
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 10 ]
+
+# reject with icmp admin-prohibited
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 13 ]
+
+# reject with icmpv6 no-route
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 0 ]
+
+# reject with icmpv6 admin-prohibited
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 1 ]
+
+# reject with icmpv6 addr-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 3 ]
+
+# reject with icmpv6 port-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 4 ]
+
+# reject with icmpv6 policy-fail
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 5 ]
+
+# reject with icmpv6 reject-route
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 6 ]
+
+# mark 12345 reject with tcp reset
+netdev
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ meta load mark => reg 1 ]
+ [ cmp eq reg 1 0x00003039 ]
+ [ reject type 1 code 0 ]
+
+# reject
+netdev
+ [ reject type 2 code 1 ]
+
+# meta protocol ip reject
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 3 ]
+
+# meta protocol ip6 reject
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 4 ]
+
+# reject with icmpx host-unreachable
+netdev
+ [ reject type 2 code 2 ]
+
+# reject with icmpx no-route
+netdev
+ [ reject type 2 code 0 ]
+
+# reject with icmpx admin-prohibited
+netdev
+ [ reject type 2 code 3 ]
+
+# reject with icmpx port-unreachable
+netdev
+ [ reject type 2 code 1 ]
+
+# meta protocol ip reject with icmp host-unreachable
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 0 code 1 ]
+
+# meta protocol ip6 reject with icmpv6 no-route
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 0 code 0 ]
+
+# meta protocol ip reject with icmpx admin-prohibited
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ reject type 2 code 3 ]
+
+# meta protocol ip6 reject with icmpx admin-prohibited
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x0000dd86 ]
+ [ reject type 2 code 3 ]
+
diff --git a/tests/py/nft-test.py b/tests/py/nft-test.py
index bc0849e0..1bc89558 100755
--- a/tests/py/nft-test.py
+++ b/tests/py/nft-test.py
@@ -24,10 +24,11 @@ import tempfile
TESTS_PATH = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.join(TESTS_PATH, '../../py/'))
+os.environ['TZ'] = 'UTC-2'
from nftables import Nftables
-TESTS_DIRECTORY = ["any", "arp", "bridge", "inet", "ip", "ip6"]
+TESTS_DIRECTORY = ["any", "arp", "bridge", "inet", "ip", "ip6", "netdev"]
LOGFILE = "/tmp/nftables-test.log"
log_file = None
table_list = []
@@ -38,7 +39,7 @@ signal_received = 0
class Colors:
- if sys.stdout.isatty():
+ if sys.stdout.isatty() and sys.stderr.isatty():
HEADER = '\033[95m'
GREEN = '\033[92m'
YELLOW = '\033[93m'
@@ -85,11 +86,12 @@ class Table:
class Set:
"""Class that represents a set"""
- def __init__(self, family, table, name, type, timeout, flags):
+ def __init__(self, family, table, name, type, data, timeout, flags):
self.family = family
self.table = table
self.name = name
self.type = type
+ self.data = data
self.timeout = timeout
self.flags = flags
@@ -115,12 +117,12 @@ def print_msg(reason, errstr, filename=None, lineno=None, color=None):
'''
Prints a message with nice colors, indicating file and line number.
'''
+ color_errstr = "%s%s%s" % (color, errstr, Colors.ENDC)
if filename and lineno:
- sys.stderr.write(filename + ": " + color + errstr + Colors.ENDC + \
- " line %d: %s" % (lineno + 1, reason))
+ sys.stderr.write("%s: %s line %d: %s\n" %
+ (filename, color_errstr, lineno + 1, reason))
else:
- sys.stderr.write(color + errstr + Colors.ENDC + " %s" % reason)
- sys.stderr.write("\n")
+ sys.stderr.write("%s %s\n" % (color_errstr, reason))
sys.stderr.flush() # So that the message stay in the right place.
@@ -365,7 +367,11 @@ def set_add(s, test_result, filename, lineno):
if flags != "":
flags = "flags %s; " % flags
- cmd = "add set %s %s { type %s;%s %s}" % (table, s.name, s.type, s.timeout, flags)
+ if s.data == "":
+ cmd = "add set %s %s { %s;%s %s}" % (table, s.name, s.type, s.timeout, flags)
+ else:
+ cmd = "add map %s %s { %s : %s;%s %s}" % (table, s.name, s.type, s.data, s.timeout, flags)
+
ret = execute_cmd(cmd, filename, lineno)
if (ret == 0 and test_result == "fail") or \
@@ -383,6 +389,44 @@ def set_add(s, test_result, filename, lineno):
return 0
+def map_add(s, test_result, filename, lineno):
+ '''
+ Adds a map
+ '''
+ if not table_list:
+ reason = "Missing table to add rule"
+ print_error(reason, filename, lineno)
+ return -1
+
+ for table in table_list:
+ s.table = table.name
+ s.family = table.family
+ if _map_exist(s, filename, lineno):
+ reason = "Map %s already exists in %s" % (s.name, table)
+ print_error(reason, filename, lineno)
+ return -1
+
+ flags = s.flags
+ if flags != "":
+ flags = "flags %s; " % flags
+
+ cmd = "add map %s %s { %s : %s;%s %s}" % (table, s.name, s.type, s.data, s.timeout, flags)
+
+ ret = execute_cmd(cmd, filename, lineno)
+
+ if (ret == 0 and test_result == "fail") or \
+ (ret != 0 and test_result == "ok"):
+ reason = "%s: I cannot add the set %s" % (cmd, s.name)
+ print_error(reason, filename, lineno)
+ return -1
+
+ if not _map_exist(s, filename, lineno):
+ reason = "I have just added the set %s to " \
+ "the table %s but it does not exist" % (s.name, table)
+ print_error(reason, filename, lineno)
+ return -1
+
+
def set_add_elements(set_element, set_name, state, filename, lineno):
'''
Adds elements to the set.
@@ -406,7 +450,11 @@ def set_add_elements(set_element, set_name, state, filename, lineno):
ret = execute_cmd(cmd, filename, lineno)
if (state == "fail" and ret == 0) or (state == "ok" and ret != 0):
- test_state = "This rule should have failed."
+ if state == "fail":
+ test_state = "This rule should have failed."
+ else:
+ test_state = "This rule should not have failed."
+
reason = cmd + ": " + test_state
print_error(reason, filename, lineno)
return -1
@@ -485,6 +533,16 @@ def _set_exist(s, filename, lineno):
return True if (ret == 0) else False
+def _map_exist(s, filename, lineno):
+ '''
+ Check if the map exists.
+ '''
+ cmd = "list map %s %s %s" % (s.family, s.table, s.name)
+ ret = execute_cmd(cmd, filename, lineno)
+
+ return True if (ret == 0) else False
+
+
def set_check_element(rule1, rule2):
'''
Check if element exists in anonymous sets.
@@ -711,8 +769,10 @@ def rule_add(rule, filename, lineno, force_all_family_option, filename_path):
if rule[1].strip() == "ok":
payload_expected = None
+ payload_path = None
try:
payload_log = open("%s.payload" % filename_path)
+ payload_path = payload_log.name
payload_expected = payload_find_expected(payload_log, rule[0])
except:
payload_log = None
@@ -749,12 +809,15 @@ def rule_add(rule, filename, lineno, force_all_family_option, filename_path):
reason = "Invalid JSON syntax in expected output: %s" % json_expected
print_error(reason)
return [-1, warning, error, unit_tests]
+ if json_expected == json_input:
+ print_warning("Recorded JSON output matches input for: %s" % rule[0])
for table in table_list:
if rule[1].strip() == "ok":
table_payload_expected = None
try:
payload_log = open("%s.payload.%s" % (filename_path, table.family))
+ payload_path = payload_log.name
table_payload_expected = payload_find_expected(payload_log, rule[0])
except:
if not payload_log:
@@ -801,17 +864,26 @@ def rule_add(rule, filename, lineno, force_all_family_option, filename_path):
if state == "ok" and not payload_check(table_payload_expected,
payload_log, cmd):
error += 1
- gotf = open("%s.payload.got" % filename_path, 'a')
+
+ try:
+ gotf = open("%s.got" % payload_path)
+ gotf_payload_expected = payload_find_expected(gotf, rule[0])
+ gotf.close()
+ except:
+ gotf_payload_expected = None
payload_log.seek(0, 0)
- gotf.write("# %s\n" % rule[0])
- while True:
- line = payload_log.readline()
- if line == "":
- break
- gotf.write(line)
- gotf.close()
- print_warning("Wrote payload for rule %s" % rule[0],
- gotf.name, 1)
+ if not payload_check(gotf_payload_expected, payload_log, cmd):
+ gotf = open("%s.got" % payload_path, 'a')
+ payload_log.seek(0, 0)
+ gotf.write("# %s\n" % rule[0])
+ while True:
+ line = payload_log.readline()
+ if line == "":
+ break
+ gotf.write(line)
+ gotf.close()
+ print_warning("Wrote payload for rule %s" % rule[0],
+ gotf.name, 1)
# Check for matching ruleset listing
numeric_proto_old = nftables.set_numeric_proto_output(True)
@@ -1021,6 +1093,8 @@ def execute_cmd(cmd, filename, lineno, stdout_log=False, debug=False):
if debug_option:
print(cmd)
+ log_file.flush()
+
if debug:
debug_old = nftables.get_debug()
nftables.set_debug(debug)
@@ -1072,14 +1146,28 @@ def set_process(set_line, filename, lineno):
tokens = set_line[0].split(" ")
set_name = tokens[0]
- set_type = tokens[2]
+ parse_typeof = tokens[1] == "typeof"
+ set_type = tokens[1] + " " + tokens[2]
+ set_data = ""
set_flags = ""
i = 3
+ if parse_typeof and tokens[i] == "id":
+ set_type += " " + tokens[i]
+ i += 1;
+
while len(tokens) > i and tokens[i] == ".":
set_type += " . " + tokens[i+1]
i += 2
+ while len(tokens) > i and tokens[i] == ":":
+ set_data = tokens[i+1]
+ i += 2
+
+ if parse_typeof and tokens[i] == "mark":
+ set_data += " " + tokens[i]
+ i += 1;
+
if len(tokens) == i+2 and tokens[i] == "timeout":
timeout = "timeout " + tokens[i+1] + ";"
i += 2
@@ -1089,9 +1177,13 @@ def set_process(set_line, filename, lineno):
elif len(tokens) != i:
print_error(set_name + " bad flag: " + tokens[i], filename, lineno)
- s = Set("", "", set_name, set_type, timeout, set_flags)
+ s = Set("", "", set_name, set_type, set_data, timeout, set_flags)
+
+ if set_data == "":
+ ret = set_add(s, test_result, filename, lineno)
+ else:
+ ret = map_add(s, test_result, filename, lineno)
- ret = set_add(s, test_result, filename, lineno)
if ret == 0:
all_set[set_name] = set()
@@ -1339,6 +1431,33 @@ def run_test_file(filename, force_all_family_option, specific_file):
return [tests, passed, total_warning, total_error, total_unit_run]
+def spawn_netns():
+ # prefer unshare module
+ try:
+ import unshare
+ unshare.unshare(unshare.CLONE_NEWNET)
+ return True
+ except:
+ pass
+
+ # sledgehammer style:
+ # - call ourselves prefixed by 'unshare -n' if found
+ # - pass extra --no-netns parameter to avoid another recursion
+ try:
+ import shutil
+
+ unshare = shutil.which("unshare")
+ if unshare is None:
+ return False
+
+ sys.argv.append("--no-netns")
+ if debug_option:
+ print("calling: ", [unshare, "-n", sys.executable] + sys.argv)
+ os.execv(unshare, [unshare, "-n", sys.executable] + sys.argv)
+ except:
+ pass
+
+ return False
def main():
parser = argparse.ArgumentParser(description='Run nft tests')
@@ -1356,10 +1475,20 @@ def main():
dest='force_all_family',
help='keep testing all families on error')
+ parser.add_argument('-H', '--host', action='store_true',
+ help='run tests against installed libnftables.so.1')
+
parser.add_argument('-j', '--enable-json', action='store_true',
dest='enable_json',
help='test JSON functionality as well')
+ parser.add_argument('-l', '--library', default=None,
+ help='path to libntables.so.1, overrides --host')
+
+ parser.add_argument('-N', '--no-netns', action='store_true',
+ dest='no_netns',
+ help='Do not run in own network namespace')
+
parser.add_argument('-s', '--schema', action='store_true',
dest='enable_schema',
help='verify json input/output against schema')
@@ -1384,12 +1513,23 @@ def main():
print("You need to be root to run this, sorry")
return
+ if not args.no_netns and not spawn_netns():
+ print_warning("cannot run in own namespace, connectivity might break")
+
# Change working directory to repository root
os.chdir(TESTS_PATH + "/../..")
- if not os.path.exists('src/.libs/libnftables.so'):
- print("The nftables library does not exist. "
- "You need to build the project.")
+ check_lib_path = True
+ if args.library is None:
+ if args.host:
+ args.library = 'libnftables.so.1'
+ check_lib_path = False
+ else:
+ args.library = 'src/.libs/libnftables.so.1'
+
+ if check_lib_path and not os.path.exists(args.library):
+ print("The nftables library at '%s' does not exist. "
+ "You need to build the project." % args.library)
return
if args.enable_schema and not args.enable_json:
@@ -1397,7 +1537,7 @@ def main():
return
global nftables
- nftables = Nftables(sofile = 'src/.libs/libnftables.so')
+ nftables = Nftables(sofile = args.library)
test_files = files_ok = run_total = 0
tests = passed = warnings = errors = 0
diff --git a/tests/py/tools/test-sanitizer.sh b/tests/py/tools/test-sanitizer.sh
new file mode 100755
index 00000000..92354d2b
--- /dev/null
+++ b/tests/py/tools/test-sanitizer.sh
@@ -0,0 +1,78 @@
+#!/bin/bash
+
+# Do some simple sanity checks on tests:
+# - Report tests where reply matches command
+# - Report tests with non-ok exit but reply
+# - Check for duplicate test commands in *.t files
+# - Check for duplicate or stale payload records in *.t.payload* files
+# - Check for duplicate or stale json equivalents in *.t.json files
+
+cd $(dirname $0)/../
+
+[[ $1 ]] && tests="$@" || tests="*/*.t"
+
+reportfile=""
+report() { # (file, msg)
+ [[ "$reportfile" == "$1" ]] || {
+ reportfile="$1"
+ echo ""
+ echo "In $reportfile:"
+ }
+ shift
+ echo "$@"
+}
+
+for t in $tests; do
+ [[ -f $t ]] || continue
+
+ readarray -t cmdlines <<< $(grep -v -e '^ *[:*#-?]' -e '^ *$' $t)
+
+ cmds=""
+ for cmdline in "${cmdlines[@]}"; do
+ readarray -t -d ';' cmdparts <<< "$cmdline"
+ cmd="${cmdparts[0]}"
+ rc="${cmdparts[1]}"
+ out="${cmdparts[2]}"
+
+ [[ -n $cmd ]] || continue
+
+ #echo "cmdline: $cmdline"
+ #echo "cmd: $cmd"
+ #echo "rc: $rc"
+ #echo "out: $out"
+
+ [[ "$cmd" != "$out" ]] || \
+ report $t "reply matches cmd: $cmd"
+ [[ "$rc" != "ok" && "$out" ]] && \
+ report $t "output record with non-ok exit: $cmd"
+
+ cmds+="${cmd}\n"
+ done
+
+ readarray -t dups <<< $(echo -e "$cmds" | sort | uniq -d)
+ for dup in "${dups[@]}"; do
+ [[ -n $dup ]] || continue
+ report $t "duplicate command: $dup"
+ done
+
+ for p in $t.payload* $t.json; do
+ [[ -f $p ]] || continue
+ [[ $p == *.got ]] && continue
+ [[ $p == *.json ]] && t="json" || t="payload"
+
+ pcmds=$(grep '^#' $p)
+ readarray -t dups <<< $(echo "$pcmds" | sort | uniq -d)
+ readarray -t stales <<< $(echo "$pcmds" | while read hash pcmd; do
+ echo -e "$cmds" | grep -qxF "${pcmd}" || echo "# ${pcmd}"
+ done)
+
+ for stale in "${stales[@]}"; do
+ [[ -n $stale ]] || continue
+ report $p "stale $t record: $stale"
+ done
+ for dup in "${dups[@]}"; do
+ [[ -n $dup ]] || continue
+ report $p "duplicate $t record: $dup"
+ done
+ done
+done
diff --git a/tests/shell/README b/tests/shell/README
index e0279bbd..3af17a9e 100644
--- a/tests/shell/README
+++ b/tests/shell/README
@@ -1,16 +1,20 @@
-This test-suite is intended to perform tests of higher level than
-the other regression test-suite.
+This test suite is intended to perform tests on a higher level
+than the other regression test suites.
-It can run arbitrary executables which can perform any test apart of testing
-the nft syntax or netlink code (which is what the regression tests does).
+It can run arbitrary executables which can perform any test, not
+limited to testing the nft syntax or netlink code (which is what
+the regression tests do).
To run the test suite (as root):
$ cd tests/shell
# ./run-tests.sh
-Test files are executables files with the pattern <<name_N>>, where N is the
-expected return code of the executable. Since they are located with `find',
-test-files can be spread in any sub-directories.
+Test files are executable files matching the pattern <<name_N>>,
+where N should be 0 in all new tests. All tests should return 0 on
+success.
+
+Since they are located with `find', test files can be put in any
+subdirectory.
You can turn on a verbose execution by calling:
# ./run-tests.sh -v
@@ -18,11 +22,14 @@ You can turn on a verbose execution by calling:
And generate missing dump files with:
# ./run-tests.sh -g <TESTFILE>
-Before each call to the test-files, `nft flush ruleset' will be called.
-Also, test-files will receive the environment variable $NFT which contains the
-path to the nftables binary being tested.
+Before each test file invocation, `nft flush ruleset' will be called.
+Also, test file process environment will include the variable $NFT
+which contains the nft command being tested.
You can pass an arbitrary $NFT value as well:
# NFT=/usr/local/sbin/nft ./run-tests.sh
-By default the tests are run with the nft binary at '../../src/nft'
+Note that, to support usage such as NFT='valgrind nft', tests must
+invoke $NFT unquoted.
+
+By default, the tests are run with the nft binary at '../../src/nft'
diff --git a/tests/shell/features/bitshift.nft b/tests/shell/features/bitshift.nft
new file mode 100644
index 00000000..7f9ccb64
--- /dev/null
+++ b/tests/shell/features/bitshift.nft
@@ -0,0 +1,7 @@
+# 567d746b55bc ("netfilter: bitwise: add support for shifts.")
+# v5.6-rc1~151^2~73^2
+table ip t {
+ chain c {
+ meta mark set meta mark << 2
+ }
+}
diff --git a/tests/shell/features/catchall_element.nft b/tests/shell/features/catchall_element.nft
new file mode 100644
index 00000000..1a02fd61
--- /dev/null
+++ b/tests/shell/features/catchall_element.nft
@@ -0,0 +1,8 @@
+# aaa31047a6d2 ("netfilter: nftables: add catch-all set element support")
+# v5.13-rc1~94^2~10^2~2
+table t {
+ map m {
+ type inet_service : inet_service
+ elements = { * : 42 }
+ }
+}
diff --git a/tests/shell/features/chain_binding.nft b/tests/shell/features/chain_binding.nft
new file mode 100644
index 00000000..b381ec54
--- /dev/null
+++ b/tests/shell/features/chain_binding.nft
@@ -0,0 +1,7 @@
+# d0e2c7de92c7 ("netfilter: nf_tables: add NFT_CHAIN_BINDING")
+# v5.9-rc1~133^2~302^2~1
+table ip t {
+ chain c {
+ jump { counter; }
+ }
+}
diff --git a/tests/shell/features/comment.sh b/tests/shell/features/comment.sh
new file mode 100755
index 00000000..0ad24d04
--- /dev/null
+++ b/tests/shell/features/comment.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# 002f21765320 ("netfilter: nf_tables: add userdata attributes to nft_chain")
+# v5.10-rc1~107^2~60^2~5
+
+EXPECTED="table ip x {
+ chain y {
+ comment \"test\"
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
+diff -u <($NFT list ruleset) - <<<"$EXPECTED"
diff --git a/tests/shell/features/ctexpect.nft b/tests/shell/features/ctexpect.nft
new file mode 100644
index 00000000..02c3dfd7
--- /dev/null
+++ b/tests/shell/features/ctexpect.nft
@@ -0,0 +1,10 @@
+# 857b46027d6f ("netfilter: nft_ct: add ct expectations support")
+# v5.3-rc1~140^2~153^2~19
+table t {
+ ct expectation ctexpect {
+ protocol tcp
+ dport 5432
+ timeout 1h
+ size 12;
+ }
+}
diff --git a/tests/shell/features/cttimeout.nft b/tests/shell/features/cttimeout.nft
new file mode 100644
index 00000000..4be58cd3
--- /dev/null
+++ b/tests/shell/features/cttimeout.nft
@@ -0,0 +1,8 @@
+# 7e0b2b57f01d ("netfilter: nft_ct: add ct timeout support")
+# v4.19-rc1~140^2~64^2~3
+table t {
+ ct timeout cttime {
+ protocol tcp;
+ policy = {established: 120 }
+ }
+}
diff --git a/tests/shell/features/destroy.nft b/tests/shell/features/destroy.nft
new file mode 100644
index 00000000..b97242e4
--- /dev/null
+++ b/tests/shell/features/destroy.nft
@@ -0,0 +1,3 @@
+# f80a612dd77c ("netfilter: nf_tables: add support to destroy operation")
+# v6.3-rc1~162^2~264^2
+destroy table t
diff --git a/tests/shell/features/dynset_op_delete.nft b/tests/shell/features/dynset_op_delete.nft
new file mode 100644
index 00000000..125b4526
--- /dev/null
+++ b/tests/shell/features/dynset_op_delete.nft
@@ -0,0 +1,12 @@
+# d0a8d877da97 ("netfilter: nft_dynset: support for element deletion")
+# v5.4-rc1~131^2~59^2~4
+table ip x {
+ set s {
+ flags dynamic;
+ type inet_service;
+ }
+
+ chain y {
+ delete @s { tcp dport }
+ }
+}
diff --git a/tests/shell/features/flowtable_counter.sh b/tests/shell/features/flowtable_counter.sh
new file mode 100755
index 00000000..a4c4c621
--- /dev/null
+++ b/tests/shell/features/flowtable_counter.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+# 53c2b2899af7 ("netfilter: flowtable: add counter support")
+# v5.7-rc1~146^2~12^2~16
+
+EXPECTED="table ip filter2 {
+ flowtable main_ft2 {
+ hook ingress priority filter
+ devices = { lo }
+ counter
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
+diff -u <($NFT list ruleset) - <<<"$EXPECTED"
diff --git a/tests/shell/features/flowtable_no_devices.nft b/tests/shell/features/flowtable_no_devices.nft
new file mode 100755
index 00000000..30dd3db8
--- /dev/null
+++ b/tests/shell/features/flowtable_no_devices.nft
@@ -0,0 +1,8 @@
+# 05abe4456fa3 ("netfilter: nf_tables: allow to register flowtable with no devices")
+# v5.8-rc1~165^2~27^2~1
+table ip filter2 {
+ flowtable main_ft2 {
+ hook ingress priority filter
+ counter
+ }
+}
diff --git a/tests/shell/features/inet_ingress.nft b/tests/shell/features/inet_ingress.nft
new file mode 100644
index 00000000..944a5c77
--- /dev/null
+++ b/tests/shell/features/inet_ingress.nft
@@ -0,0 +1,7 @@
+# d3519cb89f6d ("netfilter: nf_tables: add inet ingress support")
+# v5.10-rc1~107^2~17^2~1
+table inet t {
+ chain c {
+ type filter hook ingress device "lo" priority filter; policy accept;
+ }
+}
diff --git a/tests/shell/features/inet_nat.nft b/tests/shell/features/inet_nat.nft
new file mode 100644
index 00000000..189ea1d0
--- /dev/null
+++ b/tests/shell/features/inet_nat.nft
@@ -0,0 +1,7 @@
+# v5.2-rc1~133^2~174^2~15
+# d164385ec572 ("netfilter: nat: add inet family nat support")
+table inet x {
+ chain y {
+ type nat hook prerouting priority dstnat;
+ }
+}
diff --git a/tests/shell/features/inner_matching.nft b/tests/shell/features/inner_matching.nft
new file mode 100644
index 00000000..6c86fd35
--- /dev/null
+++ b/tests/shell/features/inner_matching.nft
@@ -0,0 +1,7 @@
+# 3a07327d10a0 ("netfilter: nft_inner: support for inner tunnel header matching")
+# v6.2-rc1~99^2~350^2~4
+table ip t {
+ chain c {
+ udp dport 4789 vxlan ip saddr 1.2.3.4
+ }
+}
diff --git a/tests/shell/features/json.sh b/tests/shell/features/json.sh
new file mode 100755
index 00000000..d8115702
--- /dev/null
+++ b/tests/shell/features/json.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+# Detect JSON support. Note that $NFT may not be the binary from our build
+# tree, hence we detect it by running the binary (instead of asking the build
+# configuration).
+$NFT -j list ruleset
diff --git a/tests/shell/features/map_lookup.nft b/tests/shell/features/map_lookup.nft
new file mode 100644
index 00000000..06c4c9d9
--- /dev/null
+++ b/tests/shell/features/map_lookup.nft
@@ -0,0 +1,11 @@
+# a4878eeae390 ("netfilter: nf_tables: relax set/map validation checks")
+# v6.5-rc1~163^2~256^2~8
+table ip t {
+ map m {
+ typeof ip daddr : meta mark
+ }
+
+ chain c {
+ ip saddr @m
+ }
+}
diff --git a/tests/shell/features/meta_time.nft b/tests/shell/features/meta_time.nft
new file mode 100644
index 00000000..34550de4
--- /dev/null
+++ b/tests/shell/features/meta_time.nft
@@ -0,0 +1,7 @@
+# 63d10e12b00d ("netfilter: nft_meta: support for time matching")
+# v5.4-rc1~131^2~59^2~6
+table ip t {
+ chain c {
+ meta time "1970-05-23 21:07:14"
+ }
+}
diff --git a/tests/shell/features/netdev_chain_multidevice.sh b/tests/shell/features/netdev_chain_multidevice.sh
new file mode 100755
index 00000000..d2a56d6d
--- /dev/null
+++ b/tests/shell/features/netdev_chain_multidevice.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# d54725cd11a5 ("netfilter: nf_tables: support for multiple devices per netdev hook")
+# v5.5-rc1~174^2~312^2~4
+
+trap "ip link del d0; ip link del d1" EXIT
+
+ip link add d0 type dummy
+ip link add d1 type dummy
+
+EXPECTED="table netdev filter2 {
+ chain Main_Ingress2 {
+ type filter hook ingress devices = { \"d0\", \"d1\" } priority -500; policy accept;
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/features/netdev_chain_without_device.nft b/tests/shell/features/netdev_chain_without_device.nft
new file mode 100644
index 00000000..25eb200f
--- /dev/null
+++ b/tests/shell/features/netdev_chain_without_device.nft
@@ -0,0 +1,7 @@
+# 207296f1a03b ("netfilter: nf_tables: allow to create netdev chain without device")
+# v6.4-rc1~132^2~14^2
+table netdev t {
+ chain c {
+ type filter hook ingress priority 0; policy accept;
+ }
+}
diff --git a/tests/shell/features/netdev_egress.nft b/tests/shell/features/netdev_egress.nft
new file mode 100644
index 00000000..67d706d8
--- /dev/null
+++ b/tests/shell/features/netdev_egress.nft
@@ -0,0 +1,7 @@
+# 42df6e1d221d ("netfilter: Introduce egress hook")
+# v5.16-rc1~159^2~167^2~10
+table netdev t {
+ chain c {
+ type filter hook egress devices = { lo } priority 0; policy accept;
+ }
+}
diff --git a/tests/shell/features/netmap.nft b/tests/shell/features/netmap.nft
new file mode 100644
index 00000000..2580a8dc
--- /dev/null
+++ b/tests/shell/features/netmap.nft
@@ -0,0 +1,8 @@
+# 3ff7ddb1353d ("netfilter: nft_nat: add netmap support")
+# v5.8-rc1~165^2~393^2
+table ip x {
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 }
+ }
+}
diff --git a/tests/shell/features/osf.nft b/tests/shell/features/osf.nft
new file mode 100644
index 00000000..dbb6b4c3
--- /dev/null
+++ b/tests/shell/features/osf.nft
@@ -0,0 +1,7 @@
+# b96af92d6eaf ("netfilter: nf_tables: implement Passive OS fingerprint module in nft_osf")
+# v4.19-rc1~140^2~135^2~15
+table t {
+ chain c {
+ osf name "Linux"
+ }
+}
diff --git a/tests/shell/features/pipapo.nft b/tests/shell/features/pipapo.nft
new file mode 100644
index 00000000..3557721e
--- /dev/null
+++ b/tests/shell/features/pipapo.nft
@@ -0,0 +1,9 @@
+# 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges")
+# v5.6-rc1~151^2~28^2~1
+table t {
+ set s {
+ type ipv4_addr . inet_service
+ flags interval
+ elements = { 1.1.1.1-2.2.2.2 . 80-90 }
+ }
+}
diff --git a/tests/shell/features/prerouting_reject.nft b/tests/shell/features/prerouting_reject.nft
new file mode 100644
index 00000000..3dcfb40e
--- /dev/null
+++ b/tests/shell/features/prerouting_reject.nft
@@ -0,0 +1,8 @@
+# f53b9b0bdc59 netfilter: introduce support for reject at prerouting stage
+# v5.9-rc1~133^2~302^2~11
+table inet t {
+ chain nat_filter {
+ type filter hook prerouting priority 0; policy accept;
+ reject with icmpx type host-unreachable
+ }
+}
diff --git a/tests/shell/features/reset_rule.sh b/tests/shell/features/reset_rule.sh
new file mode 100755
index 00000000..567ee2f1
--- /dev/null
+++ b/tests/shell/features/reset_rule.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# 8daa8fde3fc3 ("netfilter: nf_tables: Introduce NFT_MSG_GETRULE_RESET")
+# v6.2-rc1~99^2~210^2~2
+
+unshare -n bash -c "$NFT \"add table t; add chain t c ; add rule t c counter packets 1 bytes 42\"; \
+$NFT reset rules chain t c ; \
+$NFT reset rules chain t c |grep counter\ packets\ 0\ bytes\ 0"
diff --git a/tests/shell/features/reset_set.sh b/tests/shell/features/reset_set.sh
new file mode 100755
index 00000000..3d034175
--- /dev/null
+++ b/tests/shell/features/reset_set.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+# 079cd633219d ("netfilter: nf_tables: Introduce NFT_MSG_GETSETELEM_RESET")
+# v6.5-rc1~163^2~9^2~1
+
+unshare -n bash -c "$NFT add table t; \
+ $NFT add set t s { type ipv4_addr\; counter\; elements = { 127.0.0.1 counter packets 1 bytes 2 } } ; \
+ $NFT reset set t s ; \
+ $NFT reset set t s | grep counter\ packets\ 0\ bytes\ 0
+"
diff --git a/tests/shell/features/reset_tcp_options.nft b/tests/shell/features/reset_tcp_options.nft
new file mode 100644
index 00000000..47d1c7b8
--- /dev/null
+++ b/tests/shell/features/reset_tcp_options.nft
@@ -0,0 +1,5 @@
+table inet t {
+ chain c {
+ reset tcp option fastopen
+ }
+}
diff --git a/tests/shell/features/sctp_chunks.nft b/tests/shell/features/sctp_chunks.nft
new file mode 100644
index 00000000..520afd64
--- /dev/null
+++ b/tests/shell/features/sctp_chunks.nft
@@ -0,0 +1,7 @@
+# 133dc203d77d ("netfilter: nft_exthdr: Support SCTP chunks")
+# v5.14-rc1~119^2~373^2~15
+table ip t {
+ chain c {
+ sctp chunk init 0
+ }
+}
diff --git a/tests/shell/features/secmark.nft b/tests/shell/features/secmark.nft
new file mode 100644
index 00000000..ccbb572f
--- /dev/null
+++ b/tests/shell/features/secmark.nft
@@ -0,0 +1,7 @@
+# fb961945457f ("netfilter: nf_tables: add SECMARK support")
+# v4.20-rc1~14^2~125^2~5
+table inet x {
+ secmark ssh_server {
+ "system_u:object_r:ssh_server_packet_t:s0"
+ }
+}
diff --git a/tests/shell/features/set_expr.sh b/tests/shell/features/set_expr.sh
new file mode 100755
index 00000000..fbdfc228
--- /dev/null
+++ b/tests/shell/features/set_expr.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# 65038428b2c6 ("netfilter: nf_tables: allow to specify stateful expression in set definition")
+# v5.7-rc1~146^2~12^2~25
+
+# NFT_SET_EXPR to detect kernel feature only available since
+# b4e70d8dd9ea ("netfilter: nftables: add set expression flags")
+# v5.11-rc3~39^2^2
+
+EXPECTED="table ip x {
+ set y {
+ typeof ip saddr
+ counter
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
+diff -u <($NFT list ruleset) - <<<"$EXPECTED"
diff --git a/tests/shell/features/set_with_two_expressions.nft b/tests/shell/features/set_with_two_expressions.nft
new file mode 100644
index 00000000..97632a7a
--- /dev/null
+++ b/tests/shell/features/set_with_two_expressions.nft
@@ -0,0 +1,9 @@
+# 48b0ae046ee9 ("netfilter: nftables: netlink support for several set element expressions")
+# v5.11-rc1~169^2~25^2
+table x {
+ set y {
+ type ipv4_addr
+ size 65535
+ counter quota 500 bytes
+ }
+}
diff --git a/tests/shell/features/setelem_expiration.sh b/tests/shell/features/setelem_expiration.sh
new file mode 100755
index 00000000..c539ceba
--- /dev/null
+++ b/tests/shell/features/setelem_expiration.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# v5.3-rc1~140^2~153^2~8
+# 79ebb5bb4e38 ("netfilter: nf_tables: enable set expiration time for set elements")
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ flags dynamic
+ timeout 1h
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+$NFT add element ip x y { 1.1.1.1 timeout 1h expires 15m59s }
+
+$NFT list ruleset | grep "expires 15m"
diff --git a/tests/shell/features/stateful_object_update.sh b/tests/shell/features/stateful_object_update.sh
new file mode 100755
index 00000000..62fbf7e3
--- /dev/null
+++ b/tests/shell/features/stateful_object_update.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# d62d0ba97b58 ("netfilter: nf_tables: Introduce stateful object update operation")
+# v5.4-rc1~131^2~59^2~2
+
+set -e
+$NFT add table test-ip
+$NFT add quota test-ip traffic-quota 25 mbytes
+$NFT add quota test-ip traffic-quota 50 mbytes
+
+EXPECTED="table ip test-ip {
+ quota traffic-quota {
+ 50 mbytes
+ }
+}"
+
+GET="$($NFT list ruleset)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ diff -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/features/synproxy.nft b/tests/shell/features/synproxy.nft
new file mode 100644
index 00000000..bea4f920
--- /dev/null
+++ b/tests/shell/features/synproxy.nft
@@ -0,0 +1,9 @@
+# v5.3-rc1~140^2~44^2~10
+# ad49d86e07a4 ("netfilter: nf_tables: Add synproxy support")
+table inet x {
+ synproxy https-synproxy {
+ mss 1460
+ wscale 7
+ timestamp sack-perm
+ }
+}
diff --git a/tests/shell/features/table_flag_owner.nft b/tests/shell/features/table_flag_owner.nft
new file mode 100644
index 00000000..aef122a0
--- /dev/null
+++ b/tests/shell/features/table_flag_owner.nft
@@ -0,0 +1,5 @@
+# 6001a930ce03 ("netfilter: nftables: introduce table ownership")
+# v5.12-rc1~200^2~6^2
+table t {
+ flags owner;
+}
diff --git a/tests/shell/helpers/json-diff-pretty.sh b/tests/shell/helpers/json-diff-pretty.sh
new file mode 100755
index 00000000..bebb7e8e
--- /dev/null
+++ b/tests/shell/helpers/json-diff-pretty.sh
@@ -0,0 +1,17 @@
+#!/bin/bash -e
+
+BASEDIR="$(dirname "$0")"
+
+[ $# -eq 2 ] || (echo "$0: expects two JSON files as arguments" ; exit 1)
+
+FILE1="$1"
+FILE2="$2"
+
+pretty()
+{
+ "$BASEDIR/json-pretty.sh" < "$1" 2>&1 || :
+}
+
+echo "Cmd: \"$0\" \"$FILE1\" \"$FILE2\""
+diff -u "$FILE1" "$FILE2" 2>&1 || :
+diff -u <(pretty "$FILE1") <(pretty "$FILE2") 2>&1 || :
diff --git a/tests/shell/helpers/json-pretty.sh b/tests/shell/helpers/json-pretty.sh
new file mode 100755
index 00000000..5407a842
--- /dev/null
+++ b/tests/shell/helpers/json-pretty.sh
@@ -0,0 +1,30 @@
+#!/bin/bash -e
+
+exec_pretty() {
+ # The output of this command must be stable (and `jq` and python
+ # fallback must generate the same output.
+
+ if command -v jq &>/dev/null ; then
+ # If we have, use `jq`
+ exec jq
+ fi
+
+ # Fallback to python.
+ exec python -c '
+import json
+import sys
+
+parsed = json.load(sys.stdin)
+print(json.dumps(parsed, indent=2))
+'
+}
+
+[ "$#" -le 1 ] || { echo "At most one argument supported" ; exit 1 ; }
+
+if [ "$#" -eq 1 ] ; then
+ # One argument passed. This must be a JSON file.
+ [ -f "$1" ] || { echo "File \"$1\" does not exist" ; exit 1 ; }
+ exec_pretty < "$1"
+fi
+
+exec_pretty
diff --git a/tests/shell/helpers/json-sanitize-ruleset.sh b/tests/shell/helpers/json-sanitize-ruleset.sh
new file mode 100755
index 00000000..31b85cbd
--- /dev/null
+++ b/tests/shell/helpers/json-sanitize-ruleset.sh
@@ -0,0 +1,30 @@
+#!/bin/bash -e
+
+die() {
+ printf "%s\n" "$*"
+ exit 1
+}
+
+do_sed() {
+ # Normalize the "version"/"release_name", otherwise we have to
+ # regenerate the JSON output upon new release.
+ #
+ # Also, "handle" are not stable. Normalize them 0.
+ sed \
+ -e '1s/^\({"nftables": \[{"metainfo": {"version": "\)[0-9.]\+\(", "release_name": "\)[^"]\+\(", "\)/\1VERSION\2RELEASE_NAME\3/' \
+ -e '1s/"handle": [0-9]\+\>/"handle": 0/g' \
+ "$@"
+}
+
+if [ "$#" = 0 ] ; then
+ do_sed
+ exit $?
+fi
+
+for f ; do
+ test -f "$f" || die "$0: file \"$f\" does not exist"
+done
+
+for f ; do
+ do_sed -i "$f" || die "$0: \`sed -i\` failed for \"$f\""
+done
diff --git a/tests/shell/helpers/nft-valgrind-wrapper.sh b/tests/shell/helpers/nft-valgrind-wrapper.sh
new file mode 100755
index 00000000..98bbdf43
--- /dev/null
+++ b/tests/shell/helpers/nft-valgrind-wrapper.sh
@@ -0,0 +1,31 @@
+#!/bin/bash -e
+
+SUFFIX="$(date "+%H%M%S.%6N").$$"
+
+rc=0
+libtool \
+ --mode=execute \
+ valgrind \
+ --log-file="$NFT_TEST_TESTTMPDIR/valgrind.$SUFFIX.%p.log" \
+ --trace-children=yes \
+ --leak-check=full \
+ --show-leak-kinds=all \
+ --num-callers=100 \
+ --error-exitcode=122 \
+ --vgdb-prefix="$_NFT_TEST_VALGRIND_VGDB_PREFIX-$SUFFIX" \
+ $NFT_TEST_VALGRIND_OPTS \
+ "$NFT_REAL" \
+ "$@" \
+ || rc=$?
+
+if [ "$rc" -eq 122 ] ; then
+ shopt -s nullglob
+ FILES=( "$NFT_TEST_TESTTMPDIR/valgrind.$SUFFIX."*".log" )
+ shopt -u nullglob
+ (
+ printf '%s\n' "args: $*"
+ printf '%s\n' "${FILES[*]}"
+ ) >> "$NFT_TEST_TESTTMPDIR/rc-failed-valgrind"
+fi
+
+exit $rc
diff --git a/tests/shell/helpers/random-source.sh b/tests/shell/helpers/random-source.sh
new file mode 100755
index 00000000..91a8248b
--- /dev/null
+++ b/tests/shell/helpers/random-source.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# Commands like `sort` and `shuf` have a "--random-source" argument, for
+# generating a stable, reproducible output. However, they require an input
+# that provides sufficiently many bytes (depending on the input).
+#
+# This script generates a stream that can be used like
+#
+# shuf --random-source=<($0 "$seed")
+
+seed=""
+for a; do
+ seed="$seed${#a}:$a\n"
+done
+
+if command -v openssl &>/dev/null ; then
+ # We have openssl. Use it.
+ # https://www.gnu.org/software/coreutils/manual/html_node/Random-sources.html#Random-sources
+ #
+ # Note that we don't care that different installations/architectures generate the
+ # same output.
+ openssl enc -aes-256-ctr -pass "pass:$seed" -nosalt </dev/zero 2>/dev/null
+else
+ # Hack something. It's much slower.
+ idx=0
+ while : ; do
+ idx="$((idx++))"
+ seed="$(sha256sum <<<"$idx.$seed")"
+ echo ">>>$seed" >> a
+ seed="${seed%% *}"
+ LANG=C awk -v s="$seed" 'BEGIN{
+ for (i=1; i <= length(s); i+=2) {
+ xchar = substr(s, i, 2);
+ decnum = strtonum("0x"xchar);
+ printf("%c", decnum);
+ }
+ }' || break
+ done
+fi
+exit 0
diff --git a/tests/shell/helpers/test-wrapper.sh b/tests/shell/helpers/test-wrapper.sh
new file mode 100755
index 00000000..c016e0ce
--- /dev/null
+++ b/tests/shell/helpers/test-wrapper.sh
@@ -0,0 +1,328 @@
+#!/bin/bash -e
+
+# This wrapper wraps the invocation of the test. It is called by run-tests.sh,
+# and already in the unshared namespace.
+#
+# For some printf debugging, you can also patch this file.
+
+array_contains() {
+ local needle="$1"
+ local a
+ shift
+ for a; do
+ [ "$a" = "$needle" ] && return 0
+ done
+ return 1
+}
+
+show_file() {
+ local filename="$1"
+ shift
+ local msg="$*"
+
+ printf '%s\n>>>>\n' "$msg"
+ cat "$filename"
+ printf "<<<<\n"
+}
+
+json_pretty() {
+ "$NFT_TEST_BASEDIR/helpers/json-pretty.sh" "$@" 2>&1 || :
+}
+
+TEST="$1"
+TESTBASE="$(basename "$TEST")"
+TESTDIR="$(dirname "$TEST")"
+
+START_TIME="$(cut -d ' ' -f1 /proc/uptime)"
+
+export TMPDIR="$NFT_TEST_TESTTMPDIR"
+
+CLEANUP_UMOUNT_VAR_RUN=n
+
+cleanup() {
+ if [ "$CLEANUP_UMOUNT_VAR_RUN" = y ] ; then
+ umount "/var/run" &>/dev/null || :
+ fi
+}
+
+trap cleanup EXIT
+
+printf '%s\n' "$TEST" > "$NFT_TEST_TESTTMPDIR/name"
+
+read tainted_before < /proc/sys/kernel/tainted
+
+if [ "$NFT_TEST_HAS_UNSHARED_MOUNT" = y ] ; then
+ # We have a private mount namespace. We will mount /var/run/ as a tmpfs.
+ #
+ # The main purpose is so that we can create /var/run/netns, which is
+ # required for `ip netns add` to work. When running as rootless, this
+ # is necessary to get such tests to pass. When running rootful, it's
+ # still useful to not touch the "real" /var/run/netns of the system.
+ #
+ # Note that this also hides everything that might reside in /var/run.
+ # That is desirable, as tests should not depend on content there (or if
+ # they do, we need to explicitly handle it as appropriate).
+ if mount -t tmpfs --make-private tmpfs "/var/run" ; then
+ CLEANUP_UMOUNT_VAR_RUN=y
+ fi
+ mkdir -p /var/run/netns
+fi
+
+TEST_TAGS_PARSED=0
+ensure_TEST_TAGS() {
+ if [ "$TEST_TAGS_PARSED" = 0 ] ; then
+ TEST_TAGS_PARSED=1
+ TEST_TAGS=( $(sed -n '1,10 { s/^.*\<\(NFT_TEST_REQUIRES\|NFT_TEST_SKIP\)\>\s*(\s*\(NFT_TEST_SKIP_[a-zA-Z0-9_]\+\|NFT_TEST_HAVE_[a-zA-Z0-9_]\+\)\s*).*$/\1(\2)/p }' "$1" 2>/dev/null || : ) )
+ fi
+}
+
+rc_test=0
+
+if [ "$rc_test" -eq 0 ] ; then
+ for KEY in $(compgen -v | grep '^NFT_TEST_HAVE_') ; do
+ if [ "${!KEY}" != n ]; then
+ continue
+ fi
+ ensure_TEST_TAGS "$TEST"
+ if array_contains "NFT_TEST_REQUIRES($KEY)" "${TEST_TAGS[@]}" ; then
+ echo "Test skipped due to $KEY=n (test has \"NFT_TEST_REQUIRES($KEY)\" tag)" >> "$NFT_TEST_TESTTMPDIR/testout.log"
+ rc_test=77
+ break
+ fi
+ done
+fi
+
+if [ "$rc_test" -eq 0 ] ; then
+ for KEY in $(compgen -v | grep '^NFT_TEST_SKIP_') ; do
+ if [ "${!KEY}" != y ]; then
+ continue
+ fi
+ ensure_TEST_TAGS "$TEST"
+ if array_contains "NFT_TEST_SKIP($KEY)" "${TEST_TAGS[@]}" ; then
+ echo "Test skipped due to $KEY=y (test has \"NFT_TEST_SKIP($KEY)\" tag)" >> "$NFT_TEST_TESTTMPDIR/testout.log"
+ rc_test=77
+ break
+ fi
+ done
+fi
+
+if [ "$rc_test" -eq 0 ] ; then
+ CMD=( "$TEST" )
+ if [ "$NFT_TEST_VERBOSE_TEST" = y ] ; then
+ X="$(sed -n '1 s/^#!\(\/bin\/bash\>.*$\)/\1/p' "$TEST" 2>/dev/null)"
+ if [ -n "$X" ] ; then
+ # Note that kernel parses the shebang differently and does not
+ # word splitting for the arguments. We do split the arguments here
+ # which would matter if there are spaces. For our tests, there
+ # are either no arguments or only one argument without space. So
+ # this is good enough.
+ CMD=( $X -x "$TEST" )
+ fi
+ fi
+ printf "Command: $(printf '%q ' "${CMD[@]}")\n" &>> "$NFT_TEST_TESTTMPDIR/testout.log"
+ "${CMD[@]}" &>> "$NFT_TEST_TESTTMPDIR/testout.log" || rc_test=$?
+fi
+
+rc_chkdump=0
+rc=0
+$NFT list ruleset > "$NFT_TEST_TESTTMPDIR/ruleset-after" 2> "$NFT_TEST_TESTTMPDIR/chkdump" || rc=$?
+if [ "$rc" -ne 0 -o -s "$NFT_TEST_TESTTMPDIR/chkdump" ] ; then
+ show_file "$NFT_TEST_TESTTMPDIR/chkdump" "Command \`$NFT list ruleset\` failed" >> "$NFT_TEST_TESTTMPDIR/rc-failed-chkdump"
+ rc_chkdump=1
+fi
+if [ "$NFT_TEST_HAVE_json" != n ] ; then
+ rc=0
+ $NFT -j list ruleset > "$NFT_TEST_TESTTMPDIR/ruleset-after.json" 2> "$NFT_TEST_TESTTMPDIR/chkdump" || rc=$?
+
+ # Workaround known bug in stmt_print_json(), due to
+ # "chain_stmt_ops.json" being NULL. This spams stderr.
+ sed -i '/^warning: stmt ops chain have no json callback$/d' "$NFT_TEST_TESTTMPDIR/chkdump"
+
+ if [ "$rc" -ne 0 -o -s "$NFT_TEST_TESTTMPDIR/chkdump" ] ; then
+ show_file "$NFT_TEST_TESTTMPDIR/chkdump" "Command \`$NFT -j list ruleset\` failed" >> "$NFT_TEST_TESTTMPDIR/rc-failed-chkdump"
+ rc_chkdump=1
+ fi
+ # JSON output needs normalization/sanitization, otherwise it's not stable.
+ "$NFT_TEST_BASEDIR/helpers/json-sanitize-ruleset.sh" "$NFT_TEST_TESTTMPDIR/ruleset-after.json"
+ json_pretty "$NFT_TEST_TESTTMPDIR/ruleset-after.json" > "$NFT_TEST_TESTTMPDIR/ruleset-after.json-pretty"
+fi
+
+read tainted_after < /proc/sys/kernel/tainted
+
+DUMPPATH="$TESTDIR/dumps"
+DUMPFILE="$DUMPPATH/$TESTBASE.nft"
+JDUMPFILE="$DUMPPATH/$TESTBASE.json-nft"
+NODUMPFILE="$DUMPPATH/$TESTBASE.nodump"
+
+# The caller can request a re-geneating of the .nft, .nodump, .json-nft dump files
+# by setting DUMPGEN=y. In that case, only the existing files will be regenerated
+# (unless all three files are missing, in which case all of them are generated).
+#
+# By setting DUMPGEN=all, all 3 files are always regenerated.
+dump_written=n
+if [ "$rc_test" -eq 0 -a '(' "$DUMPGEN" = all -o "$DUMPGEN" = y ')' ] ; then
+ dump_written=y
+ if [ ! -d "$DUMPPATH" ] ; then
+ mkdir "$DUMPPATH"
+ fi
+ if [ "$DUMPGEN" = all ] ; then
+ gen_nodumpfile=y
+ gen_dumpfile=y
+ gen_jdumpfile=y
+ else
+ # by default, only regenerate the files that we already have on disk.
+ gen_nodumpfile=n
+ gen_dumpfile=n
+ gen_jdumpfile=n
+ test -f "$DUMPFILE" && gen_dumpfile=y
+ test -f "$JDUMPFILE" && gen_jdumpfile=y
+ test -f "$NODUMPFILE" && gen_nodumpfile=y
+ if [ "$gen_dumpfile" != y -a "$gen_jdumpfile" != y -a "$gen_nodumpfile" != y ] ; then
+ # Except, if no files exist. Them generate all files.
+ gen_dumpfile=y
+ gen_jdumpfile=y
+ gen_nodumpfile=y
+ fi
+ fi
+ if [ "$gen_nodumpfile" = y ] ; then
+ : > "$NODUMPFILE"
+ fi
+ if [ "$gen_dumpfile" = y ] ; then
+ cat "$NFT_TEST_TESTTMPDIR/ruleset-after" > "$DUMPFILE"
+ fi
+ if [ "$NFT_TEST_HAVE_json" != n -a "$gen_jdumpfile" = y ] ; then
+ cat "$NFT_TEST_TESTTMPDIR/ruleset-after.json-pretty" > "$JDUMPFILE"
+ fi
+fi
+
+rc_dump=0
+if [ "$rc_test" -ne 77 -a "$dump_written" != y ] ; then
+ if [ -f "$DUMPFILE" ] ; then
+ if ! $DIFF -u "$DUMPFILE" "$NFT_TEST_TESTTMPDIR/ruleset-after" &> "$NFT_TEST_TESTTMPDIR/ruleset-diff" ; then
+ show_file "$NFT_TEST_TESTTMPDIR/ruleset-diff" "Failed \`$DIFF -u \"$DUMPFILE\" \"$NFT_TEST_TESTTMPDIR/ruleset-after\"\`" >> "$NFT_TEST_TESTTMPDIR/rc-failed-dump"
+ rc_dump=1
+ else
+ rm -f "$NFT_TEST_TESTTMPDIR/ruleset-diff"
+ fi
+ fi
+ if [ "$NFT_TEST_HAVE_json" != n -a -f "$JDUMPFILE" ] ; then
+ if ! $DIFF -u "$JDUMPFILE" "$NFT_TEST_TESTTMPDIR/ruleset-after.json-pretty" &> "$NFT_TEST_TESTTMPDIR/ruleset-diff.json" ; then
+ show_file "$NFT_TEST_TESTTMPDIR/ruleset-diff.json" "Failed \`$DIFF -u \"$JDUMPFILE\" \"$NFT_TEST_TESTTMPDIR/ruleset-after.json-pretty\"\`" >> "$NFT_TEST_TESTTMPDIR/rc-failed-dump"
+ rc_dump=1
+ else
+ rm -f "$NFT_TEST_TESTTMPDIR/ruleset-diff.json"
+ fi
+ fi
+fi
+
+# check that a flush after the test succeeds. We anyway need a clean ruleset
+# for the `nft --check` next.
+rc=0
+$NFT flush ruleset &> "$NFT_TEST_TESTTMPDIR/chkdump" || rc=1
+if [ "$rc" = 1 -o -s "$NFT_TEST_TESTTMPDIR/chkdump" ] ; then
+ show_file "$NFT_TEST_TESTTMPDIR/chkdump" "Command \`$NFT flush ruleset\` failed" >> "$NFT_TEST_TESTTMPDIR/rc-failed-chkdump"
+ rc_chkdump=1
+fi
+# Check that `nft [-j] list ruleset | nft [-j] --check -f -` works.
+fail=n
+$NFT --check -f "$NFT_TEST_TESTTMPDIR/ruleset-after" &> "$NFT_TEST_TESTTMPDIR/chkdump" || fail=y
+test -s "$NFT_TEST_TESTTMPDIR/chkdump" && fail=y
+if [ "$fail" = y ] ; then
+ show_file "$NFT_TEST_TESTTMPDIR/chkdump" "Command \`$NFT --check -f \"$NFT_TEST_TESTTMPDIR/ruleset-after\"\` failed" >> "$NFT_TEST_TESTTMPDIR/rc-failed-chkdump"
+ rc_chkdump=1
+fi
+if [ -f "$DUMPFILE" ] && ! cmp "$DUMPFILE" "$NFT_TEST_TESTTMPDIR/ruleset-after" &>/dev/null ; then
+ # Also check the $DUMPFILE to hit possibly new code paths. This
+ # is useful to see crashes and with ASAN/valgrind.
+ $NFT --check -f "$DUMPFILE" &>/dev/null || :
+fi
+if [ "$NFT_TEST_HAVE_json" != n ] ; then
+ if [ ! -f "$JDUMPFILE" ] ; then
+ # Optimally, `nft -j list ruleset | nft -j --check -f -` never
+ # fails. However, there are known issues where this doesn't
+ # work, and we cannot assert hard against that. It's those
+ # tests that don't have a .json-nft file.
+ #
+ # This should be fixed, every test should have a .json-nft
+ # file, and this workaround removed.
+ $NFT -j --check -f "$NFT_TEST_TESTTMPDIR/ruleset-after.json" &>/dev/null || :
+ $NFT -j --check -f "$NFT_TEST_TESTTMPDIR/ruleset-after.json-pretty" &>/dev/null || :
+ else
+ fail=n
+ $NFT -j --check -f "$NFT_TEST_TESTTMPDIR/ruleset-after.json" &> "$NFT_TEST_TESTTMPDIR/chkdump" || fail=y
+ test -s "$NFT_TEST_TESTTMPDIR/chkdump" && fail=y
+ if [ "$fail" = y ] ; then
+ show_file "$NFT_TEST_TESTTMPDIR/chkdump" "Command \`$NFT -j --check -f \"$NFT_TEST_TESTTMPDIR/ruleset-after.json\"\` failed" >> "$NFT_TEST_TESTTMPDIR/rc-failed-chkdump"
+ rc_chkdump=1
+ fi
+ fail=n
+ $NFT -j --check -f "$NFT_TEST_TESTTMPDIR/ruleset-after.json-pretty" &> "$NFT_TEST_TESTTMPDIR/chkdump" || fail=y
+ test -s "$NFT_TEST_TESTTMPDIR/chkdump" && fail=y
+ if [ "$fail" = y ] ; then
+ show_file "$NFT_TEST_TESTTMPDIR/chkdump" "Command \`$NFT -j --check -f \"$NFT_TEST_TESTTMPDIR/ruleset-after.json-pretty\"\` failed" >> "$NFT_TEST_TESTTMPDIR/rc-failed-chkdump"
+ rc_chkdump=1
+ fi
+ fi
+ if [ -f "$JDUMPFILE" ] \
+ && ! cmp "$JDUMPFILE" "$NFT_TEST_TESTTMPDIR/ruleset-after.json" &>/dev/null \
+ && ! cmp "$JDUMPFILE" "$NFT_TEST_TESTTMPDIR/ruleset-after.json-pretty" &>/dev/null ; \
+ then
+ $NFT -j --check -f "$JDUMPFILE" &>/dev/null || :
+ fi
+fi
+rm -f "$NFT_TEST_TESTTMPDIR/chkdump"
+
+rc_valgrind=0
+[ -f "$NFT_TEST_TESTTMPDIR/rc-failed-valgrind" ] && rc_valgrind=1
+
+rc_tainted=0
+if [ "$tainted_before" != "$tainted_after" ] ; then
+ echo "$tainted_after" > "$NFT_TEST_TESTTMPDIR/rc-failed-tainted"
+ rc_tainted=1
+fi
+
+if [ "$rc_valgrind" -ne 0 ] ; then
+ rc_exit=122
+elif [ "$rc_tainted" -ne 0 ] ; then
+ rc_exit=123
+elif [ "$rc_test" -ge 118 -a "$rc_test" -le 124 ] ; then
+ # Special exit codes are reserved. Coerce them.
+ rc_exit=125
+elif [ "$rc_test" -ne 0 ] ; then
+ rc_exit="$rc_test"
+elif [ "$rc_dump" -ne 0 ] ; then
+ rc_exit=124
+elif [ "$rc_chkdump" -ne 0 ] ; then
+ rc_exit=121
+else
+ rc_exit=0
+fi
+
+
+# We always write the real exit code of the test ($rc_test) to one of the files
+# rc-{ok,skipped,failed}, depending on which it is.
+#
+# Note that there might be other rc-failed-{dump,tainted,valgrind} files with
+# additional errors. Note that if such files exist, the overall state will
+# always be failed too (and an "rc-failed" file exists).
+#
+# On failure, we also write the combined "$rc_exit" code from "test-wrapper.sh"
+# to "rc-failed-exit" file.
+#
+# This means, failed tests will have a "rc-failed" file, and additional
+# "rc-failed-*" files exist for further information.
+if [ "$rc_exit" -eq 0 ] ; then
+ RC_FILENAME="rc-ok"
+elif [ "$rc_exit" -eq 77 ] ; then
+ RC_FILENAME="rc-skipped"
+else
+ RC_FILENAME="rc-failed"
+ echo "$rc_exit" > "$NFT_TEST_TESTTMPDIR/rc-failed-exit"
+fi
+echo "$rc_test" > "$NFT_TEST_TESTTMPDIR/$RC_FILENAME"
+
+END_TIME="$(cut -d ' ' -f1 /proc/uptime)"
+WALL_TIME="$(awk -v start="$START_TIME" -v end="$END_TIME" "BEGIN { print(end - start) }")"
+printf "%s\n" "$WALL_TIME" "$START_TIME" "$END_TIME" > "$NFT_TEST_TESTTMPDIR/times"
+
+exit "$rc_exit"
diff --git a/tests/shell/run-tests.sh b/tests/shell/run-tests.sh
index 632cccee..6a9b518c 100755
--- a/tests/shell/run-tests.sh
+++ b/tests/shell/run-tests.sh
@@ -1,65 +1,720 @@
#!/bin/bash
-# Configuration
-TESTDIR="./$(dirname $0)/testcases"
-SRC_NFT="$(dirname $0)/../../src/nft"
-DIFF=$(which diff)
+unset LANGUAGE
+export LANG=C
+export LC_ALL=C
+
+GREEN=""
+YELLOW=""
+RED=""
+RESET=""
+if [ -z "$NO_COLOR" ] ; then
+ if [ -n "$CLICOLOR_FORCE" ] || [[ -t 1 ]] ; then
+ # See https://bixense.com/clicolors/ . We only check isatty() on
+ # file descriptor 1, to decide whether colorizing happens (although,
+ # we might also colorize on other places/FDs).
+ GREEN=$'\e[32m'
+ YELLOW=$'\e[33m'
+ RED=$'\e[31m'
+ RESET=$'\e[0m'
+ fi
+fi
+
+array_contains() {
+ local needle="$1"
+ local a
+ shift
+ for a; do
+ [ "$a" = "$needle" ] && return 0
+ done
+ return 1
+}
+
+array_remove_first() {
+ local _varname="$1"
+ local _needle="$2"
+ local _result=()
+ local _a
+
+ eval "local _input=( \"\${$_varname[@]}\" )"
+ for _a in "${_input[@]}" ; do
+ if [ -n "${_needle+x}" -a "$_needle" = "$_a" ] ; then
+ unset _needle
+ else
+ _result+=("$_a")
+ fi
+ done
+ eval "$_varname="'( "${_result[@]}" )'
+}
+
+colorize_keywords() {
+ local out_variable="$1"
+ local color="$2"
+ local val="$3"
+ local val2
+ shift 3
+
+ printf -v val2 '%q' "$val"
+ array_contains "$val" "$@" && val2="$color$val2$RESET"
+ printf -v "$out_variable" '%s' "$val2"
+}
+
+strtonum() {
+ local s="$1"
+ local n
+ local n2
+
+ re='^[[:space:]]*([0-9]+)[[:space:]]*$'
+ if [[ "$s" =~ $re ]] ; then
+ n="${BASH_REMATCH[1]}"
+ if [ "$(( n + 0 ))" = "$n" ] ; then
+ echo "$n"
+ return 0
+ fi
+ fi
+ re='^[[:space:]]*0x([0-9a-fA-F]+)[[:space:]]*$'
+ if [[ "$s" =~ $re ]] ; then
+ n="${BASH_REMATCH[1]}"
+ n2="$(( 16#$n + 0 ))"
+ if [ "$n2" = "$(printf '%d' "0x$n" 2>/dev/null)" ] ; then
+ echo "$n2"
+ return 0
+ fi
+ fi
+ return 1
+}
+
+_msg() {
+ local level="$1"
+ shift
+
+ if [ "$level" = E ] ; then
+ printf '%s\n' "$RED$level$RESET: $*"
+ elif [ "$level" = W ] ; then
+ printf '%s\n' "$YELLOW$level$RESET: $*"
+ else
+ printf '%s\n' "$level: $*"
+ fi
+ if [ "$level" = E ] ; then
+ exit 1
+ fi
+}
msg_error() {
- echo "E: $1 ..." >&2
- exit 1
+ _msg E "$@"
}
msg_warn() {
- echo "W: $1" >&2
+ _msg W "$@"
}
msg_info() {
- echo "I: $1"
+ _msg I "$@"
}
-if [ "$(id -u)" != "0" ] ; then
- msg_error "this requires root!"
+align_text() {
+ local _OUT_VARNAME="$1"
+ local _LEFT_OR_RIGHT="$2"
+ local _INDENT="$3"
+ shift 3
+ local _text="$*"
+ local _text_plain
+ local _text_align
+ local _text_result
+ local _i
+
+ # This function is needed, because "$text" might contain color escape
+ # sequences. A plain `printf '%12s' "$text"` will not align properly.
+
+ # strip escape sequences
+ _text_plain="${_text//$'\e['[0-9]m/}"
+ _text_plain="${_text_plain//$'\e['[0-9][0-9]m/}"
+
+ _text_align=""
+ for (( _i = "${#_text_plain}" ; "$_i" < "$_INDENT" ; _i++ )) ; do
+ _text_align="$_text_align "
+ done
+
+ if [ "$_LEFT_OR_RIGHT" = left ] ; then
+ _text_result="$(printf "%s$_text_align-" "$_text")"
+ else
+ _text_result="$(printf "$_text_align%s-" "$_text")"
+ fi
+ _text_result="${_text_result%-}"
+
+ eval "$_OUT_VARNAME=\"\$_text_result\""
+}
+
+bool_n() {
+ case "$1" in
+ n|N|no|No|NO|0|false|False|FALSE)
+ printf n
+ ;;
+ *)
+ printf y
+ ;;
+ esac
+}
+
+bool_y() {
+ case "$1" in
+ y|Y|yes|Yes|YES|1|true|True|TRUE)
+ printf y
+ ;;
+ *)
+ printf n
+ ;;
+ esac
+}
+
+usage() {
+ echo " $0 [OPTIONS] [TESTS...]"
+ echo
+ echo "OPTIONS:"
+ echo " -h|--help : Print usage."
+ echo " -L|--list-tests : List test names and quit."
+ echo " -v : Sets VERBOSE=y."
+ echo " -g : Sets DUMPGEN=y."
+ echo " -V : Sets VALGRIND=y."
+ echo " -K : Sets KMEMLEAK=y."
+ echo " -R|--without-realroot : Sets NFT_TEST_HAS_REALROOT=n."
+ echo " -U|--no-unshare : Sets NFT_TEST_UNSHARE_CMD=\"\"."
+ echo " -k|--keep-logs : Sets NFT_TEST_KEEP_LOGS=y."
+ echo " -x : Sets NFT_TEST_VERBOSE_TEST=y."
+ echo " -s|--sequential : Sets NFT_TEST_JOBS=0, which also enables global cleanups."
+ echo " Also sets NFT_TEST_SHUFFLE_TESTS=n if left unspecified."
+ echo " -Q|--quick : Sets NFT_TEST_SKIP_slow=y."
+ echo " -S|--setup-host : Modify the host to run as rootless. Otherwise, some tests will be"
+ echo " skipped. Basically, this bumps /proc/sys/net/core/{wmem_max,rmem_max}."
+ echo " Must run as root and this option must be specified alone."
+ echo " -- : Separate options from tests."
+ echo " [TESTS...] : Other options are treated as test names,"
+ echo " that is, executables that are run by the runner."
+ echo
+ echo "ENVIRONMENT VARIABLES:"
+ echo " NFT=<CMD> : Path to nft executable. Will be called as \`\$NFT [...]\` so"
+ echo " it can be a command with parameters. Note that in this mode quoting"
+ echo " does not work, so the usage is limited and the command cannot contain"
+ echo " spaces."
+ echo " NFT_REAL=<CMD> : Real nft comand. Usually this is just the same as \$NFT,"
+ echo " however, you may set NFT='valgrind nft' and NFT_REAL to the real command."
+ echo " VERBOSE=*|y : Enable verbose output."
+ echo " NFT_TEST_VERBOSE_TEST=*|y: if true, enable verbose output for tests. For bash scripts, this means"
+ echo " to pass \"-x\" to the interpreter."
+ echo " DUMPGEN=*|y|all : Regenerate dump files \".{nft,json-nft,nodump}\". \"DUMPGEN=y\" only regenerates existing"
+ echo " files, unless the test has no files (then all three files are generated, and you need to"
+ echo " choose which to keep). With \"DUMPGEN=all\" all 3 files are regenerated, regardless"
+ echo " whether they already exist."
+ echo " VALGRIND=*|y : Run \$NFT in valgrind."
+ echo " KMEMLEAK=*|y : Check for kernel memleaks."
+ echo " NFT_TEST_HAS_REALROOT=*|y : To indicate whether the test has real root permissions."
+ echo " Usually, you don't need this and it gets autodetected."
+ echo " You might want to set it, if you know better than the"
+ echo " \`id -u\` check, whether the user is root in the main namespace."
+ echo " Note that without real root, certain tests may not work,"
+ echo " e.g. due to limited /proc/sys/net/core/{wmem_max,rmem_max}."
+ echo " Checks that cannot pass in such environment should check for"
+ echo " [ \"\$NFT_TEST_HAS_REALROOT\" != y ] and skip gracefully."
+ echo " NFT_TEST_HAS_SOCKET_LIMITS=*|n : some tests will fail if /proc/sys/net/core/{wmem_max,rmem_max} is"
+ echo " too small. When running as real root, then test can override those limits. However,"
+ echo " with rootless the test would fail. Tests will check for [ "\$NFT_TEST_HAS_SOCKET_LIMITS" = y ]"
+ echo " and skip. You may set NFT_TEST_HAS_SOCKET_LIMITS=n if you ensure those limits are"
+ echo " suitable to run the test rootless. Otherwise will be autodetected."
+ echo " Set /proc/sys/net/core/{wmem_max,rmem_max} to at least 4MB to get them to pass automatically."
+ echo " NFT_TEST_UNSHARE_CMD=cmd : when set, this is the command line for an unshare"
+ echo " command, which is used to sandbox each test invocation. By"
+ echo " setting it to empty, no unsharing is done."
+ echo " By default it is unset, in which case it's autodetected as"
+ echo " \`unshare -f -p\` (for root) or as \`unshare -f -p --mount-proc -U --map-root-user -n\`"
+ echo " for non-root."
+ echo " When setting this, you may also want to set NFT_TEST_HAS_UNSHARED=,"
+ echo " NFT_TEST_HAS_REALROOT= and NFT_TEST_HAS_UNSHARED_MOUNT= accordingly."
+ echo " NFT_TEST_HAS_UNSHARED=*|y : To indicate to the test whether the test run will be unshared."
+ echo " Test may consider this."
+ echo " This is only honored when \$NFT_TEST_UNSHARE_CMD= is set. Otherwise it's detected."
+ echo " NFT_TEST_HAS_UNSHARED_MOUNT=*|y : To indicate to the test whether the test run will have a private"
+ echo " mount namespace."
+ echo " This is only honored when \$NFT_TEST_UNSHARE_CMD= is set. Otherwise it's detected."
+ echo " NFT_TEST_KEEP_LOGS=*|y: Keep the temp directory. On success, it will be deleted by default."
+ echo " NFT_TEST_JOBS=<NUM}>: number of jobs for parallel execution. Defaults to \"\$(nproc)*1.5\" for parallel run."
+ echo " Setting this to \"0\" or \"1\", means to run jobs sequentially."
+ echo " Setting this to \"0\" means also to perform global cleanups between tests (remove"
+ echo " kernel modules)."
+ echo " Parallel jobs requires unshare and are disabled with NFT_TEST_UNSHARE_CMD=\"\"."
+ echo " NFT_TEST_FAIL_ON_SKIP=*|y: if any jobs are skipped, exit with error."
+ echo " NFT_TEST_RANDOM_SEED=<SEED>: The test runner will export the environment variable NFT_TEST_RANDOM_SEED"
+ echo " set to a random number. This can be used as a stable seed for tests to randomize behavior."
+ echo " Set this to a fixed value to get reproducible behavior."
+ echo " NFT_TEST_SHUFFLE_TESTS=*|n|y: control whether to randomly shuffle the order of tests. By default, if"
+ echo " tests are specified explicitly, they are not shuffled while they are shuffled when"
+ echo " all tests are run. The shuffling is based on NFT_TEST_RANDOM_SEED."
+ echo " TMPDIR=<PATH> : select a different base directory for the result data."
+ echo
+ echo " NFT_TEST_HAVE_<FEATURE>=*|y: Some tests requires certain features or will be skipped."
+ echo " The features are autodetected, but you can force it by setting the variable."
+ echo " Supported <FEATURE>s are: ${_HAVE_OPTS[@]}."
+ echo " NFT_TEST_SKIP_<OPTION>=*|y: if set, certain tests are skipped."
+ echo " Supported <OPTION>s are: ${_SKIP_OPTS[@]}."
+}
+
+NFT_TEST_BASEDIR="$(dirname "$0")"
+
+# Export the base directory. It may be used by tests.
+export NFT_TEST_BASEDIR
+
+_HAVE_OPTS=()
+shopt -s nullglob
+F=( "$NFT_TEST_BASEDIR/features/"*.nft "$NFT_TEST_BASEDIR/features/"*.sh )
+shopt -u nullglob
+for file in "${F[@]}"; do
+ feat="${file##*/}"
+ feat="${feat%.*}"
+ re="^[a-z_0-9]+$"
+ if [[ "$feat" =~ $re ]] && ! array_contains "$feat" "${_HAVE_OPTS[@]}" && [[ "$file" != *.sh || -x "$file" ]] ; then
+ _HAVE_OPTS+=( "$feat" )
+ else
+ msg_warn "Ignore feature file \"$file\""
+ fi
+done
+_HAVE_OPTS=( $(printf '%s\n' "${_HAVE_OPTS[@]}" | sort) )
+
+for KEY in $(compgen -v | grep '^NFT_TEST_HAVE_' | sort) ; do
+ if ! array_contains "${KEY#NFT_TEST_HAVE_}" "${_HAVE_OPTS[@]}" ; then
+ unset "$KEY"
+ fi
+done
+
+_SKIP_OPTS=( slow )
+for KEY in $(compgen -v | grep '^NFT_TEST_SKIP_' | sort) ; do
+ if ! array_contains "${KEY#NFT_TEST_SKIP_}" "${_SKIP_OPTS[@]}" ; then
+ unset "$KEY"
+ fi
+done
+
+_NFT_TEST_JOBS_DEFAULT="$(nproc)"
+[ "$_NFT_TEST_JOBS_DEFAULT" -gt 0 ] 2>/dev/null || _NFT_TEST_JOBS_DEFAULT=1
+_NFT_TEST_JOBS_DEFAULT="$(( _NFT_TEST_JOBS_DEFAULT + (_NFT_TEST_JOBS_DEFAULT + 1) / 2 ))"
+
+VERBOSE="$(bool_y "$VERBOSE")"
+NFT_TEST_VERBOSE_TEST="$(bool_y "$NFT_TEST_VERBOSE_TEST")"
+if [ "$DUMPGEN" != "all" ] ; then
+ DUMPGEN="$(bool_y "$DUMPGEN")"
fi
+VALGRIND="$(bool_y "$VALGRIND")"
+KMEMLEAK="$(bool_y "$KMEMLEAK")"
+NFT_TEST_KEEP_LOGS="$(bool_y "$NFT_TEST_KEEP_LOGS")"
+NFT_TEST_HAS_REALROOT="$NFT_TEST_HAS_REALROOT"
+NFT_TEST_JOBS="${NFT_TEST_JOBS:-$_NFT_TEST_JOBS_DEFAULT}"
+NFT_TEST_FAIL_ON_SKIP="$(bool_y "$NFT_TEST_FAIL_ON_SKIP")"
+NFT_TEST_RANDOM_SEED="$NFT_TEST_RANDOM_SEED"
+NFT_TEST_SHUFFLE_TESTS="$NFT_TEST_SHUFFLE_TESTS"
+NFT_TEST_SKIP_slow="$(bool_y "$NFT_TEST_SKIP_slow")"
+DO_LIST_TESTS=
-[ -z "$NFT" ] && NFT=$SRC_NFT
-if [ ! -x "$NFT" ] ; then
- msg_error "no nft binary!"
+if [ -z "$NFT_TEST_RANDOM_SEED" ] ; then
+ # Choose a random value.
+ n="$SRANDOM"
+ [ -z "$n" ] && n="$RANDOM"
else
- msg_info "using nft binary $NFT"
+ # Parse as number.
+ n="$(strtonum "$NFT_TEST_RANDOM_SEED")"
+ if [ -z "$n" ] ; then
+ # If not a number, pick a hash based on the SHA-sum of the seed.
+ n="$(printf "%d" "0x$(sha256sum <<<"NFT_TEST_RANDOM_SEED:$NFT_TEST_RANDOM_SEED" | sed -n '1 { s/^\(........\).*/\1/p }')")"
+ fi
fi
+# Limit a 31 bit decimal so tests can rely on this being in a certain
+# restricted form.
+NFT_TEST_RANDOM_SEED="$(( $n % 0x80000000 ))"
+export NFT_TEST_RANDOM_SEED
-if [ ! -d "$TESTDIR" ] ; then
- msg_error "missing testdir $TESTDIR"
+TESTS=()
+
+SETUP_HOST=
+SETUP_HOST_OTHER=
+
+ARGV_ORIG=( "$@" )
+
+while [ $# -gt 0 ] ; do
+ A="$1"
+ shift
+ case "$A" in
+ -S|--setup-host)
+ ;;
+ *)
+ SETUP_HOST_OTHER=y
+ ;;
+ esac
+ case "$A" in
+ -S|--setup-host)
+ SETUP_HOST="$A"
+ ;;
+ -v)
+ VERBOSE=y
+ ;;
+ -x)
+ NFT_TEST_VERBOSE_TEST=y
+ ;;
+ -g)
+ DUMPGEN=y
+ ;;
+ -V)
+ VALGRIND=y
+ ;;
+ -K)
+ KMEMLEAK=y
+ ;;
+ -h|--help)
+ usage
+ exit 0
+ ;;
+ -k|--keep-logs)
+ NFT_TEST_KEEP_LOGS=y
+ ;;
+ -L|--list-tests)
+ DO_LIST_TESTS=y
+ ;;
+ -R|--without-realroot)
+ NFT_TEST_HAS_REALROOT=n
+ ;;
+ -U|--no-unshare)
+ NFT_TEST_UNSHARE_CMD=
+ ;;
+ -s|--sequential)
+ NFT_TEST_JOBS=0
+ if [ -z "$NFT_TEST_SHUFFLE_TESTS" ] ; then
+ NFT_TEST_SHUFFLE_TESTS=n
+ fi
+ ;;
+ -Q|--quick)
+ NFT_TEST_SKIP_slow=y
+ ;;
+ --)
+ TESTS+=( "$@" )
+ shift $#
+ ;;
+ *)
+ TESTS+=( "$A" )
+ ;;
+ esac
+done
+
+sysctl_bump() {
+ local sysctl="$1"
+ local val="$2"
+ local cur;
+
+ cur="$(cat "$sysctl" 2>/dev/null)" || :
+ if [ -n "$cur" -a "$cur" -ge "$val" ] ; then
+ echo "# Skip: echo $val > $sysctl (current value $cur)"
+ return 0
+ fi
+ echo " echo $val > $sysctl (previous value $cur)"
+ echo "$val" > "$sysctl"
+}
+
+setup_host() {
+ echo "Setting up host for running as rootless (requires root)."
+ sysctl_bump /proc/sys/net/core/rmem_max $((4000*1024)) || return $?
+ sysctl_bump /proc/sys/net/core/wmem_max $((4000*1024)) || return $?
+}
+
+if [ -n "$SETUP_HOST" ] ; then
+ if [ "$SETUP_HOST_OTHER" = y ] ; then
+ msg_error "The $SETUP_HOST option must be specified alone."
+ fi
+ setup_host
+ exit $?
fi
-FIND="$(which find)"
-if [ ! -x "$FIND" ] ; then
- msg_error "no find binary found"
+find_tests() {
+ find "$1" -type f -executable | sort
+}
+
+if [ "${#TESTS[@]}" -eq 0 ] ; then
+ d="$NFT_TEST_BASEDIR/testcases/"
+ d="${d#./}"
+ TESTS=( $(find_tests "$d") )
+ test "${#TESTS[@]}" -gt 0 || msg_error "Could not find tests"
+ if [ -z "$NFT_TEST_SHUFFLE_TESTS" ] ; then
+ NFT_TEST_SHUFFLE_TESTS=y
+ fi
fi
-MODPROBE="$(which modprobe)"
-if [ ! -x "$MODPROBE" ] ; then
- msg_error "no modprobe binary found"
+TESTSOLD=( "${TESTS[@]}" )
+TESTS=()
+for t in "${TESTSOLD[@]}" ; do
+ if [ -f "$t" -a -x "$t" ] ; then
+ TESTS+=( "$t" )
+ elif [ -d "$t" ] ; then
+ TESTS+=( $(find_tests "$t") )
+ else
+ msg_error "Unknown test \"$t\""
+ fi
+done
+
+NFT_TEST_SHUFFLE_TESTS="$(bool_y "$NFT_TEST_SHUFFLE_TESTS")"
+
+if [ "$DO_LIST_TESTS" = y ] ; then
+ printf '%s\n' "${TESTS[@]}"
+ exit 0
fi
-if [ "$1" == "-v" ] ; then
- VERBOSE=y
- shift
+START_TIME="$(cut -d ' ' -f1 /proc/uptime)"
+
+_TMPDIR="${TMPDIR:-/tmp}"
+
+# Export the orignal TMPDIR for the tests. "test-wrapper.sh" sets TMPDIR to
+# NFT_TEST_TESTTMPDIR, so that temporary files are placed along side the
+# test data. In some cases, we may want to know the original TMPDIR.
+export NFT_TEST_TMPDIR_ORIG="$_TMPDIR"
+
+if [ "$NFT_TEST_HAS_REALROOT" = "" ] ; then
+ # The caller didn't set NFT_TEST_HAS_REALROOT and didn't specify
+ # -R/--without-root option. Autodetect it based on `id -u`.
+ export NFT_TEST_HAS_REALROOT="$(test "$(id -u)" = "0" && echo y || echo n)"
+else
+ NFT_TEST_HAS_REALROOT="$(bool_y "$NFT_TEST_HAS_REALROOT")"
fi
+export NFT_TEST_HAS_REALROOT
-if [ "$1" == "-g" ] ; then
- DUMPGEN=y
- shift
+if [ "$NFT_TEST_HAS_SOCKET_LIMITS" = "" ] ; then
+ if [ "$NFT_TEST_HAS_REALROOT" = y ] ; then
+ NFT_TEST_HAS_SOCKET_LIMITS=n
+ elif [ "$(cat /proc/sys/net/core/wmem_max 2>/dev/null)" -ge $((4000*1024)) ] 2>/dev/null && \
+ [ "$(cat /proc/sys/net/core/rmem_max 2>/dev/null)" -ge $((4000*1024)) ] 2>/dev/null ; then
+ NFT_TEST_HAS_SOCKET_LIMITS=n
+ else
+ NFT_TEST_HAS_SOCKET_LIMITS=y
+ fi
+else
+ NFT_TEST_HAS_SOCKET_LIMITS="$(bool_n "$NFT_TEST_HAS_SOCKET_LIMITS")"
+fi
+export NFT_TEST_HAS_SOCKET_LIMITS
+
+detect_unshare() {
+ if ! $1 true &>/dev/null ; then
+ return 1
+ fi
+ NFT_TEST_UNSHARE_CMD="$1"
+ return 0
+}
+
+if [ -n "${NFT_TEST_UNSHARE_CMD+x}" ] ; then
+ # User overrides the unshare command.
+ if ! detect_unshare "$NFT_TEST_UNSHARE_CMD" ; then
+ msg_error "Cannot unshare via NFT_TEST_UNSHARE_CMD=$(printf '%q' "$NFT_TEST_UNSHARE_CMD")"
+ fi
+ if [ -z "${NFT_TEST_HAS_UNSHARED+x}" ] ; then
+ # Autodetect NFT_TEST_HAS_UNSHARED based one whether
+ # $NFT_TEST_UNSHARE_CMD is set.
+ if [ -n "$NFT_TEST_UNSHARE_CMD" ] ; then
+ NFT_TEST_HAS_UNSHARED="y"
+ else
+ NFT_TEST_HAS_UNSHARED="n"
+ fi
+ else
+ NFT_TEST_HAS_UNSHARED="$(bool_y "$NFT_TEST_HAS_UNSHARED")"
+ fi
+ if [ -z "${NFT_TEST_HAS_UNSHARED_MOUNT+x}" ] ; then
+ NFT_TEST_HAS_UNSHARED_MOUNT=n
+ if [ "$NFT_TEST_HAS_UNSHARED" == y ] ; then
+ case "$NFT_TEST_UNSHARE_CMD" in
+ unshare*-m*|unshare*--mount-proc*)
+ NFT_TEST_HAS_UNSHARED_MOUNT=y
+ ;;
+ esac
+ fi
+ else
+ NFT_TEST_HAS_UNSHARED_MOUNT="$(bool_y "$NFT_TEST_HAS_UNSHARED_MOUNT")"
+ fi
+else
+ NFT_TEST_HAS_UNSHARED_MOUNT=n
+ if [ "$NFT_TEST_HAS_REALROOT" = y ] ; then
+ # We appear to have real root. So try to unshare
+ # without a separate USERNS. CLONE_NEWUSER will break
+ # tests that are limited by
+ # /proc/sys/net/core/{wmem_max,rmem_max}. With real
+ # root, we want to test that.
+ if detect_unshare "unshare -f -n -m" ; then
+ NFT_TEST_HAS_UNSHARED_MOUNT=y
+ else
+ detect_unshare "unshare -f -n" ||
+ detect_unshare "unshare -f -p -m --mount-proc -U --map-root-user -n" ||
+ detect_unshare "unshare -f -U --map-root-user -n"
+ fi
+ else
+ if detect_unshare "unshare -f -p -m --mount-proc -U --map-root-user -n" ; then
+ NFT_TEST_HAS_UNSHARED_MOUNT=y
+ else
+ detect_unshare "unshare -f -U --map-root-user -n"
+ fi
+ fi
+ if [ -z "$NFT_TEST_UNSHARE_CMD" ] ; then
+ msg_error "Unshare does not work. Run as root with -U/--no-unshare or set NFT_TEST_UNSHARE_CMD"
+ fi
+ NFT_TEST_HAS_UNSHARED=y
+fi
+# If tests wish, they can know whether they are unshared via this variable.
+export NFT_TEST_HAS_UNSHARED
+export NFT_TEST_HAS_UNSHARED_MOUNT
+
+# normalize the jobs number to be an integer.
+case "$NFT_TEST_JOBS" in
+ ''|*[!0-9]*) NFT_TEST_JOBS=_NFT_TEST_JOBS_DEFAULT ;;
+esac
+if [ -z "$NFT_TEST_UNSHARE_CMD" -a "$NFT_TEST_JOBS" -gt 1 ] ; then
+ NFT_TEST_JOBS=1
+fi
+
+[ -z "$NFT" ] && NFT="$NFT_TEST_BASEDIR/../../src/nft"
+${NFT} > /dev/null 2>&1
+ret=$?
+if [ ${ret} -eq 126 ] || [ ${ret} -eq 127 ]; then
+ msg_error "cannot execute nft command: $NFT"
fi
-for arg in "$@"; do
- SINGLE+=" $arg"
- VERBOSE=y
+NFT_REAL="${NFT_REAL-$NFT}"
+
+feature_probe()
+{
+ local with_path="$NFT_TEST_BASEDIR/features/$1"
+
+ if [ -r "$with_path.nft" ] ; then
+ $NFT_TEST_UNSHARE_CMD "$NFT_REAL" --check -f "$with_path.nft" &>/dev/null
+ return $?
+ fi
+
+ if [ -x "$with_path.sh" ] ; then
+ NFT="$NFT_REAL" $NFT_TEST_UNSHARE_CMD "$with_path.sh" &>/dev/null
+ return $?
+ fi
+
+ return 1
+}
+
+for feat in "${_HAVE_OPTS[@]}" ; do
+ var="NFT_TEST_HAVE_$feat"
+ if [ -z "${!var+x}" ] ; then
+ val='y'
+ feature_probe "$feat" || val='n'
+ else
+ val="$(bool_n "${!var}")"
+ fi
+ eval "export $var=$val"
+ if [ "$NFT_TEST_HAS_UNSHARED" != y ] ; then
+ $NFT flush ruleset
+ fi
+done
+
+if [ "$NFT_TEST_JOBS" -eq 0 ] ; then
+ MODPROBE="$(which modprobe)"
+ if [ ! -x "$MODPROBE" ] ; then
+ msg_error "no modprobe binary found"
+ fi
+fi
+
+DIFF="$(which diff)"
+if [ ! -x "$DIFF" ] ; then
+ DIFF=true
+fi
+
+JOBS_PIDLIST_ARR=()
+declare -A JOBS_PIDLIST
+
+_NFT_TEST_VALGRIND_VGDB_PREFIX=
+
+cleanup_on_exit() {
+ pids_search=''
+ for pid in "${JOBS_PIDLIST_ARR[@]}" ; do
+ kill -- "-$pid" &>/dev/null
+ pids_search="$pids_search\\|\\<$pid\\>"
+ done
+ if [ -n "$pids_search" ] ; then
+ pids_search="${pids_search:2}"
+ for i in {1..100}; do
+ ps xh -o pgrp | grep -q "$pids_search" || break
+ sleep 0.01
+ done
+ fi
+ if [ "$NFT_TEST_KEEP_LOGS" != y -a -n "$NFT_TEST_TMPDIR" ] ; then
+ rm -rf "$NFT_TEST_TMPDIR"
+ fi
+ if [ -n "$_NFT_TEST_VALGRIND_VGDB_PREFIX" ] ; then
+ rm -rf "$_NFT_TEST_VALGRIND_VGDB_PREFIX"* &>/dev/null
+ fi
+}
+
+trap 'exit 130' SIGINT
+trap 'exit 143' SIGTERM
+trap 'rc=$?; cleanup_on_exit; exit $rc' EXIT
+
+TIMESTAMP=$(date '+%Y%m%d-%H%M%S.%3N')
+NFT_TEST_TMPDIR="$(mktemp --tmpdir="$_TMPDIR" -d "nft-test.$TIMESTAMP$NFT_TEST_TMPDIR_TAG.XXXXXX")" ||
+ msg_error "Failure to create temp directory in \"$_TMPDIR\""
+chmod 755 "$NFT_TEST_TMPDIR"
+
+exec &> >(tee "$NFT_TEST_TMPDIR/test.log")
+
+msg_info "conf: NFT=$(printf '%q' "$NFT")"
+msg_info "conf: NFT_REAL=$(printf '%q' "$NFT_REAL")"
+msg_info "conf: VERBOSE=$(printf '%q' "$VERBOSE")"
+msg_info "conf: NFT_TEST_VERBOSE_TEST=$(printf '%q' "$NFT_TEST_VERBOSE_TEST")"
+msg_info "conf: DUMPGEN=$(printf '%q' "$DUMPGEN")"
+msg_info "conf: VALGRIND=$(printf '%q' "$VALGRIND")"
+msg_info "conf: KMEMLEAK=$(printf '%q' "$KMEMLEAK")"
+msg_info "conf: NFT_TEST_HAS_REALROOT=$(printf '%q' "$NFT_TEST_HAS_REALROOT")"
+colorize_keywords value "$YELLOW" "$NFT_TEST_HAS_SOCKET_LIMITS" y
+msg_info "conf: NFT_TEST_HAS_SOCKET_LIMITS=$value"
+msg_info "conf: NFT_TEST_UNSHARE_CMD=$(printf '%q' "$NFT_TEST_UNSHARE_CMD")"
+msg_info "conf: NFT_TEST_HAS_UNSHARED=$(printf '%q' "$NFT_TEST_HAS_UNSHARED")"
+msg_info "conf: NFT_TEST_HAS_UNSHARED_MOUNT=$(printf '%q' "$NFT_TEST_HAS_UNSHARED_MOUNT")"
+msg_info "conf: NFT_TEST_KEEP_LOGS=$(printf '%q' "$NFT_TEST_KEEP_LOGS")"
+msg_info "conf: NFT_TEST_JOBS=$NFT_TEST_JOBS"
+msg_info "conf: NFT_TEST_FAIL_ON_SKIP=$NFT_TEST_FAIL_ON_SKIP"
+msg_info "conf: NFT_TEST_RANDOM_SEED=$NFT_TEST_RANDOM_SEED"
+msg_info "conf: NFT_TEST_SHUFFLE_TESTS=$NFT_TEST_SHUFFLE_TESTS"
+msg_info "conf: TMPDIR=$(printf '%q' "$_TMPDIR")"
+echo
+for KEY in $(compgen -v | grep '^NFT_TEST_SKIP_' | sort) ; do
+ colorize_keywords value "$YELLOW" "${!KEY}" y
+ msg_info "conf: $KEY=$value"
+ export "$KEY"
+done
+for KEY in $(compgen -v | grep '^NFT_TEST_HAVE_' | sort) ; do
+ colorize_keywords value "$YELLOW" "${!KEY}" n
+ msg_info "conf: $KEY=$value"
+ export "$KEY"
done
+NFT_TEST_LATEST="$_TMPDIR/nft-test.latest.$USER"
+
+ln -snf "$NFT_TEST_TMPDIR" "$NFT_TEST_LATEST"
+
+# export the tmp directory for tests. They may use it, but create distinct
+# files! On success, it will be deleted on EXIT. See also "--keep-logs"
+export NFT_TEST_TMPDIR
+
+echo
+msg_info "info: NFT_TEST_BASEDIR=$(printf '%q' "$NFT_TEST_BASEDIR")"
+msg_info "info: NFT_TEST_TMPDIR=$(printf '%q' "$NFT_TEST_TMPDIR")"
+
+if [ "$VALGRIND" == "y" ]; then
+ NFT="$NFT_TEST_BASEDIR/helpers/nft-valgrind-wrapper.sh"
+ msg_info "info: NFT=$(printf '%q' "$NFT")"
+ _NFT_TEST_VALGRIND_VGDB_PREFIX="$NFT_TEST_TMPDIR_ORIG/vgdb-pipe-nft-test-$TIMESTAMP.$$.$RANDOM"
+ export _NFT_TEST_VALGRIND_VGDB_PREFIX
+fi
+
kernel_cleanup() {
- $NFT flush ruleset
+ if [ "$NFT_TEST_JOBS" -ne 0 ] ; then
+ # When we run jobs in parallel (even with only one "parallel"
+ # job via `NFT_TEST_JOBS=1`), we skip such global cleanups.
+ return
+ fi
+ if [ "$NFT_TEST_HAS_UNSHARED" != y ] ; then
+ $NFT flush ruleset
+ fi
$MODPROBE -raq \
nft_reject_ipv4 nft_reject_bridge nft_reject_ipv6 nft_reject \
nft_redir_ipv4 nft_redir_ipv6 nft_redir \
@@ -68,79 +723,276 @@ kernel_cleanup() {
nft_exthdr nft_payload nft_cmp nft_range \
nft_quota nft_queue nft_numgen nft_osf nft_socket nft_tproxy \
nft_meta nft_meta_bridge nft_counter nft_log nft_limit \
- nft_fib nft_fib_ipv4 nft_fib_ipv6 \
+ nft_fib nft_fib_ipv4 nft_fib_ipv6 nft_fib_inet \
nft_hash nft_ct nft_compat nft_rt nft_objref \
nft_set_hash nft_set_rbtree nft_set_bitmap \
- nft_chain_nat_ipv4 nft_chain_nat_ipv6 \
+ nft_synproxy nft_connlimit \
+ nft_chain_nat \
nft_chain_route_ipv4 nft_chain_route_ipv6 \
nft_dup_netdev nft_fwd_netdev \
- nft_reject nft_reject_inet \
+ nft_reject nft_reject_inet nft_reject_netdev \
nf_tables_set nf_tables \
nf_flow_table nf_flow_table_ipv4 nf_flow_tables_ipv6 \
- nf_flow_table_inet nft_flow_offload
+ nf_flow_table_inet nft_flow_offload \
+ nft_xfrm
}
-find_tests() {
- if [ ! -z "$SINGLE" ] ; then
- echo $SINGLE
+echo ""
+ok=0
+skipped=0
+failed=0
+
+kmem_runs=0
+kmemleak_found=0
+
+check_kmemleak_force()
+{
+ test -f /sys/kernel/debug/kmemleak || return 0
+
+ echo scan > /sys/kernel/debug/kmemleak
+
+ lines=$(grep "unreferenced object" /sys/kernel/debug/kmemleak | wc -l)
+ if [ $lines -ne $kmemleak_found ];then
+ msg_warn "[FAILED] kmemleak detected $lines memory leaks"
+ kmemleak_found=$lines
+ fi
+
+ if [ $lines -ne 0 ];then
+ return 1
+ fi
+
+ return 0
+}
+
+check_kmemleak()
+{
+ test -f /sys/kernel/debug/kmemleak || return
+
+ if [ "$KMEMLEAK" == "y" ] ; then
+ check_kmemleak_force
return
fi
- ${FIND} ${TESTDIR} -type f -executable | sort
+
+ kmem_runs=$((kmem_runs + 1))
+ if [ $((kmem_runs % 30)) -eq 0 ]; then
+ # scan slows tests down quite a bit, hence
+ # do this only for every 30th test file by
+ # default.
+ check_kmemleak_force
+ fi
}
-echo ""
-ok=0
-failed=0
-for testfile in $(find_tests)
-do
- kernel_cleanup
+read kernel_tainted < /proc/sys/kernel/tainted
+if [ "$kernel_tainted" -ne 0 ] ; then
+ msg_warn "kernel is tainted"
+ echo
+fi
+
+print_test_header() {
+ local msglevel="$1"
+ local testfile="$2"
+ local testidx_completed="$3"
+ local status="$4"
+ local text
+ local s_idx
+
+ s_idx="${#TESTS[@]}"
+ align_text text right "${#s_idx}" "$testidx_completed"
+ s_idx="$text/${#TESTS[@]}"
- msg_info "[EXECUTING] $testfile"
- test_output=$(NFT=$NFT ${testfile} 2>&1)
- rc_got=$?
- echo -en "\033[1A\033[K" # clean the [EXECUTING] foobar line
+ align_text text left 12 "[$status]"
+ _msg "$msglevel" "$text $s_idx $testfile"
+}
+
+print_test_result() {
+ local NFT_TEST_TESTTMPDIR="$1"
+ local testfile="$2"
+ local rc_got="$3"
+
+ local result_msg_level="I"
+ local result_msg_files=( "$NFT_TEST_TESTTMPDIR/testout.log" "$NFT_TEST_TESTTMPDIR/ruleset-diff" )
+ local result_msg_status
if [ "$rc_got" -eq 0 ] ; then
- # check nft dump only for positive tests
- dumppath="$(dirname ${testfile})/dumps"
- dumpfile="${dumppath}/$(basename ${testfile}).nft"
- rc_spec=0
- if [ "$rc_got" -eq 0 ] && [ -f ${dumpfile} ]; then
- test_output=$(${DIFF} -u ${dumpfile} <($NFT list ruleset) 2>&1)
- rc_spec=$?
+ ((ok++))
+ result_msg_status="${GREEN}OK$RESET"
+ elif [ "$rc_got" -eq 77 ] ; then
+ ((skipped++))
+ result_msg_status="${YELLOW}SKIPPED$RESET"
+ else
+ ((failed++))
+ result_msg_level="W"
+ if [ "$rc_got" -eq 121 ] ; then
+ result_msg_status="CHK DUMP"
+ elif [ "$rc_got" -eq 122 ] ; then
+ result_msg_status="VALGRIND"
+ elif [ "$rc_got" -eq 123 ] ; then
+ result_msg_status="TAINTED"
+ elif [ "$rc_got" -eq 124 ] ; then
+ result_msg_status="DUMP FAIL"
+ else
+ result_msg_status="FAILED"
fi
+ result_msg_status="$RED$result_msg_status$RESET"
+ result_msg_files=( "$NFT_TEST_TESTTMPDIR/testout.log" )
+ fi
- if [ "$rc_spec" -eq 0 ]; then
- msg_info "[OK] $testfile"
- [ "$VERBOSE" == "y" ] && [ ! -z "$test_output" ] && echo "$test_output"
- ((ok++))
+ print_test_header "$result_msg_level" "$testfile" "$((ok + skipped + failed))" "$result_msg_status"
- if [ "$DUMPGEN" == "y" ] && [ "$rc_got" == 0 ] && [ ! -f "${dumpfile}" ]; then
- mkdir -p "${dumppath}"
- nft list ruleset > "${dumpfile}"
- fi
- else
- ((failed++))
- if [ "$VERBOSE" == "y" ] ; then
- msg_warn "[DUMP FAIL] $testfile: dump diff detected"
- [ ! -z "$test_output" ] && echo "$test_output"
- else
- msg_warn "[DUMP FAIL] $testfile"
+ if [ "$VERBOSE" = "y" ] ; then
+ local f
+
+ for f in "${result_msg_files[@]}"; do
+ if [ -s "$f" ] ; then
+ cat "$f"
fi
+ done
+
+ if [ "$rc_got" -ne 0 ] ; then
+ msg_info "check \"$NFT_TEST_TESTTMPDIR\""
fi
- else
- ((failed++))
- if [ "$VERBOSE" == "y" ] ; then
- msg_warn "[FAILED] $testfile: got $rc_got"
- [ ! -z "$test_output" ] && echo "$test_output"
+ fi
+}
+
+declare -A JOBS_TEMPDIR
+
+job_start() {
+ local testfile="$1"
+ local testidx="$2"
+
+ if [ "$NFT_TEST_JOBS" -le 1 ] && [[ -t 1 ]]; then
+ print_test_header I "$testfile" "$testidx" "EXECUTING"
+ fi
+
+ NFT_TEST_TESTTMPDIR="${JOBS_TEMPDIR["$testfile"]}" \
+ NFT="$NFT" \
+ NFT_REAL="$NFT_REAL" \
+ DIFF="$DIFF" \
+ DUMPGEN="$DUMPGEN" \
+ NFT_TEST_VERBOSE_TEST="$NFT_TEST_VERBOSE_TEST" \
+ $NFT_TEST_UNSHARE_CMD "$NFT_TEST_BASEDIR/helpers/test-wrapper.sh" "$testfile"
+ local rc_got=$?
+
+ if [ "$NFT_TEST_JOBS" -le 1 ] && [[ -t 1 ]]; then
+ echo -en "\033[1A\033[K" # clean the [EXECUTING] foobar line
+ fi
+
+ return "$rc_got"
+}
+
+# `wait -p` is only supported since bash 5.1
+WAIT_SUPPORTS_P=1
+[ "${BASH_VERSINFO[0]}" -le 4 -o \( "${BASH_VERSINFO[0]}" -eq 5 -a "${BASH_VERSINFO[1]}" -eq 0 \) ] && WAIT_SUPPORTS_P=0
+
+job_wait()
+{
+ local num_jobs="$1"
+ local JOBCOMPLETED
+ local rc_got
+
+ while [ "${#JOBS_PIDLIST_ARR[@]}" -gt 0 -a "${#JOBS_PIDLIST_ARR[@]}" -ge "$num_jobs" ] ; do
+ if [ "$WAIT_SUPPORTS_P" = 1 ] ; then
+ wait -n -p JOBCOMPLETED
+ rc_got="$?"
+ array_remove_first JOBS_PIDLIST_ARR "$JOBCOMPLETED"
else
- msg_warn "[FAILED] $testfile"
+ # Without `wait -p` support, we need to explicitly wait
+ # for a PID. That reduces parallelism.
+ JOBCOMPLETED="${JOBS_PIDLIST_ARR[0]}"
+ JOBS_PIDLIST_ARR=( "${JOBS_PIDLIST_ARR[@]:1}" )
+ wait -n "$JOBCOMPLETED"
+ rc_got="$?"
fi
- fi
+
+ local testfile2="${JOBS_PIDLIST[$JOBCOMPLETED]}"
+ unset JOBS_PIDLIST[$JOBCOMPLETED]
+ print_test_result "${JOBS_TEMPDIR["$testfile2"]}" "$testfile2" "$rc_got"
+ check_kmemleak
+ done
+}
+
+if [ "$NFT_TEST_SHUFFLE_TESTS" = y ] ; then
+ TESTS=( $(printf '%s\n' "${TESTS[@]}" | shuf --random-source=<("$NFT_TEST_BASEDIR/helpers/random-source.sh" "nft-test-shuffle-tests" "$NFT_TEST_RANDOM_SEED") ) )
+fi
+
+TESTIDX=0
+for testfile in "${TESTS[@]}" ; do
+ job_wait "$NFT_TEST_JOBS"
+
+ kernel_cleanup
+
+ ((TESTIDX++))
+
+ NFT_TEST_TESTTMPDIR="$NFT_TEST_TMPDIR/test-${testfile//\//-}.$TESTIDX"
+ mkdir "$NFT_TEST_TESTTMPDIR"
+ chmod 755 "$NFT_TEST_TESTTMPDIR"
+ JOBS_TEMPDIR["$testfile"]="$NFT_TEST_TESTTMPDIR"
+
+ [[ -o monitor ]] && set_old_state='set -m' || set_old_state='set +m'
+ set -m
+ ( job_start "$testfile" "$TESTIDX" ) &
+ pid=$!
+ eval "$set_old_state"
+ JOBS_PIDLIST[$pid]="$testfile"
+ JOBS_PIDLIST_ARR+=( "$pid" )
done
+job_wait 0
+
echo ""
-msg_info "results: [OK] $ok [FAILED] $failed [TOTAL] $((ok+failed))"
+
+# kmemleak may report suspected leaks
+# that get free'd after all, so always do
+# a check after all test cases
+# have completed and reset the counter
+# so another warning gets emitted.
+kmemleak_found=0
+check_kmemleak_force
+
+failed_total="$failed"
+if [ "$NFT_TEST_FAIL_ON_SKIP" = y ] ; then
+ failed_total="$((failed_total + skipped))"
+fi
+
+if [ "$failed_total" -gt 0 ] ; then
+ RR="$RED"
+elif [ "$skipped" -gt 0 ] ; then
+ RR="$YELLOW"
+else
+ RR="$GREEN"
+fi
+msg_info "${RR}results$RESET: [OK] $GREEN$ok$RESET [SKIPPED] $YELLOW$skipped$RESET [FAILED] $RED$failed$RESET [TOTAL] $((ok+skipped+failed))"
kernel_cleanup
-exit $failed
+
+# ( \
+# for d in /tmp/nft-test.latest.*/test-*/ ; do \
+# printf '%10.2f %s\n' \
+# "$(sed '1!d' "$d/times")" \
+# "$(cat "$d/name")" ; \
+# done \
+# | sort -n \
+# | awk '{print $0; s+=$1} END{printf("%10.2f\n", s)}' ; \
+# printf '%10.2f wall time\n' "$(sed '1!d' /tmp/nft-test.latest.*/times)" \
+# )
+END_TIME="$(cut -d ' ' -f1 /proc/uptime)"
+WALL_TIME="$(awk -v start="$START_TIME" -v end="$END_TIME" "BEGIN { print(end - start) }")"
+printf "%s\n" "$WALL_TIME" "$START_TIME" "$END_TIME" > "$NFT_TEST_TMPDIR/times"
+
+if [ "$failed_total" -gt 0 -o "$NFT_TEST_KEEP_LOGS" = y ] ; then
+ msg_info "check the temp directory \"$NFT_TEST_TMPDIR\" (\"$NFT_TEST_LATEST\")"
+ msg_info " ls -lad \"$NFT_TEST_LATEST\"/*/*"
+ msg_info " grep -R ^ \"$NFT_TEST_LATEST\"/"
+ NFT_TEST_TMPDIR=
+fi
+
+if [ "$failed" -gt 0 ] ; then
+ exit 1
+elif [ "$NFT_TEST_FAIL_ON_SKIP" = y -a "$skipped" -gt 0 ] ; then
+ msg_info "some tests were skipped. Fail due to NFT_TEST_FAIL_ON_SKIP=y"
+ exit 1
+elif [ "$ok" -eq 0 -a "$skipped" -gt 0 ] ; then
+ exit 77
+else
+ exit 0
+fi
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_0 b/tests/shell/testcases/bitwise/0040mark_binop_0
new file mode 100755
index 00000000..4ecc9d3d
--- /dev/null
+++ b/tests/shell/testcases/bitwise/0040mark_binop_0
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="
+ add table t
+ add chain t c { type filter hook output priority filter; }
+ add rule t c oif lo ct mark set (meta mark | 0x10) << 8
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_1 b/tests/shell/testcases/bitwise/0040mark_binop_1
new file mode 100755
index 00000000..bd9e028d
--- /dev/null
+++ b/tests/shell/testcases/bitwise/0040mark_binop_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="
+ add table t
+ add chain t c { type filter hook input priority filter; }
+ add rule t c iif lo ct mark & 0xff 0x10 meta mark set ct mark >> 8
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_2 b/tests/shell/testcases/bitwise/0040mark_binop_2
new file mode 100755
index 00000000..5e66a27a
--- /dev/null
+++ b/tests/shell/testcases/bitwise/0040mark_binop_2
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="
+ add table t
+ add chain t c { type filter hook output priority filter; }
+ add rule t c ct mark set ip dscp lshift 2 or 0x10
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_3 b/tests/shell/testcases/bitwise/0040mark_binop_3
new file mode 100755
index 00000000..21dda670
--- /dev/null
+++ b/tests/shell/testcases/bitwise/0040mark_binop_3
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="
+ add table t
+ add chain t c { type filter hook input priority filter; }
+ add rule t c meta mark set ip dscp lshift 2 or 0x10
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_4 b/tests/shell/testcases/bitwise/0040mark_binop_4
new file mode 100755
index 00000000..e5c8a42a
--- /dev/null
+++ b/tests/shell/testcases/bitwise/0040mark_binop_4
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="
+ add table t
+ add chain t c { type filter hook output priority filter; }
+ add rule t c ct mark set ip dscp lshift 26 or 0x10
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_5 b/tests/shell/testcases/bitwise/0040mark_binop_5
new file mode 100755
index 00000000..184fbed0
--- /dev/null
+++ b/tests/shell/testcases/bitwise/0040mark_binop_5
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="
+ add table t
+ add chain t c { type filter hook input priority filter; }
+ add rule t c meta mark set ip dscp lshift 26 or 0x10
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_6 b/tests/shell/testcases/bitwise/0040mark_binop_6
new file mode 100755
index 00000000..129dd5c0
--- /dev/null
+++ b/tests/shell/testcases/bitwise/0040mark_binop_6
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="
+ add table ip6 t
+ add chain ip6 t c { type filter hook output priority filter; }
+ add rule ip6 t c ct mark set ip6 dscp lshift 2 or 0x10
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_7 b/tests/shell/testcases/bitwise/0040mark_binop_7
new file mode 100755
index 00000000..791a7943
--- /dev/null
+++ b/tests/shell/testcases/bitwise/0040mark_binop_7
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="
+ add table ip6 t
+ add chain ip6 t c { type filter hook input priority filter; }
+ add rule ip6 t c meta mark set ip6 dscp lshift 2 or 0x10
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_8 b/tests/shell/testcases/bitwise/0040mark_binop_8
new file mode 100755
index 00000000..5e7bd28d
--- /dev/null
+++ b/tests/shell/testcases/bitwise/0040mark_binop_8
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="
+ add table ip6 t
+ add chain ip6 t c { type filter hook output priority filter; }
+ add rule ip6 t c ct mark set ip6 dscp lshift 26 or 0x10
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/bitwise/0040mark_binop_9 b/tests/shell/testcases/bitwise/0040mark_binop_9
new file mode 100755
index 00000000..a7b60fb8
--- /dev/null
+++ b/tests/shell/testcases/bitwise/0040mark_binop_9
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="
+ add table ip6 t
+ add chain ip6 t c { type filter hook input priority filter; }
+ add rule ip6 t c meta mark set ip6 dscp lshift 26 or 0x10
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_0.json-nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_0.json-nft
new file mode 100644
index 00000000..8973de85
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_0.json-nft
@@ -0,0 +1,75 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oif"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "<<": [
+ {
+ "|": [
+ {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ 16
+ ]
+ },
+ 8
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_0.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_0.nft
new file mode 100644
index 00000000..fc0a600a
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_0.nft
@@ -0,0 +1,6 @@
+table ip t {
+ chain c {
+ type filter hook output priority filter; policy accept;
+ oif "lo" ct mark set (meta mark | 0x00000010) << 8
+ }
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_1.json-nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_1.json-nft
new file mode 100644
index 00000000..ed8e1a0d
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_1.json-nft
@@ -0,0 +1,86 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iif"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "&": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 255
+ ]
+ },
+ "right": 16
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ ">>": [
+ {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ 8
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_1.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_1.nft
new file mode 100644
index 00000000..dbaacefb
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_1.nft
@@ -0,0 +1,6 @@
+table ip t {
+ chain c {
+ type filter hook input priority filter; policy accept;
+ iif "lo" ct mark & 0x000000ff == 0x00000010 meta mark set ct mark >> 8
+ }
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_2.json-nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_2.json-nft
new file mode 100644
index 00000000..3cd9a831
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_2.json-nft
@@ -0,0 +1,65 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "dscp"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_2.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_2.nft
new file mode 100644
index 00000000..2b9be36e
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_2.nft
@@ -0,0 +1,6 @@
+table ip t {
+ chain c {
+ type filter hook output priority filter; policy accept;
+ ct mark set ip dscp << 2 | 0x10
+ }
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_3.json-nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_3.json-nft
new file mode 100644
index 00000000..00c5b78a
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_3.json-nft
@@ -0,0 +1,65 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "dscp"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_3.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_3.nft
new file mode 100644
index 00000000..8206fec0
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_3.nft
@@ -0,0 +1,6 @@
+table ip t {
+ chain c {
+ type filter hook input priority filter; policy accept;
+ meta mark set ip dscp << 2 | 0x10
+ }
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_4.json-nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_4.json-nft
new file mode 100644
index 00000000..3aa81605
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_4.json-nft
@@ -0,0 +1,65 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "dscp"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_4.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_4.nft
new file mode 100644
index 00000000..91d9f566
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_4.nft
@@ -0,0 +1,6 @@
+table ip t {
+ chain c {
+ type filter hook output priority filter; policy accept;
+ ct mark set ip dscp << 26 | 0x10
+ }
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_5.json-nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_5.json-nft
new file mode 100644
index 00000000..a3214973
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_5.json-nft
@@ -0,0 +1,65 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "dscp"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_5.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_5.nft
new file mode 100644
index 00000000..f2b51eb8
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_5.nft
@@ -0,0 +1,6 @@
+table ip t {
+ chain c {
+ type filter hook input priority filter; policy accept;
+ meta mark set ip dscp << 26 | 0x10
+ }
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_6.json-nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_6.json-nft
new file mode 100644
index 00000000..2de0323d
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_6.json-nft
@@ -0,0 +1,65 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "protocol": "ip6",
+ "field": "dscp"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_6.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_6.nft
new file mode 100644
index 00000000..cf7be90c
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_6.nft
@@ -0,0 +1,6 @@
+table ip6 t {
+ chain c {
+ type filter hook output priority filter; policy accept;
+ ct mark set ip6 dscp << 2 | 0x10
+ }
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_7.json-nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_7.json-nft
new file mode 100644
index 00000000..72aee701
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_7.json-nft
@@ -0,0 +1,65 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "protocol": "ip6",
+ "field": "dscp"
+ }
+ },
+ 2
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_7.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_7.nft
new file mode 100644
index 00000000..a9663e62
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_7.nft
@@ -0,0 +1,6 @@
+table ip6 t {
+ chain c {
+ type filter hook input priority filter; policy accept;
+ meta mark set ip6 dscp << 2 | 0x10
+ }
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_8.json-nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_8.json-nft
new file mode 100644
index 00000000..1cf84be5
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_8.json-nft
@@ -0,0 +1,65 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "protocol": "ip6",
+ "field": "dscp"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_8.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_8.nft
new file mode 100644
index 00000000..04b866ad
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_8.nft
@@ -0,0 +1,6 @@
+table ip6 t {
+ chain c {
+ type filter hook output priority filter; policy accept;
+ ct mark set ip6 dscp << 26 | 0x10
+ }
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_9.json-nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_9.json-nft
new file mode 100644
index 00000000..6f4494b1
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_9.json-nft
@@ -0,0 +1,65 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "|": [
+ {
+ "<<": [
+ {
+ "payload": {
+ "protocol": "ip6",
+ "field": "dscp"
+ }
+ },
+ 26
+ ]
+ },
+ 16
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/bitwise/dumps/0040mark_binop_9.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_9.nft
new file mode 100644
index 00000000..d4745ea4
--- /dev/null
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_9.nft
@@ -0,0 +1,6 @@
+table ip6 t {
+ chain c {
+ type filter hook input priority filter; policy accept;
+ meta mark set ip6 dscp << 26 | 0x10
+ }
+}
diff --git a/tests/shell/testcases/bogons/assert_failures b/tests/shell/testcases/bogons/assert_failures
new file mode 100755
index 00000000..79099427
--- /dev/null
+++ b/tests/shell/testcases/bogons/assert_failures
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+dir=$(dirname $0)/nft-f/
+
+for f in $dir/*; do
+ $NFT --check -f "$f"
+
+ if [ $? -ne 1 ]; then
+ echo "Bogus input file $f did not cause expected error code" 1>&2
+ exit 111
+ fi
+done
diff --git a/tests/shell/testcases/bogons/dumps/assert_failures.json-nft b/tests/shell/testcases/bogons/dumps/assert_failures.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/bogons/dumps/assert_failures.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/bogons/dumps/assert_failures.nft b/tests/shell/testcases/bogons/dumps/assert_failures.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/bogons/dumps/assert_failures.nft
diff --git a/tests/shell/testcases/bogons/nft-f/add_to_a_set_crash b/tests/shell/testcases/bogons/nft-f/add_to_a_set_crash
new file mode 100644
index 00000000..80a01b45
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/add_to_a_set_crash
@@ -0,0 +1,11 @@
+table t {
+ set candidates_ipv4 {
+ type ipv4_addr . inet_service
+ size 65535
+ flags dynamic,timeout
+ }
+
+ chain input {
+ tcp dport 10003 ip saddr . tcp dport @candidates_ipv4 add @candidates_ipv4 { ip saddr . 10 :0004 timeout 1s }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/binop_with_different_basetype_assert b/tests/shell/testcases/bogons/nft-f/binop_with_different_basetype_assert
new file mode 100644
index 00000000..e8436008
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/binop_with_different_basetype_assert
@@ -0,0 +1,5 @@
+table ip t {
+ chain c {
+ oifname set ip9dscp << 26 | 0x10
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/bitwise_masklen_assert b/tests/shell/testcases/bogons/nft-f/bitwise_masklen_assert
new file mode 100644
index 00000000..0e75e6f1
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/bitwise_masklen_assert
@@ -0,0 +1,5 @@
+table inet t {
+ chain c {
+ udp length . @th,160,138 vmap { 47-63 . 0xe37313536313033&131303735353203 : accept }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/byteorder_switch_stack_overflow b/tests/shell/testcases/bogons/nft-f/byteorder_switch_stack_overflow
new file mode 100644
index 00000000..01640528
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/byteorder_switch_stack_overflow
@@ -0,0 +1,6 @@
+table inet x {
+ chain nat_dns_acme {
+ udp length . @th,260,118 vmap { 47-63 . 0xe373135363130333131303735353203 : goto nat_dns_dnstc, }
+ drop
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/counter_objref_crash b/tests/shell/testcases/bogons/nft-f/counter_objref_crash
new file mode 100644
index 00000000..3a4b981b
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/counter_objref_crash
@@ -0,0 +1,5 @@
+table inet x {
+ chain y {
+ counter name ip saddr bytes 1.1.1. 1024
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/ct_helper_yystate_underflow b/tests/shell/testcases/bogons/nft-f/ct_helper_yystate_underflow
new file mode 100644
index 00000000..18eb25eb
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/ct_helper_yystate_underflow
@@ -0,0 +1,14 @@
+table inet filter {
+ ct helper sip-5060u {
+ type "sip" protocol udp
+ l3proto ip
+ }5060t {
+ type "sip" protocol tcp
+ l3pownerip
+ }
+
+ chain input {
+ type filtol/dev/stdinok input priority f)lser; policy accept;
+ ct helper set ip protocol . th dport map { udp . 1-20000 : "si60u", tcp . 10000-20000 : "sip-5060t" }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/ct_timeout_memleak b/tests/shell/testcases/bogons/nft-f/ct_timeout_memleak
new file mode 100644
index 00000000..014525a3
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/ct_timeout_memleak
@@ -0,0 +1,7 @@
+table ip filter {
+ ct timeout cttime {
+ protocol tcp
+ l3proto ip
+ policy = { estabQisheestablished : 2m3s, cd : 2m3s, }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/ct_timeout_memleak_objfree b/tests/shell/testcases/bogons/nft-f/ct_timeout_memleak_objfree
new file mode 100644
index 00000000..28b1a211
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/ct_timeout_memleak_objfree
@@ -0,0 +1,5 @@
+table ip filter {
+ ct timeout cttime {
+ protocol tcp
+ l3proto ip
+ policy = { close : 12s }
diff --git a/tests/shell/testcases/bogons/nft-f/define_policy_assert b/tests/shell/testcases/bogons/nft-f/define_policy_assert
new file mode 100644
index 00000000..f1e58b55
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/define_policy_assert
@@ -0,0 +1,3 @@
+chain y x { priority filter
+define p = foo
+policy $p
diff --git a/tests/shell/testcases/bogons/nft-f/double-free-on-binop-dtype_assert b/tests/shell/testcases/bogons/nft-f/double-free-on-binop-dtype_assert
new file mode 100644
index 00000000..b7a9a1cc
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/double-free-on-binop-dtype_assert
@@ -0,0 +1,6 @@
+table inet t {
+ chain c {
+ udp length . @th,160,118 vmap { 47-63 . 0xe3731353631303331313037353532/3 : accept }
+ jump noexist # only here so this fails to load after patch.
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/dup_fwd_ranges b/tests/shell/testcases/bogons/nft-f/dup_fwd_ranges
new file mode 100644
index 00000000..efaff9e5
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/dup_fwd_ranges
@@ -0,0 +1,14 @@
+define dev = "1"-"2"
+
+table netdev t {
+ chain c {
+ fwd to 1-2
+ dup to 1-2
+ }
+}
+
+table ip t {
+ chain c {
+ dup to 1-2 device $dev
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/dynamic-stack-buffer-overflow_gen_prefix b/tests/shell/testcases/bogons/nft-f/dynamic-stack-buffer-overflow_gen_prefix
new file mode 100644
index 00000000..23c2dc31
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/dynamic-stack-buffer-overflow_gen_prefix
@@ -0,0 +1,5 @@
+table ip test {
+ chain test {
+ tcp dport set ip daddr map { 192.168.0.1 : 0x000/0001 }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/evaluate_conflict_resolution_gen_dependency_base_ll_hdr_assert b/tests/shell/testcases/bogons/nft-f/evaluate_conflict_resolution_gen_dependency_base_ll_hdr_assert
new file mode 100644
index 00000000..43d72c4d
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/evaluate_conflict_resolution_gen_dependency_base_ll_hdr_assert
@@ -0,0 +1,5 @@
+table ip6 t {
+ chain c {
+ ip6 nexthdr comp udp dport 4789
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/exthdr_with_range_bug b/tests/shell/testcases/bogons/nft-f/exthdr_with_range_bug
new file mode 100644
index 00000000..e307e7cc
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/exthdr_with_range_bug
@@ -0,0 +1 @@
+add rule t c ip option ra set 0-1
diff --git a/tests/shell/testcases/bogons/nft-f/huge_binop_expr_chain_crash b/tests/shell/testcases/bogons/nft-f/huge_binop_expr_chain_crash
new file mode 100644
index 00000000..8d1da726
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/huge_binop_expr_chain_crash
@@ -0,0 +1,5 @@
+table t {
+ chain c {
+ meta oifname^a^b^c^d^e^f^g^h^i^j^k^l^m^n^o^p^q^r^s^t^u^v^w^x^y^z^A^B^C^D^E^F^G^H^I^J^K^L^M^N^O^P^Q^R^S^T^U^V^W^X^Y^Z^0^1^2^3^4^5^6^7^8^9 bar
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/huge_chain_name_assert b/tests/shell/testcases/bogons/nft-f/huge_chain_name_assert
new file mode 100644
index 00000000..161f867d
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/huge_chain_name_assert
@@ -0,0 +1,5 @@
+table inet x {
+ chain c {
+ udp length vmap { 1 : goto rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/huge_chain_name_define_assert b/tests/shell/testcases/bogons/nft-f/huge_chain_name_define_assert
new file mode 100644
index 00000000..3c2c0d3e
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/huge_chain_name_define_assert
@@ -0,0 +1,7 @@
+define huge = rrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr
+
+table t {
+ chain d {
+ jump $huge
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/huge_chain_prio b/tests/shell/testcases/bogons/nft-f/huge_chain_prio
new file mode 100644
index 00000000..41f8061a
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/huge_chain_prio
@@ -0,0 +1,5 @@
+table t {
+ chain c {
+ type filter hook input priority srcnDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD#DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/huge_shift_assert b/tests/shell/testcases/bogons/nft-f/huge_shift_assert
new file mode 100644
index 00000000..7599f850
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/huge_shift_assert
@@ -0,0 +1,5 @@
+table ip t {
+ chain c {
+ counter name meta mark >> 88888888888888888888
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/icmp_reject_type_uint8_assert b/tests/shell/testcases/bogons/nft-f/icmp_reject_type_uint8_assert
new file mode 100644
index 00000000..1fc85b29
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/icmp_reject_type_uint8_assert
@@ -0,0 +1 @@
+rule t c reject with icmp 512
diff --git a/tests/shell/testcases/bogons/nft-f/include-device b/tests/shell/testcases/bogons/nft-f/include-device
new file mode 100644
index 00000000..1eb79773
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/include-device
@@ -0,0 +1 @@
+include "/dev/null"
diff --git a/tests/shell/testcases/bogons/nft-f/invalid_mapping_expr_binop_assert b/tests/shell/testcases/bogons/nft-f/invalid_mapping_expr_binop_assert
new file mode 100644
index 00000000..7205ff4f
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/invalid_mapping_expr_binop_assert
@@ -0,0 +1 @@
+xy mame ip saddr map h& p p
diff --git a/tests/shell/testcases/bogons/nft-f/invalid_range_expr_type_binop b/tests/shell/testcases/bogons/nft-f/invalid_range_expr_type_binop
new file mode 100644
index 00000000..514d6ffe
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/invalid_range_expr_type_binop
@@ -0,0 +1,12 @@
+table ip x {
+ map z {
+ type ipv4_addr : ipv4_addr
+ elements = { 1&.141.0.1 - 192.168.0.2}
+ }
+
+ map z {
+ type ipv4_addr : ipv4_addr
+ flags interval
+ elements = { 10.141.0.0, * : 192.168.0.4 }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/map_without_key b/tests/shell/testcases/bogons/nft-f/map_without_key
new file mode 100644
index 00000000..78f16b23
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/map_without_key
@@ -0,0 +1,5 @@
+table t {
+ map m {
+ elements = { 0x00000023 : 0x00001337 }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/mapping_with_invalid_datatype_crash b/tests/shell/testcases/bogons/nft-f/mapping_with_invalid_datatype_crash
new file mode 100644
index 00000000..9f7084c8
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/mapping_with_invalid_datatype_crash
@@ -0,0 +1 @@
+bla to tcp dport map { 80 : 1.1.1.1 . 8001, 81 : 2.2.2.2 . 9001 } bla
diff --git a/tests/shell/testcases/bogons/nft-f/memleak_on_hookspec_error b/tests/shell/testcases/bogons/nft-f/memleak_on_hookspec_error
new file mode 100644
index 00000000..6f52658f
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/memleak_on_hookspec_error
@@ -0,0 +1,21 @@
+table ip filter {
+ ct expectation ctexpect {
+ protocol tcp
+ size 12
+ l3proto ip
+ } . inet_proto : mark
+ flags interval,timeout
+ }
+
+ chain output {
+ type gilter hook output priori
+
+ chain c {
+ cttable inet filter {
+ map test {
+ type mark . inet_service . inet_proto : mark
+ flags interval,timeout
+ }
+
+ chain output {
+ type gilter hook output priority filuer; policy \ No newline at end of file
diff --git a/tests/shell/testcases/bogons/nft-f/memleak_on_meta_set_errpath b/tests/shell/testcases/bogons/nft-f/memleak_on_meta_set_errpath
new file mode 100644
index 00000000..917e8bf8
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/memleak_on_meta_set_errpath
@@ -0,0 +1,5 @@
+table filter {
+ chain y {
+ meta seccark set ct secmark
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/nat_prefix_map_with_set_element_assert b/tests/shell/testcases/bogons/nft-f/nat_prefix_map_with_set_element_assert
new file mode 100644
index 00000000..18c7edd1
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/nat_prefix_map_with_set_element_assert
@@ -0,0 +1,7 @@
+table ip x {
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24, 10.141.12.1 }
+ }
+}
+
diff --git a/tests/shell/testcases/bogons/nft-f/nat_stmt_with_set_instead_of_map b/tests/shell/testcases/bogons/nft-f/nat_stmt_with_set_instead_of_map
new file mode 100644
index 00000000..b1302278
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/nat_stmt_with_set_instead_of_map
@@ -0,0 +1,10 @@
+table inet x {
+ set y {
+ type ipv4_addr
+ elements = { 2.2.2.2, 3.3.3.3 }
+ }
+
+ chain y {
+ snat ip to ip saddr map @y
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/netlink_gen_stmt_stateful_assert b/tests/shell/testcases/bogons/nft-f/netlink_gen_stmt_stateful_assert
new file mode 100644
index 00000000..547b937f
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/netlink_gen_stmt_stateful_assert
@@ -0,0 +1,6 @@
+table ip x {
+ map sctm_o1 {
+ type mark : counter
+ counter name meta mark
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/no_integer_basetype_crash b/tests/shell/testcases/bogons/nft-f/no_integer_basetype_crash
new file mode 100644
index 00000000..16d3e41f
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/no_integer_basetype_crash
@@ -0,0 +1 @@
+cPoR et ip dscp << 2>0 ,xl rt ipsec c0tt in tabl rt ipsec cl
diff --git a/tests/shell/testcases/bogons/nft-f/objmap_to_prefix_assert b/tests/shell/testcases/bogons/nft-f/objmap_to_prefix_assert
new file mode 100644
index 00000000..d880a377
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/objmap_to_prefix_assert
@@ -0,0 +1,6 @@
+table t {
+ chain y {
+ type filter hook input priority filter; policy accept;
+ synproxy name ip saddr map { 192.168.1.0/24 : "x*" }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/payload_expr_pctx_update_assert b/tests/shell/testcases/bogons/nft-f/payload_expr_pctx_update_assert
new file mode 100644
index 00000000..64bd596a
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/payload_expr_pctx_update_assert
@@ -0,0 +1 @@
+x x comp nexthdr comp
diff --git a/tests/shell/testcases/bogons/nft-f/payload_expr_unaligned_store b/tests/shell/testcases/bogons/nft-f/payload_expr_unaligned_store
new file mode 100644
index 00000000..c1358df4
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/payload_expr_unaligned_store
@@ -0,0 +1 @@
+add rule f i @th,1,128 set 1
diff --git a/tests/shell/testcases/bogons/nft-f/payload_expr_with_0_length_assert b/tests/shell/testcases/bogons/nft-f/payload_expr_with_0_length_assert
new file mode 100644
index 00000000..f85a04e7
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/payload_expr_with_0_length_assert
@@ -0,0 +1 @@
+add rule t c @th,0,0 0
diff --git a/tests/shell/testcases/bogons/nft-f/scope_underflow_assert b/tests/shell/testcases/bogons/nft-f/scope_underflow_assert
new file mode 100644
index 00000000..aee1dcbf
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/scope_underflow_assert
@@ -0,0 +1,6 @@
+table t {
+ chain c {
+ jump{
+ jump {
+ jump
+
diff --git a/tests/shell/testcases/bogons/nft-f/set_definition_with_no_key_assert b/tests/shell/testcases/bogons/nft-f/set_definition_with_no_key_assert
new file mode 100644
index 00000000..59ef1ab3
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/set_definition_with_no_key_assert
@@ -0,0 +1,12 @@
+table inet testifsets {
+ map map_wild { elements = { "abcdex*",
+ "othername",
+ "ppp0" }
+ }
+ map map_wild {
+ type ifname : verdict
+ flags interval
+ elements = { "abcdez*" : jump do_nothing,
+ "eth0" : jump do_nothing }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/set_without_key b/tests/shell/testcases/bogons/nft-f/set_without_key
new file mode 100644
index 00000000..f194afbf
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/set_without_key
@@ -0,0 +1,5 @@
+table ip t {
+ set s {
+ elements = { 0x00000023-0x00000142, 0x00001337 }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_concat_expr b/tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_concat_expr
new file mode 100644
index 00000000..8b0d2744
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_concat_expr
@@ -0,0 +1,5 @@
+table t {
+ chain c {
+ udp length . @th,0,512 . @th,512,512 { 47-63 . 0xe373135363130 . 0x33131303735353203 }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_raw_expr b/tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_raw_expr
new file mode 100644
index 00000000..66bd6bf8
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/stack_overflow_via_large_raw_expr
@@ -0,0 +1,5 @@
+table t {
+ chain c {
+ @th,160,1272 gt 0
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/tchandle_type_parse_heap_overflow b/tests/shell/testcases/bogons/nft-f/tchandle_type_parse_heap_overflow
new file mode 100644
index 00000000..ea7186bf
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/tchandle_type_parse_heap_overflow
@@ -0,0 +1,6 @@
+table t {
+map m {
+ type ipv4_addr : classid
+ elements = { 1.1.26.3 : ::a }
+}
+}
diff --git a/tests/shell/testcases/bogons/nft-f/tcp_option_without_template b/tests/shell/testcases/bogons/nft-f/tcp_option_without_template
new file mode 100644
index 00000000..fd732fd3
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/tcp_option_without_template
@@ -0,0 +1 @@
+add rule f i tcp option nop length . @ih,32,3 1
diff --git a/tests/shell/testcases/bogons/nft-f/tproxy_ranges b/tests/shell/testcases/bogons/nft-f/tproxy_ranges
new file mode 100644
index 00000000..1230860e
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/tproxy_ranges
@@ -0,0 +1,8 @@
+define range = 42-80
+
+table t {
+ chain c {
+ tcp dport 42 tproxy to 192.168.0.1:$range
+ tcp dport 42 tproxy to 192.168.0.0/16
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/unhandled_key_type_13_assert b/tests/shell/testcases/bogons/nft-f/unhandled_key_type_13_assert
new file mode 100644
index 00000000..35eecf60
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/unhandled_key_type_13_assert
@@ -0,0 +1,5 @@
+table ip x {
+ chain y {
+ ip protocol . th dport { tcp / 22, udp . 67 }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/unhandled_key_type_13_assert_map b/tests/shell/testcases/bogons/nft-f/unhandled_key_type_13_assert_map
new file mode 100644
index 00000000..3da16ce1
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/unhandled_key_type_13_assert_map
@@ -0,0 +1,5 @@
+table ip x {
+ chain y {
+ meta mark set ip protocol . th dport map { tcp / 22 : 1234, udp . 67 : 1234 }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/unhandled_key_type_13_assert_vmap b/tests/shell/testcases/bogons/nft-f/unhandled_key_type_13_assert_vmap
new file mode 100644
index 00000000..f4dc273f
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/unhandled_key_type_13_assert_vmap
@@ -0,0 +1,5 @@
+table ip x {
+ chain y {
+ ip protocol . th dport vmap { tcp / 22 : accept, udp . 67 : drop }
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/unknown_expr_type_range_assert b/tests/shell/testcases/bogons/nft-f/unknown_expr_type_range_assert
new file mode 100644
index 00000000..e6206736
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/unknown_expr_type_range_assert
@@ -0,0 +1,7 @@
+table ip x {
+ chain k {
+ meta mark set 0x001-3434
+ ct mark set 0x001-3434
+ tcp dport set 1-3
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/use_after_free_on_chain_removal b/tests/shell/testcases/bogons/nft-f/use_after_free_on_chain_removal
new file mode 100644
index 00000000..bb9632b0
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/use_after_free_on_chain_removal
@@ -0,0 +1,5 @@
+delete chain d iUi {
+}}
+delete chain d hUi {
+delete chain o
+c b icmpv6 id$i
diff --git a/tests/shell/testcases/bogons/nft-f/zero_length_devicename2_assert b/tests/shell/testcases/bogons/nft-f/zero_length_devicename2_assert
new file mode 100644
index 00000000..fe416f85
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/zero_length_devicename2_assert
@@ -0,0 +1,5 @@
+table netdev x {
+ chain Main_Ingress1 {
+ type filter hook ingress device "" priority -1
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/zero_length_devicename_assert b/tests/shell/testcases/bogons/nft-f/zero_length_devicename_assert
new file mode 100644
index 00000000..84f33073
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/zero_length_devicename_assert
@@ -0,0 +1,5 @@
+table ip x {
+ chain Main_Ingress1 {
+ type filter hook ingress device""lo" priority -1
+ }
+}
diff --git a/tests/shell/testcases/bogons/nft-f/zero_length_devicename_flowtable_assert b/tests/shell/testcases/bogons/nft-f/zero_length_devicename_flowtable_assert
new file mode 100644
index 00000000..2c3e6c3f
--- /dev/null
+++ b/tests/shell/testcases/bogons/nft-f/zero_length_devicename_flowtable_assert
@@ -0,0 +1,5 @@
+table t {
+ flowtable f {
+ devices = { """"lo }
+ }
+}
diff --git a/tests/shell/testcases/cache/0001_cache_handling_0 b/tests/shell/testcases/cache/0001_cache_handling_0
index 431aada5..0a684404 100755
--- a/tests/shell/testcases/cache/0001_cache_handling_0
+++ b/tests/shell/testcases/cache/0001_cache_handling_0
@@ -20,7 +20,7 @@ TMP=$(mktemp)
echo "$RULESET" >> "$TMP"
$NFT "flush ruleset;include \"$TMP\""
rm -f "$TMP"
-rule_handle=$($NFT list ruleset -a | awk '/saddr/{print $NF}')
+rule_handle=$($NFT -a list ruleset | awk '/saddr/{print $NF}')
$NFT delete rule inet test test handle $rule_handle
$NFT delete set inet test test
$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/cache/0008_delete_by_handle_0 b/tests/shell/testcases/cache/0008_delete_by_handle_0
new file mode 100755
index 00000000..0db4c693
--- /dev/null
+++ b/tests/shell/testcases/cache/0008_delete_by_handle_0
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -e
+
+$NFT add table t
+HANDLE=`$NFT -a list ruleset | grep "table.*handle" | cut -d' ' -f7`
+$NFT delete table handle $HANDLE
+
+$NFT add table t
+
+$NFT add chain t c
+HANDLE=`$NFT -a list ruleset | grep "chain.*handle" | cut -d' ' -f6`
+$NFT delete chain t handle $HANDLE
+
+$NFT add set t s { type ipv4_addr\; }
+HANDLE=`$NFT -a list ruleset | grep "set.*handle" | cut -d' ' -f6`
+$NFT delete set t handle $HANDLE
+
+$NFT add flowtable t f { hook ingress priority 0\; devices = { lo } \; }
+HANDLE=`$NFT -a list ruleset | grep "flowtable.*handle" | cut -d' ' -f6`
+$NFT delete flowtable t handle $HANDLE
+
+$NFT add counter t x
+HANDLE=`$NFT -a list ruleset | grep "counter.*handle" | cut -d' ' -f6`
+$NFT delete counter t handle $HANDLE
diff --git a/tests/shell/testcases/cache/0009_delete_by_handle_incorrect_0 b/tests/shell/testcases/cache/0009_delete_by_handle_incorrect_0
new file mode 100755
index 00000000..f0bb02a6
--- /dev/null
+++ b/tests/shell/testcases/cache/0009_delete_by_handle_incorrect_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+$NFT delete table handle 4000 && exit 1
+$NFT delete chain t handle 4000 && exit 1
+$NFT delete set t handle 4000 && exit 1
+$NFT delete flowtable t handle 4000 && exit 1
+$NFT delete counter t handle 4000 && exit 1
+exit 0
diff --git a/tests/shell/testcases/cache/0010_implicit_chain_0 b/tests/shell/testcases/cache/0010_implicit_chain_0
new file mode 100755
index 00000000..834dc6e4
--- /dev/null
+++ b/tests/shell/testcases/cache/0010_implicit_chain_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_chain_binding)
+
+set -e
+
+EXPECTED="table ip f {
+ chain c {
+ jump {
+ accept
+ }
+ }
+}"
+
+$NFT 'table ip f { chain c { jump { accept; }; }; }'
+GET="$($NFT list chain ip f c)"
+
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/cache/0011_index_0 b/tests/shell/testcases/cache/0011_index_0
new file mode 100755
index 00000000..c9eb8683
--- /dev/null
+++ b/tests/shell/testcases/cache/0011_index_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -e
+
+RULESET="flush ruleset
+add table inet t
+add chain inet t c { type filter hook input priority 0 ; }
+add rule inet t c tcp dport 1234 accept
+add rule inet t c accept
+insert rule inet t c index 1 udp dport 4321 accept"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/cache/dumps/0001_cache_handling_0.json-nft b/tests/shell/testcases/cache/dumps/0001_cache_handling_0.json-nft
new file mode 100644
index 00000000..7a2eacdd
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0001_cache_handling_0.json-nft
@@ -0,0 +1,142 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "test",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "test",
+ "table": "test",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "1.1.1.1",
+ "3.3.3.3"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "set": [
+ "2.2.2.2",
+ "4.4.4.4"
+ ]
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@test"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "set": [
+ "2.2.2.2",
+ "4.4.4.4"
+ ]
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/cache/dumps/0002_interval_0.json-nft b/tests/shell/testcases/cache/dumps/0002_interval_0.json-nft
new file mode 100644
index 00000000..fa15d658
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0002_interval_0.json-nft
@@ -0,0 +1,38 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "192.168.0.0",
+ "len": 24
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/cache/dumps/0003_cache_update_0.json-nft b/tests/shell/testcases/cache/dumps/0003_cache_update_0.json-nft
new file mode 100644
index 00000000..e09a694c
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0003_cache_update_0.json-nft
@@ -0,0 +1,137 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t2",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t2",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t3",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t4",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t4",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t4",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": "icmp"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t4",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t4",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": "igmp"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t4",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/cache/dumps/0003_cache_update_0.nft b/tests/shell/testcases/cache/dumps/0003_cache_update_0.nft
new file mode 100644
index 00000000..43898d33
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0003_cache_update_0.nft
@@ -0,0 +1,18 @@
+table ip t {
+ chain c {
+ }
+}
+table ip t2 {
+ chain c {
+ }
+}
+table ip t3 {
+}
+table ip t4 {
+ chain c {
+ meta l4proto icmp accept
+ drop
+ meta l4proto igmp accept
+ drop
+ }
+}
diff --git a/tests/shell/testcases/cache/dumps/0004_cache_update_0.json-nft b/tests/shell/testcases/cache/dumps/0004_cache_update_0.json-nft
new file mode 100644
index 00000000..d1864f00
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0004_cache_update_0.json-nft
@@ -0,0 +1,42 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "testfilter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "testfilter",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "testfilter",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/cache/dumps/0004_cache_update_0.nft b/tests/shell/testcases/cache/dumps/0004_cache_update_0.nft
new file mode 100644
index 00000000..4f5761bc
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0004_cache_update_0.nft
@@ -0,0 +1,5 @@
+table inet testfilter {
+ chain test {
+ counter packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/cache/dumps/0005_cache_chain_flush.json-nft b/tests/shell/testcases/cache/dumps/0005_cache_chain_flush.json-nft
new file mode 100644
index 00000000..1c47d3ef
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0005_cache_chain_flush.json-nft
@@ -0,0 +1,77 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "z",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "mapping",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "inet_service",
+ "size": 65535,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "map": {
+ "op": "update",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "sport"
+ }
+ },
+ "map": "@mapping"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/cache/dumps/0005_cache_chain_flush.nft b/tests/shell/testcases/cache/dumps/0005_cache_chain_flush.nft
new file mode 100644
index 00000000..8ab55a2c
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0005_cache_chain_flush.nft
@@ -0,0 +1,14 @@
+table ip x {
+ map mapping {
+ type ipv4_addr : inet_service
+ size 65535
+ flags dynamic,timeout
+ }
+
+ chain y {
+ update @mapping { ip saddr : tcp sport }
+ }
+
+ chain z {
+ }
+}
diff --git a/tests/shell/testcases/cache/dumps/0006_cache_table_flush.json-nft b/tests/shell/testcases/cache/dumps/0006_cache_table_flush.json-nft
new file mode 100644
index 00000000..1c47d3ef
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0006_cache_table_flush.json-nft
@@ -0,0 +1,77 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "z",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "mapping",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "inet_service",
+ "size": 65535,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "map": {
+ "op": "update",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "sport"
+ }
+ },
+ "map": "@mapping"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/cache/dumps/0006_cache_table_flush.nft b/tests/shell/testcases/cache/dumps/0006_cache_table_flush.nft
new file mode 100644
index 00000000..8ab55a2c
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0006_cache_table_flush.nft
@@ -0,0 +1,14 @@
+table ip x {
+ map mapping {
+ type ipv4_addr : inet_service
+ size 65535
+ flags dynamic,timeout
+ }
+
+ chain y {
+ update @mapping { ip saddr : tcp sport }
+ }
+
+ chain z {
+ }
+}
diff --git a/tests/shell/testcases/cache/dumps/0007_echo_cache_init_0.json-nft b/tests/shell/testcases/cache/dumps/0007_echo_cache_init_0.json-nft
new file mode 100644
index 00000000..0968d8a4
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0007_echo_cache_init_0.json-nft
@@ -0,0 +1,68 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "comment": "first",
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "comment": "second",
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "comment": "third",
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/cache/dumps/0008_delete_by_handle_0.json-nft b/tests/shell/testcases/cache/dumps/0008_delete_by_handle_0.json-nft
new file mode 100644
index 00000000..e0e56fec
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0008_delete_by_handle_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/cache/dumps/0008_delete_by_handle_0.nft b/tests/shell/testcases/cache/dumps/0008_delete_by_handle_0.nft
new file mode 100644
index 00000000..985768ba
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0008_delete_by_handle_0.nft
@@ -0,0 +1,2 @@
+table ip t {
+}
diff --git a/tests/shell/testcases/cache/dumps/0009_delete_by_handle_incorrect_0.json-nft b/tests/shell/testcases/cache/dumps/0009_delete_by_handle_incorrect_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0009_delete_by_handle_incorrect_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/cache/dumps/0009_delete_by_handle_incorrect_0.nft b/tests/shell/testcases/cache/dumps/0009_delete_by_handle_incorrect_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0009_delete_by_handle_incorrect_0.nft
diff --git a/tests/shell/testcases/cache/dumps/0010_implicit_chain_0.nft b/tests/shell/testcases/cache/dumps/0010_implicit_chain_0.nft
new file mode 100644
index 00000000..aba92c0e
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0010_implicit_chain_0.nft
@@ -0,0 +1,7 @@
+table ip f {
+ chain c {
+ jump {
+ accept
+ }
+ }
+}
diff --git a/tests/shell/testcases/cache/dumps/0011_index_0.json-nft b/tests/shell/testcases/cache/dumps/0011_index_0.json-nft
new file mode 100644
index 00000000..46b2909f
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0011_index_0.json-nft
@@ -0,0 +1,93 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 1234
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 4321
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/cache/dumps/0011_index_0.nft b/tests/shell/testcases/cache/dumps/0011_index_0.nft
new file mode 100644
index 00000000..7e855eb1
--- /dev/null
+++ b/tests/shell/testcases/cache/dumps/0011_index_0.nft
@@ -0,0 +1,8 @@
+table inet t {
+ chain c {
+ type filter hook input priority filter; policy accept;
+ tcp dport 1234 accept
+ udp dport 4321 accept
+ accept
+ }
+}
diff --git a/tests/shell/testcases/chains/0012reject_in_prerouting_1 b/tests/shell/testcases/chains/0012reject_in_prerouting_1
deleted file mode 100755
index 0ee86c11..00000000
--- a/tests/shell/testcases/chains/0012reject_in_prerouting_1
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/bash
-
-set -e
-
-$NFT add table t
-$NFT add chain t prerouting {type filter hook prerouting priority 0 \; }
-
-# wrong hook prerouting, only input/forward/output is valid
-$NFT add rule t prerouting reject 2>/dev/null || exit 0
-echo "E: accepted reject in prerouting hook" >&2
-exit 1
diff --git a/tests/shell/testcases/chains/0014rename_0 b/tests/shell/testcases/chains/0014rename_0
index bebe48d6..bd84e957 100755
--- a/tests/shell/testcases/chains/0014rename_0
+++ b/tests/shell/testcases/chains/0014rename_0
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
$NFT add table t || exit 1
$NFT add chain t c1 || exit 1
diff --git a/tests/shell/testcases/chains/0016delete_handle_0 b/tests/shell/testcases/chains/0016delete_handle_0
index 4633d771..8fd1ad86 100755
--- a/tests/shell/testcases/chains/0016delete_handle_0
+++ b/tests/shell/testcases/chains/0016delete_handle_0
@@ -10,8 +10,8 @@ $NFT add chain ip6 test-ip6 x
$NFT add chain ip6 test-ip6 y
$NFT add chain ip6 test-ip6 z
-chain_y_handle=$($NFT list ruleset -a | awk -v n=1 '/chain y/ && !--n {print $NF; exit}');
-chain_z_handle=$($NFT list ruleset -a | awk -v n=2 '/chain z/ && !--n {print $NF; exit}');
+chain_y_handle=$($NFT -a list ruleset | awk -v n=1 '/chain y/ && !--n {print $NF; exit}');
+chain_z_handle=$($NFT -a list ruleset | awk -v n=2 '/chain z/ && !--n {print $NF; exit}');
$NFT delete chain test-ip handle $chain_y_handle
$NFT delete chain ip6 test-ip6 handle $chain_z_handle
diff --git a/tests/shell/testcases/chains/0021prio_0 b/tests/shell/testcases/chains/0021prio_0
index e7612974..ceda1558 100755
--- a/tests/shell/testcases/chains/0021prio_0
+++ b/tests/shell/testcases/chains/0021prio_0
@@ -69,6 +69,7 @@ done
family=netdev
echo "add table $family x"
gen_chains $family ingress filter lo
+[ "$NFT_TEST_HAVE_netdev_egress" != n ] && gen_chains $family egress filter lo
family=bridge
echo "add table $family x"
@@ -82,3 +83,8 @@ gen_chains $family postrouting srcnat
) >$tmpfile
$NFT -f $tmpfile
+
+if [ "$NFT_TEST_HAVE_netdev_egress" = n ]; then
+ echo "Ran a modified version of the test due to NFT_TEST_HAVE_netdev_egress=n"
+ exit 77
+fi
diff --git a/tests/shell/testcases/chains/0023prio_inet_srcnat_1 b/tests/shell/testcases/chains/0023prio_inet_srcnat_1
index d2b1fa43..e4a668e1 100755
--- a/tests/shell/testcases/chains/0023prio_inet_srcnat_1
+++ b/tests/shell/testcases/chains/0023prio_inet_srcnat_1
@@ -2,7 +2,7 @@
for family in ip ip6 inet
do
- for hook in prerouting input forward output
+ for hook in prerouting forward output
do
$NFT add table $family x
$NFT add chain $family x y "{ type filter hook $hook priority srcnat; }" &> /dev/null
diff --git a/tests/shell/testcases/chains/0024prio_inet_dstnat_1 b/tests/shell/testcases/chains/0024prio_inet_dstnat_1
index d112f2c9..f1b802a0 100755
--- a/tests/shell/testcases/chains/0024prio_inet_dstnat_1
+++ b/tests/shell/testcases/chains/0024prio_inet_dstnat_1
@@ -2,7 +2,7 @@
for family in ip ip6 inet
do
- for hook in input forward output postrouting
+ for hook in input forward postrouting
do
$NFT add table $family x
$NFT add chain $family x y "{ type filter hook $hook priority dstnat; }" &> /dev/null
diff --git a/tests/shell/testcases/chains/0026prio_netdev_1 b/tests/shell/testcases/chains/0026prio_netdev_1
index aa902e9b..b6fa3db5 100755
--- a/tests/shell/testcases/chains/0026prio_netdev_1
+++ b/tests/shell/testcases/chains/0026prio_netdev_1
@@ -1,7 +1,8 @@
#!/bin/bash
family=netdev
- hook=ingress
+ for hook in ingress egress
+ do
for prioname in raw mangle dstnat security srcnat
do
$NFT add table $family x || exit 1
@@ -12,4 +13,5 @@ family=netdev
exit 1
fi
done
+ done
exit 0
diff --git a/tests/shell/testcases/chains/0030create_0 b/tests/shell/testcases/chains/0030create_0
index 0b457f91..0b457f91 100644..100755
--- a/tests/shell/testcases/chains/0030create_0
+++ b/tests/shell/testcases/chains/0030create_0
diff --git a/tests/shell/testcases/chains/0032priority_variable_0 b/tests/shell/testcases/chains/0032priority_variable_0
index 51bc5eb1..8f2e57b9 100755
--- a/tests/shell/testcases/chains/0032priority_variable_0
+++ b/tests/shell/testcases/chains/0032priority_variable_0
@@ -6,12 +6,22 @@ set -e
RULESET="
define pri = 10
+define post = -10
+define for = \"filter - 100\"
table inet global {
chain prerouting {
type filter hook prerouting priority \$pri
policy accept
}
+ chain forward {
+ type filter hook prerouting priority \$for
+ policy accept
+ }
+ chain postrouting {
+ type filter hook postrouting priority \$post
+ policy accept
+ }
}"
$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/chains/0039negative_priority_0 b/tests/shell/testcases/chains/0039negative_priority_0
new file mode 100755
index 00000000..ba17b8cc
--- /dev/null
+++ b/tests/shell/testcases/chains/0039negative_priority_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# Test parsing of negative priority values
+
+set -e
+
+$NFT add table t
+$NFT add chain t c { type filter hook input priority -30\; }
diff --git a/tests/shell/testcases/chains/0041chain_binding_0 b/tests/shell/testcases/chains/0041chain_binding_0
new file mode 100755
index 00000000..141a4b6d
--- /dev/null
+++ b/tests/shell/testcases/chains/0041chain_binding_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# no table x, caused segfault in earlier nft releases
+$NFT insert rule inet x y handle 107 'goto { log prefix "MOO! "; }'
+if [ $? -ne 1 ]; then
+ exit 1
+fi
+
+if [ $NFT_TEST_HAVE_chain_binding = "n" ] ; then
+ echo "Test partially skipped due to NFT_TEST_HAVE_chain_binding=n"
+ exit 77
+fi
+
+set -e
+
+EXPECTED="table inet x {
+ chain y {
+ type filter hook input priority 0;
+ meta l4proto { tcp, udp } th dport 53 jump {
+ ip saddr { 127.0.0.0/8, 172.23.0.0/16, 192.168.13.0/24 } counter accept
+ ip6 saddr ::1/128 counter accept
+ }
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+$NFT add rule inet x y meta l4proto icmpv6 jump { counter accept\; }
+$NFT add rule inet x y meta l4proto sctp jump { drop\; }
+$NFT delete rule inet x y handle 13
diff --git a/tests/shell/testcases/chains/0042chain_variable_0 b/tests/shell/testcases/chains/0042chain_variable_0
new file mode 100755
index 00000000..c5de495e
--- /dev/null
+++ b/tests/shell/testcases/chains/0042chain_variable_0
@@ -0,0 +1,71 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_netdev_chain_multidevice)
+
+set -e
+
+ip link add name d23456789012345 type dummy
+
+
+EXPECTED="define if_main = \"lo\"
+
+table netdev filter1 {
+ chain Main_Ingress1 {
+ type filter hook ingress device \$if_main priority -500; policy accept;
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
+
+EXPECTED="define if_main = \"lo\"
+
+table netdev filter2 {
+ chain Main_Ingress2 {
+ type filter hook ingress devices = { \$if_main, d23456789012345x } priority -500; policy accept;
+ }
+}"
+
+rc=0
+$NFT -f - <<< $EXPECTED || rc=$?
+test "$rc" = 1
+cat <<EOF | $DIFF -u <($NFT list ruleset) -
+table netdev filter1 {
+ chain Main_Ingress1 {
+ type filter hook ingress device "lo" priority -500; policy accept;
+ }
+}
+EOF
+
+
+EXPECTED="define if_main = \"lo\"
+
+table netdev filter2 {
+ chain Main_Ingress2 {
+ type filter hook ingress devices = { \$if_main, d23456789012345 } priority -500; policy accept;
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
+
+if [ "$NFT_TEST_HAVE_netdev_egress" = n ] ; then
+ echo "Skip parts of the test due to NFT_TEST_HAVE_netdev_egress=n"
+ exit 77
+fi
+
+
+EXPECTED="define if_main = { lo, d23456789012345 }
+define lan_interfaces = { lo }
+
+table netdev filter3 {
+ chain Main_Ingress3 {
+ type filter hook ingress devices = \$if_main priority -500; policy accept;
+ }
+ chain Main_Egress3 {
+ type filter hook egress devices = \$lan_interfaces priority -500; policy accept;
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
diff --git a/tests/shell/testcases/chains/0043chain_ingress_0 b/tests/shell/testcases/chains/0043chain_ingress_0
new file mode 100755
index 00000000..a6973b99
--- /dev/null
+++ b/tests/shell/testcases/chains/0043chain_ingress_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_inet_ingress)
+
+set -e
+RULESET="table inet filter {
+ chain ingress {
+ type filter hook ingress device \"lo\" priority filter; policy accept;
+ }
+ chain input {
+ type filter hook input priority filter; policy accept;
+ }
+ chain forward {
+ type filter hook forward priority filter; policy accept;
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 0
+exit 1
diff --git a/tests/shell/testcases/chains/0044chain_destroy_0 b/tests/shell/testcases/chains/0044chain_destroy_0
new file mode 100755
index 00000000..5c5a10a7
--- /dev/null
+++ b/tests/shell/testcases/chains/0044chain_destroy_0
@@ -0,0 +1,12 @@
+#!/bin/bash -e
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_destroy)
+
+$NFT add table t
+
+# pass for non-existent chain
+$NFT destroy chain t c
+
+# successfully delete existing chain
+$NFT add chain t c
+$NFT destroy chain t c
diff --git a/tests/shell/testcases/chains/dumps/0001jumps_0.json-nft b/tests/shell/testcases/chains/dumps/0001jumps_0.json-nft
new file mode 100644
index 00000000..ceef3224
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0001jumps_0.json-nft
@@ -0,0 +1,371 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c2",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c3",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c4",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c5",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c6",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c7",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c8",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c9",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c10",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c11",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c12",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c13",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c14",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c15",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c16",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c1",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c2"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c2",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c3"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c3",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c4"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c4",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c5"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c5",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c6"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c6",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c7"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c7",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c8"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c8",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c9"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c9",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c10"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c10",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c11"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c11",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c12"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c12",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c13"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c13",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c14"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c14",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c15"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c15",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c16"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0002jumps_1.json-nft b/tests/shell/testcases/chains/dumps/0002jumps_1.json-nft
new file mode 100644
index 00000000..66f921a0
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0002jumps_1.json-nft
@@ -0,0 +1,383 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c2",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c3",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c4",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c5",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c6",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c7",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c8",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c9",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c10",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c11",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c12",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c13",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c14",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c15",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c16",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c17",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c1",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c2"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c2",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c3"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c3",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c4"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c4",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c5"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c5",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c6"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c6",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c7"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c7",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c8"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c8",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c9"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c9",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c10"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c10",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c11"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c11",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c12"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c12",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c13"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c13",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c14"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c14",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c15"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c15",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c16"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0002jumps_1.nft b/tests/shell/testcases/chains/dumps/0002jumps_1.nft
new file mode 100644
index 00000000..ed37ad0e
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0002jumps_1.nft
@@ -0,0 +1,68 @@
+table ip t {
+ chain c1 {
+ type filter hook input priority filter; policy accept;
+ jump c2
+ }
+
+ chain c2 {
+ jump c3
+ }
+
+ chain c3 {
+ jump c4
+ }
+
+ chain c4 {
+ jump c5
+ }
+
+ chain c5 {
+ jump c6
+ }
+
+ chain c6 {
+ jump c7
+ }
+
+ chain c7 {
+ jump c8
+ }
+
+ chain c8 {
+ jump c9
+ }
+
+ chain c9 {
+ jump c10
+ }
+
+ chain c10 {
+ jump c11
+ }
+
+ chain c11 {
+ jump c12
+ }
+
+ chain c12 {
+ jump c13
+ }
+
+ chain c13 {
+ jump c14
+ }
+
+ chain c14 {
+ jump c15
+ }
+
+ chain c15 {
+ jump c16
+ }
+
+ chain c16 {
+ }
+
+ chain c17 {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0003jump_loop_1.json-nft b/tests/shell/testcases/chains/dumps/0003jump_loop_1.json-nft
new file mode 100644
index 00000000..ceef3224
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0003jump_loop_1.json-nft
@@ -0,0 +1,371 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c2",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c3",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c4",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c5",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c6",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c7",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c8",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c9",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c10",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c11",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c12",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c13",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c14",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c15",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c16",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c1",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c2"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c2",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c3"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c3",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c4"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c4",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c5"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c5",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c6"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c6",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c7"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c7",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c8"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c8",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c9"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c9",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c10"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c10",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c11"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c11",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c12"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c12",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c13"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c13",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c14"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c14",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c15"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c15",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c16"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0003jump_loop_1.nft b/tests/shell/testcases/chains/dumps/0003jump_loop_1.nft
new file mode 100644
index 00000000..7054cde4
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0003jump_loop_1.nft
@@ -0,0 +1,64 @@
+table ip t {
+ chain c1 {
+ jump c2
+ }
+
+ chain c2 {
+ jump c3
+ }
+
+ chain c3 {
+ jump c4
+ }
+
+ chain c4 {
+ jump c5
+ }
+
+ chain c5 {
+ jump c6
+ }
+
+ chain c6 {
+ jump c7
+ }
+
+ chain c7 {
+ jump c8
+ }
+
+ chain c8 {
+ jump c9
+ }
+
+ chain c9 {
+ jump c10
+ }
+
+ chain c10 {
+ jump c11
+ }
+
+ chain c11 {
+ jump c12
+ }
+
+ chain c12 {
+ jump c13
+ }
+
+ chain c13 {
+ jump c14
+ }
+
+ chain c14 {
+ jump c15
+ }
+
+ chain c15 {
+ jump c16
+ }
+
+ chain c16 {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0004busy_1.json-nft b/tests/shell/testcases/chains/dumps/0004busy_1.json-nft
new file mode 100644
index 00000000..314245ff
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0004busy_1.json-nft
@@ -0,0 +1,49 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c2",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c1",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c2"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0004busy_1.nft b/tests/shell/testcases/chains/dumps/0004busy_1.nft
new file mode 100644
index 00000000..429dd494
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0004busy_1.nft
@@ -0,0 +1,8 @@
+table ip t {
+ chain c1 {
+ jump c2
+ }
+
+ chain c2 {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0005busy_map_1.json-nft b/tests/shell/testcases/chains/dumps/0005busy_map_1.json-nft
new file mode 100644
index 00000000..ce776822
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0005busy_map_1.json-nft
@@ -0,0 +1,66 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c2",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c1",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 1,
+ {
+ "jump": {
+ "target": "c2"
+ }
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0005busy_map_1.nft b/tests/shell/testcases/chains/dumps/0005busy_map_1.nft
new file mode 100644
index 00000000..acf23183
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0005busy_map_1.nft
@@ -0,0 +1,8 @@
+table ip t {
+ chain c1 {
+ tcp dport vmap { 1 : jump c2 }
+ }
+
+ chain c2 {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0006masquerade_0.json-nft b/tests/shell/testcases/chains/dumps/0006masquerade_0.json-nft
new file mode 100644
index 00000000..b6fc221f
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0006masquerade_0.json-nft
@@ -0,0 +1,43 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0,
+ "type": "nat",
+ "hook": "postrouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c1",
+ "handle": 0,
+ "expr": [
+ {
+ "masquerade": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0007masquerade_1.json-nft b/tests/shell/testcases/chains/dumps/0007masquerade_1.json-nft
new file mode 100644
index 00000000..98b51044
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0007masquerade_1.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0007masquerade_1.nft b/tests/shell/testcases/chains/dumps/0007masquerade_1.nft
new file mode 100644
index 00000000..b25355f7
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0007masquerade_1.nft
@@ -0,0 +1,5 @@
+table ip t {
+ chain c1 {
+ type filter hook output priority filter; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0008masquerade_jump_1.json-nft b/tests/shell/testcases/chains/dumps/0008masquerade_jump_1.json-nft
new file mode 100644
index 00000000..3215496f
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0008masquerade_jump_1.json-nft
@@ -0,0 +1,51 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "output",
+ "handle": 0,
+ "type": "nat",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c1",
+ "handle": 0,
+ "expr": [
+ {
+ "masquerade": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0008masquerade_jump_1.nft b/tests/shell/testcases/chains/dumps/0008masquerade_jump_1.nft
new file mode 100644
index 00000000..49910711
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0008masquerade_jump_1.nft
@@ -0,0 +1,9 @@
+table ip t {
+ chain output {
+ type nat hook output priority filter; policy accept;
+ }
+
+ chain c1 {
+ masquerade
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0009masquerade_jump_1.json-nft b/tests/shell/testcases/chains/dumps/0009masquerade_jump_1.json-nft
new file mode 100644
index 00000000..3215496f
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0009masquerade_jump_1.json-nft
@@ -0,0 +1,51 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "output",
+ "handle": 0,
+ "type": "nat",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c1",
+ "handle": 0,
+ "expr": [
+ {
+ "masquerade": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0009masquerade_jump_1.nft b/tests/shell/testcases/chains/dumps/0009masquerade_jump_1.nft
new file mode 100644
index 00000000..49910711
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0009masquerade_jump_1.nft
@@ -0,0 +1,9 @@
+table ip t {
+ chain output {
+ type nat hook output priority filter; policy accept;
+ }
+
+ chain c1 {
+ masquerade
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0010endless_jump_loop_1.json-nft b/tests/shell/testcases/chains/dumps/0010endless_jump_loop_1.json-nft
new file mode 100644
index 00000000..db64cdbc
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0010endless_jump_loop_1.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0010endless_jump_loop_1.nft b/tests/shell/testcases/chains/dumps/0010endless_jump_loop_1.nft
new file mode 100644
index 00000000..1e0d1d60
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0010endless_jump_loop_1.nft
@@ -0,0 +1,4 @@
+table ip t {
+ chain c {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0011endless_jump_loop_1.json-nft b/tests/shell/testcases/chains/dumps/0011endless_jump_loop_1.json-nft
new file mode 100644
index 00000000..e1a2262f
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0011endless_jump_loop_1.json-nft
@@ -0,0 +1,75 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c2",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "m",
+ "table": "t",
+ "type": "inet_service",
+ "handle": 0,
+ "map": "verdict",
+ "elem": [
+ [
+ 2,
+ {
+ "jump": {
+ "target": "c2"
+ }
+ }
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c1",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "data": "@m"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0011endless_jump_loop_1.nft b/tests/shell/testcases/chains/dumps/0011endless_jump_loop_1.nft
new file mode 100644
index 00000000..ca0a7378
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0011endless_jump_loop_1.nft
@@ -0,0 +1,13 @@
+table ip t {
+ map m {
+ type inet_service : verdict
+ elements = { 2 : jump c2 }
+ }
+
+ chain c1 {
+ tcp dport vmap @m
+ }
+
+ chain c2 {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0013rename_0.json-nft b/tests/shell/testcases/chains/dumps/0013rename_0.json-nft
new file mode 100644
index 00000000..f89c455a
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0013rename_0.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c2",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0014rename_0.json-nft b/tests/shell/testcases/chains/dumps/0014rename_0.json-nft
new file mode 100644
index 00000000..f4c6855e
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0014rename_0.json-nft
@@ -0,0 +1,34 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c2",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0014rename_0.nft b/tests/shell/testcases/chains/dumps/0014rename_0.nft
new file mode 100644
index 00000000..574c4863
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0014rename_0.nft
@@ -0,0 +1,7 @@
+table ip t {
+ chain c1 {
+ }
+
+ chain c2 {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0015check_jump_loop_1.json-nft b/tests/shell/testcases/chains/dumps/0015check_jump_loop_1.json-nft
new file mode 100644
index 00000000..314245ff
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0015check_jump_loop_1.json-nft
@@ -0,0 +1,49 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c2",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c1",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c2"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0015check_jump_loop_1.nft b/tests/shell/testcases/chains/dumps/0015check_jump_loop_1.nft
new file mode 100644
index 00000000..429dd494
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0015check_jump_loop_1.nft
@@ -0,0 +1,8 @@
+table ip t {
+ chain c1 {
+ jump c2
+ }
+
+ chain c2 {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0016delete_handle_0.json-nft b/tests/shell/testcases/chains/dumps/0016delete_handle_0.json-nft
new file mode 100644
index 00000000..ca1311db
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0016delete_handle_0.json-nft
@@ -0,0 +1,57 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test-ip",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test-ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test-ip",
+ "name": "z",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "test-ip6",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "test-ip6",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "test-ip6",
+ "name": "y",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0017masquerade_jump_1.json-nft b/tests/shell/testcases/chains/dumps/0017masquerade_jump_1.json-nft
new file mode 100644
index 00000000..b368c23a
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0017masquerade_jump_1.json-nft
@@ -0,0 +1,53 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 4,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "c1"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0017masquerade_jump_1.nft b/tests/shell/testcases/chains/dumps/0017masquerade_jump_1.nft
new file mode 100644
index 00000000..636e8440
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0017masquerade_jump_1.nft
@@ -0,0 +1,9 @@
+table ip t {
+ chain input {
+ type filter hook input priority filter + 4; policy accept;
+ jump c1
+ }
+
+ chain c1 {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0018check_jump_loop_1.json-nft b/tests/shell/testcases/chains/dumps/0018check_jump_loop_1.json-nft
new file mode 100644
index 00000000..7294c841
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0018check_jump_loop_1.json-nft
@@ -0,0 +1,49 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "ap1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "ap2",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "ap1",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "ap2"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0018check_jump_loop_1.nft b/tests/shell/testcases/chains/dumps/0018check_jump_loop_1.nft
new file mode 100644
index 00000000..437900bc
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0018check_jump_loop_1.nft
@@ -0,0 +1,8 @@
+table ip filter {
+ chain ap1 {
+ jump ap2
+ }
+
+ chain ap2 {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0019masquerade_jump_1.json-nft b/tests/shell/testcases/chains/dumps/0019masquerade_jump_1.json-nft
new file mode 100644
index 00000000..c164ffb8
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0019masquerade_jump_1.json-nft
@@ -0,0 +1,70 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 4,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ {
+ "jump": {
+ "target": "c1"
+ }
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0019masquerade_jump_1.nft b/tests/shell/testcases/chains/dumps/0019masquerade_jump_1.nft
new file mode 100644
index 00000000..81cf9cc7
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0019masquerade_jump_1.nft
@@ -0,0 +1,9 @@
+table ip t {
+ chain input {
+ type filter hook input priority filter + 4; policy accept;
+ ip saddr vmap { 1.1.1.1 : jump c1 }
+ }
+
+ chain c1 {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0020depth_1.json-nft b/tests/shell/testcases/chains/dumps/0020depth_1.json-nft
new file mode 100644
index 00000000..31bc2b13
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0020depth_1.json-nft
@@ -0,0 +1,475 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a0",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a2",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a3",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a4",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a5",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a6",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a7",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a8",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a9",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a10",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a11",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a12",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a13",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a14",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a15",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a16",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a17",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a18",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "a19",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a1"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a0",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a1"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a1",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a2"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a2",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a3"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a3",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a4"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a4",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a5"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a5",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a6"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a6",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a7"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a7",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a8"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a8",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a9"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a9",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a10"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a11",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a12"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a12",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a13"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a13",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a14"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a14",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a15"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a15",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a16"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a16",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a17"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a17",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a18"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "a18",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "a19"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0020depth_1.nft b/tests/shell/testcases/chains/dumps/0020depth_1.nft
new file mode 100644
index 00000000..422c3952
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0020depth_1.nft
@@ -0,0 +1,84 @@
+table ip filter {
+ chain input {
+ type filter hook input priority filter; policy accept;
+ jump a1
+ }
+
+ chain a0 {
+ jump a1
+ }
+
+ chain a1 {
+ jump a2
+ }
+
+ chain a2 {
+ jump a3
+ }
+
+ chain a3 {
+ jump a4
+ }
+
+ chain a4 {
+ jump a5
+ }
+
+ chain a5 {
+ jump a6
+ }
+
+ chain a6 {
+ jump a7
+ }
+
+ chain a7 {
+ jump a8
+ }
+
+ chain a8 {
+ jump a9
+ }
+
+ chain a9 {
+ jump a10
+ }
+
+ chain a10 {
+ }
+
+ chain a11 {
+ jump a12
+ }
+
+ chain a12 {
+ jump a13
+ }
+
+ chain a13 {
+ jump a14
+ }
+
+ chain a14 {
+ jump a15
+ }
+
+ chain a15 {
+ jump a16
+ }
+
+ chain a16 {
+ jump a17
+ }
+
+ chain a17 {
+ jump a18
+ }
+
+ chain a18 {
+ jump a19
+ }
+
+ chain a19 {
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0021prio_0.json-nft b/tests/shell/testcases/chains/dumps/0021prio_0.json-nft
new file mode 100644
index 00000000..1a3e1161
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0021prio_0.json-nft
@@ -0,0 +1,4743 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "inputsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "forwardsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "outputsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingdstnatm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -111,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingdstnatm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -110,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingdstnat",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -100,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingdstnatp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -90,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "preroutingdstnatp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -89,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingsrcnatm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 89,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingsrcnatm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 90,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingsrcnat",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 100,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingsrcnatp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 110,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "postroutingsrcnatp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 111,
+ "policy": "accept"
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "inputsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "forwardsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "outputsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingdstnatm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -111,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingdstnatm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -110,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingdstnat",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -100,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingdstnatp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -90,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "preroutingdstnatp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -89,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingsrcnatm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 89,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingsrcnatm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 90,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingsrcnat",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 100,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingsrcnatp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 110,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "postroutingsrcnatp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 111,
+ "policy": "accept"
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "inputsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "forwardsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "outputsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingrawm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingrawm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingraw",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingrawp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingrawp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingmanglem11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -161,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingmanglem10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -160,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingmangle",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -150,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingmanglep10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingmanglep11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -139,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingsecuritym11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 39,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingsecuritym10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 40,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingsecurity",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 50,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingsecurityp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 60,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingsecurityp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 61,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingdstnatm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -111,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingdstnatm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -110,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingdstnat",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -100,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingdstnatp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -90,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "preroutingdstnatp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -89,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingsrcnatm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 89,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingsrcnatm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 90,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingsrcnat",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 100,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingsrcnatp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 110,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "postroutingsrcnatp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 111,
+ "policy": "accept"
+ }
+ },
+ {
+ "table": {
+ "family": "arp",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "arp",
+ "table": "x",
+ "name": "inputfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "arp",
+ "table": "x",
+ "name": "inputfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "arp",
+ "table": "x",
+ "name": "inputfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "arp",
+ "table": "x",
+ "name": "inputfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "arp",
+ "table": "x",
+ "name": "inputfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "arp",
+ "table": "x",
+ "name": "outputfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "arp",
+ "table": "x",
+ "name": "outputfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "arp",
+ "table": "x",
+ "name": "outputfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "arp",
+ "table": "x",
+ "name": "outputfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "arp",
+ "table": "x",
+ "name": "outputfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "table": {
+ "family": "netdev",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "x",
+ "name": "ingressfilterm11",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "ingress",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "x",
+ "name": "ingressfilterm10",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "ingress",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "x",
+ "name": "ingressfilter",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "ingress",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "x",
+ "name": "ingressfilterp10",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "ingress",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "x",
+ "name": "ingressfilterp11",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "ingress",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "x",
+ "name": "egressfilterm11",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "egress",
+ "prio": -11,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "x",
+ "name": "egressfilterm10",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "egress",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "x",
+ "name": "egressfilter",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "egress",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "x",
+ "name": "egressfilterp10",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "egress",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "x",
+ "name": "egressfilterp11",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "egress",
+ "prio": 11,
+ "policy": "accept"
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "preroutingfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -211,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "preroutingfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -210,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "preroutingfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -200,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "preroutingfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -190,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "preroutingfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -189,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "inputfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -211,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "inputfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -210,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "inputfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -200,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "inputfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -190,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "inputfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -189,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "forwardfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -211,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "forwardfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -210,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "forwardfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -200,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "forwardfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -190,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "forwardfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": -189,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "outputfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -211,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "outputfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -210,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "outputfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -200,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "outputfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -190,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "outputfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": -189,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "postroutingfilterm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -211,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "postroutingfilterm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -210,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "postroutingfilter",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -200,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "postroutingfilterp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -190,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "postroutingfilterp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -189,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "preroutingdstnatm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -311,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "preroutingdstnatm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "preroutingdstnat",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "preroutingdstnatp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "preroutingdstnatp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "outputoutm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 89,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "outputoutm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 90,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "outputout",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 100,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "outputoutp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 110,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "outputoutp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 111,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "postroutingsrcnatm11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 289,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "postroutingsrcnatm10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "postroutingsrcnat",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 300,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "postroutingsrcnatp10",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 310,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "x",
+ "name": "postroutingsrcnatp11",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 311,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0021prio_0.nft b/tests/shell/testcases/chains/dumps/0021prio_0.nft
index ca94d441..4297d246 100644
--- a/tests/shell/testcases/chains/dumps/0021prio_0.nft
+++ b/tests/shell/testcases/chains/dumps/0021prio_0.nft
@@ -1382,6 +1382,26 @@ table netdev x {
chain ingressfilterp11 {
type filter hook ingress device "lo" priority 11; policy accept;
}
+
+ chain egressfilterm11 {
+ type filter hook egress device "lo" priority -11; policy accept;
+ }
+
+ chain egressfilterm10 {
+ type filter hook egress device "lo" priority filter - 10; policy accept;
+ }
+
+ chain egressfilter {
+ type filter hook egress device "lo" priority filter; policy accept;
+ }
+
+ chain egressfilterp10 {
+ type filter hook egress device "lo" priority filter + 10; policy accept;
+ }
+
+ chain egressfilterp11 {
+ type filter hook egress device "lo" priority 11; policy accept;
+ }
}
table bridge x {
chain preroutingfilterm11 {
diff --git a/tests/shell/testcases/chains/dumps/0022prio_dummy_1.json-nft b/tests/shell/testcases/chains/dumps/0022prio_dummy_1.json-nft
new file mode 100644
index 00000000..15ec0aac
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0022prio_dummy_1.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0022prio_dummy_1.nft b/tests/shell/testcases/chains/dumps/0022prio_dummy_1.nft
new file mode 100644
index 00000000..5d4d2caf
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0022prio_dummy_1.nft
@@ -0,0 +1,2 @@
+table ip x {
+}
diff --git a/tests/shell/testcases/chains/dumps/0023prio_inet_srcnat_1.json-nft b/tests/shell/testcases/chains/dumps/0023prio_inet_srcnat_1.json-nft
new file mode 100644
index 00000000..72e0d438
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0023prio_inet_srcnat_1.json-nft
@@ -0,0 +1,32 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0023prio_inet_srcnat_1.nft b/tests/shell/testcases/chains/dumps/0023prio_inet_srcnat_1.nft
new file mode 100644
index 00000000..46912eaa
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0023prio_inet_srcnat_1.nft
@@ -0,0 +1,6 @@
+table ip x {
+}
+table ip6 x {
+}
+table inet x {
+}
diff --git a/tests/shell/testcases/chains/dumps/0024prio_inet_dstnat_1.json-nft b/tests/shell/testcases/chains/dumps/0024prio_inet_dstnat_1.json-nft
new file mode 100644
index 00000000..72e0d438
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0024prio_inet_dstnat_1.json-nft
@@ -0,0 +1,32 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0024prio_inet_dstnat_1.nft b/tests/shell/testcases/chains/dumps/0024prio_inet_dstnat_1.nft
new file mode 100644
index 00000000..46912eaa
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0024prio_inet_dstnat_1.nft
@@ -0,0 +1,6 @@
+table ip x {
+}
+table ip6 x {
+}
+table inet x {
+}
diff --git a/tests/shell/testcases/chains/dumps/0025prio_arp_1.json-nft b/tests/shell/testcases/chains/dumps/0025prio_arp_1.json-nft
new file mode 100644
index 00000000..17410e32
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0025prio_arp_1.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "arp",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0025prio_arp_1.nft b/tests/shell/testcases/chains/dumps/0025prio_arp_1.nft
new file mode 100644
index 00000000..7483cdaa
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0025prio_arp_1.nft
@@ -0,0 +1,2 @@
+table arp x {
+}
diff --git a/tests/shell/testcases/chains/dumps/0026prio_netdev_1.json-nft b/tests/shell/testcases/chains/dumps/0026prio_netdev_1.json-nft
new file mode 100644
index 00000000..7d78bd67
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0026prio_netdev_1.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "netdev",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0026prio_netdev_1.nft b/tests/shell/testcases/chains/dumps/0026prio_netdev_1.nft
new file mode 100644
index 00000000..aa571e00
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0026prio_netdev_1.nft
@@ -0,0 +1,2 @@
+table netdev x {
+}
diff --git a/tests/shell/testcases/chains/dumps/0027prio_bridge_dstnat_1.json-nft b/tests/shell/testcases/chains/dumps/0027prio_bridge_dstnat_1.json-nft
new file mode 100644
index 00000000..af6ff0a4
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0027prio_bridge_dstnat_1.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0027prio_bridge_dstnat_1.nft b/tests/shell/testcases/chains/dumps/0027prio_bridge_dstnat_1.nft
new file mode 100644
index 00000000..d17be818
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0027prio_bridge_dstnat_1.nft
@@ -0,0 +1,2 @@
+table bridge x {
+}
diff --git a/tests/shell/testcases/chains/dumps/0028prio_bridge_out_1.json-nft b/tests/shell/testcases/chains/dumps/0028prio_bridge_out_1.json-nft
new file mode 100644
index 00000000..af6ff0a4
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0028prio_bridge_out_1.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0028prio_bridge_out_1.nft b/tests/shell/testcases/chains/dumps/0028prio_bridge_out_1.nft
new file mode 100644
index 00000000..d17be818
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0028prio_bridge_out_1.nft
@@ -0,0 +1,2 @@
+table bridge x {
+}
diff --git a/tests/shell/testcases/chains/dumps/0029prio_bridge_srcnat_1.json-nft b/tests/shell/testcases/chains/dumps/0029prio_bridge_srcnat_1.json-nft
new file mode 100644
index 00000000..af6ff0a4
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0029prio_bridge_srcnat_1.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0029prio_bridge_srcnat_1.nft b/tests/shell/testcases/chains/dumps/0029prio_bridge_srcnat_1.nft
new file mode 100644
index 00000000..d17be818
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0029prio_bridge_srcnat_1.nft
@@ -0,0 +1,2 @@
+table bridge x {
+}
diff --git a/tests/shell/testcases/chains/dumps/0030create_0.json-nft b/tests/shell/testcases/chains/dumps/0030create_0.json-nft
new file mode 100644
index 00000000..b6088c80
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0030create_0.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0031priority_variable_0.json-nft b/tests/shell/testcases/chains/dumps/0031priority_variable_0.json-nft
new file mode 100644
index 00000000..9572eda3
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0031priority_variable_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "global",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "global",
+ "name": "prerouting",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0021priority_variable_0.nft b/tests/shell/testcases/chains/dumps/0031priority_variable_0.nft
index f4093097..f4093097 100644
--- a/tests/shell/testcases/nft-f/dumps/0021priority_variable_0.nft
+++ b/tests/shell/testcases/chains/dumps/0031priority_variable_0.nft
diff --git a/tests/shell/testcases/chains/dumps/0032priority_variable_0.json-nft b/tests/shell/testcases/chains/dumps/0032priority_variable_0.json-nft
new file mode 100644
index 00000000..3044a668
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0032priority_variable_0.json-nft
@@ -0,0 +1,54 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "global",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "global",
+ "name": "prerouting",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "global",
+ "name": "forward",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -100,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "global",
+ "name": "postrouting",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": -10,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0032priority_variable_0.nft b/tests/shell/testcases/chains/dumps/0032priority_variable_0.nft
new file mode 100644
index 00000000..1a1b0794
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0032priority_variable_0.nft
@@ -0,0 +1,13 @@
+table inet global {
+ chain prerouting {
+ type filter hook prerouting priority filter + 10; policy accept;
+ }
+
+ chain forward {
+ type filter hook prerouting priority dstnat; policy accept;
+ }
+
+ chain postrouting {
+ type filter hook postrouting priority filter - 10; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0033priority_variable_1.json-nft b/tests/shell/testcases/chains/dumps/0033priority_variable_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0033priority_variable_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0033priority_variable_1.nft b/tests/shell/testcases/chains/dumps/0033priority_variable_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0033priority_variable_1.nft
diff --git a/tests/shell/testcases/chains/dumps/0034priority_variable_1.json-nft b/tests/shell/testcases/chains/dumps/0034priority_variable_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0034priority_variable_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0034priority_variable_1.nft b/tests/shell/testcases/chains/dumps/0034priority_variable_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0034priority_variable_1.nft
diff --git a/tests/shell/testcases/chains/dumps/0035policy_variable_0.json-nft b/tests/shell/testcases/chains/dumps/0035policy_variable_0.json-nft
new file mode 100644
index 00000000..9572eda3
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0035policy_variable_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "global",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "global",
+ "name": "prerouting",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0025policy_variable_0.nft b/tests/shell/testcases/chains/dumps/0035policy_variable_0.nft
index f4093097..f4093097 100644
--- a/tests/shell/testcases/nft-f/dumps/0025policy_variable_0.nft
+++ b/tests/shell/testcases/chains/dumps/0035policy_variable_0.nft
diff --git a/tests/shell/testcases/chains/dumps/0036policy_variable_0.json-nft b/tests/shell/testcases/chains/dumps/0036policy_variable_0.json-nft
new file mode 100644
index 00000000..fc688463
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0036policy_variable_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "global",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "global",
+ "name": "prerouting",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 0,
+ "policy": "drop"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0026policy_variable_0.nft b/tests/shell/testcases/chains/dumps/0036policy_variable_0.nft
index d729e1ea..d729e1ea 100644
--- a/tests/shell/testcases/nft-f/dumps/0026policy_variable_0.nft
+++ b/tests/shell/testcases/chains/dumps/0036policy_variable_0.nft
diff --git a/tests/shell/testcases/chains/dumps/0037policy_variable_1.json-nft b/tests/shell/testcases/chains/dumps/0037policy_variable_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0037policy_variable_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0037policy_variable_1.nft b/tests/shell/testcases/chains/dumps/0037policy_variable_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0037policy_variable_1.nft
diff --git a/tests/shell/testcases/chains/dumps/0038policy_variable_1.json-nft b/tests/shell/testcases/chains/dumps/0038policy_variable_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0038policy_variable_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0038policy_variable_1.nft b/tests/shell/testcases/chains/dumps/0038policy_variable_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0038policy_variable_1.nft
diff --git a/tests/shell/testcases/chains/dumps/0039negative_priority_0.json-nft b/tests/shell/testcases/chains/dumps/0039negative_priority_0.json-nft
new file mode 100644
index 00000000..94218a8d
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0039negative_priority_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -30,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0039negative_priority_0.nft b/tests/shell/testcases/chains/dumps/0039negative_priority_0.nft
new file mode 100644
index 00000000..20f8272a
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0039negative_priority_0.nft
@@ -0,0 +1,5 @@
+table ip t {
+ chain c {
+ type filter hook input priority -30; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0041chain_binding_0.nft b/tests/shell/testcases/chains/dumps/0041chain_binding_0.nft
new file mode 100644
index 00000000..520203d8
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0041chain_binding_0.nft
@@ -0,0 +1,12 @@
+table inet x {
+ chain y {
+ type filter hook input priority filter; policy accept;
+ meta l4proto { tcp, udp } th dport 53 jump {
+ ip saddr { 127.0.0.0/8, 172.23.0.0/16, 192.168.13.0/24 } counter packets 0 bytes 0 accept
+ ip6 saddr ::1 counter packets 0 bytes 0 accept
+ }
+ meta l4proto ipv6-icmp jump {
+ counter packets 0 bytes 0 accept
+ }
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0042chain_variable_0.json-nft b/tests/shell/testcases/chains/dumps/0042chain_variable_0.json-nft
new file mode 100644
index 00000000..4059e85b
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0042chain_variable_0.json-nft
@@ -0,0 +1,90 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "netdev",
+ "name": "filter1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "filter1",
+ "name": "Main_Ingress1",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "ingress",
+ "prio": -500,
+ "policy": "accept"
+ }
+ },
+ {
+ "table": {
+ "family": "netdev",
+ "name": "filter2",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "filter2",
+ "name": "Main_Ingress2",
+ "handle": 0,
+ "dev": [
+ "d23456789012345",
+ "lo"
+ ],
+ "type": "filter",
+ "hook": "ingress",
+ "prio": -500,
+ "policy": "accept"
+ }
+ },
+ {
+ "table": {
+ "family": "netdev",
+ "name": "filter3",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "filter3",
+ "name": "Main_Ingress3",
+ "handle": 0,
+ "dev": [
+ "d23456789012345",
+ "lo"
+ ],
+ "type": "filter",
+ "hook": "ingress",
+ "prio": -500,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "filter3",
+ "name": "Main_Egress3",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "egress",
+ "prio": -500,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0042chain_variable_0.nft b/tests/shell/testcases/chains/dumps/0042chain_variable_0.nft
new file mode 100644
index 00000000..84a908d3
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0042chain_variable_0.nft
@@ -0,0 +1,19 @@
+table netdev filter1 {
+ chain Main_Ingress1 {
+ type filter hook ingress device "lo" priority -500; policy accept;
+ }
+}
+table netdev filter2 {
+ chain Main_Ingress2 {
+ type filter hook ingress devices = { d23456789012345, lo } priority -500; policy accept;
+ }
+}
+table netdev filter3 {
+ chain Main_Ingress3 {
+ type filter hook ingress devices = { d23456789012345, lo } priority -500; policy accept;
+ }
+
+ chain Main_Egress3 {
+ type filter hook egress device "lo" priority -500; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0043chain_ingress_0.json-nft b/tests/shell/testcases/chains/dumps/0043chain_ingress_0.json-nft
new file mode 100644
index 00000000..6753658e
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0043chain_ingress_0.json-nft
@@ -0,0 +1,55 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "ingress",
+ "handle": 0,
+ "dev": "lo",
+ "type": "filter",
+ "hook": "ingress",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "forward",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 0,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0043chain_ingress_0.nft b/tests/shell/testcases/chains/dumps/0043chain_ingress_0.nft
new file mode 100644
index 00000000..8483b265
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0043chain_ingress_0.nft
@@ -0,0 +1,13 @@
+table inet filter {
+ chain ingress {
+ type filter hook ingress device "lo" priority filter; policy accept;
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ }
+
+ chain forward {
+ type filter hook forward priority filter; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/chains/dumps/0044chain_destroy_0.json-nft b/tests/shell/testcases/chains/dumps/0044chain_destroy_0.json-nft
new file mode 100644
index 00000000..e0e56fec
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0044chain_destroy_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/0044chain_destroy_0.nft b/tests/shell/testcases/chains/dumps/0044chain_destroy_0.nft
new file mode 100644
index 00000000..985768ba
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/0044chain_destroy_0.nft
@@ -0,0 +1,2 @@
+table ip t {
+}
diff --git a/tests/shell/testcases/chains/dumps/netdev_chain_0.json-nft b/tests/shell/testcases/chains/dumps/netdev_chain_0.json-nft
new file mode 100644
index 00000000..7d78bd67
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/netdev_chain_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "netdev",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/netdev_chain_0.nft b/tests/shell/testcases/chains/dumps/netdev_chain_0.nft
new file mode 100644
index 00000000..aa571e00
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/netdev_chain_0.nft
@@ -0,0 +1,2 @@
+table netdev x {
+}
diff --git a/tests/shell/testcases/chains/dumps/netdev_chain_autoremove.json-nft b/tests/shell/testcases/chains/dumps/netdev_chain_autoremove.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/netdev_chain_autoremove.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/chains/dumps/netdev_chain_autoremove.nft b/tests/shell/testcases/chains/dumps/netdev_chain_autoremove.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/netdev_chain_autoremove.nft
diff --git a/tests/shell/testcases/chains/dumps/netdev_chain_dev_gone.nodump b/tests/shell/testcases/chains/dumps/netdev_chain_dev_gone.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/netdev_chain_dev_gone.nodump
diff --git a/tests/shell/testcases/chains/dumps/netdev_chain_multidev_gone.nodump b/tests/shell/testcases/chains/dumps/netdev_chain_multidev_gone.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/netdev_chain_multidev_gone.nodump
diff --git a/tests/shell/testcases/chains/dumps/netdev_multidev_netns_gone.nodump b/tests/shell/testcases/chains/dumps/netdev_multidev_netns_gone.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/netdev_multidev_netns_gone.nodump
diff --git a/tests/shell/testcases/chains/dumps/netdev_netns_gone.nodump b/tests/shell/testcases/chains/dumps/netdev_netns_gone.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/chains/dumps/netdev_netns_gone.nodump
diff --git a/tests/shell/testcases/chains/netdev_chain_0 b/tests/shell/testcases/chains/netdev_chain_0
new file mode 100755
index 00000000..a323e6ec
--- /dev/null
+++ b/tests/shell/testcases/chains/netdev_chain_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_netdev_chain_without_device)
+
+set -e
+
+iface_cleanup() {
+ ip link del d0 &>/dev/null || :
+ ip link del d1 &>/dev/null || :
+ ip link del d2 &>/dev/null || :
+}
+trap 'iface_cleanup' EXIT
+iface_cleanup
+
+ip link add d0 type dummy
+ip link add d1 type dummy
+ip link add d2 type dummy
+
+RULESET="table netdev x {
+ chain y {
+ type filter hook ingress priority 0; policy accept;
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+
+$NFT add chain netdev x y '{ devices = { d0 }; }'
+$NFT add chain netdev x y '{ devices = { d1, d2, lo }; }'
+$NFT delete chain netdev x y '{ devices = { lo }; }'
diff --git a/tests/shell/testcases/chains/netdev_chain_autoremove b/tests/shell/testcases/chains/netdev_chain_autoremove
new file mode 100755
index 00000000..21f3ad29
--- /dev/null
+++ b/tests/shell/testcases/chains/netdev_chain_autoremove
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -e
+
+# Test auto-removal of chain hook on netns removal
+unshare -n bash -e -c "ip link add br0 type bridge; \
+ $NFT add table netdev test; \
+ $NFT add chain netdev test ingress { type filter hook ingress device \"br0\" priority 0\; policy drop\; } ; \
+"
diff --git a/tests/shell/testcases/chains/netdev_chain_dev_gone b/tests/shell/testcases/chains/netdev_chain_dev_gone
new file mode 100755
index 00000000..99933a31
--- /dev/null
+++ b/tests/shell/testcases/chains/netdev_chain_dev_gone
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_inet_ingress)
+
+set -e
+
+iface_cleanup() {
+ ip link del d0 &>/dev/null || :
+}
+trap 'iface_cleanup' EXIT
+
+ip link add d0 type dummy
+
+load_ruleset() {
+ family=$1
+
+ # Test auto-removal of chain hook on device removal
+ RULESET="table $family x {
+ chain x {}
+ chain w {
+ ip daddr 8.7.6.0/24 jump x
+ }
+ chain y {
+ type filter hook ingress device \"d0\" priority 0;
+ ip saddr { 1.2.3.4, 2.3.4.5 } counter
+ ip daddr vmap { 5.4.3.0/24 : jump w, 8.9.0.0/24 : jump x }
+ }
+}"
+ $NFT -c -f - <<< $RULESET
+ $NFT -f - <<< $RULESET
+}
+
+load_ruleset "inet"
+load_ruleset "netdev"
diff --git a/tests/shell/testcases/chains/netdev_chain_multidev_gone b/tests/shell/testcases/chains/netdev_chain_multidev_gone
new file mode 100755
index 00000000..e82698a7
--- /dev/null
+++ b/tests/shell/testcases/chains/netdev_chain_multidev_gone
@@ -0,0 +1,41 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_chain_binding)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_netdev_chain_multidevice)
+
+set -e
+
+iface_cleanup() {
+ ip link del d0 &>/dev/null || :
+ ip link del d1 &>/dev/null || :
+ ip link del d2 &>/dev/null || :
+}
+trap 'iface_cleanup' EXIT
+
+ip link add d0 type dummy
+ip link add d1 type dummy
+ip link add d2 type dummy
+
+load_ruleset() {
+ family=$1
+
+ # Test auto-removal of chain hook on device removal
+ RULESET="table $family x {
+ chain x {}
+ chain w {
+ ip daddr 8.7.6.0/24 jump {
+ ip daddr vmap { 8.7.6.3 : jump x, 8.7.6.4 : jump x }
+ }
+ }
+ chain y {
+ type filter hook ingress devices = { d0, d1, d2 } priority 0;
+ ip saddr { 1.2.3.4, 2.3.4.5 } counter
+ ip daddr vmap { 5.4.3.0/24 : jump w, 8.9.0.0/24 : jump x }
+ }
+}"
+ $NFT -c -f - <<< $RULESET
+ $NFT -f - <<< $RULESET
+}
+
+load_ruleset "inet"
+load_ruleset "netdev"
diff --git a/tests/shell/testcases/chains/netdev_multidev_netns_gone b/tests/shell/testcases/chains/netdev_multidev_netns_gone
new file mode 100755
index 00000000..31ab29bd
--- /dev/null
+++ b/tests/shell/testcases/chains/netdev_multidev_netns_gone
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_chain_binding)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_netdev_chain_multidevice)
+
+set -e
+
+rnd=$(mktemp -u XXXXXXXX)
+ns1="nft1ns-$rnd"
+
+iface_cleanup() {
+ ip netns del $ns1 &>/dev/null || :
+}
+trap 'iface_cleanup' EXIT
+
+load_ruleset() {
+ family=$1
+
+ ip netns add $ns1
+ ip -net $ns1 link add d0 type dummy
+ ip -net $ns1 link add d1 type dummy
+ ip -net $ns1 link add d2 type dummy
+
+ # Test auto-removal of chain hook on device removal
+ RULESET="table $family x {
+ chain x {}
+ chain w {
+ ip daddr 8.7.6.0/24 jump {
+ ip daddr vmap { 8.7.6.3 : jump x, 8.7.6.4 : jump x }
+ }
+ }
+ chain y {
+ type filter hook ingress devices = { d0, d1, d2 } priority 0;
+ ip saddr { 1.2.3.4, 2.3.4.5 } counter
+ ip daddr vmap { 5.4.3.0/24 : jump w, 8.9.0.0/24 : jump x }
+ }
+}"
+ ip netns exec $ns1 $NFT -f - <<< $RULESET
+ ip netns del $ns1
+}
+
+load_ruleset "inet"
+load_ruleset "netdev"
diff --git a/tests/shell/testcases/chains/netdev_netns_gone b/tests/shell/testcases/chains/netdev_netns_gone
new file mode 100755
index 00000000..3a92c99e
--- /dev/null
+++ b/tests/shell/testcases/chains/netdev_netns_gone
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_inet_ingress)
+
+set -e
+
+rnd=$(mktemp -u XXXXXXXX)
+ns1="nft1ns-$rnd"
+
+iface_cleanup() {
+ ip netns del $ns1 &>/dev/null || :
+}
+trap 'iface_cleanup' EXIT
+
+load_ruleset() {
+ family=$1
+
+ ip netns add $ns1
+ ip -net $ns1 link add d0 type dummy
+
+ RULESET="table $family x {
+ chain x {}
+ chain w {
+ ip daddr 8.7.6.0/24 jump x
+ }
+ chain y {
+ type filter hook ingress device \"d0\" priority 0;
+ ip saddr { 1.2.3.4, 2.3.4.5 } counter
+ ip daddr vmap { 5.4.3.0/24 : jump w, 8.9.0.0/24 : jump x }
+ }
+}"
+ ip netns exec $ns1 $NFT -f - <<< $RULESET
+ ip netns del $ns1
+}
+
+load_ruleset "inet"
+load_ruleset "netdev"
diff --git a/tests/shell/testcases/comments/comments_0 b/tests/shell/testcases/comments/comments_0
new file mode 100755
index 00000000..a50387d6
--- /dev/null
+++ b/tests/shell/testcases/comments/comments_0
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+RULESET="table inet x { # comment
+ # comment 1
+ # comment 2
+ set y { # comment here
+ type ipv4_addr # comment
+ elements = {
+ # 1.1.1.1
+ 2.2.2.2, # comment
+ # more comments
+ 3.3.3.3, # comment
+# comment
+ }
+ # comment
+ }
+
+ # comments are allowed here
+ chain y {
+ # comments are allowed here
+ icmpv6 type {
+ 1, # comments are allowed here
+ 2,
+ } accept
+
+ icmp type {
+# comment
+ 1,
+ # comments also allowed here
+ 2,
+ } accept
+
+ tcp dport {
+ # normal FTP
+ 21,
+ # patched FTP
+ 2121
+ } counter accept
+ }
+}
+"
+
+$NFT -f - <<< "$RULESET"
+
diff --git a/tests/shell/testcases/comments/dumps/comments_0.json-nft b/tests/shell/testcases/comments/dumps/comments_0.json-nft
new file mode 100644
index 00000000..201abd6f
--- /dev/null
+++ b/tests/shell/testcases/comments/dumps/comments_0.json-nft
@@ -0,0 +1,135 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "2.2.2.2",
+ "3.3.3.3"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmpv6",
+ "field": "type"
+ }
+ },
+ "right": {
+ "set": [
+ "destination-unreachable",
+ "packet-too-big"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "type"
+ }
+ },
+ "right": {
+ "set": [
+ 1,
+ 2
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 21,
+ 2121
+ ]
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/comments/dumps/comments_0.nft b/tests/shell/testcases/comments/dumps/comments_0.nft
new file mode 100644
index 00000000..82ae510b
--- /dev/null
+++ b/tests/shell/testcases/comments/dumps/comments_0.nft
@@ -0,0 +1,12 @@
+table inet x {
+ set y {
+ type ipv4_addr
+ elements = { 2.2.2.2, 3.3.3.3 }
+ }
+
+ chain y {
+ icmpv6 type { destination-unreachable, packet-too-big } accept
+ icmp type { 1, 2 } accept
+ tcp dport { 21, 2121 } counter packets 0 bytes 0 accept
+ }
+}
diff --git a/tests/shell/testcases/flowtable/0006segfault_0 b/tests/shell/testcases/flowtable/0006segfault_0
index de590b77..fb7c52fe 100755
--- a/tests/shell/testcases/flowtable/0006segfault_0
+++ b/tests/shell/testcases/flowtable/0006segfault_0
@@ -9,6 +9,3 @@ $NFT add flowtable ip t f { hook ingress priority 10\; devices = { lo } }
$NFT add flowtable ip t f { hook ingress\; priority 10\; }
[[ $? -eq 1 ]] || exit 1
-
-$NFT add flowtable ip t f { hook ingress priority 10\; }
-[[ $? -eq 1 ]] || exit 1
diff --git a/tests/shell/testcases/flowtable/0010delete_handle_0 b/tests/shell/testcases/flowtable/0010delete_handle_0
new file mode 100755
index 00000000..8dd8d9fd
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0010delete_handle_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# delete flowtable by handle
+
+set -e
+
+$NFT add table inet t
+$NFT add flowtable inet t f { hook ingress priority filter\; devices = { lo }\; }
+
+FH=$($NFT -a list ruleset | awk '/flowtable f/ { print $NF }')
+
+$NFT delete flowtable inet t handle $FH
+
+EXPECTED="table inet t {
+}"
+
+GET="$($NFT list ruleset)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/flowtable/0011deleteafterflush_0 b/tests/shell/testcases/flowtable/0011deleteafterflush_0
new file mode 100755
index 00000000..4f519a7c
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0011deleteafterflush_0
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+set -e
+$NFT add table x
+$NFT add chain x y
+$NFT add flowtable x f { hook ingress priority 0\; devices = { lo }\;}
+$NFT add rule x y ip protocol tcp flow add @f
+$NFT add rule x y ip protocol udp flow add @f
+$NFT flush chain x y
+$NFT delete flowtable x f
diff --git a/tests/shell/testcases/flowtable/0012flowtable_variable_0 b/tests/shell/testcases/flowtable/0012flowtable_variable_0
new file mode 100755
index 00000000..9c03820f
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0012flowtable_variable_0
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_flowtable_counter)
+
+set -e
+
+iface_cleanup() {
+ ip link del dummy1 &>/dev/null || :
+}
+trap 'iface_cleanup' EXIT
+iface_cleanup
+
+ip link add name dummy1 type dummy
+
+EXPECTED="define if_main = { lo, dummy1 }
+
+table filter1 {
+ flowtable Main_ft1 {
+ hook ingress priority filter
+ counter
+ devices = \$if_main
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
+EXPECTED="define if_main = \"lo\"
+
+table filter2 {
+ flowtable Main_ft2 {
+ hook ingress priority filter
+ counter
+ devices = { \$if_main, dummy1 }
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/flowtable/0013addafterdelete_0 b/tests/shell/testcases/flowtable/0013addafterdelete_0
new file mode 100755
index 00000000..56c9834f
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0013addafterdelete_0
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -e
+
+RULESET='table inet filter {
+
+ flowtable f {
+ hook ingress priority filter - 1
+ devices = { lo }
+ }
+}'
+
+$NFT -f - <<< "$RULESET"
+
+RULESET='delete flowtable inet filter f
+
+table inet filter {
+
+ flowtable f {
+ hook ingress priority filter - 1
+ devices = { lo }
+ }
+}'
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/flowtable/0014addafterdelete_0 b/tests/shell/testcases/flowtable/0014addafterdelete_0
new file mode 100755
index 00000000..1ac65104
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0014addafterdelete_0
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_flowtable_counter)
+
+set -e
+
+RULESET='table inet filter {
+
+ flowtable f {
+ hook ingress priority filter - 1
+ devices = { lo }
+ }
+
+ chain y {
+ type filter hook forward priority 0;
+ flow add @f counter
+ }
+}'
+
+$NFT -f - <<< "$RULESET"
+
+RULESET='delete rule inet filter y handle 3
+delete flowtable inet filter f
+
+table inet filter {
+ flowtable f {
+ hook ingress priority filter - 1
+ devices = { lo }
+ counter
+ }
+
+ chain y {
+ type filter hook forward priority 0;
+ flow add @f counter
+ }
+}'
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/flowtable/0015destroy_0 b/tests/shell/testcases/flowtable/0015destroy_0
new file mode 100755
index 00000000..cea33524
--- /dev/null
+++ b/tests/shell/testcases/flowtable/0015destroy_0
@@ -0,0 +1,20 @@
+#!/bin/bash -e
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_destroy)
+
+trap "ip link del dummy1" EXIT
+
+ip link add dummy1 type dummy
+ip link set dummy1 up
+
+$NFT add table t
+
+# pass for non-existent flowtable
+$NFT destroy flowtable t f
+
+# successfully delete existing flowtable
+$NFT add flowtable t f '{ hook ingress priority 10; devices = { lo }; }'
+
+$NFT 'add flowtable t f { devices = { dummy1 } ; }'
+
+$NFT destroy flowtable t f
diff --git a/tests/shell/testcases/flowtable/dumps/0001flowtable_0.json-nft b/tests/shell/testcases/flowtable/dumps/0001flowtable_0.json-nft
new file mode 100644
index 00000000..4d15fe3a
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0001flowtable_0.json-nft
@@ -0,0 +1,53 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "flowtable": {
+ "family": "inet",
+ "name": "f",
+ "table": "t",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": 10,
+ "dev": "lo"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "flow": {
+ "op": "add",
+ "flowtable": "@f"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0002create_flowtable_0.json-nft b/tests/shell/testcases/flowtable/dumps/0002create_flowtable_0.json-nft
new file mode 100644
index 00000000..0013512b
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0002create_flowtable_0.json-nft
@@ -0,0 +1,29 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "flowtable": {
+ "family": "ip",
+ "name": "f",
+ "table": "t",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": 10,
+ "dev": "lo"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0002create_flowtable_0.nft b/tests/shell/testcases/flowtable/dumps/0002create_flowtable_0.nft
new file mode 100644
index 00000000..aecfb2ab
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0002create_flowtable_0.nft
@@ -0,0 +1,6 @@
+table ip t {
+ flowtable f {
+ hook ingress priority filter + 10
+ devices = { lo }
+ }
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0003add_after_flush_0.json-nft b/tests/shell/testcases/flowtable/dumps/0003add_after_flush_0.json-nft
new file mode 100644
index 00000000..04057f1f
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0003add_after_flush_0.json-nft
@@ -0,0 +1,29 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "flowtable": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": 0,
+ "dev": "lo"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0003add_after_flush_0.nft b/tests/shell/testcases/flowtable/dumps/0003add_after_flush_0.nft
new file mode 100644
index 00000000..dd904f44
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0003add_after_flush_0.nft
@@ -0,0 +1,6 @@
+table ip x {
+ flowtable y {
+ hook ingress priority filter
+ devices = { lo }
+ }
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0004delete_after_add_0.json-nft b/tests/shell/testcases/flowtable/dumps/0004delete_after_add_0.json-nft
new file mode 100644
index 00000000..15ec0aac
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0004delete_after_add_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0004delete_after_add_0.nft b/tests/shell/testcases/flowtable/dumps/0004delete_after_add_0.nft
new file mode 100644
index 00000000..5d4d2caf
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0004delete_after_add_0.nft
@@ -0,0 +1,2 @@
+table ip x {
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0005delete_in_use_1.json-nft b/tests/shell/testcases/flowtable/dumps/0005delete_in_use_1.json-nft
new file mode 100644
index 00000000..302502dc
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0005delete_in_use_1.json-nft
@@ -0,0 +1,53 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "flowtable": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": 0,
+ "dev": "lo"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "x",
+ "handle": 0,
+ "expr": [
+ {
+ "flow": {
+ "op": "add",
+ "flowtable": "@y"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0005delete_in_use_1.nft b/tests/shell/testcases/flowtable/dumps/0005delete_in_use_1.nft
new file mode 100644
index 00000000..c1d79e7b
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0005delete_in_use_1.nft
@@ -0,0 +1,10 @@
+table ip x {
+ flowtable y {
+ hook ingress priority filter
+ devices = { lo }
+ }
+
+ chain x {
+ flow add @y
+ }
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0006segfault_0.json-nft b/tests/shell/testcases/flowtable/dumps/0006segfault_0.json-nft
new file mode 100644
index 00000000..e0e56fec
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0006segfault_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0006segfault_0.nft b/tests/shell/testcases/flowtable/dumps/0006segfault_0.nft
new file mode 100644
index 00000000..985768ba
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0006segfault_0.nft
@@ -0,0 +1,2 @@
+table ip t {
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0007prio_0.json-nft b/tests/shell/testcases/flowtable/dumps/0007prio_0.json-nft
new file mode 100644
index 00000000..e0e56fec
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0007prio_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0007prio_0.nft b/tests/shell/testcases/flowtable/dumps/0007prio_0.nft
new file mode 100644
index 00000000..985768ba
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0007prio_0.nft
@@ -0,0 +1,2 @@
+table ip t {
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0008prio_1.json-nft b/tests/shell/testcases/flowtable/dumps/0008prio_1.json-nft
new file mode 100644
index 00000000..e0e56fec
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0008prio_1.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0008prio_1.nft b/tests/shell/testcases/flowtable/dumps/0008prio_1.nft
new file mode 100644
index 00000000..985768ba
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0008prio_1.nft
@@ -0,0 +1,2 @@
+table ip t {
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0009deleteafterflush_0.json-nft b/tests/shell/testcases/flowtable/dumps/0009deleteafterflush_0.json-nft
new file mode 100644
index 00000000..b6088c80
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0009deleteafterflush_0.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0009deleteafterflush_0.nft b/tests/shell/testcases/flowtable/dumps/0009deleteafterflush_0.nft
new file mode 100644
index 00000000..8e818d2d
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0009deleteafterflush_0.nft
@@ -0,0 +1,4 @@
+table ip x {
+ chain y {
+ }
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0010delete_handle_0.json-nft b/tests/shell/testcases/flowtable/dumps/0010delete_handle_0.json-nft
new file mode 100644
index 00000000..10372b0e
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0010delete_handle_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0010delete_handle_0.nft b/tests/shell/testcases/flowtable/dumps/0010delete_handle_0.nft
new file mode 100644
index 00000000..17838bdf
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0010delete_handle_0.nft
@@ -0,0 +1,2 @@
+table inet t {
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0011deleteafterflush_0.json-nft b/tests/shell/testcases/flowtable/dumps/0011deleteafterflush_0.json-nft
new file mode 100644
index 00000000..b6088c80
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0011deleteafterflush_0.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0011deleteafterflush_0.nft b/tests/shell/testcases/flowtable/dumps/0011deleteafterflush_0.nft
new file mode 100644
index 00000000..8e818d2d
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0011deleteafterflush_0.nft
@@ -0,0 +1,4 @@
+table ip x {
+ chain y {
+ }
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.json-nft b/tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.json-nft
new file mode 100644
index 00000000..10f1df98
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.json-nft
@@ -0,0 +1,47 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter1",
+ "handle": 0
+ }
+ },
+ {
+ "flowtable": {
+ "family": "ip",
+ "name": "Main_ft1",
+ "table": "filter1",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": 0,
+ "dev": "lo"
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter2",
+ "handle": 0
+ }
+ },
+ {
+ "flowtable": {
+ "family": "ip",
+ "name": "Main_ft2",
+ "table": "filter2",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": 0,
+ "dev": "lo"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.nft b/tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.nft
new file mode 100644
index 00000000..df1c51a2
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.nft
@@ -0,0 +1,14 @@
+table ip filter1 {
+ flowtable Main_ft1 {
+ hook ingress priority filter
+ devices = { lo }
+ counter
+ }
+}
+table ip filter2 {
+ flowtable Main_ft2 {
+ hook ingress priority filter
+ devices = { lo }
+ counter
+ }
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0013addafterdelete_0.json-nft b/tests/shell/testcases/flowtable/dumps/0013addafterdelete_0.json-nft
new file mode 100644
index 00000000..85c7b327
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0013addafterdelete_0.json-nft
@@ -0,0 +1,29 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "flowtable": {
+ "family": "inet",
+ "name": "f",
+ "table": "filter",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": -1,
+ "dev": "lo"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0013addafterdelete_0.nft b/tests/shell/testcases/flowtable/dumps/0013addafterdelete_0.nft
new file mode 100644
index 00000000..67db7d02
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0013addafterdelete_0.nft
@@ -0,0 +1,6 @@
+table inet filter {
+ flowtable f {
+ hook ingress priority filter - 1
+ devices = { lo }
+ }
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0014addafterdelete_0.json-nft b/tests/shell/testcases/flowtable/dumps/0014addafterdelete_0.json-nft
new file mode 100644
index 00000000..471ba5be
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0014addafterdelete_0.json-nft
@@ -0,0 +1,63 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "y",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "flowtable": {
+ "family": "inet",
+ "name": "f",
+ "table": "filter",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": -1,
+ "dev": "lo"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "flow": {
+ "op": "add",
+ "flowtable": "@f"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0014addafterdelete_0.nft b/tests/shell/testcases/flowtable/dumps/0014addafterdelete_0.nft
new file mode 100644
index 00000000..145aa081
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0014addafterdelete_0.nft
@@ -0,0 +1,12 @@
+table inet filter {
+ flowtable f {
+ hook ingress priority filter - 1
+ devices = { lo }
+ counter
+ }
+
+ chain y {
+ type filter hook forward priority filter; policy accept;
+ flow add @f counter packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0015destroy_0.json-nft b/tests/shell/testcases/flowtable/dumps/0015destroy_0.json-nft
new file mode 100644
index 00000000..e0e56fec
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0015destroy_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/flowtable/dumps/0015destroy_0.nft b/tests/shell/testcases/flowtable/dumps/0015destroy_0.nft
new file mode 100644
index 00000000..985768ba
--- /dev/null
+++ b/tests/shell/testcases/flowtable/dumps/0015destroy_0.nft
@@ -0,0 +1,2 @@
+table ip t {
+}
diff --git a/tests/shell/testcases/include/0003includepath_0 b/tests/shell/testcases/include/0003includepath_0
index ba722068..20037a8f 100755
--- a/tests/shell/testcases/include/0003includepath_0
+++ b/tests/shell/testcases/include/0003includepath_0
@@ -8,7 +8,7 @@ if [ ! -w $tmpfile1 ] ; then
exit 0
fi
-tmpfile3=$(echo "$tmpfile1" | cut -d'/' -f 3)
+tmpfile3="$(basename "$tmpfile1")"
tmpfile2=$(mktemp)
if [ ! -w $tmpfile2 ] ; then
@@ -24,7 +24,7 @@ RULESET2="include \"$tmpfile3\""
echo "$RULESET1" > $tmpfile1
echo "$RULESET2" > $tmpfile2
-$NFT -I /tmp -f $tmpfile2
+$NFT -I "$(dirname "$tmpfile1")" -f $tmpfile2
if [ $? -ne 0 ] ; then
echo "E: unable to load good ruleset" >&2
exit 1
diff --git a/tests/shell/testcases/include/0016maxdepth_0 b/tests/shell/testcases/include/0016maxdepth_0
new file mode 100755
index 00000000..89eb13c4
--- /dev/null
+++ b/tests/shell/testcases/include/0016maxdepth_0
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -e
+
+tmpfile=$(mktemp)
+
+echo 'include "/tmp/rules.nft"' > $tmpfile
+$NFT -f $tmpfile || exit 0
diff --git a/tests/shell/testcases/include/0017glob_more_than_maxdepth_1 b/tests/shell/testcases/include/0017glob_more_than_maxdepth_1
new file mode 100755
index 00000000..6499bcc8
--- /dev/null
+++ b/tests/shell/testcases/include/0017glob_more_than_maxdepth_1
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+set -e
+
+tmpfile=$(mktemp)
+if [ ! -w $tmpfile ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+tmpdir1=$(mktemp -d)
+if [ ! -d $tmpdir1 ] ; then
+ echo "Failed to create tmp directory" >&2
+ exit 0
+fi
+
+tmpfiles=""
+for i in `seq -w 1 32`; do
+ tmpfile2=$(mktemp -p $tmpdir1)
+ if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+ fi
+ tmpfiles="$tmpfiles $tmpfile2"
+done
+
+trap "rm -rf $tmpfile $tmpfiles && rmdir $tmpdir1" EXIT # cleanup if aborted
+
+RULESET=" \
+include \"$tmpdir1/*\"
+"
+
+echo "$RULESET" > $tmpfile
+
+$NFT -f $tmpfile
+if [ $? -ne 0 ] ; then
+ echo "E: unable to load good ruleset" >&2
+ exit 1
+fi
diff --git a/tests/shell/testcases/include/0018include_error_0 b/tests/shell/testcases/include/0018include_error_0
new file mode 100755
index 00000000..ae2dba3c
--- /dev/null
+++ b/tests/shell/testcases/include/0018include_error_0
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+tmpfile1=$(mktemp)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+touch $tmpfile1
+
+RULESET="include \"$tmpfile1\"
+)
+"
+
+tmpfile2=$(mktemp)
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+tmpfile3=$(mktemp)
+if [ ! -w $tmpfile3 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+echo "/dev/stdin:2:1-1: Error: syntax error, unexpected ')'
+)
+^" > $tmpfile3
+
+$NFT -I/tmp/ -f - <<< "$RULESET" 2> $tmpfile2
+$DIFF -u $tmpfile2 $tmpfile3
+
+rm $tmpfile1 $tmpfile2 $tmpfile3
diff --git a/tests/shell/testcases/include/0019include_error_0 b/tests/shell/testcases/include/0019include_error_0
new file mode 100755
index 00000000..4b84a578
--- /dev/null
+++ b/tests/shell/testcases/include/0019include_error_0
@@ -0,0 +1,63 @@
+#!/bin/bash
+
+tmpfile1=$(mktemp)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+tmpfile2=$(mktemp)
+if [ ! -w $tmpfile2 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+echo "(" >> $tmpfile2
+
+tmpdir=$(mktemp -d)
+
+echo "include \"$tmpfile2\"
+include \"$tmpdir/*.nft\"
+x" > $tmpfile1
+
+echo "=" > $tmpdir/1.nft
+echo ")" > $tmpdir/2.nft
+echo "-" > $tmpdir/3.nft
+
+tmpfile3=$(mktemp)
+if [ ! -w $tmpfile3 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+echo "In file included from $tmpfile1:1:1-30:
+$tmpfile2:1:1-1: Error: syntax error, unexpected '('
+(
+^
+In file included from $tmpfile1:2:1-36:
+$tmpdir/1.nft:1:1-1: Error: syntax error, unexpected '='
+=
+^
+In file included from $tmpfile1:2:1-36:
+$tmpdir/2.nft:1:1-1: Error: syntax error, unexpected ')'
+)
+^
+In file included from $tmpfile1:2:1-36:
+$tmpdir/3.nft:1:1-1: Error: syntax error, unexpected -
+-
+^
+$tmpfile1:3:2-2: Error: syntax error, unexpected newline, expecting string
+x
+ ^" > $tmpfile3
+
+tmpfile4=$(mktemp)
+if [ ! -w $tmpfile4 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 1
+fi
+
+$NFT -I/tmp/ -f $tmpfile1 2> $tmpfile4
+$DIFF -u $tmpfile3 $tmpfile4
+
+rm $tmpfile1 $tmpfile2 $tmpfile3 $tmpfile4
+rm -r $tmpdir
diff --git a/tests/shell/testcases/include/0020include_chain_0 b/tests/shell/testcases/include/0020include_chain_0
new file mode 100755
index 00000000..49b6f76c
--- /dev/null
+++ b/tests/shell/testcases/include/0020include_chain_0
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+set -e
+
+tmpfile1=$(mktemp -p .)
+if [ ! -w $tmpfile1 ] ; then
+ echo "Failed to create tmp file" >&2
+ exit 0
+fi
+
+trap "rm -rf $tmpfile1" EXIT # cleanup if aborted
+
+RULESET="table inet filter { }
+include \"$tmpfile1\""
+
+RULESET2="chain inet filter input2 {
+ type filter hook input priority filter; policy accept;
+ ip saddr 1.2.3.4 tcp dport { 22, 443, 123 } drop
+}"
+
+echo "$RULESET2" > $tmpfile1
+
+RULESET3="create chain inet filter output2 {
+ type filter hook output priority filter; policy accept;
+ ip daddr 1.2.3.4 tcp dport { 22, 443, 123 } drop
+}"
+
+echo "$RULESET3" >> $tmpfile1
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/include/dumps/0001absolute_0.json-nft b/tests/shell/testcases/include/dumps/0001absolute_0.json-nft
new file mode 100644
index 00000000..15ec0aac
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0001absolute_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0002relative_0.json-nft b/tests/shell/testcases/include/dumps/0002relative_0.json-nft
new file mode 100644
index 00000000..15ec0aac
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0002relative_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0003includepath_0.json-nft b/tests/shell/testcases/include/dumps/0003includepath_0.json-nft
new file mode 100644
index 00000000..15ec0aac
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0003includepath_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0004endlessloop_1.json-nft b/tests/shell/testcases/include/dumps/0004endlessloop_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0004endlessloop_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0004endlessloop_1.nft b/tests/shell/testcases/include/dumps/0004endlessloop_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0004endlessloop_1.nft
diff --git a/tests/shell/testcases/include/dumps/0005glob_empty_0.json-nft b/tests/shell/testcases/include/dumps/0005glob_empty_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0005glob_empty_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0005glob_empty_0.nft b/tests/shell/testcases/include/dumps/0005glob_empty_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0005glob_empty_0.nft
diff --git a/tests/shell/testcases/include/dumps/0006glob_single_0.json-nft b/tests/shell/testcases/include/dumps/0006glob_single_0.json-nft
new file mode 100644
index 00000000..15ec0aac
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0006glob_single_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0007glob_double_0.json-nft b/tests/shell/testcases/include/dumps/0007glob_double_0.json-nft
new file mode 100644
index 00000000..ea75b43f
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0007glob_double_0.json-nft
@@ -0,0 +1,25 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "y",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0008glob_nofile_wildcard_0.json-nft b/tests/shell/testcases/include/dumps/0008glob_nofile_wildcard_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0008glob_nofile_wildcard_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0008glob_nofile_wildcard_0.nft b/tests/shell/testcases/include/dumps/0008glob_nofile_wildcard_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0008glob_nofile_wildcard_0.nft
diff --git a/tests/shell/testcases/include/dumps/0009glob_nofile_1.json-nft b/tests/shell/testcases/include/dumps/0009glob_nofile_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0009glob_nofile_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0009glob_nofile_1.nft b/tests/shell/testcases/include/dumps/0009glob_nofile_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0009glob_nofile_1.nft
diff --git a/tests/shell/testcases/include/dumps/0010glob_broken_file_1.json-nft b/tests/shell/testcases/include/dumps/0010glob_broken_file_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0010glob_broken_file_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0010glob_broken_file_1.nft b/tests/shell/testcases/include/dumps/0010glob_broken_file_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0010glob_broken_file_1.nft
diff --git a/tests/shell/testcases/include/dumps/0011glob_dependency_0.json-nft b/tests/shell/testcases/include/dumps/0011glob_dependency_0.json-nft
new file mode 100644
index 00000000..b6088c80
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0011glob_dependency_0.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0012glob_dependency_1.json-nft b/tests/shell/testcases/include/dumps/0012glob_dependency_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0012glob_dependency_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0012glob_dependency_1.nft b/tests/shell/testcases/include/dumps/0012glob_dependency_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0012glob_dependency_1.nft
diff --git a/tests/shell/testcases/include/dumps/0013glob_dotfile_0.json-nft b/tests/shell/testcases/include/dumps/0013glob_dotfile_0.json-nft
new file mode 100644
index 00000000..15ec0aac
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0013glob_dotfile_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0013input_descriptors_included_files_0.json-nft b/tests/shell/testcases/include/dumps/0013input_descriptors_included_files_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0013input_descriptors_included_files_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0013input_descriptors_included_files_0.nft b/tests/shell/testcases/include/dumps/0013input_descriptors_included_files_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0013input_descriptors_included_files_0.nft
diff --git a/tests/shell/testcases/include/dumps/0014glob_directory_0.json-nft b/tests/shell/testcases/include/dumps/0014glob_directory_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0014glob_directory_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0014glob_directory_0.nft b/tests/shell/testcases/include/dumps/0014glob_directory_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0014glob_directory_0.nft
diff --git a/tests/shell/testcases/include/dumps/0015doubleincludepath_0.json-nft b/tests/shell/testcases/include/dumps/0015doubleincludepath_0.json-nft
new file mode 100644
index 00000000..b6088c80
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0015doubleincludepath_0.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0016maxdepth_0.json-nft b/tests/shell/testcases/include/dumps/0016maxdepth_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0016maxdepth_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0016maxdepth_0.nft b/tests/shell/testcases/include/dumps/0016maxdepth_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0016maxdepth_0.nft
diff --git a/tests/shell/testcases/include/dumps/0017glob_more_than_maxdepth_1.json-nft b/tests/shell/testcases/include/dumps/0017glob_more_than_maxdepth_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0017glob_more_than_maxdepth_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0017glob_more_than_maxdepth_1.nft b/tests/shell/testcases/include/dumps/0017glob_more_than_maxdepth_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0017glob_more_than_maxdepth_1.nft
diff --git a/tests/shell/testcases/include/dumps/0018include_error_0.json-nft b/tests/shell/testcases/include/dumps/0018include_error_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0018include_error_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0018include_error_0.nft b/tests/shell/testcases/include/dumps/0018include_error_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0018include_error_0.nft
diff --git a/tests/shell/testcases/include/dumps/0019include_error_0.json-nft b/tests/shell/testcases/include/dumps/0019include_error_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0019include_error_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0019include_error_0.nft b/tests/shell/testcases/include/dumps/0019include_error_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0019include_error_0.nft
diff --git a/tests/shell/testcases/include/dumps/0020include_chain_0.json-nft b/tests/shell/testcases/include/dumps/0020include_chain_0.json-nft
new file mode 100644
index 00000000..e893ccf1
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0020include_chain_0.json-nft
@@ -0,0 +1,128 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "input2",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "output2",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "input2",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 22,
+ 123,
+ 443
+ ]
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "output2",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 22,
+ 123,
+ 443
+ ]
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/include/dumps/0020include_chain_0.nft b/tests/shell/testcases/include/dumps/0020include_chain_0.nft
new file mode 100644
index 00000000..bf596ffb
--- /dev/null
+++ b/tests/shell/testcases/include/dumps/0020include_chain_0.nft
@@ -0,0 +1,11 @@
+table inet filter {
+ chain input2 {
+ type filter hook input priority filter; policy accept;
+ ip saddr 1.2.3.4 tcp dport { 22, 123, 443 } drop
+ }
+
+ chain output2 {
+ type filter hook output priority filter; policy accept;
+ ip daddr 1.2.3.4 tcp dport { 22, 123, 443 } drop
+ }
+}
diff --git a/tests/shell/testcases/json/0001set_statements_0 b/tests/shell/testcases/json/0001set_statements_0
new file mode 100755
index 00000000..fc4941f4
--- /dev/null
+++ b/tests/shell/testcases/json/0001set_statements_0
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_json)
+
+set -e
+
+$NFT flush ruleset
+
+RULESET='{"nftables": [{"metainfo": {"version": "1.0.5", "release_name": "Lester Gooch #4", "json_schema_version": 1}}, {"table": {"family": "ip", "name": "testt", "handle": 3}}, {"set": {"family": "ip", "name": "ssh_meter", "table": "testt", "type": "ipv4_addr", "handle": 2, "size": 65535}}, {"chain": {"family": "ip", "table": "testt", "name": "testc", "handle": 1, "type": "filter", "hook": "input", "prio": 0, "policy": "accept"}}, {"rule": {"family": "ip", "table": "testt", "chain": "testc", "handle": 3, "expr": [{"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": 22}}, {"match": {"op": "in", "left": {"ct": {"key": "state"}}, "right": "new"}}, {"set": {"op": "add", "elem": {"payload": {"protocol": "ip", "field": "saddr"}}, "stmt": [{"limit": {"rate": 10, "burst": 5, "per": "second"}}], "set": "@ssh_meter"}}, {"accept": null}]}}]}'
+
+$NFT -j -f - <<< $RULESET
diff --git a/tests/shell/testcases/json/0002table_map_0 b/tests/shell/testcases/json/0002table_map_0
new file mode 100755
index 00000000..a1e9f263
--- /dev/null
+++ b/tests/shell/testcases/json/0002table_map_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_json)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
+set -e
+
+$NFT flush ruleset
+
+RULESET='{"nftables": [{"metainfo": {"version": "1.0.5", "release_name": "Lester Gooch #4", "json_schema_version": 1}}, {"table": {"family": "ip", "name": "t", "handle": 4}}, {"map": {"family": "ip", "name": "m", "table": "t", "type": "ipv4_addr", "handle": 1, "map": "mark", "stmt": [{"counter": {"packets": 0, "bytes": 0}}]}}]}'
+
+$NFT -j -f - <<< $RULESET
diff --git a/tests/shell/testcases/json/0003json_schema_version_0 b/tests/shell/testcases/json/0003json_schema_version_0
new file mode 100755
index 00000000..43f387a1
--- /dev/null
+++ b/tests/shell/testcases/json/0003json_schema_version_0
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_json)
+
+set -e
+
+$NFT flush ruleset
+
+RULESET='{"nftables": [{"metainfo": {"json_schema_version": 1}}]}'
+
+$NFT -j -f - <<< $RULESET
diff --git a/tests/shell/testcases/json/0004json_schema_version_1 b/tests/shell/testcases/json/0004json_schema_version_1
new file mode 100755
index 00000000..0f8d586f
--- /dev/null
+++ b/tests/shell/testcases/json/0004json_schema_version_1
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_json)
+
+set -e
+
+$NFT flush ruleset
+
+RULESET='{"nftables": [{"metainfo": {"json_schema_version": 999}}]}'
+
+$NFT -j -f - <<< $RULESET && exit 1
+
+exit 0
diff --git a/tests/shell/testcases/json/0005secmark_objref_0 b/tests/shell/testcases/json/0005secmark_objref_0
new file mode 100755
index 00000000..5c44f093
--- /dev/null
+++ b/tests/shell/testcases/json/0005secmark_objref_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_json)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_secmark)
+
+set -e
+
+$NFT flush ruleset
+
+RULESET='{"nftables": [{"metainfo": {"version": "1.0.5", "release_name": "Lester Gooch #4", "json_schema_version": 1}}, {"table": {"family": "inet", "name": "x", "handle": 4}}, {"secmark": {"family": "inet", "name": "ssh_server", "table": "x", "handle": 1, "context": "system_u:object_r:ssh_server_packet_t:s0"}}, {"chain": {"family": "inet", "table": "x", "name": "y", "handle": 2, "type": "filter", "hook": "input", "prio": -225, "policy": "accept"}}, {"chain": {"family": "inet", "table": "x", "name": "z", "handle": 3, "type": "filter", "hook": "output", "prio": 225, "policy": "accept"}}, {"rule": {"family": "inet", "table": "x", "chain": "y", "handle": 4, "expr": [{"match": {"op": "==", "left": {"payload": {"protocol": "tcp", "field": "dport"}}, "right": 2222}}, {"match": {"op": "in", "left": {"ct": {"key": "state"}}, "right": "new"}}, {"secmark": "ssh_server"}]}}, {"rule": {"family": "inet", "table": "x", "chain": "y", "handle": 5, "expr": [{"match": {"op": "in", "left": {"ct": {"key": "state"}}, "right": "new"}}, {"mangle": {"key": {"ct": {"key": "secmark"}}, "value": {"meta": {"key": "secmark"}}}}]}}, {"rule": {"family": "inet", "table": "x", "chain": "y", "handle": 6, "expr": [{"match": {"op": "in", "left": {"ct": {"key": "state"}}, "right": ["established", "related"]}}, {"mangle": {"key": {"meta": {"key": "secmark"}}, "value": {"ct": {"key": "secmark"}}}}]}}, {"rule": {"family": "inet", "table": "x", "chain": "z", "handle": 7, "expr": [{"match": {"op": "in", "left": {"ct": {"key": "state"}}, "right": "new"}}, {"mangle": {"key": {"ct": {"key": "secmark"}}, "value": {"meta": {"key": "secmark"}}}}]}}, {"rule": {"family": "inet", "table": "x", "chain": "z", "handle": 8, "expr": [{"match": {"op": "in", "left": {"ct": {"key": "state"}}, "right": ["established", "related"]}}, {"mangle": {"key": {"meta": {"key": "secmark"}}, "value": {"ct": {"key": "secmark"}}}}]}}]}'
+
+$NFT -j -f - <<< $RULESET
diff --git a/tests/shell/testcases/json/0006obj_comment_0 b/tests/shell/testcases/json/0006obj_comment_0
new file mode 100755
index 00000000..7ce859d2
--- /dev/null
+++ b/tests/shell/testcases/json/0006obj_comment_0
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_json)
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_comment)
+
+set -e
+
+$NFT flush ruleset
+
+RULESET='{"nftables": [{"metainfo": {"version": "1.0.5", "release_name": "Lester Gooch #4", "json_schema_version": 1}}, {"table": {"family": "inet", "name": "t", "handle": 9}}, {"counter": {"family": "inet", "name": "mycounter", "table": "t", "handle": 1, "comment": "my comment in counter", "packets": 0, "bytes": 0}}]}'
+
+$NFT -j -f - <<< $RULESET
diff --git a/tests/shell/testcases/json/dumps/0001set_statements_0.json-nft b/tests/shell/testcases/json/dumps/0001set_statements_0.json-nft
new file mode 100644
index 00000000..91db43e2
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0001set_statements_0.json-nft
@@ -0,0 +1,100 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "testt",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "testt",
+ "name": "testc",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "ssh_meter",
+ "table": "testt",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "testt",
+ "chain": "testc",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "new"
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "set": "@ssh_meter",
+ "stmt": [
+ {
+ "limit": {
+ "rate": 10,
+ "burst": 5,
+ "per": "second"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/json/dumps/0001set_statements_0.nft b/tests/shell/testcases/json/dumps/0001set_statements_0.nft
new file mode 100644
index 00000000..d80a4321
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0001set_statements_0.nft
@@ -0,0 +1,12 @@
+table ip testt {
+ set ssh_meter {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ }
+
+ chain testc {
+ type filter hook input priority filter; policy accept;
+ tcp dport 22 ct state new add @ssh_meter { ip saddr limit rate 10/second burst 5 packets } accept
+ }
+}
diff --git a/tests/shell/testcases/json/dumps/0002table_map_0.json-nft b/tests/shell/testcases/json/dumps/0002table_map_0.json-nft
new file mode 100644
index 00000000..78e3c8ad
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0002table_map_0.json-nft
@@ -0,0 +1,33 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "m",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "mark",
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/json/dumps/0002table_map_0.nft b/tests/shell/testcases/json/dumps/0002table_map_0.nft
new file mode 100644
index 00000000..357e92cc
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0002table_map_0.nft
@@ -0,0 +1,6 @@
+table ip t {
+ map m {
+ type ipv4_addr : mark
+ counter
+ }
+}
diff --git a/tests/shell/testcases/json/dumps/0003json_schema_version_0.json-nft b/tests/shell/testcases/json/dumps/0003json_schema_version_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0003json_schema_version_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/json/dumps/0003json_schema_version_0.nft b/tests/shell/testcases/json/dumps/0003json_schema_version_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0003json_schema_version_0.nft
diff --git a/tests/shell/testcases/json/dumps/0004json_schema_version_1.json-nft b/tests/shell/testcases/json/dumps/0004json_schema_version_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0004json_schema_version_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/json/dumps/0004json_schema_version_1.nft b/tests/shell/testcases/json/dumps/0004json_schema_version_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0004json_schema_version_1.nft
diff --git a/tests/shell/testcases/json/dumps/0005secmark_objref_0.json-nft b/tests/shell/testcases/json/dumps/0005secmark_objref_0.json-nft
new file mode 100644
index 00000000..3783c6b7
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0005secmark_objref_0.json-nft
@@ -0,0 +1,233 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -225,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "z",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 225,
+ "policy": "accept"
+ }
+ },
+ {
+ "secmark": {
+ "family": "inet",
+ "name": "ssh_server",
+ "table": "x",
+ "handle": 0,
+ "context": "system_u:object_r:ssh_server_packet_t:s0"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 2222
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "new"
+ }
+ },
+ {
+ "secmark": "ssh_server"
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "new"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "secmark"
+ }
+ },
+ "value": {
+ "meta": {
+ "key": "secmark"
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "established",
+ "related"
+ ]
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "secmark"
+ }
+ },
+ "value": {
+ "ct": {
+ "key": "secmark"
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "new"
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "ct": {
+ "key": "secmark"
+ }
+ },
+ "value": {
+ "meta": {
+ "key": "secmark"
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "established",
+ "related"
+ ]
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "secmark"
+ }
+ },
+ "value": {
+ "ct": {
+ "key": "secmark"
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/json/dumps/0005secmark_objref_0.nft b/tests/shell/testcases/json/dumps/0005secmark_objref_0.nft
new file mode 100644
index 00000000..4c218e93
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0005secmark_objref_0.nft
@@ -0,0 +1,18 @@
+table inet x {
+ secmark ssh_server {
+ "system_u:object_r:ssh_server_packet_t:s0"
+ }
+
+ chain y {
+ type filter hook input priority -225; policy accept;
+ tcp dport 2222 ct state new meta secmark set "ssh_server"
+ ct state new ct secmark set meta secmark
+ ct state established,related meta secmark set ct secmark
+ }
+
+ chain z {
+ type filter hook output priority 225; policy accept;
+ ct state new ct secmark set meta secmark
+ ct state established,related meta secmark set ct secmark
+ }
+}
diff --git a/tests/shell/testcases/json/dumps/0006obj_comment_0.json-nft b/tests/shell/testcases/json/dumps/0006obj_comment_0.json-nft
new file mode 100644
index 00000000..208e13ad
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0006obj_comment_0.json-nft
@@ -0,0 +1,29 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "counter": {
+ "family": "inet",
+ "name": "mycounter",
+ "table": "t",
+ "handle": 0,
+ "comment": "my comment in counter",
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/json/dumps/0006obj_comment_0.nft b/tests/shell/testcases/json/dumps/0006obj_comment_0.nft
new file mode 100644
index 00000000..e52b21b4
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/0006obj_comment_0.nft
@@ -0,0 +1,6 @@
+table inet t {
+ counter mycounter {
+ comment "my comment in counter"
+ packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/json/dumps/netdev.json-nft b/tests/shell/testcases/json/dumps/netdev.json-nft
new file mode 100644
index 00000000..e0d2bfb4
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/netdev.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "netdev",
+ "name": "test_table",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/json/dumps/netdev.nft b/tests/shell/testcases/json/dumps/netdev.nft
new file mode 100644
index 00000000..3c568ed3
--- /dev/null
+++ b/tests/shell/testcases/json/dumps/netdev.nft
@@ -0,0 +1,2 @@
+table netdev test_table {
+}
diff --git a/tests/shell/testcases/json/netdev b/tests/shell/testcases/json/netdev
new file mode 100755
index 00000000..8c16cf42
--- /dev/null
+++ b/tests/shell/testcases/json/netdev
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+set -e
+
+iface_cleanup() {
+ ip link del d0 &>/dev/null || :
+}
+trap 'iface_cleanup' EXIT
+iface_cleanup
+
+ip link add d0 type dummy
+
+$NFT flush ruleset
+$NFT add table inet test
+$NFT add chain inet test c
+
+$NFT flush ruleset
+
+RULESET='{"nftables":[{"flush":{"ruleset":null}},{"add":{"table":{"family":"netdev","name":"test_table"}}},{"add":{"chain":{"family":"netdev","table":"test_table","name":"test_chain","type":"filter","hook":"ingress","prio":0,"dev":"d0","policy":"accept"}}}]}'
+
+if [ "$NFT_TEST_HAVE_json" != n ]; then
+ $NFT -j -f - <<< $RULESET
+fi
+
+if [ "$NFT_TEST_HAVE_json" = n ]; then
+ echo "Test partially skipped due to missing JSON support."
+ exit 77
+fi
diff --git a/tests/shell/testcases/listing/0003table_0 b/tests/shell/testcases/listing/0003table_0
index 1b288e43..5060be01 100755
--- a/tests/shell/testcases/listing/0003table_0
+++ b/tests/shell/testcases/listing/0003table_0
@@ -11,15 +11,13 @@ $NFT add table test
GET="$($NFT list table test)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
# also this way
GET="$($NFT list table ip test)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0004table_0 b/tests/shell/testcases/listing/0004table_0
index 2c7c9952..1d69119f 100755
--- a/tests/shell/testcases/listing/0004table_0
+++ b/tests/shell/testcases/listing/0004table_0
@@ -12,8 +12,7 @@ $NFT add table test2
GET="$($NFT list table test)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0005ruleset_ip_0 b/tests/shell/testcases/listing/0005ruleset_ip_0
index c3266806..39c03282 100755
--- a/tests/shell/testcases/listing/0005ruleset_ip_0
+++ b/tests/shell/testcases/listing/0005ruleset_ip_0
@@ -15,7 +15,6 @@ $NFT add table bridge test
GET="$($NFT list ruleset ip)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0006ruleset_ip6_0 b/tests/shell/testcases/listing/0006ruleset_ip6_0
index 093d5a57..1b67f50c 100755
--- a/tests/shell/testcases/listing/0006ruleset_ip6_0
+++ b/tests/shell/testcases/listing/0006ruleset_ip6_0
@@ -15,7 +15,6 @@ $NFT add table bridge test
GET="$($NFT list ruleset ip6)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0007ruleset_inet_0 b/tests/shell/testcases/listing/0007ruleset_inet_0
index b24cc4c0..257c7a90 100755
--- a/tests/shell/testcases/listing/0007ruleset_inet_0
+++ b/tests/shell/testcases/listing/0007ruleset_inet_0
@@ -15,7 +15,6 @@ $NFT add table bridge test
GET="$($NFT list ruleset inet)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0008ruleset_arp_0 b/tests/shell/testcases/listing/0008ruleset_arp_0
index fff0fee3..be42c478 100755
--- a/tests/shell/testcases/listing/0008ruleset_arp_0
+++ b/tests/shell/testcases/listing/0008ruleset_arp_0
@@ -15,7 +15,6 @@ $NFT add table bridge test
GET="$($NFT list ruleset arp)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0009ruleset_bridge_0 b/tests/shell/testcases/listing/0009ruleset_bridge_0
index 247ed477..c6a99f50 100755
--- a/tests/shell/testcases/listing/0009ruleset_bridge_0
+++ b/tests/shell/testcases/listing/0009ruleset_bridge_0
@@ -15,7 +15,6 @@ $NFT add table bridge test
GET="$($NFT list ruleset bridge)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0010sets_0 b/tests/shell/testcases/listing/0010sets_0
index 855cceb8..0f5f2bd5 100755
--- a/tests/shell/testcases/listing/0010sets_0
+++ b/tests/shell/testcases/listing/0010sets_0
@@ -57,7 +57,6 @@ $NFT add set inet filter set2 { type icmpv6_type \; }
GET="$($NFT list sets)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0011sets_0 b/tests/shell/testcases/listing/0011sets_0
index aac9eac9..b6f12b59 100755
--- a/tests/shell/testcases/listing/0011sets_0
+++ b/tests/shell/testcases/listing/0011sets_0
@@ -38,7 +38,6 @@ $NFT add rule inet filter test tcp dport {80, 443}
GET="$($NFT list sets)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0012sets_0 b/tests/shell/testcases/listing/0012sets_0
index da16d94d..6e4c9590 100755
--- a/tests/shell/testcases/listing/0012sets_0
+++ b/tests/shell/testcases/listing/0012sets_0
@@ -33,7 +33,6 @@ $NFT add set inet filter set2 { type icmpv6_type \; }
GET="$($NFT list sets inet)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0013objects_0 b/tests/shell/testcases/listing/0013objects_0
index f6915796..c78ada94 100755
--- a/tests/shell/testcases/listing/0013objects_0
+++ b/tests/shell/testcases/listing/0013objects_0
@@ -1,48 +1,23 @@
#!/bin/bash
-# list table with all objects and chains
-
-EXPECTED="table ip test {
- quota https-quota {
- 25 mbytes
- }
-
- ct helper cthelp {
- type \"sip\" protocol tcp
- l3proto ip
- }
-
- ct timeout cttime {
- protocol udp
- l3proto ip
- policy = { unreplied : 15, replied : 12 }
- }
-
- ct expectation ctexpect {
- protocol tcp
- dport 5432
- timeout 1h
- size 12
- l3proto ip
- }
-
- chain input {
- }
-}"
-
set -e
$NFT add table test
$NFT add chain test input
$NFT add quota test https-quota 25 mbytes
$NFT add ct helper test cthelp { type \"sip\" protocol tcp \; }
-$NFT add ct timeout test cttime { protocol udp \; policy = {replied : 12, unreplied : 15 } \; }
-$NFT add ct expectation test ctexpect { protocol tcp \; dport 5432 \; timeout 1h \; size 12 \; }
-$NFT add table test-ip
+if [ "$NFT_TEST_HAVE_cttimeout" != n ] ; then
+ $NFT add ct timeout test cttime { protocol udp \; policy = {replied : 12, unreplied : 15 } \; }
+fi
+if [ "$NFT_TEST_HAVE_ctexpect" != n ] ; then
+ $NFT add ct expectation test ctexpect { protocol tcp \; dport 5432 \; timeout 1h \; size 12 \; }
+fi
-GET="$($NFT list table test)"
-if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
- exit 1
+if [ "$NFT_TEST_HAVE_cttimeout" = n ] ; then
+ echo "Ran partial test due to NFT_TEST_HAVE_cttimeout=n (skipped)"
+ exit 77
+fi
+if [ "$NFT_TEST_HAVE_ctexpect" = n ] ; then
+ echo "Ran partial test due to NFT_TEST_HAVE_ctexpect=n (skipped)"
+ exit 77
fi
diff --git a/tests/shell/testcases/listing/0014objects_0 b/tests/shell/testcases/listing/0014objects_0
index 20f68406..31d94f86 100755
--- a/tests/shell/testcases/listing/0014objects_0
+++ b/tests/shell/testcases/listing/0014objects_0
@@ -17,15 +17,13 @@ $NFT add table test-ip
GET="$($NFT list quotas)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
GET="$($NFT list quota test https-quota)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0015dynamic_0 b/tests/shell/testcases/listing/0015dynamic_0
index 4ff74e32..65fbe62c 100755
--- a/tests/shell/testcases/listing/0015dynamic_0
+++ b/tests/shell/testcases/listing/0015dynamic_0
@@ -16,8 +16,7 @@ $NFT -f - <<< "$EXPECTED"
GET="$($NFT list set ip filter test_set)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0017objects_0 b/tests/shell/testcases/listing/0017objects_0
index 8a586e80..c4e72db0 100755
--- a/tests/shell/testcases/listing/0017objects_0
+++ b/tests/shell/testcases/listing/0017objects_0
@@ -13,7 +13,6 @@ $NFT flush map inet filter countermap
GET="$($NFT list map inet filter countermap)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0018data_0 b/tests/shell/testcases/listing/0018data_0
index 544b6bf5..4af253dc 100755
--- a/tests/shell/testcases/listing/0018data_0
+++ b/tests/shell/testcases/listing/0018data_0
@@ -13,7 +13,6 @@ $NFT flush map inet filter ipmap
GET="$($NFT list map inet filter ipmap)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0019set_0 b/tests/shell/testcases/listing/0019set_0
index 54a8a064..6e8cb4d6 100755
--- a/tests/shell/testcases/listing/0019set_0
+++ b/tests/shell/testcases/listing/0019set_0
@@ -13,7 +13,6 @@ $NFT flush set inet filter ipset
GET="$($NFT list set inet filter ipset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/listing/0020flowtable_0 b/tests/shell/testcases/listing/0020flowtable_0
new file mode 100755
index 00000000..0e89f5dd
--- /dev/null
+++ b/tests/shell/testcases/listing/0020flowtable_0
@@ -0,0 +1,65 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_flowtable_no_devices)
+
+# list only the flowtable asked for with table
+
+set -e
+
+FLOWTABLES="flowtable f {
+ hook ingress priority filter
+ devices = { lo }
+}
+flowtable f2 {
+ hook ingress priority filter
+ devices = { d0 }
+}"
+
+RULESET="table inet filter {
+ $FLOWTABLES
+}
+table ip filter {
+ $FLOWTABLES
+}"
+
+EXPECTED="table inet filter {
+ flowtable f {
+ hook ingress priority filter
+ devices = { lo }
+ }
+}"
+EXPECTED2="table ip filter {
+ flowtable f2 {
+ hook ingress priority filter
+ devices = { d0 }
+ }
+}"
+EXPECTED3="table ip filter {
+ flowtable f {
+ hook ingress priority filter
+ devices = { lo }
+ }
+ flowtable f2 {
+ hook ingress priority filter
+ devices = { d0 }
+ }
+}"
+
+iface_cleanup() {
+ ip link del d0 &>/dev/null || :
+}
+trap 'iface_cleanup' EXIT
+iface_cleanup
+
+ip link add d0 type dummy
+
+$NFT -f - <<< "$RULESET"
+
+GET="$($NFT list flowtable inet filter f)"
+$DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+
+GET="$($NFT list flowtable ip filter f2)"
+$DIFF -u <(echo "$EXPECTED2") <(echo "$GET")
+
+GET="$($NFT list flowtables ip)"
+$DIFF -u <(echo "$EXPECTED3") <(echo "$GET")
diff --git a/tests/shell/testcases/listing/0021ruleset_json_terse_0 b/tests/shell/testcases/listing/0021ruleset_json_terse_0
new file mode 100755
index 00000000..98a7ce8a
--- /dev/null
+++ b/tests/shell/testcases/listing/0021ruleset_json_terse_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+$NFT flush ruleset
+$NFT add table ip test
+$NFT add chain ip test c
+$NFT add set ip test s { type ipv4_addr\; }
+$NFT add element ip test s { 192.168.3.4, 192.168.3.5 }
+
+if [ "$NFT_TEST_HAVE_json" != n ]; then
+ if $NFT -j -t list ruleset | grep '192\.168'
+ then
+ exit 1
+ fi
+fi
+
+if [ "$NFT_TEST_HAVE_json" = n ]; then
+ echo "Test partially skipped due to missing JSON support."
+ exit 77
+fi
diff --git a/tests/shell/testcases/listing/0022terse_0 b/tests/shell/testcases/listing/0022terse_0
new file mode 100755
index 00000000..4841771c
--- /dev/null
+++ b/tests/shell/testcases/listing/0022terse_0
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+RULESET="table inet filter {
+ set example {
+ type ipv4_addr
+ flags interval
+ elements = { 10.10.10.10, 10.10.11.11 }
+ }
+
+ chain input {
+ type filter hook prerouting priority filter; policy accept;
+ ip saddr != { 10.10.10.100, 10.10.10.111 } ip saddr @example drop
+ }
+}"
+
+set -e
+
+$NFT -f - <<< "$RULESET"
+
+GET="$($NFT list ruleset)"
+if [ "$RULESET" != "$GET" ] ; then
+ $DIFF -u <(echo "$RULESET") <(echo "$GET")
+ exit 1
+fi
+
+EXPECTED="table inet filter {
+ set example {
+ type ipv4_addr
+ flags interval
+ }
+
+ chain input {
+ type filter hook prerouting priority filter; policy accept;
+ ip saddr != { 10.10.10.100, 10.10.10.111 } ip saddr @example drop
+ }
+}"
+
+GET="$($NFT -t list ruleset)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
+
+EXPECTED="table inet filter {
+ set example {
+ type ipv4_addr
+ flags interval
+ elements = { 10.10.10.10, 10.10.11.11 }
+ }
+}"
+
+GET="$($NFT list set inet filter example)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
+
+EXPECTED="table inet filter {
+ set example {
+ type ipv4_addr
+ flags interval
+ }
+}"
+
+GET="$($NFT -t list set inet filter example)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/listing/dumps/0001ruleset_0.json-nft b/tests/shell/testcases/listing/dumps/0001ruleset_0.json-nft
new file mode 100644
index 00000000..1bb0e1b8
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0001ruleset_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0002ruleset_0.json-nft b/tests/shell/testcases/listing/dumps/0002ruleset_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0002ruleset_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0002ruleset_0.nft b/tests/shell/testcases/listing/dumps/0002ruleset_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0002ruleset_0.nft
diff --git a/tests/shell/testcases/listing/dumps/0003table_0.json-nft b/tests/shell/testcases/listing/dumps/0003table_0.json-nft
new file mode 100644
index 00000000..1bb0e1b8
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0003table_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0003table_0.nft b/tests/shell/testcases/listing/dumps/0003table_0.nft
new file mode 100644
index 00000000..1c9f40c5
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0003table_0.nft
@@ -0,0 +1,2 @@
+table ip test {
+}
diff --git a/tests/shell/testcases/listing/dumps/0004table_0.json-nft b/tests/shell/testcases/listing/dumps/0004table_0.json-nft
new file mode 100644
index 00000000..85e9b287
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0004table_0.json-nft
@@ -0,0 +1,25 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test2",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0004table_0.nft b/tests/shell/testcases/listing/dumps/0004table_0.nft
new file mode 100644
index 00000000..56d035d1
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0004table_0.nft
@@ -0,0 +1,4 @@
+table ip test {
+}
+table ip test2 {
+}
diff --git a/tests/shell/testcases/listing/dumps/0005ruleset_ip_0.json-nft b/tests/shell/testcases/listing/dumps/0005ruleset_ip_0.json-nft
new file mode 100644
index 00000000..ffd657e5
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0005ruleset_ip_0.json-nft
@@ -0,0 +1,46 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "arp",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "test",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0005ruleset_ip_0.nft b/tests/shell/testcases/listing/dumps/0005ruleset_ip_0.nft
new file mode 100644
index 00000000..c37261b3
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0005ruleset_ip_0.nft
@@ -0,0 +1,10 @@
+table ip test {
+}
+table ip6 test {
+}
+table inet test {
+}
+table arp test {
+}
+table bridge test {
+}
diff --git a/tests/shell/testcases/listing/dumps/0006ruleset_ip6_0.json-nft b/tests/shell/testcases/listing/dumps/0006ruleset_ip6_0.json-nft
new file mode 100644
index 00000000..ffd657e5
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0006ruleset_ip6_0.json-nft
@@ -0,0 +1,46 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "arp",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "test",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0006ruleset_ip6_0.nft b/tests/shell/testcases/listing/dumps/0006ruleset_ip6_0.nft
new file mode 100644
index 00000000..c37261b3
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0006ruleset_ip6_0.nft
@@ -0,0 +1,10 @@
+table ip test {
+}
+table ip6 test {
+}
+table inet test {
+}
+table arp test {
+}
+table bridge test {
+}
diff --git a/tests/shell/testcases/listing/dumps/0007ruleset_inet_0.json-nft b/tests/shell/testcases/listing/dumps/0007ruleset_inet_0.json-nft
new file mode 100644
index 00000000..ffd657e5
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0007ruleset_inet_0.json-nft
@@ -0,0 +1,46 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "arp",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "test",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0007ruleset_inet_0.nft b/tests/shell/testcases/listing/dumps/0007ruleset_inet_0.nft
new file mode 100644
index 00000000..c37261b3
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0007ruleset_inet_0.nft
@@ -0,0 +1,10 @@
+table ip test {
+}
+table ip6 test {
+}
+table inet test {
+}
+table arp test {
+}
+table bridge test {
+}
diff --git a/tests/shell/testcases/listing/dumps/0008ruleset_arp_0.json-nft b/tests/shell/testcases/listing/dumps/0008ruleset_arp_0.json-nft
new file mode 100644
index 00000000..ffd657e5
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0008ruleset_arp_0.json-nft
@@ -0,0 +1,46 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "arp",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "test",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0008ruleset_arp_0.nft b/tests/shell/testcases/listing/dumps/0008ruleset_arp_0.nft
new file mode 100644
index 00000000..c37261b3
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0008ruleset_arp_0.nft
@@ -0,0 +1,10 @@
+table ip test {
+}
+table ip6 test {
+}
+table inet test {
+}
+table arp test {
+}
+table bridge test {
+}
diff --git a/tests/shell/testcases/listing/dumps/0009ruleset_bridge_0.json-nft b/tests/shell/testcases/listing/dumps/0009ruleset_bridge_0.json-nft
new file mode 100644
index 00000000..ffd657e5
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0009ruleset_bridge_0.json-nft
@@ -0,0 +1,46 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "arp",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "test",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0009ruleset_bridge_0.nft b/tests/shell/testcases/listing/dumps/0009ruleset_bridge_0.nft
new file mode 100644
index 00000000..c37261b3
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0009ruleset_bridge_0.nft
@@ -0,0 +1,10 @@
+table ip test {
+}
+table ip6 test {
+}
+table inet test {
+}
+table arp test {
+}
+table bridge test {
+}
diff --git a/tests/shell/testcases/listing/dumps/0010sets_0.json-nft b/tests/shell/testcases/listing/dumps/0010sets_0.json-nft
new file mode 100644
index 00000000..efca892e
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0010sets_0.json-nft
@@ -0,0 +1,124 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "nat",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "ssh",
+ "table": "nat",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip6",
+ "name": "testset",
+ "table": "test",
+ "type": "ipv6_addr",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "arp",
+ "name": "test_arp",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "arp",
+ "name": "test_set_arp00",
+ "table": "test_arp",
+ "type": "inet_service",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "arp",
+ "name": "test_set_arp01",
+ "table": "test_arp",
+ "type": "inet_service",
+ "handle": 0,
+ "flags": [
+ "constant"
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "test_bridge",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "bridge",
+ "name": "test_set_bridge",
+ "table": "test_bridge",
+ "type": "inet_service",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "set0",
+ "table": "filter",
+ "type": "inet_service",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "set1",
+ "table": "filter",
+ "type": "inet_service",
+ "handle": 0,
+ "flags": [
+ "constant"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "set2",
+ "table": "filter",
+ "type": "icmpv6_type",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0010sets_0.nft b/tests/shell/testcases/listing/dumps/0010sets_0.nft
new file mode 100644
index 00000000..7303c403
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0010sets_0.nft
@@ -0,0 +1,39 @@
+table ip nat {
+ set ssh {
+ type ipv4_addr
+ }
+}
+table ip6 test {
+ set testset {
+ type ipv6_addr
+ }
+}
+table arp test_arp {
+ set test_set_arp00 {
+ type inet_service
+ }
+
+ set test_set_arp01 {
+ type inet_service
+ flags constant
+ }
+}
+table bridge test_bridge {
+ set test_set_bridge {
+ type inet_service
+ }
+}
+table inet filter {
+ set set0 {
+ type inet_service
+ }
+
+ set set1 {
+ type inet_service
+ flags constant
+ }
+
+ set set2 {
+ type icmpv6_type
+ }
+}
diff --git a/tests/shell/testcases/listing/dumps/0011sets_0.json-nft b/tests/shell/testcases/listing/dumps/0011sets_0.json-nft
new file mode 100644
index 00000000..a742fa45
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0011sets_0.json-nft
@@ -0,0 +1,220 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "nat",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "nat",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "nat",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 123,
+ 321
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "test",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "sport"
+ }
+ },
+ "right": {
+ "set": [
+ 123,
+ 321
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "arp",
+ "name": "test_arp",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "arp",
+ "table": "test_arp",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "arp",
+ "table": "test_arp",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "right": {
+ "set": [
+ 123,
+ 321
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "test_bridge",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "test_bridge",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "bridge",
+ "table": "test_bridge",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "set": [
+ "1.1.1.1",
+ "2.2.2.2"
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 80,
+ 443
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0011sets_0.nft b/tests/shell/testcases/listing/dumps/0011sets_0.nft
new file mode 100644
index 00000000..4d0aeaf3
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0011sets_0.nft
@@ -0,0 +1,25 @@
+table ip nat {
+ chain test {
+ tcp dport { 123, 321 }
+ }
+}
+table ip6 test {
+ chain test {
+ udp sport { 123, 321 }
+ }
+}
+table arp test_arp {
+ chain test {
+ meta mark { 0x0000007b, 0x00000141 }
+ }
+}
+table bridge test_bridge {
+ chain test {
+ ip daddr { 1.1.1.1, 2.2.2.2 }
+ }
+}
+table inet filter {
+ chain test {
+ tcp dport { 80, 443 }
+ }
+}
diff --git a/tests/shell/testcases/listing/dumps/0012sets_0.json-nft b/tests/shell/testcases/listing/dumps/0012sets_0.json-nft
new file mode 100644
index 00000000..efca892e
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0012sets_0.json-nft
@@ -0,0 +1,124 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "nat",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "ssh",
+ "table": "nat",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip6",
+ "name": "testset",
+ "table": "test",
+ "type": "ipv6_addr",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "arp",
+ "name": "test_arp",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "arp",
+ "name": "test_set_arp00",
+ "table": "test_arp",
+ "type": "inet_service",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "arp",
+ "name": "test_set_arp01",
+ "table": "test_arp",
+ "type": "inet_service",
+ "handle": 0,
+ "flags": [
+ "constant"
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "test_bridge",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "bridge",
+ "name": "test_set_bridge",
+ "table": "test_bridge",
+ "type": "inet_service",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "set0",
+ "table": "filter",
+ "type": "inet_service",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "set1",
+ "table": "filter",
+ "type": "inet_service",
+ "handle": 0,
+ "flags": [
+ "constant"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "set2",
+ "table": "filter",
+ "type": "icmpv6_type",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0012sets_0.nft b/tests/shell/testcases/listing/dumps/0012sets_0.nft
new file mode 100644
index 00000000..7303c403
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0012sets_0.nft
@@ -0,0 +1,39 @@
+table ip nat {
+ set ssh {
+ type ipv4_addr
+ }
+}
+table ip6 test {
+ set testset {
+ type ipv6_addr
+ }
+}
+table arp test_arp {
+ set test_set_arp00 {
+ type inet_service
+ }
+
+ set test_set_arp01 {
+ type inet_service
+ flags constant
+ }
+}
+table bridge test_bridge {
+ set test_set_bridge {
+ type inet_service
+ }
+}
+table inet filter {
+ set set0 {
+ type inet_service
+ }
+
+ set set1 {
+ type inet_service
+ flags constant
+ }
+
+ set set2 {
+ type icmpv6_type
+ }
+}
diff --git a/tests/shell/testcases/listing/dumps/0013objects_0.json-nft b/tests/shell/testcases/listing/dumps/0013objects_0.json-nft
new file mode 100644
index 00000000..830aad85
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0013objects_0.json-nft
@@ -0,0 +1,75 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test",
+ "name": "input",
+ "handle": 0
+ }
+ },
+ {
+ "quota": {
+ "family": "ip",
+ "name": "https-quota",
+ "table": "test",
+ "handle": 0,
+ "bytes": 26214400,
+ "used": 0,
+ "inv": false
+ }
+ },
+ {
+ "ct helper": {
+ "family": "ip",
+ "name": "cthelp",
+ "table": "test",
+ "handle": 0,
+ "type": "sip",
+ "protocol": "tcp",
+ "l3proto": "ip"
+ }
+ },
+ {
+ "ct timeout": {
+ "family": "ip",
+ "name": "cttime",
+ "table": "test",
+ "handle": 0,
+ "protocol": "udp",
+ "l3proto": "ip",
+ "policy": {
+ "unreplied": 15,
+ "replied": 12
+ }
+ }
+ },
+ {
+ "ct expectation": {
+ "family": "ip",
+ "name": "ctexpect",
+ "table": "test",
+ "handle": 0,
+ "protocol": "tcp",
+ "dport": 5432,
+ "timeout": 3600000,
+ "size": 12,
+ "l3proto": "ip"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0013objects_0.nft b/tests/shell/testcases/listing/dumps/0013objects_0.nft
new file mode 100644
index 00000000..427db268
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0013objects_0.nft
@@ -0,0 +1,27 @@
+table ip test {
+ quota https-quota {
+ 25 mbytes
+ }
+
+ ct helper cthelp {
+ type "sip" protocol tcp
+ l3proto ip
+ }
+
+ ct timeout cttime {
+ protocol udp
+ l3proto ip
+ policy = { unreplied : 15s, replied : 12s }
+ }
+
+ ct expectation ctexpect {
+ protocol tcp
+ dport 5432
+ timeout 1h
+ size 12
+ l3proto ip
+ }
+
+ chain input {
+ }
+}
diff --git a/tests/shell/testcases/listing/dumps/0014objects_0.json-nft b/tests/shell/testcases/listing/dumps/0014objects_0.json-nft
new file mode 100644
index 00000000..83f72d40
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0014objects_0.json-nft
@@ -0,0 +1,47 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "quota": {
+ "family": "ip",
+ "name": "https-quota",
+ "table": "test",
+ "handle": 0,
+ "bytes": 26214400,
+ "used": 0,
+ "inv": false
+ }
+ },
+ {
+ "ct helper": {
+ "family": "ip",
+ "name": "cthelp",
+ "table": "test",
+ "handle": 0,
+ "type": "sip",
+ "protocol": "tcp",
+ "l3proto": "ip"
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test-ip",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0014objects_0.nft b/tests/shell/testcases/listing/dumps/0014objects_0.nft
new file mode 100644
index 00000000..9281a1a0
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0014objects_0.nft
@@ -0,0 +1,12 @@
+table ip test {
+ quota https-quota {
+ 25 mbytes
+ }
+
+ ct helper cthelp {
+ type "sip" protocol tcp
+ l3proto ip
+ }
+}
+table ip test-ip {
+}
diff --git a/tests/shell/testcases/listing/dumps/0015dynamic_0.json-nft b/tests/shell/testcases/listing/dumps/0015dynamic_0.json-nft
new file mode 100644
index 00000000..a94a1b04
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0015dynamic_0.json-nft
@@ -0,0 +1,38 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "test_set",
+ "table": "filter",
+ "type": [
+ "ipv4_addr",
+ "inet_service",
+ "ipv4_addr",
+ "inet_service",
+ "inet_proto"
+ ],
+ "handle": 0,
+ "size": 100000,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0015dynamic_0.nft b/tests/shell/testcases/listing/dumps/0015dynamic_0.nft
new file mode 100644
index 00000000..0f4244bf
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0015dynamic_0.nft
@@ -0,0 +1,7 @@
+table ip filter {
+ set test_set {
+ type ipv4_addr . inet_service . ipv4_addr . inet_service . inet_proto
+ size 100000
+ flags dynamic,timeout
+ }
+}
diff --git a/tests/shell/testcases/listing/dumps/0016anonymous_0.json-nft b/tests/shell/testcases/listing/dumps/0016anonymous_0.json-nft
new file mode 100644
index 00000000..e47ccb8e
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0016anonymous_0.json-nft
@@ -0,0 +1,85 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "1.1.1.1"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ 2
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0016anonymous_0.nft b/tests/shell/testcases/listing/dumps/0016anonymous_0.nft
new file mode 100644
index 00000000..cb089337
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0016anonymous_0.nft
@@ -0,0 +1,6 @@
+table ip x {
+ chain y {
+ ip saddr 1.1.1.1
+ meta mark set ip saddr map { 1.1.1.1 : 0x00000002 }
+ }
+}
diff --git a/tests/shell/testcases/listing/dumps/0017objects_0.json-nft b/tests/shell/testcases/listing/dumps/0017objects_0.json-nft
new file mode 100644
index 00000000..d735f7a1
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0017objects_0.json-nft
@@ -0,0 +1,28 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "countermap",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "counter"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0017objects_0.nft b/tests/shell/testcases/listing/dumps/0017objects_0.nft
new file mode 100644
index 00000000..e60e3afa
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0017objects_0.nft
@@ -0,0 +1,5 @@
+table inet filter {
+ map countermap {
+ type ipv4_addr : counter
+ }
+}
diff --git a/tests/shell/testcases/listing/dumps/0018data_0.json-nft b/tests/shell/testcases/listing/dumps/0018data_0.json-nft
new file mode 100644
index 00000000..211dcd30
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0018data_0.json-nft
@@ -0,0 +1,28 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "ipmap",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "ipv4_addr"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0018data_0.nft b/tests/shell/testcases/listing/dumps/0018data_0.nft
new file mode 100644
index 00000000..5d318550
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0018data_0.nft
@@ -0,0 +1,5 @@
+table inet filter {
+ map ipmap {
+ type ipv4_addr : ipv4_addr
+ }
+}
diff --git a/tests/shell/testcases/listing/dumps/0019set_0.json-nft b/tests/shell/testcases/listing/dumps/0019set_0.json-nft
new file mode 100644
index 00000000..3bb7cb8a
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0019set_0.json-nft
@@ -0,0 +1,27 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "ipset",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0019set_0.nft b/tests/shell/testcases/listing/dumps/0019set_0.nft
new file mode 100644
index 00000000..915922ca
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0019set_0.nft
@@ -0,0 +1,5 @@
+table inet filter {
+ set ipset {
+ type ipv4_addr
+ }
+}
diff --git a/tests/shell/testcases/listing/dumps/0020flowtable_0.json-nft b/tests/shell/testcases/listing/dumps/0020flowtable_0.json-nft
new file mode 100644
index 00000000..d511739a
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0020flowtable_0.json-nft
@@ -0,0 +1,67 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "flowtable": {
+ "family": "inet",
+ "name": "f",
+ "table": "filter",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": 0,
+ "dev": "lo"
+ }
+ },
+ {
+ "flowtable": {
+ "family": "inet",
+ "name": "f2",
+ "table": "filter",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "flowtable": {
+ "family": "ip",
+ "name": "f",
+ "table": "filter",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": 0,
+ "dev": "lo"
+ }
+ },
+ {
+ "flowtable": {
+ "family": "ip",
+ "name": "f2",
+ "table": "filter",
+ "handle": 0,
+ "hook": "ingress",
+ "prio": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0020flowtable_0.nft b/tests/shell/testcases/listing/dumps/0020flowtable_0.nft
new file mode 100644
index 00000000..4a64e531
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0020flowtable_0.nft
@@ -0,0 +1,20 @@
+table inet filter {
+ flowtable f {
+ hook ingress priority filter
+ devices = { lo }
+ }
+
+ flowtable f2 {
+ hook ingress priority filter
+ }
+}
+table ip filter {
+ flowtable f {
+ hook ingress priority filter
+ devices = { lo }
+ }
+
+ flowtable f2 {
+ hook ingress priority filter
+ }
+}
diff --git a/tests/shell/testcases/listing/dumps/0021ruleset_json_terse_0.json-nft b/tests/shell/testcases/listing/dumps/0021ruleset_json_terse_0.json-nft
new file mode 100644
index 00000000..d1131bb4
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0021ruleset_json_terse_0.json-nft
@@ -0,0 +1,39 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "test",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "192.168.3.4",
+ "192.168.3.5"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0021ruleset_json_terse_0.nft b/tests/shell/testcases/listing/dumps/0021ruleset_json_terse_0.nft
new file mode 100644
index 00000000..13c8ac63
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0021ruleset_json_terse_0.nft
@@ -0,0 +1,9 @@
+table ip test {
+ set s {
+ type ipv4_addr
+ elements = { 192.168.3.4, 192.168.3.5 }
+ }
+
+ chain c {
+ }
+}
diff --git a/tests/shell/testcases/listing/dumps/0022terse_0.json-nft b/tests/shell/testcases/listing/dumps/0022terse_0.json-nft
new file mode 100644
index 00000000..bd6383da
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0022terse_0.json-nft
@@ -0,0 +1,88 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "example",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ "10.10.10.10",
+ "10.10.11.11"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "!=",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": {
+ "set": [
+ "10.10.10.100",
+ "10.10.10.111"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@example"
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/listing/dumps/0022terse_0.nft b/tests/shell/testcases/listing/dumps/0022terse_0.nft
new file mode 100644
index 00000000..40665cb7
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/0022terse_0.nft
@@ -0,0 +1,12 @@
+table inet filter {
+ set example {
+ type ipv4_addr
+ flags interval
+ elements = { 10.10.10.10, 10.10.11.11 }
+ }
+
+ chain input {
+ type filter hook prerouting priority filter; policy accept;
+ ip saddr != { 10.10.10.100, 10.10.10.111 } ip saddr @example drop
+ }
+}
diff --git a/tests/shell/testcases/listing/dumps/meta_time.nodump b/tests/shell/testcases/listing/dumps/meta_time.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/meta_time.nodump
diff --git a/tests/shell/testcases/listing/meta_time b/tests/shell/testcases/listing/meta_time
new file mode 100755
index 00000000..96a9d557
--- /dev/null
+++ b/tests/shell/testcases/listing/meta_time
@@ -0,0 +1,67 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_meta_time)
+
+set -e
+
+TMP1=$(mktemp)
+TMP2=$(mktemp)
+
+cleanup()
+{
+ rm -f "$TMP1"
+ rm -f "$TMP2"
+}
+
+check_decode()
+{
+ TZ=$1 $NFT list chain t c | grep meta > "$TMP2"
+ diff -u "$TMP1" "$TMP2"
+}
+
+trap cleanup EXIT
+
+$NFT -f - <<EOF
+table t {
+ chain c {
+ }
+}
+EOF
+
+for i in $(seq -w 0 23); do
+ TZ=UTC $NFT add rule t c meta hour "$i:00"-"$i:59"
+done
+
+# Check decoding in UTC, this mirrors 1:1 what should have been added.
+for i in $(seq 0 23); do
+ printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" $i 0 $i 59 >> "$TMP1"
+done
+
+check_decode UTC
+
+printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" 23 0 23 59 > "$TMP1"
+for i in $(seq 0 22); do
+ printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" $i 0 $i 59 >> "$TMP1"
+done
+check_decode UTC+1
+
+printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" 1 0 1 59 > "$TMP1"
+for i in $(seq 2 23); do
+ printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" $i 0 $i 59 >> "$TMP1"
+done
+printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" 0 0 0 59 >> "$TMP1"
+
+check_decode UTC-1
+
+$NFT flush chain t c
+TZ=EADT $NFT add rule t c meta hour "03:00"-"14:00"
+TZ=EADT $NFT add rule t c meta hour "04:00"-"15:00"
+TZ=EADT $NFT add rule t c meta hour "05:00"-"16:00"
+TZ=EADT $NFT add rule t c meta hour "06:00"-"17:00"
+
+printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" 3 0 14 0 > "$TMP1"
+printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" 4 0 15 0 >> "$TMP1"
+printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" 5 0 16 0 >> "$TMP1"
+printf "\t\tmeta hour \"%02d:%02d\"-\"%02d:%02d\"\n" 6 0 17 0 >> "$TMP1"
+
+check_decode EADT
diff --git a/tests/shell/testcases/maps/0003map_add_many_elements_0 b/tests/shell/testcases/maps/0003map_add_many_elements_0
index 047f9497..2b254c51 100755
--- a/tests/shell/testcases/maps/0003map_add_many_elements_0
+++ b/tests/shell/testcases/maps/0003map_add_many_elements_0
@@ -61,8 +61,7 @@ EXPECTED="table ip x {
}"
GET=$($NFT list ruleset)
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/maps/0004interval_map_create_once_0 b/tests/shell/testcases/maps/0004interval_map_create_once_0
index 58b399c1..64f434ad 100755
--- a/tests/shell/testcases/maps/0004interval_map_create_once_0
+++ b/tests/shell/testcases/maps/0004interval_map_create_once_0
@@ -5,6 +5,10 @@
HOWMANY=63
+if [ "$NFT_TEST_SKIP_slow" = y ] ; then
+ HOWMANY=5
+fi
+
tmpfile=$(mktemp)
if [ ! -w $tmpfile ] ; then
echo "Failed to create tmp file" >&2
@@ -60,8 +64,11 @@ EXPECTED="table ip x {
}"
GET=$($NFT list ruleset)
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
+if [ "$HOWMANY" != 63 ] ; then
+ echo "Run a partial test due to NFT_TEST_SKIP_slow=y. Skip"
+ exit 77
+fi
diff --git a/tests/shell/testcases/maps/0008interval_map_delete_0 b/tests/shell/testcases/maps/0008interval_map_delete_0
index a43fd280..39ea3127 100755
--- a/tests/shell/testcases/maps/0008interval_map_delete_0
+++ b/tests/shell/testcases/maps/0008interval_map_delete_0
@@ -24,9 +24,8 @@ $NFT delete element filter m { 127.0.0.3 }
$NFT add element filter m { 127.0.0.3 : 0x3 }
$NFT add element filter m { 127.0.0.2 : 0x2 }
-GET=$($NFT list ruleset -s)
+GET=$($NFT -s list ruleset)
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/maps/0009vmap_0 b/tests/shell/testcases/maps/0009vmap_0
new file mode 100755
index 00000000..4e133b72
--- /dev/null
+++ b/tests/shell/testcases/maps/0009vmap_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
+set -e
+
+EXPECTED="table inet filter {
+ chain ssh_input {
+ }
+
+ chain wan_input {
+ tcp dport vmap { 22 : jump ssh_input }
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority -300; policy accept;
+ iif vmap { "lo" counter : jump wan_input }
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/maps/0010concat_map_0 b/tests/shell/testcases/maps/0010concat_map_0
new file mode 100755
index 00000000..859bbfcf
--- /dev/null
+++ b/tests/shell/testcases/maps/0010concat_map_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_inet_nat)
+
+set -e
+
+EXPECTED="table inet x {
+ map z {
+ type ipv4_addr . inet_proto . inet_service : ipv4_addr . inet_service
+ elements = {
+ 1.1.1.1 . tcp . 20 : 2.2.2.2 . 30
+ }
+ }
+
+ chain y {
+ type nat hook prerouting priority dstnat;
+ dnat ip addr . port to ip saddr . ip protocol . tcp dport map @z
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/maps/0011vmap_0 b/tests/shell/testcases/maps/0011vmap_0
new file mode 100755
index 00000000..3e6fa78d
--- /dev/null
+++ b/tests/shell/testcases/maps/0011vmap_0
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="table inet filter {
+ map portmap {
+ type inet_service : verdict
+ counter
+ }
+
+ chain ssh_input {
+ }
+
+ chain wan_input {
+ tcp dport vmap @portmap
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority -300; policy accept;
+ iif vmap { "lo" : jump wan_input }
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
+
+if [ "$NFT_TEST_HAVE_catchall_element" != n ]; then
+ $NFT 'add element inet filter portmap { 22 : jump ssh_input, * : drop }'
+fi
+
+if [ "$NFT_TEST_HAVE_catchall_element" = n ]; then
+ echo "Ran partial tests due to NFT_TEST_HAVE_catchall_element=n (skipped)"
+ exit 77
+fi
diff --git a/tests/shell/testcases/maps/0012map_0 b/tests/shell/testcases/maps/0012map_0
new file mode 100755
index 00000000..dd93c482
--- /dev/null
+++ b/tests/shell/testcases/maps/0012map_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="define interfaces = { eth0, eth1 }
+
+table ip x {
+ map z {
+ type ifname : verdict
+ elements = { \$interfaces : drop, lo : accept }
+ }
+ chain y {
+ iifname vmap { lo : accept, \$interfaces : drop }
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/maps/0012map_concat_0 b/tests/shell/testcases/maps/0012map_concat_0
new file mode 100755
index 00000000..d18c7a73
--- /dev/null
+++ b/tests/shell/testcases/maps/0012map_concat_0
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+
+EXPECTED="table ip x {
+ map w {
+ typeof ip saddr . meta mark : verdict
+ flags interval
+ counter
+ elements = {
+ 127.0.0.1-127.0.0.4 . 0x123434-0xb00122 : accept,
+ }
+ }
+
+ chain k {
+ type filter hook input priority filter + 1; policy accept;
+ meta mark set 0x123434
+ ip saddr . meta mark vmap @w
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/maps/0013map_0 b/tests/shell/testcases/maps/0013map_0
new file mode 100755
index 00000000..c8d20cee
--- /dev/null
+++ b/tests/shell/testcases/maps/0013map_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+
+RULESET="
+flush ruleset
+
+add table ip filter
+add chain ip filter FORWARD { type filter hook forward priority 0; policy drop; }
+add map ip filter forwport { type ipv4_addr . inet_proto . inet_service: verdict; flags interval; counter; }
+add rule ip filter FORWARD iifname enp0s8 ip daddr . ip protocol . th dport vmap @forwport counter
+add element ip filter forwport { 10.133.89.138 . tcp . 8081: accept }"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/maps/0014destroy_0 b/tests/shell/testcases/maps/0014destroy_0
new file mode 100755
index 00000000..ee81e3cd
--- /dev/null
+++ b/tests/shell/testcases/maps/0014destroy_0
@@ -0,0 +1,12 @@
+#!/bin/bash -e
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_destroy)
+
+$NFT add table x
+
+# pass for non-existent map
+$NFT destroy map x y
+
+# successfully delete existing map
+$NFT add map x y '{ type ipv4_addr : ipv4_addr; }'
+$NFT destroy map x y
diff --git a/tests/shell/testcases/maps/0016map_leak_0 b/tests/shell/testcases/maps/0016map_leak_0
new file mode 100755
index 00000000..e110ee4b
--- /dev/null
+++ b/tests/shell/testcases/maps/0016map_leak_0
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip t {
+ map sourcemap {
+ type ipv4_addr : verdict
+ elements = { 100.123.10.2 : jump c }
+ }
+
+ chain c {
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+# again, since it is addition, not creation, it is successful
+$NFT -f - <<< "$RULESET"
+# flush it to check for refcount leak
+$NFT flush ruleset
+
+#
+# again with stateful objects
+#
+
+RULESET="table ip t {
+ counter c {}
+
+ map sourcemap {
+ type ipv4_addr : counter
+ elements = { 100.123.10.2 : \"c\" }
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+# again, since it is addition, not creation, it is successful
+$NFT -f - <<< "$RULESET"
+# flush it to check for refcount leak
+$NFT flush ruleset
diff --git a/tests/shell/testcases/maps/0017_map_variable_0 b/tests/shell/testcases/maps/0017_map_variable_0
new file mode 100755
index 00000000..e01adb4c
--- /dev/null
+++ b/tests/shell/testcases/maps/0017_map_variable_0
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+set -e
+
+if [ "$NFT_TEST_HAVE_catchall_element" != n ] ; then
+ CATCHALL="* : 3,"
+else
+ CATCHALL=","
+fi
+
+RULESET="define x = {
+ 1.1.1.1 : 2,
+ $CATCHALL
+}
+
+table ip x {
+ map y {
+ typeof ip saddr : mark
+ elements = \$x
+ }
+ map z {
+ typeof ip saddr : mark
+ elements = \$x
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+
+if [ "$NFT_TEST_HAVE_catchall_element" = n ] ; then
+ echo "Ran modified version of test due to NFT_TEST_HAVE_catchall_element=n (skipped)"
+ exit 77
+fi
diff --git a/tests/shell/testcases/maps/0018map_leak_timeout_0 b/tests/shell/testcases/maps/0018map_leak_timeout_0
new file mode 100755
index 00000000..09db315a
--- /dev/null
+++ b/tests/shell/testcases/maps/0018map_leak_timeout_0
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+
+set -e
+
+RULESET="table ip t {
+ map sourcemap {
+ type ipv4_addr : verdict
+ timeout 3s
+ elements = { 100.123.10.2 : jump c }
+ }
+
+ chain c {
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+# again, since it is addition, not creation, it is successful
+$NFT -f - <<< "$RULESET"
+
+# wait for elements to expire
+sleep 5
+
+# flush it to check for refcount leak
+$NFT flush ruleset
+
+#
+# again with stateful objects
+#
+
+RULESET="table ip t {
+ counter c {}
+
+ map sourcemap {
+ type ipv4_addr : counter
+ timeout 3s
+ elements = { 100.123.10.2 : \"c\" }
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+# again, since it is addition, not creation, it is successful
+$NFT -f - <<< "$RULESET"
+# flush it to check for refcount leak
+
+# wait for elements to expire
+sleep 5
+
+$NFT flush ruleset
diff --git a/tests/shell/testcases/sets/0024named_objects_0 b/tests/shell/testcases/maps/0024named_objects_0
index 3bd16f2f..21200c3c 100755
--- a/tests/shell/testcases/sets/0024named_objects_0
+++ b/tests/shell/testcases/maps/0024named_objects_0
@@ -35,4 +35,14 @@ table inet x {
set -e
$NFT -f - <<< "$RULESET"
-$NFT reset counter inet x user321
+EXPECTED="table inet x {
+ counter user321 {
+ packets 12 bytes 1433
+ }
+}"
+
+GET="$($NFT reset counter inet x user321)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/maps/anon_objmap_concat b/tests/shell/testcases/maps/anon_objmap_concat
new file mode 100755
index 00000000..34465f1d
--- /dev/null
+++ b/tests/shell/testcases/maps/anon_objmap_concat
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
diff --git a/tests/shell/testcases/maps/dumps/0003map_add_many_elements_0.json-nft b/tests/shell/testcases/maps/dumps/0003map_add_many_elements_0.json-nft
new file mode 100644
index 00000000..1b5c2a23
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0003map_add_many_elements_0.json-nft
@@ -0,0 +1,3874 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "ipv4_addr",
+ "elem": [
+ [
+ "10.0.1.1",
+ "10.0.1.1"
+ ],
+ [
+ "10.0.1.2",
+ "10.0.1.2"
+ ],
+ [
+ "10.0.1.3",
+ "10.0.1.3"
+ ],
+ [
+ "10.0.1.4",
+ "10.0.1.4"
+ ],
+ [
+ "10.0.1.5",
+ "10.0.1.5"
+ ],
+ [
+ "10.0.1.6",
+ "10.0.1.6"
+ ],
+ [
+ "10.0.1.7",
+ "10.0.1.7"
+ ],
+ [
+ "10.0.1.8",
+ "10.0.1.8"
+ ],
+ [
+ "10.0.1.9",
+ "10.0.1.9"
+ ],
+ [
+ "10.0.1.10",
+ "10.0.1.10"
+ ],
+ [
+ "10.0.1.11",
+ "10.0.1.11"
+ ],
+ [
+ "10.0.1.12",
+ "10.0.1.12"
+ ],
+ [
+ "10.0.1.13",
+ "10.0.1.13"
+ ],
+ [
+ "10.0.1.14",
+ "10.0.1.14"
+ ],
+ [
+ "10.0.1.15",
+ "10.0.1.15"
+ ],
+ [
+ "10.0.1.16",
+ "10.0.1.16"
+ ],
+ [
+ "10.0.1.17",
+ "10.0.1.17"
+ ],
+ [
+ "10.0.1.18",
+ "10.0.1.18"
+ ],
+ [
+ "10.0.1.19",
+ "10.0.1.19"
+ ],
+ [
+ "10.0.1.20",
+ "10.0.1.20"
+ ],
+ [
+ "10.0.1.21",
+ "10.0.1.21"
+ ],
+ [
+ "10.0.1.22",
+ "10.0.1.22"
+ ],
+ [
+ "10.0.1.23",
+ "10.0.1.23"
+ ],
+ [
+ "10.0.1.24",
+ "10.0.1.24"
+ ],
+ [
+ "10.0.1.25",
+ "10.0.1.25"
+ ],
+ [
+ "10.0.1.26",
+ "10.0.1.26"
+ ],
+ [
+ "10.0.1.27",
+ "10.0.1.27"
+ ],
+ [
+ "10.0.1.28",
+ "10.0.1.28"
+ ],
+ [
+ "10.0.1.29",
+ "10.0.1.29"
+ ],
+ [
+ "10.0.1.30",
+ "10.0.1.30"
+ ],
+ [
+ "10.0.1.31",
+ "10.0.1.31"
+ ],
+ [
+ "10.0.2.1",
+ "10.0.2.1"
+ ],
+ [
+ "10.0.2.2",
+ "10.0.2.2"
+ ],
+ [
+ "10.0.2.3",
+ "10.0.2.3"
+ ],
+ [
+ "10.0.2.4",
+ "10.0.2.4"
+ ],
+ [
+ "10.0.2.5",
+ "10.0.2.5"
+ ],
+ [
+ "10.0.2.6",
+ "10.0.2.6"
+ ],
+ [
+ "10.0.2.7",
+ "10.0.2.7"
+ ],
+ [
+ "10.0.2.8",
+ "10.0.2.8"
+ ],
+ [
+ "10.0.2.9",
+ "10.0.2.9"
+ ],
+ [
+ "10.0.2.10",
+ "10.0.2.10"
+ ],
+ [
+ "10.0.2.11",
+ "10.0.2.11"
+ ],
+ [
+ "10.0.2.12",
+ "10.0.2.12"
+ ],
+ [
+ "10.0.2.13",
+ "10.0.2.13"
+ ],
+ [
+ "10.0.2.14",
+ "10.0.2.14"
+ ],
+ [
+ "10.0.2.15",
+ "10.0.2.15"
+ ],
+ [
+ "10.0.2.16",
+ "10.0.2.16"
+ ],
+ [
+ "10.0.2.17",
+ "10.0.2.17"
+ ],
+ [
+ "10.0.2.18",
+ "10.0.2.18"
+ ],
+ [
+ "10.0.2.19",
+ "10.0.2.19"
+ ],
+ [
+ "10.0.2.20",
+ "10.0.2.20"
+ ],
+ [
+ "10.0.2.21",
+ "10.0.2.21"
+ ],
+ [
+ "10.0.2.22",
+ "10.0.2.22"
+ ],
+ [
+ "10.0.2.23",
+ "10.0.2.23"
+ ],
+ [
+ "10.0.2.24",
+ "10.0.2.24"
+ ],
+ [
+ "10.0.2.25",
+ "10.0.2.25"
+ ],
+ [
+ "10.0.2.26",
+ "10.0.2.26"
+ ],
+ [
+ "10.0.2.27",
+ "10.0.2.27"
+ ],
+ [
+ "10.0.2.28",
+ "10.0.2.28"
+ ],
+ [
+ "10.0.2.29",
+ "10.0.2.29"
+ ],
+ [
+ "10.0.2.30",
+ "10.0.2.30"
+ ],
+ [
+ "10.0.2.31",
+ "10.0.2.31"
+ ],
+ [
+ "10.0.3.1",
+ "10.0.3.1"
+ ],
+ [
+ "10.0.3.2",
+ "10.0.3.2"
+ ],
+ [
+ "10.0.3.3",
+ "10.0.3.3"
+ ],
+ [
+ "10.0.3.4",
+ "10.0.3.4"
+ ],
+ [
+ "10.0.3.5",
+ "10.0.3.5"
+ ],
+ [
+ "10.0.3.6",
+ "10.0.3.6"
+ ],
+ [
+ "10.0.3.7",
+ "10.0.3.7"
+ ],
+ [
+ "10.0.3.8",
+ "10.0.3.8"
+ ],
+ [
+ "10.0.3.9",
+ "10.0.3.9"
+ ],
+ [
+ "10.0.3.10",
+ "10.0.3.10"
+ ],
+ [
+ "10.0.3.11",
+ "10.0.3.11"
+ ],
+ [
+ "10.0.3.12",
+ "10.0.3.12"
+ ],
+ [
+ "10.0.3.13",
+ "10.0.3.13"
+ ],
+ [
+ "10.0.3.14",
+ "10.0.3.14"
+ ],
+ [
+ "10.0.3.15",
+ "10.0.3.15"
+ ],
+ [
+ "10.0.3.16",
+ "10.0.3.16"
+ ],
+ [
+ "10.0.3.17",
+ "10.0.3.17"
+ ],
+ [
+ "10.0.3.18",
+ "10.0.3.18"
+ ],
+ [
+ "10.0.3.19",
+ "10.0.3.19"
+ ],
+ [
+ "10.0.3.20",
+ "10.0.3.20"
+ ],
+ [
+ "10.0.3.21",
+ "10.0.3.21"
+ ],
+ [
+ "10.0.3.22",
+ "10.0.3.22"
+ ],
+ [
+ "10.0.3.23",
+ "10.0.3.23"
+ ],
+ [
+ "10.0.3.24",
+ "10.0.3.24"
+ ],
+ [
+ "10.0.3.25",
+ "10.0.3.25"
+ ],
+ [
+ "10.0.3.26",
+ "10.0.3.26"
+ ],
+ [
+ "10.0.3.27",
+ "10.0.3.27"
+ ],
+ [
+ "10.0.3.28",
+ "10.0.3.28"
+ ],
+ [
+ "10.0.3.29",
+ "10.0.3.29"
+ ],
+ [
+ "10.0.3.30",
+ "10.0.3.30"
+ ],
+ [
+ "10.0.3.31",
+ "10.0.3.31"
+ ],
+ [
+ "10.0.4.1",
+ "10.0.4.1"
+ ],
+ [
+ "10.0.4.2",
+ "10.0.4.2"
+ ],
+ [
+ "10.0.4.3",
+ "10.0.4.3"
+ ],
+ [
+ "10.0.4.4",
+ "10.0.4.4"
+ ],
+ [
+ "10.0.4.5",
+ "10.0.4.5"
+ ],
+ [
+ "10.0.4.6",
+ "10.0.4.6"
+ ],
+ [
+ "10.0.4.7",
+ "10.0.4.7"
+ ],
+ [
+ "10.0.4.8",
+ "10.0.4.8"
+ ],
+ [
+ "10.0.4.9",
+ "10.0.4.9"
+ ],
+ [
+ "10.0.4.10",
+ "10.0.4.10"
+ ],
+ [
+ "10.0.4.11",
+ "10.0.4.11"
+ ],
+ [
+ "10.0.4.12",
+ "10.0.4.12"
+ ],
+ [
+ "10.0.4.13",
+ "10.0.4.13"
+ ],
+ [
+ "10.0.4.14",
+ "10.0.4.14"
+ ],
+ [
+ "10.0.4.15",
+ "10.0.4.15"
+ ],
+ [
+ "10.0.4.16",
+ "10.0.4.16"
+ ],
+ [
+ "10.0.4.17",
+ "10.0.4.17"
+ ],
+ [
+ "10.0.4.18",
+ "10.0.4.18"
+ ],
+ [
+ "10.0.4.19",
+ "10.0.4.19"
+ ],
+ [
+ "10.0.4.20",
+ "10.0.4.20"
+ ],
+ [
+ "10.0.4.21",
+ "10.0.4.21"
+ ],
+ [
+ "10.0.4.22",
+ "10.0.4.22"
+ ],
+ [
+ "10.0.4.23",
+ "10.0.4.23"
+ ],
+ [
+ "10.0.4.24",
+ "10.0.4.24"
+ ],
+ [
+ "10.0.4.25",
+ "10.0.4.25"
+ ],
+ [
+ "10.0.4.26",
+ "10.0.4.26"
+ ],
+ [
+ "10.0.4.27",
+ "10.0.4.27"
+ ],
+ [
+ "10.0.4.28",
+ "10.0.4.28"
+ ],
+ [
+ "10.0.4.29",
+ "10.0.4.29"
+ ],
+ [
+ "10.0.4.30",
+ "10.0.4.30"
+ ],
+ [
+ "10.0.4.31",
+ "10.0.4.31"
+ ],
+ [
+ "10.0.5.1",
+ "10.0.5.1"
+ ],
+ [
+ "10.0.5.2",
+ "10.0.5.2"
+ ],
+ [
+ "10.0.5.3",
+ "10.0.5.3"
+ ],
+ [
+ "10.0.5.4",
+ "10.0.5.4"
+ ],
+ [
+ "10.0.5.5",
+ "10.0.5.5"
+ ],
+ [
+ "10.0.5.6",
+ "10.0.5.6"
+ ],
+ [
+ "10.0.5.7",
+ "10.0.5.7"
+ ],
+ [
+ "10.0.5.8",
+ "10.0.5.8"
+ ],
+ [
+ "10.0.5.9",
+ "10.0.5.9"
+ ],
+ [
+ "10.0.5.10",
+ "10.0.5.10"
+ ],
+ [
+ "10.0.5.11",
+ "10.0.5.11"
+ ],
+ [
+ "10.0.5.12",
+ "10.0.5.12"
+ ],
+ [
+ "10.0.5.13",
+ "10.0.5.13"
+ ],
+ [
+ "10.0.5.14",
+ "10.0.5.14"
+ ],
+ [
+ "10.0.5.15",
+ "10.0.5.15"
+ ],
+ [
+ "10.0.5.16",
+ "10.0.5.16"
+ ],
+ [
+ "10.0.5.17",
+ "10.0.5.17"
+ ],
+ [
+ "10.0.5.18",
+ "10.0.5.18"
+ ],
+ [
+ "10.0.5.19",
+ "10.0.5.19"
+ ],
+ [
+ "10.0.5.20",
+ "10.0.5.20"
+ ],
+ [
+ "10.0.5.21",
+ "10.0.5.21"
+ ],
+ [
+ "10.0.5.22",
+ "10.0.5.22"
+ ],
+ [
+ "10.0.5.23",
+ "10.0.5.23"
+ ],
+ [
+ "10.0.5.24",
+ "10.0.5.24"
+ ],
+ [
+ "10.0.5.25",
+ "10.0.5.25"
+ ],
+ [
+ "10.0.5.26",
+ "10.0.5.26"
+ ],
+ [
+ "10.0.5.27",
+ "10.0.5.27"
+ ],
+ [
+ "10.0.5.28",
+ "10.0.5.28"
+ ],
+ [
+ "10.0.5.29",
+ "10.0.5.29"
+ ],
+ [
+ "10.0.5.30",
+ "10.0.5.30"
+ ],
+ [
+ "10.0.5.31",
+ "10.0.5.31"
+ ],
+ [
+ "10.0.6.1",
+ "10.0.6.1"
+ ],
+ [
+ "10.0.6.2",
+ "10.0.6.2"
+ ],
+ [
+ "10.0.6.3",
+ "10.0.6.3"
+ ],
+ [
+ "10.0.6.4",
+ "10.0.6.4"
+ ],
+ [
+ "10.0.6.5",
+ "10.0.6.5"
+ ],
+ [
+ "10.0.6.6",
+ "10.0.6.6"
+ ],
+ [
+ "10.0.6.7",
+ "10.0.6.7"
+ ],
+ [
+ "10.0.6.8",
+ "10.0.6.8"
+ ],
+ [
+ "10.0.6.9",
+ "10.0.6.9"
+ ],
+ [
+ "10.0.6.10",
+ "10.0.6.10"
+ ],
+ [
+ "10.0.6.11",
+ "10.0.6.11"
+ ],
+ [
+ "10.0.6.12",
+ "10.0.6.12"
+ ],
+ [
+ "10.0.6.13",
+ "10.0.6.13"
+ ],
+ [
+ "10.0.6.14",
+ "10.0.6.14"
+ ],
+ [
+ "10.0.6.15",
+ "10.0.6.15"
+ ],
+ [
+ "10.0.6.16",
+ "10.0.6.16"
+ ],
+ [
+ "10.0.6.17",
+ "10.0.6.17"
+ ],
+ [
+ "10.0.6.18",
+ "10.0.6.18"
+ ],
+ [
+ "10.0.6.19",
+ "10.0.6.19"
+ ],
+ [
+ "10.0.6.20",
+ "10.0.6.20"
+ ],
+ [
+ "10.0.6.21",
+ "10.0.6.21"
+ ],
+ [
+ "10.0.6.22",
+ "10.0.6.22"
+ ],
+ [
+ "10.0.6.23",
+ "10.0.6.23"
+ ],
+ [
+ "10.0.6.24",
+ "10.0.6.24"
+ ],
+ [
+ "10.0.6.25",
+ "10.0.6.25"
+ ],
+ [
+ "10.0.6.26",
+ "10.0.6.26"
+ ],
+ [
+ "10.0.6.27",
+ "10.0.6.27"
+ ],
+ [
+ "10.0.6.28",
+ "10.0.6.28"
+ ],
+ [
+ "10.0.6.29",
+ "10.0.6.29"
+ ],
+ [
+ "10.0.6.30",
+ "10.0.6.30"
+ ],
+ [
+ "10.0.6.31",
+ "10.0.6.31"
+ ],
+ [
+ "10.0.7.1",
+ "10.0.7.1"
+ ],
+ [
+ "10.0.7.2",
+ "10.0.7.2"
+ ],
+ [
+ "10.0.7.3",
+ "10.0.7.3"
+ ],
+ [
+ "10.0.7.4",
+ "10.0.7.4"
+ ],
+ [
+ "10.0.7.5",
+ "10.0.7.5"
+ ],
+ [
+ "10.0.7.6",
+ "10.0.7.6"
+ ],
+ [
+ "10.0.7.7",
+ "10.0.7.7"
+ ],
+ [
+ "10.0.7.8",
+ "10.0.7.8"
+ ],
+ [
+ "10.0.7.9",
+ "10.0.7.9"
+ ],
+ [
+ "10.0.7.10",
+ "10.0.7.10"
+ ],
+ [
+ "10.0.7.11",
+ "10.0.7.11"
+ ],
+ [
+ "10.0.7.12",
+ "10.0.7.12"
+ ],
+ [
+ "10.0.7.13",
+ "10.0.7.13"
+ ],
+ [
+ "10.0.7.14",
+ "10.0.7.14"
+ ],
+ [
+ "10.0.7.15",
+ "10.0.7.15"
+ ],
+ [
+ "10.0.7.16",
+ "10.0.7.16"
+ ],
+ [
+ "10.0.7.17",
+ "10.0.7.17"
+ ],
+ [
+ "10.0.7.18",
+ "10.0.7.18"
+ ],
+ [
+ "10.0.7.19",
+ "10.0.7.19"
+ ],
+ [
+ "10.0.7.20",
+ "10.0.7.20"
+ ],
+ [
+ "10.0.7.21",
+ "10.0.7.21"
+ ],
+ [
+ "10.0.7.22",
+ "10.0.7.22"
+ ],
+ [
+ "10.0.7.23",
+ "10.0.7.23"
+ ],
+ [
+ "10.0.7.24",
+ "10.0.7.24"
+ ],
+ [
+ "10.0.7.25",
+ "10.0.7.25"
+ ],
+ [
+ "10.0.7.26",
+ "10.0.7.26"
+ ],
+ [
+ "10.0.7.27",
+ "10.0.7.27"
+ ],
+ [
+ "10.0.7.28",
+ "10.0.7.28"
+ ],
+ [
+ "10.0.7.29",
+ "10.0.7.29"
+ ],
+ [
+ "10.0.7.30",
+ "10.0.7.30"
+ ],
+ [
+ "10.0.7.31",
+ "10.0.7.31"
+ ],
+ [
+ "10.0.8.1",
+ "10.0.8.1"
+ ],
+ [
+ "10.0.8.2",
+ "10.0.8.2"
+ ],
+ [
+ "10.0.8.3",
+ "10.0.8.3"
+ ],
+ [
+ "10.0.8.4",
+ "10.0.8.4"
+ ],
+ [
+ "10.0.8.5",
+ "10.0.8.5"
+ ],
+ [
+ "10.0.8.6",
+ "10.0.8.6"
+ ],
+ [
+ "10.0.8.7",
+ "10.0.8.7"
+ ],
+ [
+ "10.0.8.8",
+ "10.0.8.8"
+ ],
+ [
+ "10.0.8.9",
+ "10.0.8.9"
+ ],
+ [
+ "10.0.8.10",
+ "10.0.8.10"
+ ],
+ [
+ "10.0.8.11",
+ "10.0.8.11"
+ ],
+ [
+ "10.0.8.12",
+ "10.0.8.12"
+ ],
+ [
+ "10.0.8.13",
+ "10.0.8.13"
+ ],
+ [
+ "10.0.8.14",
+ "10.0.8.14"
+ ],
+ [
+ "10.0.8.15",
+ "10.0.8.15"
+ ],
+ [
+ "10.0.8.16",
+ "10.0.8.16"
+ ],
+ [
+ "10.0.8.17",
+ "10.0.8.17"
+ ],
+ [
+ "10.0.8.18",
+ "10.0.8.18"
+ ],
+ [
+ "10.0.8.19",
+ "10.0.8.19"
+ ],
+ [
+ "10.0.8.20",
+ "10.0.8.20"
+ ],
+ [
+ "10.0.8.21",
+ "10.0.8.21"
+ ],
+ [
+ "10.0.8.22",
+ "10.0.8.22"
+ ],
+ [
+ "10.0.8.23",
+ "10.0.8.23"
+ ],
+ [
+ "10.0.8.24",
+ "10.0.8.24"
+ ],
+ [
+ "10.0.8.25",
+ "10.0.8.25"
+ ],
+ [
+ "10.0.8.26",
+ "10.0.8.26"
+ ],
+ [
+ "10.0.8.27",
+ "10.0.8.27"
+ ],
+ [
+ "10.0.8.28",
+ "10.0.8.28"
+ ],
+ [
+ "10.0.8.29",
+ "10.0.8.29"
+ ],
+ [
+ "10.0.8.30",
+ "10.0.8.30"
+ ],
+ [
+ "10.0.8.31",
+ "10.0.8.31"
+ ],
+ [
+ "10.0.9.1",
+ "10.0.9.1"
+ ],
+ [
+ "10.0.9.2",
+ "10.0.9.2"
+ ],
+ [
+ "10.0.9.3",
+ "10.0.9.3"
+ ],
+ [
+ "10.0.9.4",
+ "10.0.9.4"
+ ],
+ [
+ "10.0.9.5",
+ "10.0.9.5"
+ ],
+ [
+ "10.0.9.6",
+ "10.0.9.6"
+ ],
+ [
+ "10.0.9.7",
+ "10.0.9.7"
+ ],
+ [
+ "10.0.9.8",
+ "10.0.9.8"
+ ],
+ [
+ "10.0.9.9",
+ "10.0.9.9"
+ ],
+ [
+ "10.0.9.10",
+ "10.0.9.10"
+ ],
+ [
+ "10.0.9.11",
+ "10.0.9.11"
+ ],
+ [
+ "10.0.9.12",
+ "10.0.9.12"
+ ],
+ [
+ "10.0.9.13",
+ "10.0.9.13"
+ ],
+ [
+ "10.0.9.14",
+ "10.0.9.14"
+ ],
+ [
+ "10.0.9.15",
+ "10.0.9.15"
+ ],
+ [
+ "10.0.9.16",
+ "10.0.9.16"
+ ],
+ [
+ "10.0.9.17",
+ "10.0.9.17"
+ ],
+ [
+ "10.0.9.18",
+ "10.0.9.18"
+ ],
+ [
+ "10.0.9.19",
+ "10.0.9.19"
+ ],
+ [
+ "10.0.9.20",
+ "10.0.9.20"
+ ],
+ [
+ "10.0.9.21",
+ "10.0.9.21"
+ ],
+ [
+ "10.0.9.22",
+ "10.0.9.22"
+ ],
+ [
+ "10.0.9.23",
+ "10.0.9.23"
+ ],
+ [
+ "10.0.9.24",
+ "10.0.9.24"
+ ],
+ [
+ "10.0.9.25",
+ "10.0.9.25"
+ ],
+ [
+ "10.0.9.26",
+ "10.0.9.26"
+ ],
+ [
+ "10.0.9.27",
+ "10.0.9.27"
+ ],
+ [
+ "10.0.9.28",
+ "10.0.9.28"
+ ],
+ [
+ "10.0.9.29",
+ "10.0.9.29"
+ ],
+ [
+ "10.0.9.30",
+ "10.0.9.30"
+ ],
+ [
+ "10.0.9.31",
+ "10.0.9.31"
+ ],
+ [
+ "10.0.10.1",
+ "10.0.10.1"
+ ],
+ [
+ "10.0.10.2",
+ "10.0.10.2"
+ ],
+ [
+ "10.0.10.3",
+ "10.0.10.3"
+ ],
+ [
+ "10.0.10.4",
+ "10.0.10.4"
+ ],
+ [
+ "10.0.10.5",
+ "10.0.10.5"
+ ],
+ [
+ "10.0.10.6",
+ "10.0.10.6"
+ ],
+ [
+ "10.0.10.7",
+ "10.0.10.7"
+ ],
+ [
+ "10.0.10.8",
+ "10.0.10.8"
+ ],
+ [
+ "10.0.10.9",
+ "10.0.10.9"
+ ],
+ [
+ "10.0.10.10",
+ "10.0.10.10"
+ ],
+ [
+ "10.0.10.11",
+ "10.0.10.11"
+ ],
+ [
+ "10.0.10.12",
+ "10.0.10.12"
+ ],
+ [
+ "10.0.10.13",
+ "10.0.10.13"
+ ],
+ [
+ "10.0.10.14",
+ "10.0.10.14"
+ ],
+ [
+ "10.0.10.15",
+ "10.0.10.15"
+ ],
+ [
+ "10.0.10.16",
+ "10.0.10.16"
+ ],
+ [
+ "10.0.10.17",
+ "10.0.10.17"
+ ],
+ [
+ "10.0.10.18",
+ "10.0.10.18"
+ ],
+ [
+ "10.0.10.19",
+ "10.0.10.19"
+ ],
+ [
+ "10.0.10.20",
+ "10.0.10.20"
+ ],
+ [
+ "10.0.10.21",
+ "10.0.10.21"
+ ],
+ [
+ "10.0.10.22",
+ "10.0.10.22"
+ ],
+ [
+ "10.0.10.23",
+ "10.0.10.23"
+ ],
+ [
+ "10.0.10.24",
+ "10.0.10.24"
+ ],
+ [
+ "10.0.10.25",
+ "10.0.10.25"
+ ],
+ [
+ "10.0.10.26",
+ "10.0.10.26"
+ ],
+ [
+ "10.0.10.27",
+ "10.0.10.27"
+ ],
+ [
+ "10.0.10.28",
+ "10.0.10.28"
+ ],
+ [
+ "10.0.10.29",
+ "10.0.10.29"
+ ],
+ [
+ "10.0.10.30",
+ "10.0.10.30"
+ ],
+ [
+ "10.0.10.31",
+ "10.0.10.31"
+ ],
+ [
+ "10.0.11.1",
+ "10.0.11.1"
+ ],
+ [
+ "10.0.11.2",
+ "10.0.11.2"
+ ],
+ [
+ "10.0.11.3",
+ "10.0.11.3"
+ ],
+ [
+ "10.0.11.4",
+ "10.0.11.4"
+ ],
+ [
+ "10.0.11.5",
+ "10.0.11.5"
+ ],
+ [
+ "10.0.11.6",
+ "10.0.11.6"
+ ],
+ [
+ "10.0.11.7",
+ "10.0.11.7"
+ ],
+ [
+ "10.0.11.8",
+ "10.0.11.8"
+ ],
+ [
+ "10.0.11.9",
+ "10.0.11.9"
+ ],
+ [
+ "10.0.11.10",
+ "10.0.11.10"
+ ],
+ [
+ "10.0.11.11",
+ "10.0.11.11"
+ ],
+ [
+ "10.0.11.12",
+ "10.0.11.12"
+ ],
+ [
+ "10.0.11.13",
+ "10.0.11.13"
+ ],
+ [
+ "10.0.11.14",
+ "10.0.11.14"
+ ],
+ [
+ "10.0.11.15",
+ "10.0.11.15"
+ ],
+ [
+ "10.0.11.16",
+ "10.0.11.16"
+ ],
+ [
+ "10.0.11.17",
+ "10.0.11.17"
+ ],
+ [
+ "10.0.11.18",
+ "10.0.11.18"
+ ],
+ [
+ "10.0.11.19",
+ "10.0.11.19"
+ ],
+ [
+ "10.0.11.20",
+ "10.0.11.20"
+ ],
+ [
+ "10.0.11.21",
+ "10.0.11.21"
+ ],
+ [
+ "10.0.11.22",
+ "10.0.11.22"
+ ],
+ [
+ "10.0.11.23",
+ "10.0.11.23"
+ ],
+ [
+ "10.0.11.24",
+ "10.0.11.24"
+ ],
+ [
+ "10.0.11.25",
+ "10.0.11.25"
+ ],
+ [
+ "10.0.11.26",
+ "10.0.11.26"
+ ],
+ [
+ "10.0.11.27",
+ "10.0.11.27"
+ ],
+ [
+ "10.0.11.28",
+ "10.0.11.28"
+ ],
+ [
+ "10.0.11.29",
+ "10.0.11.29"
+ ],
+ [
+ "10.0.11.30",
+ "10.0.11.30"
+ ],
+ [
+ "10.0.11.31",
+ "10.0.11.31"
+ ],
+ [
+ "10.0.12.1",
+ "10.0.12.1"
+ ],
+ [
+ "10.0.12.2",
+ "10.0.12.2"
+ ],
+ [
+ "10.0.12.3",
+ "10.0.12.3"
+ ],
+ [
+ "10.0.12.4",
+ "10.0.12.4"
+ ],
+ [
+ "10.0.12.5",
+ "10.0.12.5"
+ ],
+ [
+ "10.0.12.6",
+ "10.0.12.6"
+ ],
+ [
+ "10.0.12.7",
+ "10.0.12.7"
+ ],
+ [
+ "10.0.12.8",
+ "10.0.12.8"
+ ],
+ [
+ "10.0.12.9",
+ "10.0.12.9"
+ ],
+ [
+ "10.0.12.10",
+ "10.0.12.10"
+ ],
+ [
+ "10.0.12.11",
+ "10.0.12.11"
+ ],
+ [
+ "10.0.12.12",
+ "10.0.12.12"
+ ],
+ [
+ "10.0.12.13",
+ "10.0.12.13"
+ ],
+ [
+ "10.0.12.14",
+ "10.0.12.14"
+ ],
+ [
+ "10.0.12.15",
+ "10.0.12.15"
+ ],
+ [
+ "10.0.12.16",
+ "10.0.12.16"
+ ],
+ [
+ "10.0.12.17",
+ "10.0.12.17"
+ ],
+ [
+ "10.0.12.18",
+ "10.0.12.18"
+ ],
+ [
+ "10.0.12.19",
+ "10.0.12.19"
+ ],
+ [
+ "10.0.12.20",
+ "10.0.12.20"
+ ],
+ [
+ "10.0.12.21",
+ "10.0.12.21"
+ ],
+ [
+ "10.0.12.22",
+ "10.0.12.22"
+ ],
+ [
+ "10.0.12.23",
+ "10.0.12.23"
+ ],
+ [
+ "10.0.12.24",
+ "10.0.12.24"
+ ],
+ [
+ "10.0.12.25",
+ "10.0.12.25"
+ ],
+ [
+ "10.0.12.26",
+ "10.0.12.26"
+ ],
+ [
+ "10.0.12.27",
+ "10.0.12.27"
+ ],
+ [
+ "10.0.12.28",
+ "10.0.12.28"
+ ],
+ [
+ "10.0.12.29",
+ "10.0.12.29"
+ ],
+ [
+ "10.0.12.30",
+ "10.0.12.30"
+ ],
+ [
+ "10.0.12.31",
+ "10.0.12.31"
+ ],
+ [
+ "10.0.13.1",
+ "10.0.13.1"
+ ],
+ [
+ "10.0.13.2",
+ "10.0.13.2"
+ ],
+ [
+ "10.0.13.3",
+ "10.0.13.3"
+ ],
+ [
+ "10.0.13.4",
+ "10.0.13.4"
+ ],
+ [
+ "10.0.13.5",
+ "10.0.13.5"
+ ],
+ [
+ "10.0.13.6",
+ "10.0.13.6"
+ ],
+ [
+ "10.0.13.7",
+ "10.0.13.7"
+ ],
+ [
+ "10.0.13.8",
+ "10.0.13.8"
+ ],
+ [
+ "10.0.13.9",
+ "10.0.13.9"
+ ],
+ [
+ "10.0.13.10",
+ "10.0.13.10"
+ ],
+ [
+ "10.0.13.11",
+ "10.0.13.11"
+ ],
+ [
+ "10.0.13.12",
+ "10.0.13.12"
+ ],
+ [
+ "10.0.13.13",
+ "10.0.13.13"
+ ],
+ [
+ "10.0.13.14",
+ "10.0.13.14"
+ ],
+ [
+ "10.0.13.15",
+ "10.0.13.15"
+ ],
+ [
+ "10.0.13.16",
+ "10.0.13.16"
+ ],
+ [
+ "10.0.13.17",
+ "10.0.13.17"
+ ],
+ [
+ "10.0.13.18",
+ "10.0.13.18"
+ ],
+ [
+ "10.0.13.19",
+ "10.0.13.19"
+ ],
+ [
+ "10.0.13.20",
+ "10.0.13.20"
+ ],
+ [
+ "10.0.13.21",
+ "10.0.13.21"
+ ],
+ [
+ "10.0.13.22",
+ "10.0.13.22"
+ ],
+ [
+ "10.0.13.23",
+ "10.0.13.23"
+ ],
+ [
+ "10.0.13.24",
+ "10.0.13.24"
+ ],
+ [
+ "10.0.13.25",
+ "10.0.13.25"
+ ],
+ [
+ "10.0.13.26",
+ "10.0.13.26"
+ ],
+ [
+ "10.0.13.27",
+ "10.0.13.27"
+ ],
+ [
+ "10.0.13.28",
+ "10.0.13.28"
+ ],
+ [
+ "10.0.13.29",
+ "10.0.13.29"
+ ],
+ [
+ "10.0.13.30",
+ "10.0.13.30"
+ ],
+ [
+ "10.0.13.31",
+ "10.0.13.31"
+ ],
+ [
+ "10.0.14.1",
+ "10.0.14.1"
+ ],
+ [
+ "10.0.14.2",
+ "10.0.14.2"
+ ],
+ [
+ "10.0.14.3",
+ "10.0.14.3"
+ ],
+ [
+ "10.0.14.4",
+ "10.0.14.4"
+ ],
+ [
+ "10.0.14.5",
+ "10.0.14.5"
+ ],
+ [
+ "10.0.14.6",
+ "10.0.14.6"
+ ],
+ [
+ "10.0.14.7",
+ "10.0.14.7"
+ ],
+ [
+ "10.0.14.8",
+ "10.0.14.8"
+ ],
+ [
+ "10.0.14.9",
+ "10.0.14.9"
+ ],
+ [
+ "10.0.14.10",
+ "10.0.14.10"
+ ],
+ [
+ "10.0.14.11",
+ "10.0.14.11"
+ ],
+ [
+ "10.0.14.12",
+ "10.0.14.12"
+ ],
+ [
+ "10.0.14.13",
+ "10.0.14.13"
+ ],
+ [
+ "10.0.14.14",
+ "10.0.14.14"
+ ],
+ [
+ "10.0.14.15",
+ "10.0.14.15"
+ ],
+ [
+ "10.0.14.16",
+ "10.0.14.16"
+ ],
+ [
+ "10.0.14.17",
+ "10.0.14.17"
+ ],
+ [
+ "10.0.14.18",
+ "10.0.14.18"
+ ],
+ [
+ "10.0.14.19",
+ "10.0.14.19"
+ ],
+ [
+ "10.0.14.20",
+ "10.0.14.20"
+ ],
+ [
+ "10.0.14.21",
+ "10.0.14.21"
+ ],
+ [
+ "10.0.14.22",
+ "10.0.14.22"
+ ],
+ [
+ "10.0.14.23",
+ "10.0.14.23"
+ ],
+ [
+ "10.0.14.24",
+ "10.0.14.24"
+ ],
+ [
+ "10.0.14.25",
+ "10.0.14.25"
+ ],
+ [
+ "10.0.14.26",
+ "10.0.14.26"
+ ],
+ [
+ "10.0.14.27",
+ "10.0.14.27"
+ ],
+ [
+ "10.0.14.28",
+ "10.0.14.28"
+ ],
+ [
+ "10.0.14.29",
+ "10.0.14.29"
+ ],
+ [
+ "10.0.14.30",
+ "10.0.14.30"
+ ],
+ [
+ "10.0.14.31",
+ "10.0.14.31"
+ ],
+ [
+ "10.0.15.1",
+ "10.0.15.1"
+ ],
+ [
+ "10.0.15.2",
+ "10.0.15.2"
+ ],
+ [
+ "10.0.15.3",
+ "10.0.15.3"
+ ],
+ [
+ "10.0.15.4",
+ "10.0.15.4"
+ ],
+ [
+ "10.0.15.5",
+ "10.0.15.5"
+ ],
+ [
+ "10.0.15.6",
+ "10.0.15.6"
+ ],
+ [
+ "10.0.15.7",
+ "10.0.15.7"
+ ],
+ [
+ "10.0.15.8",
+ "10.0.15.8"
+ ],
+ [
+ "10.0.15.9",
+ "10.0.15.9"
+ ],
+ [
+ "10.0.15.10",
+ "10.0.15.10"
+ ],
+ [
+ "10.0.15.11",
+ "10.0.15.11"
+ ],
+ [
+ "10.0.15.12",
+ "10.0.15.12"
+ ],
+ [
+ "10.0.15.13",
+ "10.0.15.13"
+ ],
+ [
+ "10.0.15.14",
+ "10.0.15.14"
+ ],
+ [
+ "10.0.15.15",
+ "10.0.15.15"
+ ],
+ [
+ "10.0.15.16",
+ "10.0.15.16"
+ ],
+ [
+ "10.0.15.17",
+ "10.0.15.17"
+ ],
+ [
+ "10.0.15.18",
+ "10.0.15.18"
+ ],
+ [
+ "10.0.15.19",
+ "10.0.15.19"
+ ],
+ [
+ "10.0.15.20",
+ "10.0.15.20"
+ ],
+ [
+ "10.0.15.21",
+ "10.0.15.21"
+ ],
+ [
+ "10.0.15.22",
+ "10.0.15.22"
+ ],
+ [
+ "10.0.15.23",
+ "10.0.15.23"
+ ],
+ [
+ "10.0.15.24",
+ "10.0.15.24"
+ ],
+ [
+ "10.0.15.25",
+ "10.0.15.25"
+ ],
+ [
+ "10.0.15.26",
+ "10.0.15.26"
+ ],
+ [
+ "10.0.15.27",
+ "10.0.15.27"
+ ],
+ [
+ "10.0.15.28",
+ "10.0.15.28"
+ ],
+ [
+ "10.0.15.29",
+ "10.0.15.29"
+ ],
+ [
+ "10.0.15.30",
+ "10.0.15.30"
+ ],
+ [
+ "10.0.15.31",
+ "10.0.15.31"
+ ],
+ [
+ "10.0.16.1",
+ "10.0.16.1"
+ ],
+ [
+ "10.0.16.2",
+ "10.0.16.2"
+ ],
+ [
+ "10.0.16.3",
+ "10.0.16.3"
+ ],
+ [
+ "10.0.16.4",
+ "10.0.16.4"
+ ],
+ [
+ "10.0.16.5",
+ "10.0.16.5"
+ ],
+ [
+ "10.0.16.6",
+ "10.0.16.6"
+ ],
+ [
+ "10.0.16.7",
+ "10.0.16.7"
+ ],
+ [
+ "10.0.16.8",
+ "10.0.16.8"
+ ],
+ [
+ "10.0.16.9",
+ "10.0.16.9"
+ ],
+ [
+ "10.0.16.10",
+ "10.0.16.10"
+ ],
+ [
+ "10.0.16.11",
+ "10.0.16.11"
+ ],
+ [
+ "10.0.16.12",
+ "10.0.16.12"
+ ],
+ [
+ "10.0.16.13",
+ "10.0.16.13"
+ ],
+ [
+ "10.0.16.14",
+ "10.0.16.14"
+ ],
+ [
+ "10.0.16.15",
+ "10.0.16.15"
+ ],
+ [
+ "10.0.16.16",
+ "10.0.16.16"
+ ],
+ [
+ "10.0.16.17",
+ "10.0.16.17"
+ ],
+ [
+ "10.0.16.18",
+ "10.0.16.18"
+ ],
+ [
+ "10.0.16.19",
+ "10.0.16.19"
+ ],
+ [
+ "10.0.16.20",
+ "10.0.16.20"
+ ],
+ [
+ "10.0.16.21",
+ "10.0.16.21"
+ ],
+ [
+ "10.0.16.22",
+ "10.0.16.22"
+ ],
+ [
+ "10.0.16.23",
+ "10.0.16.23"
+ ],
+ [
+ "10.0.16.24",
+ "10.0.16.24"
+ ],
+ [
+ "10.0.16.25",
+ "10.0.16.25"
+ ],
+ [
+ "10.0.16.26",
+ "10.0.16.26"
+ ],
+ [
+ "10.0.16.27",
+ "10.0.16.27"
+ ],
+ [
+ "10.0.16.28",
+ "10.0.16.28"
+ ],
+ [
+ "10.0.16.29",
+ "10.0.16.29"
+ ],
+ [
+ "10.0.16.30",
+ "10.0.16.30"
+ ],
+ [
+ "10.0.16.31",
+ "10.0.16.31"
+ ],
+ [
+ "10.0.17.1",
+ "10.0.17.1"
+ ],
+ [
+ "10.0.17.2",
+ "10.0.17.2"
+ ],
+ [
+ "10.0.17.3",
+ "10.0.17.3"
+ ],
+ [
+ "10.0.17.4",
+ "10.0.17.4"
+ ],
+ [
+ "10.0.17.5",
+ "10.0.17.5"
+ ],
+ [
+ "10.0.17.6",
+ "10.0.17.6"
+ ],
+ [
+ "10.0.17.7",
+ "10.0.17.7"
+ ],
+ [
+ "10.0.17.8",
+ "10.0.17.8"
+ ],
+ [
+ "10.0.17.9",
+ "10.0.17.9"
+ ],
+ [
+ "10.0.17.10",
+ "10.0.17.10"
+ ],
+ [
+ "10.0.17.11",
+ "10.0.17.11"
+ ],
+ [
+ "10.0.17.12",
+ "10.0.17.12"
+ ],
+ [
+ "10.0.17.13",
+ "10.0.17.13"
+ ],
+ [
+ "10.0.17.14",
+ "10.0.17.14"
+ ],
+ [
+ "10.0.17.15",
+ "10.0.17.15"
+ ],
+ [
+ "10.0.17.16",
+ "10.0.17.16"
+ ],
+ [
+ "10.0.17.17",
+ "10.0.17.17"
+ ],
+ [
+ "10.0.17.18",
+ "10.0.17.18"
+ ],
+ [
+ "10.0.17.19",
+ "10.0.17.19"
+ ],
+ [
+ "10.0.17.20",
+ "10.0.17.20"
+ ],
+ [
+ "10.0.17.21",
+ "10.0.17.21"
+ ],
+ [
+ "10.0.17.22",
+ "10.0.17.22"
+ ],
+ [
+ "10.0.17.23",
+ "10.0.17.23"
+ ],
+ [
+ "10.0.17.24",
+ "10.0.17.24"
+ ],
+ [
+ "10.0.17.25",
+ "10.0.17.25"
+ ],
+ [
+ "10.0.17.26",
+ "10.0.17.26"
+ ],
+ [
+ "10.0.17.27",
+ "10.0.17.27"
+ ],
+ [
+ "10.0.17.28",
+ "10.0.17.28"
+ ],
+ [
+ "10.0.17.29",
+ "10.0.17.29"
+ ],
+ [
+ "10.0.17.30",
+ "10.0.17.30"
+ ],
+ [
+ "10.0.17.31",
+ "10.0.17.31"
+ ],
+ [
+ "10.0.18.1",
+ "10.0.18.1"
+ ],
+ [
+ "10.0.18.2",
+ "10.0.18.2"
+ ],
+ [
+ "10.0.18.3",
+ "10.0.18.3"
+ ],
+ [
+ "10.0.18.4",
+ "10.0.18.4"
+ ],
+ [
+ "10.0.18.5",
+ "10.0.18.5"
+ ],
+ [
+ "10.0.18.6",
+ "10.0.18.6"
+ ],
+ [
+ "10.0.18.7",
+ "10.0.18.7"
+ ],
+ [
+ "10.0.18.8",
+ "10.0.18.8"
+ ],
+ [
+ "10.0.18.9",
+ "10.0.18.9"
+ ],
+ [
+ "10.0.18.10",
+ "10.0.18.10"
+ ],
+ [
+ "10.0.18.11",
+ "10.0.18.11"
+ ],
+ [
+ "10.0.18.12",
+ "10.0.18.12"
+ ],
+ [
+ "10.0.18.13",
+ "10.0.18.13"
+ ],
+ [
+ "10.0.18.14",
+ "10.0.18.14"
+ ],
+ [
+ "10.0.18.15",
+ "10.0.18.15"
+ ],
+ [
+ "10.0.18.16",
+ "10.0.18.16"
+ ],
+ [
+ "10.0.18.17",
+ "10.0.18.17"
+ ],
+ [
+ "10.0.18.18",
+ "10.0.18.18"
+ ],
+ [
+ "10.0.18.19",
+ "10.0.18.19"
+ ],
+ [
+ "10.0.18.20",
+ "10.0.18.20"
+ ],
+ [
+ "10.0.18.21",
+ "10.0.18.21"
+ ],
+ [
+ "10.0.18.22",
+ "10.0.18.22"
+ ],
+ [
+ "10.0.18.23",
+ "10.0.18.23"
+ ],
+ [
+ "10.0.18.24",
+ "10.0.18.24"
+ ],
+ [
+ "10.0.18.25",
+ "10.0.18.25"
+ ],
+ [
+ "10.0.18.26",
+ "10.0.18.26"
+ ],
+ [
+ "10.0.18.27",
+ "10.0.18.27"
+ ],
+ [
+ "10.0.18.28",
+ "10.0.18.28"
+ ],
+ [
+ "10.0.18.29",
+ "10.0.18.29"
+ ],
+ [
+ "10.0.18.30",
+ "10.0.18.30"
+ ],
+ [
+ "10.0.18.31",
+ "10.0.18.31"
+ ],
+ [
+ "10.0.19.1",
+ "10.0.19.1"
+ ],
+ [
+ "10.0.19.2",
+ "10.0.19.2"
+ ],
+ [
+ "10.0.19.3",
+ "10.0.19.3"
+ ],
+ [
+ "10.0.19.4",
+ "10.0.19.4"
+ ],
+ [
+ "10.0.19.5",
+ "10.0.19.5"
+ ],
+ [
+ "10.0.19.6",
+ "10.0.19.6"
+ ],
+ [
+ "10.0.19.7",
+ "10.0.19.7"
+ ],
+ [
+ "10.0.19.8",
+ "10.0.19.8"
+ ],
+ [
+ "10.0.19.9",
+ "10.0.19.9"
+ ],
+ [
+ "10.0.19.10",
+ "10.0.19.10"
+ ],
+ [
+ "10.0.19.11",
+ "10.0.19.11"
+ ],
+ [
+ "10.0.19.12",
+ "10.0.19.12"
+ ],
+ [
+ "10.0.19.13",
+ "10.0.19.13"
+ ],
+ [
+ "10.0.19.14",
+ "10.0.19.14"
+ ],
+ [
+ "10.0.19.15",
+ "10.0.19.15"
+ ],
+ [
+ "10.0.19.16",
+ "10.0.19.16"
+ ],
+ [
+ "10.0.19.17",
+ "10.0.19.17"
+ ],
+ [
+ "10.0.19.18",
+ "10.0.19.18"
+ ],
+ [
+ "10.0.19.19",
+ "10.0.19.19"
+ ],
+ [
+ "10.0.19.20",
+ "10.0.19.20"
+ ],
+ [
+ "10.0.19.21",
+ "10.0.19.21"
+ ],
+ [
+ "10.0.19.22",
+ "10.0.19.22"
+ ],
+ [
+ "10.0.19.23",
+ "10.0.19.23"
+ ],
+ [
+ "10.0.19.24",
+ "10.0.19.24"
+ ],
+ [
+ "10.0.19.25",
+ "10.0.19.25"
+ ],
+ [
+ "10.0.19.26",
+ "10.0.19.26"
+ ],
+ [
+ "10.0.19.27",
+ "10.0.19.27"
+ ],
+ [
+ "10.0.19.28",
+ "10.0.19.28"
+ ],
+ [
+ "10.0.19.29",
+ "10.0.19.29"
+ ],
+ [
+ "10.0.19.30",
+ "10.0.19.30"
+ ],
+ [
+ "10.0.19.31",
+ "10.0.19.31"
+ ],
+ [
+ "10.0.20.1",
+ "10.0.20.1"
+ ],
+ [
+ "10.0.20.2",
+ "10.0.20.2"
+ ],
+ [
+ "10.0.20.3",
+ "10.0.20.3"
+ ],
+ [
+ "10.0.20.4",
+ "10.0.20.4"
+ ],
+ [
+ "10.0.20.5",
+ "10.0.20.5"
+ ],
+ [
+ "10.0.20.6",
+ "10.0.20.6"
+ ],
+ [
+ "10.0.20.7",
+ "10.0.20.7"
+ ],
+ [
+ "10.0.20.8",
+ "10.0.20.8"
+ ],
+ [
+ "10.0.20.9",
+ "10.0.20.9"
+ ],
+ [
+ "10.0.20.10",
+ "10.0.20.10"
+ ],
+ [
+ "10.0.20.11",
+ "10.0.20.11"
+ ],
+ [
+ "10.0.20.12",
+ "10.0.20.12"
+ ],
+ [
+ "10.0.20.13",
+ "10.0.20.13"
+ ],
+ [
+ "10.0.20.14",
+ "10.0.20.14"
+ ],
+ [
+ "10.0.20.15",
+ "10.0.20.15"
+ ],
+ [
+ "10.0.20.16",
+ "10.0.20.16"
+ ],
+ [
+ "10.0.20.17",
+ "10.0.20.17"
+ ],
+ [
+ "10.0.20.18",
+ "10.0.20.18"
+ ],
+ [
+ "10.0.20.19",
+ "10.0.20.19"
+ ],
+ [
+ "10.0.20.20",
+ "10.0.20.20"
+ ],
+ [
+ "10.0.20.21",
+ "10.0.20.21"
+ ],
+ [
+ "10.0.20.22",
+ "10.0.20.22"
+ ],
+ [
+ "10.0.20.23",
+ "10.0.20.23"
+ ],
+ [
+ "10.0.20.24",
+ "10.0.20.24"
+ ],
+ [
+ "10.0.20.25",
+ "10.0.20.25"
+ ],
+ [
+ "10.0.20.26",
+ "10.0.20.26"
+ ],
+ [
+ "10.0.20.27",
+ "10.0.20.27"
+ ],
+ [
+ "10.0.20.28",
+ "10.0.20.28"
+ ],
+ [
+ "10.0.20.29",
+ "10.0.20.29"
+ ],
+ [
+ "10.0.20.30",
+ "10.0.20.30"
+ ],
+ [
+ "10.0.20.31",
+ "10.0.20.31"
+ ],
+ [
+ "10.0.21.1",
+ "10.0.21.1"
+ ],
+ [
+ "10.0.21.2",
+ "10.0.21.2"
+ ],
+ [
+ "10.0.21.3",
+ "10.0.21.3"
+ ],
+ [
+ "10.0.21.4",
+ "10.0.21.4"
+ ],
+ [
+ "10.0.21.5",
+ "10.0.21.5"
+ ],
+ [
+ "10.0.21.6",
+ "10.0.21.6"
+ ],
+ [
+ "10.0.21.7",
+ "10.0.21.7"
+ ],
+ [
+ "10.0.21.8",
+ "10.0.21.8"
+ ],
+ [
+ "10.0.21.9",
+ "10.0.21.9"
+ ],
+ [
+ "10.0.21.10",
+ "10.0.21.10"
+ ],
+ [
+ "10.0.21.11",
+ "10.0.21.11"
+ ],
+ [
+ "10.0.21.12",
+ "10.0.21.12"
+ ],
+ [
+ "10.0.21.13",
+ "10.0.21.13"
+ ],
+ [
+ "10.0.21.14",
+ "10.0.21.14"
+ ],
+ [
+ "10.0.21.15",
+ "10.0.21.15"
+ ],
+ [
+ "10.0.21.16",
+ "10.0.21.16"
+ ],
+ [
+ "10.0.21.17",
+ "10.0.21.17"
+ ],
+ [
+ "10.0.21.18",
+ "10.0.21.18"
+ ],
+ [
+ "10.0.21.19",
+ "10.0.21.19"
+ ],
+ [
+ "10.0.21.20",
+ "10.0.21.20"
+ ],
+ [
+ "10.0.21.21",
+ "10.0.21.21"
+ ],
+ [
+ "10.0.21.22",
+ "10.0.21.22"
+ ],
+ [
+ "10.0.21.23",
+ "10.0.21.23"
+ ],
+ [
+ "10.0.21.24",
+ "10.0.21.24"
+ ],
+ [
+ "10.0.21.25",
+ "10.0.21.25"
+ ],
+ [
+ "10.0.21.26",
+ "10.0.21.26"
+ ],
+ [
+ "10.0.21.27",
+ "10.0.21.27"
+ ],
+ [
+ "10.0.21.28",
+ "10.0.21.28"
+ ],
+ [
+ "10.0.21.29",
+ "10.0.21.29"
+ ],
+ [
+ "10.0.21.30",
+ "10.0.21.30"
+ ],
+ [
+ "10.0.21.31",
+ "10.0.21.31"
+ ],
+ [
+ "10.0.22.1",
+ "10.0.22.1"
+ ],
+ [
+ "10.0.22.2",
+ "10.0.22.2"
+ ],
+ [
+ "10.0.22.3",
+ "10.0.22.3"
+ ],
+ [
+ "10.0.22.4",
+ "10.0.22.4"
+ ],
+ [
+ "10.0.22.5",
+ "10.0.22.5"
+ ],
+ [
+ "10.0.22.6",
+ "10.0.22.6"
+ ],
+ [
+ "10.0.22.7",
+ "10.0.22.7"
+ ],
+ [
+ "10.0.22.8",
+ "10.0.22.8"
+ ],
+ [
+ "10.0.22.9",
+ "10.0.22.9"
+ ],
+ [
+ "10.0.22.10",
+ "10.0.22.10"
+ ],
+ [
+ "10.0.22.11",
+ "10.0.22.11"
+ ],
+ [
+ "10.0.22.12",
+ "10.0.22.12"
+ ],
+ [
+ "10.0.22.13",
+ "10.0.22.13"
+ ],
+ [
+ "10.0.22.14",
+ "10.0.22.14"
+ ],
+ [
+ "10.0.22.15",
+ "10.0.22.15"
+ ],
+ [
+ "10.0.22.16",
+ "10.0.22.16"
+ ],
+ [
+ "10.0.22.17",
+ "10.0.22.17"
+ ],
+ [
+ "10.0.22.18",
+ "10.0.22.18"
+ ],
+ [
+ "10.0.22.19",
+ "10.0.22.19"
+ ],
+ [
+ "10.0.22.20",
+ "10.0.22.20"
+ ],
+ [
+ "10.0.22.21",
+ "10.0.22.21"
+ ],
+ [
+ "10.0.22.22",
+ "10.0.22.22"
+ ],
+ [
+ "10.0.22.23",
+ "10.0.22.23"
+ ],
+ [
+ "10.0.22.24",
+ "10.0.22.24"
+ ],
+ [
+ "10.0.22.25",
+ "10.0.22.25"
+ ],
+ [
+ "10.0.22.26",
+ "10.0.22.26"
+ ],
+ [
+ "10.0.22.27",
+ "10.0.22.27"
+ ],
+ [
+ "10.0.22.28",
+ "10.0.22.28"
+ ],
+ [
+ "10.0.22.29",
+ "10.0.22.29"
+ ],
+ [
+ "10.0.22.30",
+ "10.0.22.30"
+ ],
+ [
+ "10.0.22.31",
+ "10.0.22.31"
+ ],
+ [
+ "10.0.23.1",
+ "10.0.23.1"
+ ],
+ [
+ "10.0.23.2",
+ "10.0.23.2"
+ ],
+ [
+ "10.0.23.3",
+ "10.0.23.3"
+ ],
+ [
+ "10.0.23.4",
+ "10.0.23.4"
+ ],
+ [
+ "10.0.23.5",
+ "10.0.23.5"
+ ],
+ [
+ "10.0.23.6",
+ "10.0.23.6"
+ ],
+ [
+ "10.0.23.7",
+ "10.0.23.7"
+ ],
+ [
+ "10.0.23.8",
+ "10.0.23.8"
+ ],
+ [
+ "10.0.23.9",
+ "10.0.23.9"
+ ],
+ [
+ "10.0.23.10",
+ "10.0.23.10"
+ ],
+ [
+ "10.0.23.11",
+ "10.0.23.11"
+ ],
+ [
+ "10.0.23.12",
+ "10.0.23.12"
+ ],
+ [
+ "10.0.23.13",
+ "10.0.23.13"
+ ],
+ [
+ "10.0.23.14",
+ "10.0.23.14"
+ ],
+ [
+ "10.0.23.15",
+ "10.0.23.15"
+ ],
+ [
+ "10.0.23.16",
+ "10.0.23.16"
+ ],
+ [
+ "10.0.23.17",
+ "10.0.23.17"
+ ],
+ [
+ "10.0.23.18",
+ "10.0.23.18"
+ ],
+ [
+ "10.0.23.19",
+ "10.0.23.19"
+ ],
+ [
+ "10.0.23.20",
+ "10.0.23.20"
+ ],
+ [
+ "10.0.23.21",
+ "10.0.23.21"
+ ],
+ [
+ "10.0.23.22",
+ "10.0.23.22"
+ ],
+ [
+ "10.0.23.23",
+ "10.0.23.23"
+ ],
+ [
+ "10.0.23.24",
+ "10.0.23.24"
+ ],
+ [
+ "10.0.23.25",
+ "10.0.23.25"
+ ],
+ [
+ "10.0.23.26",
+ "10.0.23.26"
+ ],
+ [
+ "10.0.23.27",
+ "10.0.23.27"
+ ],
+ [
+ "10.0.23.28",
+ "10.0.23.28"
+ ],
+ [
+ "10.0.23.29",
+ "10.0.23.29"
+ ],
+ [
+ "10.0.23.30",
+ "10.0.23.30"
+ ],
+ [
+ "10.0.23.31",
+ "10.0.23.31"
+ ],
+ [
+ "10.0.24.1",
+ "10.0.24.1"
+ ],
+ [
+ "10.0.24.2",
+ "10.0.24.2"
+ ],
+ [
+ "10.0.24.3",
+ "10.0.24.3"
+ ],
+ [
+ "10.0.24.4",
+ "10.0.24.4"
+ ],
+ [
+ "10.0.24.5",
+ "10.0.24.5"
+ ],
+ [
+ "10.0.24.6",
+ "10.0.24.6"
+ ],
+ [
+ "10.0.24.7",
+ "10.0.24.7"
+ ],
+ [
+ "10.0.24.8",
+ "10.0.24.8"
+ ],
+ [
+ "10.0.24.9",
+ "10.0.24.9"
+ ],
+ [
+ "10.0.24.10",
+ "10.0.24.10"
+ ],
+ [
+ "10.0.24.11",
+ "10.0.24.11"
+ ],
+ [
+ "10.0.24.12",
+ "10.0.24.12"
+ ],
+ [
+ "10.0.24.13",
+ "10.0.24.13"
+ ],
+ [
+ "10.0.24.14",
+ "10.0.24.14"
+ ],
+ [
+ "10.0.24.15",
+ "10.0.24.15"
+ ],
+ [
+ "10.0.24.16",
+ "10.0.24.16"
+ ],
+ [
+ "10.0.24.17",
+ "10.0.24.17"
+ ],
+ [
+ "10.0.24.18",
+ "10.0.24.18"
+ ],
+ [
+ "10.0.24.19",
+ "10.0.24.19"
+ ],
+ [
+ "10.0.24.20",
+ "10.0.24.20"
+ ],
+ [
+ "10.0.24.21",
+ "10.0.24.21"
+ ],
+ [
+ "10.0.24.22",
+ "10.0.24.22"
+ ],
+ [
+ "10.0.24.23",
+ "10.0.24.23"
+ ],
+ [
+ "10.0.24.24",
+ "10.0.24.24"
+ ],
+ [
+ "10.0.24.25",
+ "10.0.24.25"
+ ],
+ [
+ "10.0.24.26",
+ "10.0.24.26"
+ ],
+ [
+ "10.0.24.27",
+ "10.0.24.27"
+ ],
+ [
+ "10.0.24.28",
+ "10.0.24.28"
+ ],
+ [
+ "10.0.24.29",
+ "10.0.24.29"
+ ],
+ [
+ "10.0.24.30",
+ "10.0.24.30"
+ ],
+ [
+ "10.0.24.31",
+ "10.0.24.31"
+ ],
+ [
+ "10.0.25.1",
+ "10.0.25.1"
+ ],
+ [
+ "10.0.25.2",
+ "10.0.25.2"
+ ],
+ [
+ "10.0.25.3",
+ "10.0.25.3"
+ ],
+ [
+ "10.0.25.4",
+ "10.0.25.4"
+ ],
+ [
+ "10.0.25.5",
+ "10.0.25.5"
+ ],
+ [
+ "10.0.25.6",
+ "10.0.25.6"
+ ],
+ [
+ "10.0.25.7",
+ "10.0.25.7"
+ ],
+ [
+ "10.0.25.8",
+ "10.0.25.8"
+ ],
+ [
+ "10.0.25.9",
+ "10.0.25.9"
+ ],
+ [
+ "10.0.25.10",
+ "10.0.25.10"
+ ],
+ [
+ "10.0.25.11",
+ "10.0.25.11"
+ ],
+ [
+ "10.0.25.12",
+ "10.0.25.12"
+ ],
+ [
+ "10.0.25.13",
+ "10.0.25.13"
+ ],
+ [
+ "10.0.25.14",
+ "10.0.25.14"
+ ],
+ [
+ "10.0.25.15",
+ "10.0.25.15"
+ ],
+ [
+ "10.0.25.16",
+ "10.0.25.16"
+ ],
+ [
+ "10.0.25.17",
+ "10.0.25.17"
+ ],
+ [
+ "10.0.25.18",
+ "10.0.25.18"
+ ],
+ [
+ "10.0.25.19",
+ "10.0.25.19"
+ ],
+ [
+ "10.0.25.20",
+ "10.0.25.20"
+ ],
+ [
+ "10.0.25.21",
+ "10.0.25.21"
+ ],
+ [
+ "10.0.25.22",
+ "10.0.25.22"
+ ],
+ [
+ "10.0.25.23",
+ "10.0.25.23"
+ ],
+ [
+ "10.0.25.24",
+ "10.0.25.24"
+ ],
+ [
+ "10.0.25.25",
+ "10.0.25.25"
+ ],
+ [
+ "10.0.25.26",
+ "10.0.25.26"
+ ],
+ [
+ "10.0.25.27",
+ "10.0.25.27"
+ ],
+ [
+ "10.0.25.28",
+ "10.0.25.28"
+ ],
+ [
+ "10.0.25.29",
+ "10.0.25.29"
+ ],
+ [
+ "10.0.25.30",
+ "10.0.25.30"
+ ],
+ [
+ "10.0.25.31",
+ "10.0.25.31"
+ ],
+ [
+ "10.0.26.1",
+ "10.0.26.1"
+ ],
+ [
+ "10.0.26.2",
+ "10.0.26.2"
+ ],
+ [
+ "10.0.26.3",
+ "10.0.26.3"
+ ],
+ [
+ "10.0.26.4",
+ "10.0.26.4"
+ ],
+ [
+ "10.0.26.5",
+ "10.0.26.5"
+ ],
+ [
+ "10.0.26.6",
+ "10.0.26.6"
+ ],
+ [
+ "10.0.26.7",
+ "10.0.26.7"
+ ],
+ [
+ "10.0.26.8",
+ "10.0.26.8"
+ ],
+ [
+ "10.0.26.9",
+ "10.0.26.9"
+ ],
+ [
+ "10.0.26.10",
+ "10.0.26.10"
+ ],
+ [
+ "10.0.26.11",
+ "10.0.26.11"
+ ],
+ [
+ "10.0.26.12",
+ "10.0.26.12"
+ ],
+ [
+ "10.0.26.13",
+ "10.0.26.13"
+ ],
+ [
+ "10.0.26.14",
+ "10.0.26.14"
+ ],
+ [
+ "10.0.26.15",
+ "10.0.26.15"
+ ],
+ [
+ "10.0.26.16",
+ "10.0.26.16"
+ ],
+ [
+ "10.0.26.17",
+ "10.0.26.17"
+ ],
+ [
+ "10.0.26.18",
+ "10.0.26.18"
+ ],
+ [
+ "10.0.26.19",
+ "10.0.26.19"
+ ],
+ [
+ "10.0.26.20",
+ "10.0.26.20"
+ ],
+ [
+ "10.0.26.21",
+ "10.0.26.21"
+ ],
+ [
+ "10.0.26.22",
+ "10.0.26.22"
+ ],
+ [
+ "10.0.26.23",
+ "10.0.26.23"
+ ],
+ [
+ "10.0.26.24",
+ "10.0.26.24"
+ ],
+ [
+ "10.0.26.25",
+ "10.0.26.25"
+ ],
+ [
+ "10.0.26.26",
+ "10.0.26.26"
+ ],
+ [
+ "10.0.26.27",
+ "10.0.26.27"
+ ],
+ [
+ "10.0.26.28",
+ "10.0.26.28"
+ ],
+ [
+ "10.0.26.29",
+ "10.0.26.29"
+ ],
+ [
+ "10.0.26.30",
+ "10.0.26.30"
+ ],
+ [
+ "10.0.26.31",
+ "10.0.26.31"
+ ],
+ [
+ "10.0.27.1",
+ "10.0.27.1"
+ ],
+ [
+ "10.0.27.2",
+ "10.0.27.2"
+ ],
+ [
+ "10.0.27.3",
+ "10.0.27.3"
+ ],
+ [
+ "10.0.27.4",
+ "10.0.27.4"
+ ],
+ [
+ "10.0.27.5",
+ "10.0.27.5"
+ ],
+ [
+ "10.0.27.6",
+ "10.0.27.6"
+ ],
+ [
+ "10.0.27.7",
+ "10.0.27.7"
+ ],
+ [
+ "10.0.27.8",
+ "10.0.27.8"
+ ],
+ [
+ "10.0.27.9",
+ "10.0.27.9"
+ ],
+ [
+ "10.0.27.10",
+ "10.0.27.10"
+ ],
+ [
+ "10.0.27.11",
+ "10.0.27.11"
+ ],
+ [
+ "10.0.27.12",
+ "10.0.27.12"
+ ],
+ [
+ "10.0.27.13",
+ "10.0.27.13"
+ ],
+ [
+ "10.0.27.14",
+ "10.0.27.14"
+ ],
+ [
+ "10.0.27.15",
+ "10.0.27.15"
+ ],
+ [
+ "10.0.27.16",
+ "10.0.27.16"
+ ],
+ [
+ "10.0.27.17",
+ "10.0.27.17"
+ ],
+ [
+ "10.0.27.18",
+ "10.0.27.18"
+ ],
+ [
+ "10.0.27.19",
+ "10.0.27.19"
+ ],
+ [
+ "10.0.27.20",
+ "10.0.27.20"
+ ],
+ [
+ "10.0.27.21",
+ "10.0.27.21"
+ ],
+ [
+ "10.0.27.22",
+ "10.0.27.22"
+ ],
+ [
+ "10.0.27.23",
+ "10.0.27.23"
+ ],
+ [
+ "10.0.27.24",
+ "10.0.27.24"
+ ],
+ [
+ "10.0.27.25",
+ "10.0.27.25"
+ ],
+ [
+ "10.0.27.26",
+ "10.0.27.26"
+ ],
+ [
+ "10.0.27.27",
+ "10.0.27.27"
+ ],
+ [
+ "10.0.27.28",
+ "10.0.27.28"
+ ],
+ [
+ "10.0.27.29",
+ "10.0.27.29"
+ ],
+ [
+ "10.0.27.30",
+ "10.0.27.30"
+ ],
+ [
+ "10.0.27.31",
+ "10.0.27.31"
+ ],
+ [
+ "10.0.28.1",
+ "10.0.28.1"
+ ],
+ [
+ "10.0.28.2",
+ "10.0.28.2"
+ ],
+ [
+ "10.0.28.3",
+ "10.0.28.3"
+ ],
+ [
+ "10.0.28.4",
+ "10.0.28.4"
+ ],
+ [
+ "10.0.28.5",
+ "10.0.28.5"
+ ],
+ [
+ "10.0.28.6",
+ "10.0.28.6"
+ ],
+ [
+ "10.0.28.7",
+ "10.0.28.7"
+ ],
+ [
+ "10.0.28.8",
+ "10.0.28.8"
+ ],
+ [
+ "10.0.28.9",
+ "10.0.28.9"
+ ],
+ [
+ "10.0.28.10",
+ "10.0.28.10"
+ ],
+ [
+ "10.0.28.11",
+ "10.0.28.11"
+ ],
+ [
+ "10.0.28.12",
+ "10.0.28.12"
+ ],
+ [
+ "10.0.28.13",
+ "10.0.28.13"
+ ],
+ [
+ "10.0.28.14",
+ "10.0.28.14"
+ ],
+ [
+ "10.0.28.15",
+ "10.0.28.15"
+ ],
+ [
+ "10.0.28.16",
+ "10.0.28.16"
+ ],
+ [
+ "10.0.28.17",
+ "10.0.28.17"
+ ],
+ [
+ "10.0.28.18",
+ "10.0.28.18"
+ ],
+ [
+ "10.0.28.19",
+ "10.0.28.19"
+ ],
+ [
+ "10.0.28.20",
+ "10.0.28.20"
+ ],
+ [
+ "10.0.28.21",
+ "10.0.28.21"
+ ],
+ [
+ "10.0.28.22",
+ "10.0.28.22"
+ ],
+ [
+ "10.0.28.23",
+ "10.0.28.23"
+ ],
+ [
+ "10.0.28.24",
+ "10.0.28.24"
+ ],
+ [
+ "10.0.28.25",
+ "10.0.28.25"
+ ],
+ [
+ "10.0.28.26",
+ "10.0.28.26"
+ ],
+ [
+ "10.0.28.27",
+ "10.0.28.27"
+ ],
+ [
+ "10.0.28.28",
+ "10.0.28.28"
+ ],
+ [
+ "10.0.28.29",
+ "10.0.28.29"
+ ],
+ [
+ "10.0.28.30",
+ "10.0.28.30"
+ ],
+ [
+ "10.0.28.31",
+ "10.0.28.31"
+ ],
+ [
+ "10.0.29.1",
+ "10.0.29.1"
+ ],
+ [
+ "10.0.29.2",
+ "10.0.29.2"
+ ],
+ [
+ "10.0.29.3",
+ "10.0.29.3"
+ ],
+ [
+ "10.0.29.4",
+ "10.0.29.4"
+ ],
+ [
+ "10.0.29.5",
+ "10.0.29.5"
+ ],
+ [
+ "10.0.29.6",
+ "10.0.29.6"
+ ],
+ [
+ "10.0.29.7",
+ "10.0.29.7"
+ ],
+ [
+ "10.0.29.8",
+ "10.0.29.8"
+ ],
+ [
+ "10.0.29.9",
+ "10.0.29.9"
+ ],
+ [
+ "10.0.29.10",
+ "10.0.29.10"
+ ],
+ [
+ "10.0.29.11",
+ "10.0.29.11"
+ ],
+ [
+ "10.0.29.12",
+ "10.0.29.12"
+ ],
+ [
+ "10.0.29.13",
+ "10.0.29.13"
+ ],
+ [
+ "10.0.29.14",
+ "10.0.29.14"
+ ],
+ [
+ "10.0.29.15",
+ "10.0.29.15"
+ ],
+ [
+ "10.0.29.16",
+ "10.0.29.16"
+ ],
+ [
+ "10.0.29.17",
+ "10.0.29.17"
+ ],
+ [
+ "10.0.29.18",
+ "10.0.29.18"
+ ],
+ [
+ "10.0.29.19",
+ "10.0.29.19"
+ ],
+ [
+ "10.0.29.20",
+ "10.0.29.20"
+ ],
+ [
+ "10.0.29.21",
+ "10.0.29.21"
+ ],
+ [
+ "10.0.29.22",
+ "10.0.29.22"
+ ],
+ [
+ "10.0.29.23",
+ "10.0.29.23"
+ ],
+ [
+ "10.0.29.24",
+ "10.0.29.24"
+ ],
+ [
+ "10.0.29.25",
+ "10.0.29.25"
+ ],
+ [
+ "10.0.29.26",
+ "10.0.29.26"
+ ],
+ [
+ "10.0.29.27",
+ "10.0.29.27"
+ ],
+ [
+ "10.0.29.28",
+ "10.0.29.28"
+ ],
+ [
+ "10.0.29.29",
+ "10.0.29.29"
+ ],
+ [
+ "10.0.29.30",
+ "10.0.29.30"
+ ],
+ [
+ "10.0.29.31",
+ "10.0.29.31"
+ ],
+ [
+ "10.0.30.1",
+ "10.0.30.1"
+ ],
+ [
+ "10.0.30.2",
+ "10.0.30.2"
+ ],
+ [
+ "10.0.30.3",
+ "10.0.30.3"
+ ],
+ [
+ "10.0.30.4",
+ "10.0.30.4"
+ ],
+ [
+ "10.0.30.5",
+ "10.0.30.5"
+ ],
+ [
+ "10.0.30.6",
+ "10.0.30.6"
+ ],
+ [
+ "10.0.30.7",
+ "10.0.30.7"
+ ],
+ [
+ "10.0.30.8",
+ "10.0.30.8"
+ ],
+ [
+ "10.0.30.9",
+ "10.0.30.9"
+ ],
+ [
+ "10.0.30.10",
+ "10.0.30.10"
+ ],
+ [
+ "10.0.30.11",
+ "10.0.30.11"
+ ],
+ [
+ "10.0.30.12",
+ "10.0.30.12"
+ ],
+ [
+ "10.0.30.13",
+ "10.0.30.13"
+ ],
+ [
+ "10.0.30.14",
+ "10.0.30.14"
+ ],
+ [
+ "10.0.30.15",
+ "10.0.30.15"
+ ],
+ [
+ "10.0.30.16",
+ "10.0.30.16"
+ ],
+ [
+ "10.0.30.17",
+ "10.0.30.17"
+ ],
+ [
+ "10.0.30.18",
+ "10.0.30.18"
+ ],
+ [
+ "10.0.30.19",
+ "10.0.30.19"
+ ],
+ [
+ "10.0.30.20",
+ "10.0.30.20"
+ ],
+ [
+ "10.0.30.21",
+ "10.0.30.21"
+ ],
+ [
+ "10.0.30.22",
+ "10.0.30.22"
+ ],
+ [
+ "10.0.30.23",
+ "10.0.30.23"
+ ],
+ [
+ "10.0.30.24",
+ "10.0.30.24"
+ ],
+ [
+ "10.0.30.25",
+ "10.0.30.25"
+ ],
+ [
+ "10.0.30.26",
+ "10.0.30.26"
+ ],
+ [
+ "10.0.30.27",
+ "10.0.30.27"
+ ],
+ [
+ "10.0.30.28",
+ "10.0.30.28"
+ ],
+ [
+ "10.0.30.29",
+ "10.0.30.29"
+ ],
+ [
+ "10.0.30.30",
+ "10.0.30.30"
+ ],
+ [
+ "10.0.30.31",
+ "10.0.30.31"
+ ],
+ [
+ "10.0.31.1",
+ "10.0.31.1"
+ ],
+ [
+ "10.0.31.2",
+ "10.0.31.2"
+ ],
+ [
+ "10.0.31.3",
+ "10.0.31.3"
+ ],
+ [
+ "10.0.31.4",
+ "10.0.31.4"
+ ],
+ [
+ "10.0.31.5",
+ "10.0.31.5"
+ ],
+ [
+ "10.0.31.6",
+ "10.0.31.6"
+ ],
+ [
+ "10.0.31.7",
+ "10.0.31.7"
+ ],
+ [
+ "10.0.31.8",
+ "10.0.31.8"
+ ],
+ [
+ "10.0.31.9",
+ "10.0.31.9"
+ ],
+ [
+ "10.0.31.10",
+ "10.0.31.10"
+ ],
+ [
+ "10.0.31.11",
+ "10.0.31.11"
+ ],
+ [
+ "10.0.31.12",
+ "10.0.31.12"
+ ],
+ [
+ "10.0.31.13",
+ "10.0.31.13"
+ ],
+ [
+ "10.0.31.14",
+ "10.0.31.14"
+ ],
+ [
+ "10.0.31.15",
+ "10.0.31.15"
+ ],
+ [
+ "10.0.31.16",
+ "10.0.31.16"
+ ],
+ [
+ "10.0.31.17",
+ "10.0.31.17"
+ ],
+ [
+ "10.0.31.18",
+ "10.0.31.18"
+ ],
+ [
+ "10.0.31.19",
+ "10.0.31.19"
+ ],
+ [
+ "10.0.31.20",
+ "10.0.31.20"
+ ],
+ [
+ "10.0.31.21",
+ "10.0.31.21"
+ ],
+ [
+ "10.0.31.22",
+ "10.0.31.22"
+ ],
+ [
+ "10.0.31.23",
+ "10.0.31.23"
+ ],
+ [
+ "10.0.31.24",
+ "10.0.31.24"
+ ],
+ [
+ "10.0.31.25",
+ "10.0.31.25"
+ ],
+ [
+ "10.0.31.26",
+ "10.0.31.26"
+ ],
+ [
+ "10.0.31.27",
+ "10.0.31.27"
+ ],
+ [
+ "10.0.31.28",
+ "10.0.31.28"
+ ],
+ [
+ "10.0.31.29",
+ "10.0.31.29"
+ ],
+ [
+ "10.0.31.30",
+ "10.0.31.30"
+ ],
+ [
+ "10.0.31.31",
+ "10.0.31.31"
+ ]
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0003map_add_many_elements_0.nft b/tests/shell/testcases/maps/dumps/0003map_add_many_elements_0.nft
new file mode 100644
index 00000000..c651af06
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0003map_add_many_elements_0.nft
@@ -0,0 +1,486 @@
+table ip x {
+ map y {
+ type ipv4_addr : ipv4_addr
+ elements = { 10.0.1.1 : 10.0.1.1, 10.0.1.2 : 10.0.1.2,
+ 10.0.1.3 : 10.0.1.3, 10.0.1.4 : 10.0.1.4,
+ 10.0.1.5 : 10.0.1.5, 10.0.1.6 : 10.0.1.6,
+ 10.0.1.7 : 10.0.1.7, 10.0.1.8 : 10.0.1.8,
+ 10.0.1.9 : 10.0.1.9, 10.0.1.10 : 10.0.1.10,
+ 10.0.1.11 : 10.0.1.11, 10.0.1.12 : 10.0.1.12,
+ 10.0.1.13 : 10.0.1.13, 10.0.1.14 : 10.0.1.14,
+ 10.0.1.15 : 10.0.1.15, 10.0.1.16 : 10.0.1.16,
+ 10.0.1.17 : 10.0.1.17, 10.0.1.18 : 10.0.1.18,
+ 10.0.1.19 : 10.0.1.19, 10.0.1.20 : 10.0.1.20,
+ 10.0.1.21 : 10.0.1.21, 10.0.1.22 : 10.0.1.22,
+ 10.0.1.23 : 10.0.1.23, 10.0.1.24 : 10.0.1.24,
+ 10.0.1.25 : 10.0.1.25, 10.0.1.26 : 10.0.1.26,
+ 10.0.1.27 : 10.0.1.27, 10.0.1.28 : 10.0.1.28,
+ 10.0.1.29 : 10.0.1.29, 10.0.1.30 : 10.0.1.30,
+ 10.0.1.31 : 10.0.1.31, 10.0.2.1 : 10.0.2.1,
+ 10.0.2.2 : 10.0.2.2, 10.0.2.3 : 10.0.2.3,
+ 10.0.2.4 : 10.0.2.4, 10.0.2.5 : 10.0.2.5,
+ 10.0.2.6 : 10.0.2.6, 10.0.2.7 : 10.0.2.7,
+ 10.0.2.8 : 10.0.2.8, 10.0.2.9 : 10.0.2.9,
+ 10.0.2.10 : 10.0.2.10, 10.0.2.11 : 10.0.2.11,
+ 10.0.2.12 : 10.0.2.12, 10.0.2.13 : 10.0.2.13,
+ 10.0.2.14 : 10.0.2.14, 10.0.2.15 : 10.0.2.15,
+ 10.0.2.16 : 10.0.2.16, 10.0.2.17 : 10.0.2.17,
+ 10.0.2.18 : 10.0.2.18, 10.0.2.19 : 10.0.2.19,
+ 10.0.2.20 : 10.0.2.20, 10.0.2.21 : 10.0.2.21,
+ 10.0.2.22 : 10.0.2.22, 10.0.2.23 : 10.0.2.23,
+ 10.0.2.24 : 10.0.2.24, 10.0.2.25 : 10.0.2.25,
+ 10.0.2.26 : 10.0.2.26, 10.0.2.27 : 10.0.2.27,
+ 10.0.2.28 : 10.0.2.28, 10.0.2.29 : 10.0.2.29,
+ 10.0.2.30 : 10.0.2.30, 10.0.2.31 : 10.0.2.31,
+ 10.0.3.1 : 10.0.3.1, 10.0.3.2 : 10.0.3.2,
+ 10.0.3.3 : 10.0.3.3, 10.0.3.4 : 10.0.3.4,
+ 10.0.3.5 : 10.0.3.5, 10.0.3.6 : 10.0.3.6,
+ 10.0.3.7 : 10.0.3.7, 10.0.3.8 : 10.0.3.8,
+ 10.0.3.9 : 10.0.3.9, 10.0.3.10 : 10.0.3.10,
+ 10.0.3.11 : 10.0.3.11, 10.0.3.12 : 10.0.3.12,
+ 10.0.3.13 : 10.0.3.13, 10.0.3.14 : 10.0.3.14,
+ 10.0.3.15 : 10.0.3.15, 10.0.3.16 : 10.0.3.16,
+ 10.0.3.17 : 10.0.3.17, 10.0.3.18 : 10.0.3.18,
+ 10.0.3.19 : 10.0.3.19, 10.0.3.20 : 10.0.3.20,
+ 10.0.3.21 : 10.0.3.21, 10.0.3.22 : 10.0.3.22,
+ 10.0.3.23 : 10.0.3.23, 10.0.3.24 : 10.0.3.24,
+ 10.0.3.25 : 10.0.3.25, 10.0.3.26 : 10.0.3.26,
+ 10.0.3.27 : 10.0.3.27, 10.0.3.28 : 10.0.3.28,
+ 10.0.3.29 : 10.0.3.29, 10.0.3.30 : 10.0.3.30,
+ 10.0.3.31 : 10.0.3.31, 10.0.4.1 : 10.0.4.1,
+ 10.0.4.2 : 10.0.4.2, 10.0.4.3 : 10.0.4.3,
+ 10.0.4.4 : 10.0.4.4, 10.0.4.5 : 10.0.4.5,
+ 10.0.4.6 : 10.0.4.6, 10.0.4.7 : 10.0.4.7,
+ 10.0.4.8 : 10.0.4.8, 10.0.4.9 : 10.0.4.9,
+ 10.0.4.10 : 10.0.4.10, 10.0.4.11 : 10.0.4.11,
+ 10.0.4.12 : 10.0.4.12, 10.0.4.13 : 10.0.4.13,
+ 10.0.4.14 : 10.0.4.14, 10.0.4.15 : 10.0.4.15,
+ 10.0.4.16 : 10.0.4.16, 10.0.4.17 : 10.0.4.17,
+ 10.0.4.18 : 10.0.4.18, 10.0.4.19 : 10.0.4.19,
+ 10.0.4.20 : 10.0.4.20, 10.0.4.21 : 10.0.4.21,
+ 10.0.4.22 : 10.0.4.22, 10.0.4.23 : 10.0.4.23,
+ 10.0.4.24 : 10.0.4.24, 10.0.4.25 : 10.0.4.25,
+ 10.0.4.26 : 10.0.4.26, 10.0.4.27 : 10.0.4.27,
+ 10.0.4.28 : 10.0.4.28, 10.0.4.29 : 10.0.4.29,
+ 10.0.4.30 : 10.0.4.30, 10.0.4.31 : 10.0.4.31,
+ 10.0.5.1 : 10.0.5.1, 10.0.5.2 : 10.0.5.2,
+ 10.0.5.3 : 10.0.5.3, 10.0.5.4 : 10.0.5.4,
+ 10.0.5.5 : 10.0.5.5, 10.0.5.6 : 10.0.5.6,
+ 10.0.5.7 : 10.0.5.7, 10.0.5.8 : 10.0.5.8,
+ 10.0.5.9 : 10.0.5.9, 10.0.5.10 : 10.0.5.10,
+ 10.0.5.11 : 10.0.5.11, 10.0.5.12 : 10.0.5.12,
+ 10.0.5.13 : 10.0.5.13, 10.0.5.14 : 10.0.5.14,
+ 10.0.5.15 : 10.0.5.15, 10.0.5.16 : 10.0.5.16,
+ 10.0.5.17 : 10.0.5.17, 10.0.5.18 : 10.0.5.18,
+ 10.0.5.19 : 10.0.5.19, 10.0.5.20 : 10.0.5.20,
+ 10.0.5.21 : 10.0.5.21, 10.0.5.22 : 10.0.5.22,
+ 10.0.5.23 : 10.0.5.23, 10.0.5.24 : 10.0.5.24,
+ 10.0.5.25 : 10.0.5.25, 10.0.5.26 : 10.0.5.26,
+ 10.0.5.27 : 10.0.5.27, 10.0.5.28 : 10.0.5.28,
+ 10.0.5.29 : 10.0.5.29, 10.0.5.30 : 10.0.5.30,
+ 10.0.5.31 : 10.0.5.31, 10.0.6.1 : 10.0.6.1,
+ 10.0.6.2 : 10.0.6.2, 10.0.6.3 : 10.0.6.3,
+ 10.0.6.4 : 10.0.6.4, 10.0.6.5 : 10.0.6.5,
+ 10.0.6.6 : 10.0.6.6, 10.0.6.7 : 10.0.6.7,
+ 10.0.6.8 : 10.0.6.8, 10.0.6.9 : 10.0.6.9,
+ 10.0.6.10 : 10.0.6.10, 10.0.6.11 : 10.0.6.11,
+ 10.0.6.12 : 10.0.6.12, 10.0.6.13 : 10.0.6.13,
+ 10.0.6.14 : 10.0.6.14, 10.0.6.15 : 10.0.6.15,
+ 10.0.6.16 : 10.0.6.16, 10.0.6.17 : 10.0.6.17,
+ 10.0.6.18 : 10.0.6.18, 10.0.6.19 : 10.0.6.19,
+ 10.0.6.20 : 10.0.6.20, 10.0.6.21 : 10.0.6.21,
+ 10.0.6.22 : 10.0.6.22, 10.0.6.23 : 10.0.6.23,
+ 10.0.6.24 : 10.0.6.24, 10.0.6.25 : 10.0.6.25,
+ 10.0.6.26 : 10.0.6.26, 10.0.6.27 : 10.0.6.27,
+ 10.0.6.28 : 10.0.6.28, 10.0.6.29 : 10.0.6.29,
+ 10.0.6.30 : 10.0.6.30, 10.0.6.31 : 10.0.6.31,
+ 10.0.7.1 : 10.0.7.1, 10.0.7.2 : 10.0.7.2,
+ 10.0.7.3 : 10.0.7.3, 10.0.7.4 : 10.0.7.4,
+ 10.0.7.5 : 10.0.7.5, 10.0.7.6 : 10.0.7.6,
+ 10.0.7.7 : 10.0.7.7, 10.0.7.8 : 10.0.7.8,
+ 10.0.7.9 : 10.0.7.9, 10.0.7.10 : 10.0.7.10,
+ 10.0.7.11 : 10.0.7.11, 10.0.7.12 : 10.0.7.12,
+ 10.0.7.13 : 10.0.7.13, 10.0.7.14 : 10.0.7.14,
+ 10.0.7.15 : 10.0.7.15, 10.0.7.16 : 10.0.7.16,
+ 10.0.7.17 : 10.0.7.17, 10.0.7.18 : 10.0.7.18,
+ 10.0.7.19 : 10.0.7.19, 10.0.7.20 : 10.0.7.20,
+ 10.0.7.21 : 10.0.7.21, 10.0.7.22 : 10.0.7.22,
+ 10.0.7.23 : 10.0.7.23, 10.0.7.24 : 10.0.7.24,
+ 10.0.7.25 : 10.0.7.25, 10.0.7.26 : 10.0.7.26,
+ 10.0.7.27 : 10.0.7.27, 10.0.7.28 : 10.0.7.28,
+ 10.0.7.29 : 10.0.7.29, 10.0.7.30 : 10.0.7.30,
+ 10.0.7.31 : 10.0.7.31, 10.0.8.1 : 10.0.8.1,
+ 10.0.8.2 : 10.0.8.2, 10.0.8.3 : 10.0.8.3,
+ 10.0.8.4 : 10.0.8.4, 10.0.8.5 : 10.0.8.5,
+ 10.0.8.6 : 10.0.8.6, 10.0.8.7 : 10.0.8.7,
+ 10.0.8.8 : 10.0.8.8, 10.0.8.9 : 10.0.8.9,
+ 10.0.8.10 : 10.0.8.10, 10.0.8.11 : 10.0.8.11,
+ 10.0.8.12 : 10.0.8.12, 10.0.8.13 : 10.0.8.13,
+ 10.0.8.14 : 10.0.8.14, 10.0.8.15 : 10.0.8.15,
+ 10.0.8.16 : 10.0.8.16, 10.0.8.17 : 10.0.8.17,
+ 10.0.8.18 : 10.0.8.18, 10.0.8.19 : 10.0.8.19,
+ 10.0.8.20 : 10.0.8.20, 10.0.8.21 : 10.0.8.21,
+ 10.0.8.22 : 10.0.8.22, 10.0.8.23 : 10.0.8.23,
+ 10.0.8.24 : 10.0.8.24, 10.0.8.25 : 10.0.8.25,
+ 10.0.8.26 : 10.0.8.26, 10.0.8.27 : 10.0.8.27,
+ 10.0.8.28 : 10.0.8.28, 10.0.8.29 : 10.0.8.29,
+ 10.0.8.30 : 10.0.8.30, 10.0.8.31 : 10.0.8.31,
+ 10.0.9.1 : 10.0.9.1, 10.0.9.2 : 10.0.9.2,
+ 10.0.9.3 : 10.0.9.3, 10.0.9.4 : 10.0.9.4,
+ 10.0.9.5 : 10.0.9.5, 10.0.9.6 : 10.0.9.6,
+ 10.0.9.7 : 10.0.9.7, 10.0.9.8 : 10.0.9.8,
+ 10.0.9.9 : 10.0.9.9, 10.0.9.10 : 10.0.9.10,
+ 10.0.9.11 : 10.0.9.11, 10.0.9.12 : 10.0.9.12,
+ 10.0.9.13 : 10.0.9.13, 10.0.9.14 : 10.0.9.14,
+ 10.0.9.15 : 10.0.9.15, 10.0.9.16 : 10.0.9.16,
+ 10.0.9.17 : 10.0.9.17, 10.0.9.18 : 10.0.9.18,
+ 10.0.9.19 : 10.0.9.19, 10.0.9.20 : 10.0.9.20,
+ 10.0.9.21 : 10.0.9.21, 10.0.9.22 : 10.0.9.22,
+ 10.0.9.23 : 10.0.9.23, 10.0.9.24 : 10.0.9.24,
+ 10.0.9.25 : 10.0.9.25, 10.0.9.26 : 10.0.9.26,
+ 10.0.9.27 : 10.0.9.27, 10.0.9.28 : 10.0.9.28,
+ 10.0.9.29 : 10.0.9.29, 10.0.9.30 : 10.0.9.30,
+ 10.0.9.31 : 10.0.9.31, 10.0.10.1 : 10.0.10.1,
+ 10.0.10.2 : 10.0.10.2, 10.0.10.3 : 10.0.10.3,
+ 10.0.10.4 : 10.0.10.4, 10.0.10.5 : 10.0.10.5,
+ 10.0.10.6 : 10.0.10.6, 10.0.10.7 : 10.0.10.7,
+ 10.0.10.8 : 10.0.10.8, 10.0.10.9 : 10.0.10.9,
+ 10.0.10.10 : 10.0.10.10, 10.0.10.11 : 10.0.10.11,
+ 10.0.10.12 : 10.0.10.12, 10.0.10.13 : 10.0.10.13,
+ 10.0.10.14 : 10.0.10.14, 10.0.10.15 : 10.0.10.15,
+ 10.0.10.16 : 10.0.10.16, 10.0.10.17 : 10.0.10.17,
+ 10.0.10.18 : 10.0.10.18, 10.0.10.19 : 10.0.10.19,
+ 10.0.10.20 : 10.0.10.20, 10.0.10.21 : 10.0.10.21,
+ 10.0.10.22 : 10.0.10.22, 10.0.10.23 : 10.0.10.23,
+ 10.0.10.24 : 10.0.10.24, 10.0.10.25 : 10.0.10.25,
+ 10.0.10.26 : 10.0.10.26, 10.0.10.27 : 10.0.10.27,
+ 10.0.10.28 : 10.0.10.28, 10.0.10.29 : 10.0.10.29,
+ 10.0.10.30 : 10.0.10.30, 10.0.10.31 : 10.0.10.31,
+ 10.0.11.1 : 10.0.11.1, 10.0.11.2 : 10.0.11.2,
+ 10.0.11.3 : 10.0.11.3, 10.0.11.4 : 10.0.11.4,
+ 10.0.11.5 : 10.0.11.5, 10.0.11.6 : 10.0.11.6,
+ 10.0.11.7 : 10.0.11.7, 10.0.11.8 : 10.0.11.8,
+ 10.0.11.9 : 10.0.11.9, 10.0.11.10 : 10.0.11.10,
+ 10.0.11.11 : 10.0.11.11, 10.0.11.12 : 10.0.11.12,
+ 10.0.11.13 : 10.0.11.13, 10.0.11.14 : 10.0.11.14,
+ 10.0.11.15 : 10.0.11.15, 10.0.11.16 : 10.0.11.16,
+ 10.0.11.17 : 10.0.11.17, 10.0.11.18 : 10.0.11.18,
+ 10.0.11.19 : 10.0.11.19, 10.0.11.20 : 10.0.11.20,
+ 10.0.11.21 : 10.0.11.21, 10.0.11.22 : 10.0.11.22,
+ 10.0.11.23 : 10.0.11.23, 10.0.11.24 : 10.0.11.24,
+ 10.0.11.25 : 10.0.11.25, 10.0.11.26 : 10.0.11.26,
+ 10.0.11.27 : 10.0.11.27, 10.0.11.28 : 10.0.11.28,
+ 10.0.11.29 : 10.0.11.29, 10.0.11.30 : 10.0.11.30,
+ 10.0.11.31 : 10.0.11.31, 10.0.12.1 : 10.0.12.1,
+ 10.0.12.2 : 10.0.12.2, 10.0.12.3 : 10.0.12.3,
+ 10.0.12.4 : 10.0.12.4, 10.0.12.5 : 10.0.12.5,
+ 10.0.12.6 : 10.0.12.6, 10.0.12.7 : 10.0.12.7,
+ 10.0.12.8 : 10.0.12.8, 10.0.12.9 : 10.0.12.9,
+ 10.0.12.10 : 10.0.12.10, 10.0.12.11 : 10.0.12.11,
+ 10.0.12.12 : 10.0.12.12, 10.0.12.13 : 10.0.12.13,
+ 10.0.12.14 : 10.0.12.14, 10.0.12.15 : 10.0.12.15,
+ 10.0.12.16 : 10.0.12.16, 10.0.12.17 : 10.0.12.17,
+ 10.0.12.18 : 10.0.12.18, 10.0.12.19 : 10.0.12.19,
+ 10.0.12.20 : 10.0.12.20, 10.0.12.21 : 10.0.12.21,
+ 10.0.12.22 : 10.0.12.22, 10.0.12.23 : 10.0.12.23,
+ 10.0.12.24 : 10.0.12.24, 10.0.12.25 : 10.0.12.25,
+ 10.0.12.26 : 10.0.12.26, 10.0.12.27 : 10.0.12.27,
+ 10.0.12.28 : 10.0.12.28, 10.0.12.29 : 10.0.12.29,
+ 10.0.12.30 : 10.0.12.30, 10.0.12.31 : 10.0.12.31,
+ 10.0.13.1 : 10.0.13.1, 10.0.13.2 : 10.0.13.2,
+ 10.0.13.3 : 10.0.13.3, 10.0.13.4 : 10.0.13.4,
+ 10.0.13.5 : 10.0.13.5, 10.0.13.6 : 10.0.13.6,
+ 10.0.13.7 : 10.0.13.7, 10.0.13.8 : 10.0.13.8,
+ 10.0.13.9 : 10.0.13.9, 10.0.13.10 : 10.0.13.10,
+ 10.0.13.11 : 10.0.13.11, 10.0.13.12 : 10.0.13.12,
+ 10.0.13.13 : 10.0.13.13, 10.0.13.14 : 10.0.13.14,
+ 10.0.13.15 : 10.0.13.15, 10.0.13.16 : 10.0.13.16,
+ 10.0.13.17 : 10.0.13.17, 10.0.13.18 : 10.0.13.18,
+ 10.0.13.19 : 10.0.13.19, 10.0.13.20 : 10.0.13.20,
+ 10.0.13.21 : 10.0.13.21, 10.0.13.22 : 10.0.13.22,
+ 10.0.13.23 : 10.0.13.23, 10.0.13.24 : 10.0.13.24,
+ 10.0.13.25 : 10.0.13.25, 10.0.13.26 : 10.0.13.26,
+ 10.0.13.27 : 10.0.13.27, 10.0.13.28 : 10.0.13.28,
+ 10.0.13.29 : 10.0.13.29, 10.0.13.30 : 10.0.13.30,
+ 10.0.13.31 : 10.0.13.31, 10.0.14.1 : 10.0.14.1,
+ 10.0.14.2 : 10.0.14.2, 10.0.14.3 : 10.0.14.3,
+ 10.0.14.4 : 10.0.14.4, 10.0.14.5 : 10.0.14.5,
+ 10.0.14.6 : 10.0.14.6, 10.0.14.7 : 10.0.14.7,
+ 10.0.14.8 : 10.0.14.8, 10.0.14.9 : 10.0.14.9,
+ 10.0.14.10 : 10.0.14.10, 10.0.14.11 : 10.0.14.11,
+ 10.0.14.12 : 10.0.14.12, 10.0.14.13 : 10.0.14.13,
+ 10.0.14.14 : 10.0.14.14, 10.0.14.15 : 10.0.14.15,
+ 10.0.14.16 : 10.0.14.16, 10.0.14.17 : 10.0.14.17,
+ 10.0.14.18 : 10.0.14.18, 10.0.14.19 : 10.0.14.19,
+ 10.0.14.20 : 10.0.14.20, 10.0.14.21 : 10.0.14.21,
+ 10.0.14.22 : 10.0.14.22, 10.0.14.23 : 10.0.14.23,
+ 10.0.14.24 : 10.0.14.24, 10.0.14.25 : 10.0.14.25,
+ 10.0.14.26 : 10.0.14.26, 10.0.14.27 : 10.0.14.27,
+ 10.0.14.28 : 10.0.14.28, 10.0.14.29 : 10.0.14.29,
+ 10.0.14.30 : 10.0.14.30, 10.0.14.31 : 10.0.14.31,
+ 10.0.15.1 : 10.0.15.1, 10.0.15.2 : 10.0.15.2,
+ 10.0.15.3 : 10.0.15.3, 10.0.15.4 : 10.0.15.4,
+ 10.0.15.5 : 10.0.15.5, 10.0.15.6 : 10.0.15.6,
+ 10.0.15.7 : 10.0.15.7, 10.0.15.8 : 10.0.15.8,
+ 10.0.15.9 : 10.0.15.9, 10.0.15.10 : 10.0.15.10,
+ 10.0.15.11 : 10.0.15.11, 10.0.15.12 : 10.0.15.12,
+ 10.0.15.13 : 10.0.15.13, 10.0.15.14 : 10.0.15.14,
+ 10.0.15.15 : 10.0.15.15, 10.0.15.16 : 10.0.15.16,
+ 10.0.15.17 : 10.0.15.17, 10.0.15.18 : 10.0.15.18,
+ 10.0.15.19 : 10.0.15.19, 10.0.15.20 : 10.0.15.20,
+ 10.0.15.21 : 10.0.15.21, 10.0.15.22 : 10.0.15.22,
+ 10.0.15.23 : 10.0.15.23, 10.0.15.24 : 10.0.15.24,
+ 10.0.15.25 : 10.0.15.25, 10.0.15.26 : 10.0.15.26,
+ 10.0.15.27 : 10.0.15.27, 10.0.15.28 : 10.0.15.28,
+ 10.0.15.29 : 10.0.15.29, 10.0.15.30 : 10.0.15.30,
+ 10.0.15.31 : 10.0.15.31, 10.0.16.1 : 10.0.16.1,
+ 10.0.16.2 : 10.0.16.2, 10.0.16.3 : 10.0.16.3,
+ 10.0.16.4 : 10.0.16.4, 10.0.16.5 : 10.0.16.5,
+ 10.0.16.6 : 10.0.16.6, 10.0.16.7 : 10.0.16.7,
+ 10.0.16.8 : 10.0.16.8, 10.0.16.9 : 10.0.16.9,
+ 10.0.16.10 : 10.0.16.10, 10.0.16.11 : 10.0.16.11,
+ 10.0.16.12 : 10.0.16.12, 10.0.16.13 : 10.0.16.13,
+ 10.0.16.14 : 10.0.16.14, 10.0.16.15 : 10.0.16.15,
+ 10.0.16.16 : 10.0.16.16, 10.0.16.17 : 10.0.16.17,
+ 10.0.16.18 : 10.0.16.18, 10.0.16.19 : 10.0.16.19,
+ 10.0.16.20 : 10.0.16.20, 10.0.16.21 : 10.0.16.21,
+ 10.0.16.22 : 10.0.16.22, 10.0.16.23 : 10.0.16.23,
+ 10.0.16.24 : 10.0.16.24, 10.0.16.25 : 10.0.16.25,
+ 10.0.16.26 : 10.0.16.26, 10.0.16.27 : 10.0.16.27,
+ 10.0.16.28 : 10.0.16.28, 10.0.16.29 : 10.0.16.29,
+ 10.0.16.30 : 10.0.16.30, 10.0.16.31 : 10.0.16.31,
+ 10.0.17.1 : 10.0.17.1, 10.0.17.2 : 10.0.17.2,
+ 10.0.17.3 : 10.0.17.3, 10.0.17.4 : 10.0.17.4,
+ 10.0.17.5 : 10.0.17.5, 10.0.17.6 : 10.0.17.6,
+ 10.0.17.7 : 10.0.17.7, 10.0.17.8 : 10.0.17.8,
+ 10.0.17.9 : 10.0.17.9, 10.0.17.10 : 10.0.17.10,
+ 10.0.17.11 : 10.0.17.11, 10.0.17.12 : 10.0.17.12,
+ 10.0.17.13 : 10.0.17.13, 10.0.17.14 : 10.0.17.14,
+ 10.0.17.15 : 10.0.17.15, 10.0.17.16 : 10.0.17.16,
+ 10.0.17.17 : 10.0.17.17, 10.0.17.18 : 10.0.17.18,
+ 10.0.17.19 : 10.0.17.19, 10.0.17.20 : 10.0.17.20,
+ 10.0.17.21 : 10.0.17.21, 10.0.17.22 : 10.0.17.22,
+ 10.0.17.23 : 10.0.17.23, 10.0.17.24 : 10.0.17.24,
+ 10.0.17.25 : 10.0.17.25, 10.0.17.26 : 10.0.17.26,
+ 10.0.17.27 : 10.0.17.27, 10.0.17.28 : 10.0.17.28,
+ 10.0.17.29 : 10.0.17.29, 10.0.17.30 : 10.0.17.30,
+ 10.0.17.31 : 10.0.17.31, 10.0.18.1 : 10.0.18.1,
+ 10.0.18.2 : 10.0.18.2, 10.0.18.3 : 10.0.18.3,
+ 10.0.18.4 : 10.0.18.4, 10.0.18.5 : 10.0.18.5,
+ 10.0.18.6 : 10.0.18.6, 10.0.18.7 : 10.0.18.7,
+ 10.0.18.8 : 10.0.18.8, 10.0.18.9 : 10.0.18.9,
+ 10.0.18.10 : 10.0.18.10, 10.0.18.11 : 10.0.18.11,
+ 10.0.18.12 : 10.0.18.12, 10.0.18.13 : 10.0.18.13,
+ 10.0.18.14 : 10.0.18.14, 10.0.18.15 : 10.0.18.15,
+ 10.0.18.16 : 10.0.18.16, 10.0.18.17 : 10.0.18.17,
+ 10.0.18.18 : 10.0.18.18, 10.0.18.19 : 10.0.18.19,
+ 10.0.18.20 : 10.0.18.20, 10.0.18.21 : 10.0.18.21,
+ 10.0.18.22 : 10.0.18.22, 10.0.18.23 : 10.0.18.23,
+ 10.0.18.24 : 10.0.18.24, 10.0.18.25 : 10.0.18.25,
+ 10.0.18.26 : 10.0.18.26, 10.0.18.27 : 10.0.18.27,
+ 10.0.18.28 : 10.0.18.28, 10.0.18.29 : 10.0.18.29,
+ 10.0.18.30 : 10.0.18.30, 10.0.18.31 : 10.0.18.31,
+ 10.0.19.1 : 10.0.19.1, 10.0.19.2 : 10.0.19.2,
+ 10.0.19.3 : 10.0.19.3, 10.0.19.4 : 10.0.19.4,
+ 10.0.19.5 : 10.0.19.5, 10.0.19.6 : 10.0.19.6,
+ 10.0.19.7 : 10.0.19.7, 10.0.19.8 : 10.0.19.8,
+ 10.0.19.9 : 10.0.19.9, 10.0.19.10 : 10.0.19.10,
+ 10.0.19.11 : 10.0.19.11, 10.0.19.12 : 10.0.19.12,
+ 10.0.19.13 : 10.0.19.13, 10.0.19.14 : 10.0.19.14,
+ 10.0.19.15 : 10.0.19.15, 10.0.19.16 : 10.0.19.16,
+ 10.0.19.17 : 10.0.19.17, 10.0.19.18 : 10.0.19.18,
+ 10.0.19.19 : 10.0.19.19, 10.0.19.20 : 10.0.19.20,
+ 10.0.19.21 : 10.0.19.21, 10.0.19.22 : 10.0.19.22,
+ 10.0.19.23 : 10.0.19.23, 10.0.19.24 : 10.0.19.24,
+ 10.0.19.25 : 10.0.19.25, 10.0.19.26 : 10.0.19.26,
+ 10.0.19.27 : 10.0.19.27, 10.0.19.28 : 10.0.19.28,
+ 10.0.19.29 : 10.0.19.29, 10.0.19.30 : 10.0.19.30,
+ 10.0.19.31 : 10.0.19.31, 10.0.20.1 : 10.0.20.1,
+ 10.0.20.2 : 10.0.20.2, 10.0.20.3 : 10.0.20.3,
+ 10.0.20.4 : 10.0.20.4, 10.0.20.5 : 10.0.20.5,
+ 10.0.20.6 : 10.0.20.6, 10.0.20.7 : 10.0.20.7,
+ 10.0.20.8 : 10.0.20.8, 10.0.20.9 : 10.0.20.9,
+ 10.0.20.10 : 10.0.20.10, 10.0.20.11 : 10.0.20.11,
+ 10.0.20.12 : 10.0.20.12, 10.0.20.13 : 10.0.20.13,
+ 10.0.20.14 : 10.0.20.14, 10.0.20.15 : 10.0.20.15,
+ 10.0.20.16 : 10.0.20.16, 10.0.20.17 : 10.0.20.17,
+ 10.0.20.18 : 10.0.20.18, 10.0.20.19 : 10.0.20.19,
+ 10.0.20.20 : 10.0.20.20, 10.0.20.21 : 10.0.20.21,
+ 10.0.20.22 : 10.0.20.22, 10.0.20.23 : 10.0.20.23,
+ 10.0.20.24 : 10.0.20.24, 10.0.20.25 : 10.0.20.25,
+ 10.0.20.26 : 10.0.20.26, 10.0.20.27 : 10.0.20.27,
+ 10.0.20.28 : 10.0.20.28, 10.0.20.29 : 10.0.20.29,
+ 10.0.20.30 : 10.0.20.30, 10.0.20.31 : 10.0.20.31,
+ 10.0.21.1 : 10.0.21.1, 10.0.21.2 : 10.0.21.2,
+ 10.0.21.3 : 10.0.21.3, 10.0.21.4 : 10.0.21.4,
+ 10.0.21.5 : 10.0.21.5, 10.0.21.6 : 10.0.21.6,
+ 10.0.21.7 : 10.0.21.7, 10.0.21.8 : 10.0.21.8,
+ 10.0.21.9 : 10.0.21.9, 10.0.21.10 : 10.0.21.10,
+ 10.0.21.11 : 10.0.21.11, 10.0.21.12 : 10.0.21.12,
+ 10.0.21.13 : 10.0.21.13, 10.0.21.14 : 10.0.21.14,
+ 10.0.21.15 : 10.0.21.15, 10.0.21.16 : 10.0.21.16,
+ 10.0.21.17 : 10.0.21.17, 10.0.21.18 : 10.0.21.18,
+ 10.0.21.19 : 10.0.21.19, 10.0.21.20 : 10.0.21.20,
+ 10.0.21.21 : 10.0.21.21, 10.0.21.22 : 10.0.21.22,
+ 10.0.21.23 : 10.0.21.23, 10.0.21.24 : 10.0.21.24,
+ 10.0.21.25 : 10.0.21.25, 10.0.21.26 : 10.0.21.26,
+ 10.0.21.27 : 10.0.21.27, 10.0.21.28 : 10.0.21.28,
+ 10.0.21.29 : 10.0.21.29, 10.0.21.30 : 10.0.21.30,
+ 10.0.21.31 : 10.0.21.31, 10.0.22.1 : 10.0.22.1,
+ 10.0.22.2 : 10.0.22.2, 10.0.22.3 : 10.0.22.3,
+ 10.0.22.4 : 10.0.22.4, 10.0.22.5 : 10.0.22.5,
+ 10.0.22.6 : 10.0.22.6, 10.0.22.7 : 10.0.22.7,
+ 10.0.22.8 : 10.0.22.8, 10.0.22.9 : 10.0.22.9,
+ 10.0.22.10 : 10.0.22.10, 10.0.22.11 : 10.0.22.11,
+ 10.0.22.12 : 10.0.22.12, 10.0.22.13 : 10.0.22.13,
+ 10.0.22.14 : 10.0.22.14, 10.0.22.15 : 10.0.22.15,
+ 10.0.22.16 : 10.0.22.16, 10.0.22.17 : 10.0.22.17,
+ 10.0.22.18 : 10.0.22.18, 10.0.22.19 : 10.0.22.19,
+ 10.0.22.20 : 10.0.22.20, 10.0.22.21 : 10.0.22.21,
+ 10.0.22.22 : 10.0.22.22, 10.0.22.23 : 10.0.22.23,
+ 10.0.22.24 : 10.0.22.24, 10.0.22.25 : 10.0.22.25,
+ 10.0.22.26 : 10.0.22.26, 10.0.22.27 : 10.0.22.27,
+ 10.0.22.28 : 10.0.22.28, 10.0.22.29 : 10.0.22.29,
+ 10.0.22.30 : 10.0.22.30, 10.0.22.31 : 10.0.22.31,
+ 10.0.23.1 : 10.0.23.1, 10.0.23.2 : 10.0.23.2,
+ 10.0.23.3 : 10.0.23.3, 10.0.23.4 : 10.0.23.4,
+ 10.0.23.5 : 10.0.23.5, 10.0.23.6 : 10.0.23.6,
+ 10.0.23.7 : 10.0.23.7, 10.0.23.8 : 10.0.23.8,
+ 10.0.23.9 : 10.0.23.9, 10.0.23.10 : 10.0.23.10,
+ 10.0.23.11 : 10.0.23.11, 10.0.23.12 : 10.0.23.12,
+ 10.0.23.13 : 10.0.23.13, 10.0.23.14 : 10.0.23.14,
+ 10.0.23.15 : 10.0.23.15, 10.0.23.16 : 10.0.23.16,
+ 10.0.23.17 : 10.0.23.17, 10.0.23.18 : 10.0.23.18,
+ 10.0.23.19 : 10.0.23.19, 10.0.23.20 : 10.0.23.20,
+ 10.0.23.21 : 10.0.23.21, 10.0.23.22 : 10.0.23.22,
+ 10.0.23.23 : 10.0.23.23, 10.0.23.24 : 10.0.23.24,
+ 10.0.23.25 : 10.0.23.25, 10.0.23.26 : 10.0.23.26,
+ 10.0.23.27 : 10.0.23.27, 10.0.23.28 : 10.0.23.28,
+ 10.0.23.29 : 10.0.23.29, 10.0.23.30 : 10.0.23.30,
+ 10.0.23.31 : 10.0.23.31, 10.0.24.1 : 10.0.24.1,
+ 10.0.24.2 : 10.0.24.2, 10.0.24.3 : 10.0.24.3,
+ 10.0.24.4 : 10.0.24.4, 10.0.24.5 : 10.0.24.5,
+ 10.0.24.6 : 10.0.24.6, 10.0.24.7 : 10.0.24.7,
+ 10.0.24.8 : 10.0.24.8, 10.0.24.9 : 10.0.24.9,
+ 10.0.24.10 : 10.0.24.10, 10.0.24.11 : 10.0.24.11,
+ 10.0.24.12 : 10.0.24.12, 10.0.24.13 : 10.0.24.13,
+ 10.0.24.14 : 10.0.24.14, 10.0.24.15 : 10.0.24.15,
+ 10.0.24.16 : 10.0.24.16, 10.0.24.17 : 10.0.24.17,
+ 10.0.24.18 : 10.0.24.18, 10.0.24.19 : 10.0.24.19,
+ 10.0.24.20 : 10.0.24.20, 10.0.24.21 : 10.0.24.21,
+ 10.0.24.22 : 10.0.24.22, 10.0.24.23 : 10.0.24.23,
+ 10.0.24.24 : 10.0.24.24, 10.0.24.25 : 10.0.24.25,
+ 10.0.24.26 : 10.0.24.26, 10.0.24.27 : 10.0.24.27,
+ 10.0.24.28 : 10.0.24.28, 10.0.24.29 : 10.0.24.29,
+ 10.0.24.30 : 10.0.24.30, 10.0.24.31 : 10.0.24.31,
+ 10.0.25.1 : 10.0.25.1, 10.0.25.2 : 10.0.25.2,
+ 10.0.25.3 : 10.0.25.3, 10.0.25.4 : 10.0.25.4,
+ 10.0.25.5 : 10.0.25.5, 10.0.25.6 : 10.0.25.6,
+ 10.0.25.7 : 10.0.25.7, 10.0.25.8 : 10.0.25.8,
+ 10.0.25.9 : 10.0.25.9, 10.0.25.10 : 10.0.25.10,
+ 10.0.25.11 : 10.0.25.11, 10.0.25.12 : 10.0.25.12,
+ 10.0.25.13 : 10.0.25.13, 10.0.25.14 : 10.0.25.14,
+ 10.0.25.15 : 10.0.25.15, 10.0.25.16 : 10.0.25.16,
+ 10.0.25.17 : 10.0.25.17, 10.0.25.18 : 10.0.25.18,
+ 10.0.25.19 : 10.0.25.19, 10.0.25.20 : 10.0.25.20,
+ 10.0.25.21 : 10.0.25.21, 10.0.25.22 : 10.0.25.22,
+ 10.0.25.23 : 10.0.25.23, 10.0.25.24 : 10.0.25.24,
+ 10.0.25.25 : 10.0.25.25, 10.0.25.26 : 10.0.25.26,
+ 10.0.25.27 : 10.0.25.27, 10.0.25.28 : 10.0.25.28,
+ 10.0.25.29 : 10.0.25.29, 10.0.25.30 : 10.0.25.30,
+ 10.0.25.31 : 10.0.25.31, 10.0.26.1 : 10.0.26.1,
+ 10.0.26.2 : 10.0.26.2, 10.0.26.3 : 10.0.26.3,
+ 10.0.26.4 : 10.0.26.4, 10.0.26.5 : 10.0.26.5,
+ 10.0.26.6 : 10.0.26.6, 10.0.26.7 : 10.0.26.7,
+ 10.0.26.8 : 10.0.26.8, 10.0.26.9 : 10.0.26.9,
+ 10.0.26.10 : 10.0.26.10, 10.0.26.11 : 10.0.26.11,
+ 10.0.26.12 : 10.0.26.12, 10.0.26.13 : 10.0.26.13,
+ 10.0.26.14 : 10.0.26.14, 10.0.26.15 : 10.0.26.15,
+ 10.0.26.16 : 10.0.26.16, 10.0.26.17 : 10.0.26.17,
+ 10.0.26.18 : 10.0.26.18, 10.0.26.19 : 10.0.26.19,
+ 10.0.26.20 : 10.0.26.20, 10.0.26.21 : 10.0.26.21,
+ 10.0.26.22 : 10.0.26.22, 10.0.26.23 : 10.0.26.23,
+ 10.0.26.24 : 10.0.26.24, 10.0.26.25 : 10.0.26.25,
+ 10.0.26.26 : 10.0.26.26, 10.0.26.27 : 10.0.26.27,
+ 10.0.26.28 : 10.0.26.28, 10.0.26.29 : 10.0.26.29,
+ 10.0.26.30 : 10.0.26.30, 10.0.26.31 : 10.0.26.31,
+ 10.0.27.1 : 10.0.27.1, 10.0.27.2 : 10.0.27.2,
+ 10.0.27.3 : 10.0.27.3, 10.0.27.4 : 10.0.27.4,
+ 10.0.27.5 : 10.0.27.5, 10.0.27.6 : 10.0.27.6,
+ 10.0.27.7 : 10.0.27.7, 10.0.27.8 : 10.0.27.8,
+ 10.0.27.9 : 10.0.27.9, 10.0.27.10 : 10.0.27.10,
+ 10.0.27.11 : 10.0.27.11, 10.0.27.12 : 10.0.27.12,
+ 10.0.27.13 : 10.0.27.13, 10.0.27.14 : 10.0.27.14,
+ 10.0.27.15 : 10.0.27.15, 10.0.27.16 : 10.0.27.16,
+ 10.0.27.17 : 10.0.27.17, 10.0.27.18 : 10.0.27.18,
+ 10.0.27.19 : 10.0.27.19, 10.0.27.20 : 10.0.27.20,
+ 10.0.27.21 : 10.0.27.21, 10.0.27.22 : 10.0.27.22,
+ 10.0.27.23 : 10.0.27.23, 10.0.27.24 : 10.0.27.24,
+ 10.0.27.25 : 10.0.27.25, 10.0.27.26 : 10.0.27.26,
+ 10.0.27.27 : 10.0.27.27, 10.0.27.28 : 10.0.27.28,
+ 10.0.27.29 : 10.0.27.29, 10.0.27.30 : 10.0.27.30,
+ 10.0.27.31 : 10.0.27.31, 10.0.28.1 : 10.0.28.1,
+ 10.0.28.2 : 10.0.28.2, 10.0.28.3 : 10.0.28.3,
+ 10.0.28.4 : 10.0.28.4, 10.0.28.5 : 10.0.28.5,
+ 10.0.28.6 : 10.0.28.6, 10.0.28.7 : 10.0.28.7,
+ 10.0.28.8 : 10.0.28.8, 10.0.28.9 : 10.0.28.9,
+ 10.0.28.10 : 10.0.28.10, 10.0.28.11 : 10.0.28.11,
+ 10.0.28.12 : 10.0.28.12, 10.0.28.13 : 10.0.28.13,
+ 10.0.28.14 : 10.0.28.14, 10.0.28.15 : 10.0.28.15,
+ 10.0.28.16 : 10.0.28.16, 10.0.28.17 : 10.0.28.17,
+ 10.0.28.18 : 10.0.28.18, 10.0.28.19 : 10.0.28.19,
+ 10.0.28.20 : 10.0.28.20, 10.0.28.21 : 10.0.28.21,
+ 10.0.28.22 : 10.0.28.22, 10.0.28.23 : 10.0.28.23,
+ 10.0.28.24 : 10.0.28.24, 10.0.28.25 : 10.0.28.25,
+ 10.0.28.26 : 10.0.28.26, 10.0.28.27 : 10.0.28.27,
+ 10.0.28.28 : 10.0.28.28, 10.0.28.29 : 10.0.28.29,
+ 10.0.28.30 : 10.0.28.30, 10.0.28.31 : 10.0.28.31,
+ 10.0.29.1 : 10.0.29.1, 10.0.29.2 : 10.0.29.2,
+ 10.0.29.3 : 10.0.29.3, 10.0.29.4 : 10.0.29.4,
+ 10.0.29.5 : 10.0.29.5, 10.0.29.6 : 10.0.29.6,
+ 10.0.29.7 : 10.0.29.7, 10.0.29.8 : 10.0.29.8,
+ 10.0.29.9 : 10.0.29.9, 10.0.29.10 : 10.0.29.10,
+ 10.0.29.11 : 10.0.29.11, 10.0.29.12 : 10.0.29.12,
+ 10.0.29.13 : 10.0.29.13, 10.0.29.14 : 10.0.29.14,
+ 10.0.29.15 : 10.0.29.15, 10.0.29.16 : 10.0.29.16,
+ 10.0.29.17 : 10.0.29.17, 10.0.29.18 : 10.0.29.18,
+ 10.0.29.19 : 10.0.29.19, 10.0.29.20 : 10.0.29.20,
+ 10.0.29.21 : 10.0.29.21, 10.0.29.22 : 10.0.29.22,
+ 10.0.29.23 : 10.0.29.23, 10.0.29.24 : 10.0.29.24,
+ 10.0.29.25 : 10.0.29.25, 10.0.29.26 : 10.0.29.26,
+ 10.0.29.27 : 10.0.29.27, 10.0.29.28 : 10.0.29.28,
+ 10.0.29.29 : 10.0.29.29, 10.0.29.30 : 10.0.29.30,
+ 10.0.29.31 : 10.0.29.31, 10.0.30.1 : 10.0.30.1,
+ 10.0.30.2 : 10.0.30.2, 10.0.30.3 : 10.0.30.3,
+ 10.0.30.4 : 10.0.30.4, 10.0.30.5 : 10.0.30.5,
+ 10.0.30.6 : 10.0.30.6, 10.0.30.7 : 10.0.30.7,
+ 10.0.30.8 : 10.0.30.8, 10.0.30.9 : 10.0.30.9,
+ 10.0.30.10 : 10.0.30.10, 10.0.30.11 : 10.0.30.11,
+ 10.0.30.12 : 10.0.30.12, 10.0.30.13 : 10.0.30.13,
+ 10.0.30.14 : 10.0.30.14, 10.0.30.15 : 10.0.30.15,
+ 10.0.30.16 : 10.0.30.16, 10.0.30.17 : 10.0.30.17,
+ 10.0.30.18 : 10.0.30.18, 10.0.30.19 : 10.0.30.19,
+ 10.0.30.20 : 10.0.30.20, 10.0.30.21 : 10.0.30.21,
+ 10.0.30.22 : 10.0.30.22, 10.0.30.23 : 10.0.30.23,
+ 10.0.30.24 : 10.0.30.24, 10.0.30.25 : 10.0.30.25,
+ 10.0.30.26 : 10.0.30.26, 10.0.30.27 : 10.0.30.27,
+ 10.0.30.28 : 10.0.30.28, 10.0.30.29 : 10.0.30.29,
+ 10.0.30.30 : 10.0.30.30, 10.0.30.31 : 10.0.30.31,
+ 10.0.31.1 : 10.0.31.1, 10.0.31.2 : 10.0.31.2,
+ 10.0.31.3 : 10.0.31.3, 10.0.31.4 : 10.0.31.4,
+ 10.0.31.5 : 10.0.31.5, 10.0.31.6 : 10.0.31.6,
+ 10.0.31.7 : 10.0.31.7, 10.0.31.8 : 10.0.31.8,
+ 10.0.31.9 : 10.0.31.9, 10.0.31.10 : 10.0.31.10,
+ 10.0.31.11 : 10.0.31.11, 10.0.31.12 : 10.0.31.12,
+ 10.0.31.13 : 10.0.31.13, 10.0.31.14 : 10.0.31.14,
+ 10.0.31.15 : 10.0.31.15, 10.0.31.16 : 10.0.31.16,
+ 10.0.31.17 : 10.0.31.17, 10.0.31.18 : 10.0.31.18,
+ 10.0.31.19 : 10.0.31.19, 10.0.31.20 : 10.0.31.20,
+ 10.0.31.21 : 10.0.31.21, 10.0.31.22 : 10.0.31.22,
+ 10.0.31.23 : 10.0.31.23, 10.0.31.24 : 10.0.31.24,
+ 10.0.31.25 : 10.0.31.25, 10.0.31.26 : 10.0.31.26,
+ 10.0.31.27 : 10.0.31.27, 10.0.31.28 : 10.0.31.28,
+ 10.0.31.29 : 10.0.31.29, 10.0.31.30 : 10.0.31.30,
+ 10.0.31.31 : 10.0.31.31 }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0004interval_map_create_once_0.nodump b/tests/shell/testcases/maps/dumps/0004interval_map_create_once_0.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0004interval_map_create_once_0.nodump
diff --git a/tests/shell/testcases/maps/dumps/0005interval_map_add_many_elements_0.json-nft b/tests/shell/testcases/maps/dumps/0005interval_map_add_many_elements_0.json-nft
new file mode 100644
index 00000000..d1a46295
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0005interval_map_add_many_elements_0.json-nft
@@ -0,0 +1,69 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "ipv4_addr",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "prefix": {
+ "addr": "10.1.1.0",
+ "len": 24
+ }
+ },
+ "10.0.1.1"
+ ],
+ [
+ {
+ "prefix": {
+ "addr": "10.1.2.0",
+ "len": 24
+ }
+ },
+ "10.0.1.2"
+ ],
+ [
+ {
+ "prefix": {
+ "addr": "10.2.1.0",
+ "len": 24
+ }
+ },
+ "10.0.2.1"
+ ],
+ [
+ {
+ "prefix": {
+ "addr": "10.2.2.0",
+ "len": 24
+ }
+ },
+ "10.0.2.2"
+ ]
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0006interval_map_overlap_0.json-nft b/tests/shell/testcases/maps/dumps/0006interval_map_overlap_0.json-nft
new file mode 100644
index 00000000..1e983219
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0006interval_map_overlap_0.json-nft
@@ -0,0 +1,51 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "ipv4_addr",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "prefix": {
+ "addr": "10.0.1.0",
+ "len": 24
+ }
+ },
+ "10.0.0.1"
+ ],
+ [
+ {
+ "prefix": {
+ "addr": "10.0.2.0",
+ "len": 24
+ }
+ },
+ "10.0.0.2"
+ ]
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0007named_ifname_dtype_0.json-nft b/tests/shell/testcases/maps/dumps/0007named_ifname_dtype_0.json-nft
new file mode 100644
index 00000000..ef57a749
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0007named_ifname_dtype_0.json-nft
@@ -0,0 +1,102 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "m1",
+ "table": "t",
+ "type": "ifname",
+ "handle": 0,
+ "map": "ipv4_addr",
+ "elem": [
+ [
+ "eth0",
+ "1.1.1.1"
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "data": "@m1"
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "data": "@m1"
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0008interval_map_delete_0.json-nft b/tests/shell/testcases/maps/dumps/0008interval_map_delete_0.json-nft
new file mode 100644
index 00000000..bd3c6cc7
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0008interval_map_delete_0.json-nft
@@ -0,0 +1,159 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "m",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "mark",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ "127.0.0.2",
+ 2
+ ],
+ [
+ "127.0.0.3",
+ 3
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "data": "@m"
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "right": 2
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "right": 3
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0008interval_map_delete_0.nft b/tests/shell/testcases/maps/dumps/0008interval_map_delete_0.nft
new file mode 100644
index 00000000..a470a340
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0008interval_map_delete_0.nft
@@ -0,0 +1,15 @@
+table ip filter {
+ map m {
+ type ipv4_addr : mark
+ flags interval
+ elements = { 127.0.0.2 : 0x00000002, 127.0.0.3 : 0x00000003 }
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ meta mark set ip daddr map @m
+ meta mark 0x00000002 counter packets 0 bytes 0 accept
+ meta mark 0x00000003 counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0009vmap_0.json-nft b/tests/shell/testcases/maps/dumps/0009vmap_0.json-nft
new file mode 100644
index 00000000..345a2c74
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0009vmap_0.json-nft
@@ -0,0 +1,117 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "ssh_input",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "wan_input",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "prerouting",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "wan_input",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 22,
+ {
+ "jump": {
+ "target": "ssh_input"
+ }
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "prerouting",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "meta": {
+ "key": "iif"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "elem": {
+ "val": "lo",
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ },
+ {
+ "jump": {
+ "target": "wan_input"
+ }
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0009vmap_0.nft b/tests/shell/testcases/maps/dumps/0009vmap_0.nft
new file mode 100644
index 00000000..c37574ad
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0009vmap_0.nft
@@ -0,0 +1,13 @@
+table inet filter {
+ chain ssh_input {
+ }
+
+ chain wan_input {
+ tcp dport vmap { 22 : jump ssh_input }
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority raw; policy accept;
+ iif vmap { "lo" counter packets 0 bytes 0 : jump wan_input }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0010concat_map_0.json-nft b/tests/shell/testcases/maps/dumps/0010concat_map_0.json-nft
new file mode 100644
index 00000000..fcc23bb8
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0010concat_map_0.json-nft
@@ -0,0 +1,106 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "nat",
+ "hook": "prerouting",
+ "prio": -100,
+ "policy": "accept"
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "z",
+ "table": "x",
+ "type": [
+ "ipv4_addr",
+ "inet_proto",
+ "inet_service"
+ ],
+ "handle": 0,
+ "map": [
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "elem": [
+ [
+ {
+ "concat": [
+ "1.1.1.1",
+ "tcp",
+ 20
+ ]
+ },
+ {
+ "concat": [
+ "2.2.2.2",
+ 30
+ ]
+ }
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "dnat": {
+ "family": "ip",
+ "addr": {
+ "map": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "protocol"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "data": "@z"
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0010concat_map_0.nft b/tests/shell/testcases/maps/dumps/0010concat_map_0.nft
new file mode 100644
index 00000000..2f796b51
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0010concat_map_0.nft
@@ -0,0 +1,11 @@
+table inet x {
+ map z {
+ type ipv4_addr . inet_proto . inet_service : ipv4_addr . inet_service
+ elements = { 1.1.1.1 . tcp . 20 : 2.2.2.2 . 30 }
+ }
+
+ chain y {
+ type nat hook prerouting priority dstnat; policy accept;
+ dnat ip to ip saddr . ip protocol . tcp dport map @z
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0011vmap_0.json-nft b/tests/shell/testcases/maps/dumps/0011vmap_0.json-nft
new file mode 100644
index 00000000..8f07378a
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0011vmap_0.json-nft
@@ -0,0 +1,145 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "ssh_input",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "wan_input",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "prerouting",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "portmap",
+ "table": "filter",
+ "type": "inet_service",
+ "handle": 0,
+ "map": "verdict",
+ "elem": [
+ [
+ {
+ "elem": {
+ "val": 22,
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ },
+ {
+ "jump": {
+ "target": "ssh_input"
+ }
+ }
+ ],
+ [
+ {
+ "elem": {
+ "val": "*",
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ ],
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "wan_input",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "data": "@portmap"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "prerouting",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "meta": {
+ "key": "iif"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "lo",
+ {
+ "jump": {
+ "target": "wan_input"
+ }
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0011vmap_0.nft b/tests/shell/testcases/maps/dumps/0011vmap_0.nft
new file mode 100644
index 00000000..4a72b5e7
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0011vmap_0.nft
@@ -0,0 +1,19 @@
+table inet filter {
+ map portmap {
+ type inet_service : verdict
+ counter
+ elements = { 22 counter packets 0 bytes 0 : jump ssh_input, * counter packets 0 bytes 0 : drop }
+ }
+
+ chain ssh_input {
+ }
+
+ chain wan_input {
+ tcp dport vmap @portmap
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority raw; policy accept;
+ iif vmap { "lo" : jump wan_input }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0012map_0.json-nft b/tests/shell/testcases/maps/dumps/0012map_0.json-nft
new file mode 100644
index 00000000..2892e11d
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0012map_0.json-nft
@@ -0,0 +1,97 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "z",
+ "table": "x",
+ "type": "ifname",
+ "handle": 0,
+ "map": "verdict",
+ "elem": [
+ [
+ "lo",
+ {
+ "accept": null
+ }
+ ],
+ [
+ "eth0",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "eth1",
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "lo",
+ {
+ "accept": null
+ }
+ ],
+ [
+ "eth0",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "eth1",
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0012map_0.nft b/tests/shell/testcases/maps/dumps/0012map_0.nft
new file mode 100644
index 00000000..e734fc1c
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0012map_0.nft
@@ -0,0 +1,12 @@
+table ip x {
+ map z {
+ type ifname : verdict
+ elements = { "lo" : accept,
+ "eth0" : drop,
+ "eth1" : drop }
+ }
+
+ chain y {
+ iifname vmap { "lo" : accept, "eth0" : drop, "eth1" : drop }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0012map_concat_0.json-nft b/tests/shell/testcases/maps/dumps/0012map_concat_0.json-nft
new file mode 100644
index 00000000..00052236
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0012map_concat_0.json-nft
@@ -0,0 +1,132 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "k",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 1,
+ "policy": "accept"
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "w",
+ "table": "x",
+ "type": [
+ "ipv4_addr",
+ "mark"
+ ],
+ "handle": 0,
+ "map": "verdict",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "elem": {
+ "val": {
+ "concat": [
+ {
+ "range": [
+ "127.0.0.1",
+ "127.0.0.4"
+ ]
+ },
+ {
+ "range": [
+ 1193012,
+ 11534626
+ ]
+ }
+ ]
+ },
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ ],
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "k",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": 1193012
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "k",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "mark"
+ }
+ }
+ ]
+ },
+ "data": "@w"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0012map_concat_0.nft b/tests/shell/testcases/maps/dumps/0012map_concat_0.nft
new file mode 100644
index 00000000..6649d034
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0012map_concat_0.nft
@@ -0,0 +1,14 @@
+table ip x {
+ map w {
+ typeof ip saddr . meta mark : verdict
+ flags interval
+ counter
+ elements = { 127.0.0.1-127.0.0.4 . 0x00123434-0x00b00122 counter packets 0 bytes 0 : accept }
+ }
+
+ chain k {
+ type filter hook input priority filter + 1; policy accept;
+ meta mark set 0x00123434
+ ip saddr . meta mark vmap @w
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0013map_0.json-nft b/tests/shell/testcases/maps/dumps/0013map_0.json-nft
new file mode 100644
index 00000000..e91a269d
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0013map_0.json-nft
@@ -0,0 +1,128 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "FORWARD",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 0,
+ "policy": "drop"
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "forwport",
+ "table": "filter",
+ "type": [
+ "ipv4_addr",
+ "inet_proto",
+ "inet_service"
+ ],
+ "handle": 0,
+ "map": "verdict",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "elem": {
+ "val": {
+ "concat": [
+ "10.133.89.138",
+ "tcp",
+ 8081
+ ]
+ },
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ ],
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "enp0s8"
+ }
+ },
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "protocol"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "th",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "data": "@forwport"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0013map_0.nft b/tests/shell/testcases/maps/dumps/0013map_0.nft
new file mode 100644
index 00000000..1455877d
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0013map_0.nft
@@ -0,0 +1,13 @@
+table ip filter {
+ map forwport {
+ type ipv4_addr . inet_proto . inet_service : verdict
+ flags interval
+ counter
+ elements = { 10.133.89.138 . tcp . 8081 counter packets 0 bytes 0 : accept }
+ }
+
+ chain FORWARD {
+ type filter hook forward priority filter; policy drop;
+ iifname "enp0s8" ip daddr . ip protocol . th dport vmap @forwport counter packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0014destroy_0.json-nft b/tests/shell/testcases/maps/dumps/0014destroy_0.json-nft
new file mode 100644
index 00000000..15ec0aac
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0014destroy_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0014destroy_0.nft b/tests/shell/testcases/maps/dumps/0014destroy_0.nft
new file mode 100644
index 00000000..5d4d2caf
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0014destroy_0.nft
@@ -0,0 +1,2 @@
+table ip x {
+}
diff --git a/tests/shell/testcases/maps/dumps/0016map_leak_0.json-nft b/tests/shell/testcases/maps/dumps/0016map_leak_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0016map_leak_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0016map_leak_0.nft b/tests/shell/testcases/maps/dumps/0016map_leak_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0016map_leak_0.nft
diff --git a/tests/shell/testcases/maps/dumps/0017_map_variable_0.json-nft b/tests/shell/testcases/maps/dumps/0017_map_variable_0.json-nft
new file mode 100644
index 00000000..725498cd
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0017_map_variable_0.json-nft
@@ -0,0 +1,58 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "mark",
+ "elem": [
+ [
+ "1.1.1.1",
+ 2
+ ],
+ [
+ "*",
+ 3
+ ]
+ ]
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "z",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "mark",
+ "elem": [
+ [
+ "1.1.1.1",
+ 2
+ ],
+ [
+ "*",
+ 3
+ ]
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0017_map_variable_0.nft b/tests/shell/testcases/maps/dumps/0017_map_variable_0.nft
new file mode 100644
index 00000000..796dd729
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0017_map_variable_0.nft
@@ -0,0 +1,11 @@
+table ip x {
+ map y {
+ typeof ip saddr : meta mark
+ elements = { 1.1.1.1 : 0x00000002, * : 0x00000003 }
+ }
+
+ map z {
+ typeof ip saddr : meta mark
+ elements = { 1.1.1.1 : 0x00000002, * : 0x00000003 }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/0018map_leak_timeout_0.json-nft b/tests/shell/testcases/maps/dumps/0018map_leak_timeout_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0018map_leak_timeout_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/0018map_leak_timeout_0.nft b/tests/shell/testcases/maps/dumps/0018map_leak_timeout_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0018map_leak_timeout_0.nft
diff --git a/tests/shell/testcases/maps/dumps/0024named_objects_0.json-nft b/tests/shell/testcases/maps/dumps/0024named_objects_0.json-nft
new file mode 100644
index 00000000..aa2f6f8c
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/0024named_objects_0.json-nft
@@ -0,0 +1,165 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "counter": {
+ "family": "inet",
+ "name": "user123",
+ "table": "x",
+ "handle": 0,
+ "packets": 12,
+ "bytes": 1433
+ }
+ },
+ {
+ "counter": {
+ "family": "inet",
+ "name": "user321",
+ "table": "x",
+ "handle": 0,
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "quota": {
+ "family": "inet",
+ "name": "user123",
+ "table": "x",
+ "handle": 0,
+ "bytes": 2000,
+ "used": 0,
+ "inv": true
+ }
+ },
+ {
+ "quota": {
+ "family": "inet",
+ "name": "user124",
+ "table": "x",
+ "handle": 0,
+ "bytes": 2000,
+ "used": 0,
+ "inv": true
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "test",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "quota",
+ "elem": [
+ [
+ "192.168.2.2",
+ "user124"
+ ],
+ [
+ "192.168.2.3",
+ "user124"
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ "user123"
+ ],
+ [
+ "2.2.2.2",
+ "user123"
+ ],
+ [
+ "192.168.2.2",
+ "user123"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "quota": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": "@test"
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0024named_objects_0.nft b/tests/shell/testcases/maps/dumps/0024named_objects_0.nft
index 2ffa4f2f..2ffa4f2f 100644
--- a/tests/shell/testcases/sets/dumps/0024named_objects_0.nft
+++ b/tests/shell/testcases/maps/dumps/0024named_objects_0.nft
diff --git a/tests/shell/testcases/maps/dumps/anon_objmap_concat.json-nft b/tests/shell/testcases/maps/dumps/anon_objmap_concat.json-nft
new file mode 100644
index 00000000..64209842
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/anon_objmap_concat.json-nft
@@ -0,0 +1,116 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "ct helper": {
+ "family": "inet",
+ "name": "sip-5060u",
+ "table": "filter",
+ "handle": 0,
+ "type": "sip",
+ "protocol": "udp",
+ "l3proto": "ip"
+ }
+ },
+ {
+ "ct helper": {
+ "family": "inet",
+ "name": "sip-5060t",
+ "table": "filter",
+ "handle": 0,
+ "type": "sip",
+ "protocol": "tcp",
+ "l3proto": "ip"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "ct helper": {
+ "map": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "protocol"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "th",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "udp",
+ {
+ "range": [
+ 10000,
+ 20000
+ ]
+ }
+ ]
+ },
+ "sip-5060u"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "range": [
+ 10000,
+ 20000
+ ]
+ }
+ ]
+ },
+ "sip-5060t"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/anon_objmap_concat.nft b/tests/shell/testcases/maps/dumps/anon_objmap_concat.nft
new file mode 100644
index 00000000..23aca0a2
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/anon_objmap_concat.nft
@@ -0,0 +1,16 @@
+table inet filter {
+ ct helper sip-5060u {
+ type "sip" protocol udp
+ l3proto ip
+ }
+
+ ct helper sip-5060t {
+ type "sip" protocol tcp
+ l3proto ip
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ ct helper set ip protocol . th dport map { udp . 10000-20000 : "sip-5060u", tcp . 10000-20000 : "sip-5060t" }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/anonymous_snat_map_0.json-nft b/tests/shell/testcases/maps/dumps/anonymous_snat_map_0.json-nft
new file mode 100644
index 00000000..f4c55706
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/anonymous_snat_map_0.json-nft
@@ -0,0 +1,58 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "nat",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "nat",
+ "name": "postrouting",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "nat",
+ "chain": "postrouting",
+ "handle": 0,
+ "expr": [
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ "2.2.2.2"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/different_map_types_1.json-nft b/tests/shell/testcases/maps/dumps/different_map_types_1.json-nft
new file mode 100644
index 00000000..ed0ce0ed
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/different_map_types_1.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "output",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/different_map_types_1.nft b/tests/shell/testcases/maps/dumps/different_map_types_1.nft
new file mode 100644
index 00000000..3c18b5c7
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/different_map_types_1.nft
@@ -0,0 +1,5 @@
+table ip filter {
+ chain output {
+ type filter hook output priority filter; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/map_catchall_double_deactivate.json-nft b/tests/shell/testcases/maps/dumps/map_catchall_double_deactivate.json-nft
new file mode 100644
index 00000000..49b8bb29
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/map_catchall_double_deactivate.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test",
+ "name": "testchain",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/map_catchall_double_deactivate.nft b/tests/shell/testcases/maps/dumps/map_catchall_double_deactivate.nft
new file mode 100644
index 00000000..37c48bf3
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/map_catchall_double_deactivate.nft
@@ -0,0 +1,4 @@
+table ip test {
+ chain testchain {
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/map_catchall_double_free.nodump b/tests/shell/testcases/maps/dumps/map_catchall_double_free.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/map_catchall_double_free.nodump
diff --git a/tests/shell/testcases/maps/dumps/map_catchall_double_free_2.json-nft b/tests/shell/testcases/maps/dumps/map_catchall_double_free_2.json-nft
new file mode 100644
index 00000000..a9d4c8e9
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/map_catchall_double_free_2.json-nft
@@ -0,0 +1,46 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test",
+ "name": "testchain",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "testmap",
+ "table": "test",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "verdict",
+ "elem": [
+ [
+ "*",
+ {
+ "jump": {
+ "target": "testchain"
+ }
+ }
+ ]
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/map_catchall_double_free_2.nft b/tests/shell/testcases/maps/dumps/map_catchall_double_free_2.nft
new file mode 100644
index 00000000..68958c40
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/map_catchall_double_free_2.nft
@@ -0,0 +1,9 @@
+table ip test {
+ map testmap {
+ type ipv4_addr : verdict
+ elements = { * : jump testchain }
+ }
+
+ chain testchain {
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/map_with_flags_0.json-nft b/tests/shell/testcases/maps/dumps/map_with_flags_0.json-nft
new file mode 100644
index 00000000..97b7e94e
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/map_with_flags_0.json-nft
@@ -0,0 +1,31 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "ipv4_addr",
+ "flags": [
+ "timeout"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/named_ct_objects.nft b/tests/shell/testcases/maps/dumps/named_ct_objects.nft
new file mode 100644
index 00000000..59f18932
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/named_ct_objects.nft
@@ -0,0 +1,71 @@
+table inet t {
+ ct expectation exp1 {
+ protocol tcp
+ dport 9876
+ timeout 1m
+ size 12
+ l3proto ip
+ }
+
+ ct expectation exp2 {
+ protocol tcp
+ dport 9876
+ timeout 3s
+ size 13
+ l3proto ip6
+ }
+
+ ct helper myftp {
+ type "ftp" protocol tcp
+ l3proto inet
+ }
+
+ ct timeout dns {
+ protocol tcp
+ l3proto ip
+ policy = { established : 3s, close : 1s }
+ }
+
+ map exp {
+ typeof ip saddr : ct expectation
+ elements = { 192.168.2.2 : "exp1" }
+ }
+
+ map exp6 {
+ typeof ip6 saddr : ct expectation
+ flags interval
+ elements = { dead:beef::/64 : "exp2" }
+ }
+
+ map helpobj {
+ typeof ip6 saddr : ct helper
+ flags interval
+ elements = { dead:beef::/64 : "myftp" }
+ }
+
+ map timeoutmap {
+ typeof ip daddr : ct timeout
+ elements = { 192.168.0.1 : "dns" }
+ }
+
+ set helpname {
+ typeof ct helper
+ elements = { "sip",
+ "ftp" }
+ }
+
+ chain y {
+ ct expectation set ip saddr map @exp
+ ct expectation set ip6 saddr map { dead::beef : "exp2" }
+ ct expectation set ip6 daddr map { dead::beef : "exp2", feed::17 : "exp2" }
+ ct expectation set ip6 daddr . tcp dport map { feed::17 . 512 : "exp2", dead::beef . 123 : "exp2" }
+ ct helper set ip6 saddr map { 1c3::c01d : "myftp", dead::beef : "myftp" }
+ ct helper set ip6 saddr map @helpobj
+ ct timeout set ip daddr map @timeoutmap
+ ct timeout set ip daddr map { 1.2.3.4 : "dns", 5.6.7.8 : "dns", 192.168.8.0/24 : "dns" }
+ ct timeout set ip daddr map { 1.2.3.4-1.2.3.8 : "dns" }
+ ct timeout set ip6 daddr map { 1ce::/64 : "dns", dead::beef : "dns" }
+ ct helper @helpname accept
+ ip saddr 192.168.1.1 ct timeout set "dns"
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/named_limits.json-nft b/tests/shell/testcases/maps/dumps/named_limits.json-nft
new file mode 100644
index 00000000..7fa12981
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/named_limits.json-nft
@@ -0,0 +1,328 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "limit": {
+ "family": "inet",
+ "name": "tarpit-pps",
+ "table": "filter",
+ "handle": 0,
+ "rate": 1,
+ "per": "second",
+ "burst": 5
+ }
+ },
+ {
+ "limit": {
+ "family": "inet",
+ "name": "tarpit-bps",
+ "table": "filter",
+ "handle": 0,
+ "rate": 1,
+ "per": "second",
+ "rate_unit": "kbytes"
+ }
+ },
+ {
+ "limit": {
+ "family": "inet",
+ "name": "http-bulk-rl-1m",
+ "table": "filter",
+ "handle": 0,
+ "rate": 1,
+ "per": "second",
+ "rate_unit": "mbytes"
+ }
+ },
+ {
+ "limit": {
+ "family": "inet",
+ "name": "http-bulk-rl-10m",
+ "table": "filter",
+ "handle": 0,
+ "rate": 10,
+ "per": "second",
+ "rate_unit": "mbytes"
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "tarpit4",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 10000,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ],
+ "timeout": 60
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "tarpit6",
+ "table": "filter",
+ "type": "ipv6_addr",
+ "handle": 0,
+ "size": 10000,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ],
+ "timeout": 60
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "addr4limit",
+ "table": "filter",
+ "type": [
+ "inet_proto",
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "map": "limit",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "prefix": {
+ "addr": "192.168.0.0",
+ "len": 16
+ }
+ },
+ {
+ "range": [
+ 1,
+ 65535
+ ]
+ }
+ ]
+ },
+ "tarpit-bps"
+ ],
+ [
+ {
+ "concat": [
+ "udp",
+ {
+ "prefix": {
+ "addr": "192.168.0.0",
+ "len": 16
+ }
+ },
+ {
+ "range": [
+ 1,
+ 65535
+ ]
+ }
+ ]
+ },
+ "tarpit-pps"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "range": [
+ "127.0.0.1",
+ "127.1.2.3"
+ ]
+ },
+ {
+ "range": [
+ 1,
+ 1024
+ ]
+ }
+ ]
+ },
+ "tarpit-pps"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "range": [
+ "10.0.0.1",
+ "10.0.0.255"
+ ]
+ },
+ 80
+ ]
+ },
+ "http-bulk-rl-1m"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "range": [
+ "10.0.0.1",
+ "10.0.0.255"
+ ]
+ },
+ 443
+ ]
+ },
+ "http-bulk-rl-1m"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ {
+ "prefix": {
+ "addr": "10.0.1.0",
+ "len": 24
+ }
+ },
+ {
+ "range": [
+ 1024,
+ 65535
+ ]
+ }
+ ]
+ },
+ "http-bulk-rl-10m"
+ ],
+ [
+ {
+ "concat": [
+ "tcp",
+ "10.0.2.1",
+ 22
+ ]
+ },
+ "http-bulk-rl-10m"
+ ]
+ ]
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "saddr6limit",
+ "table": "filter",
+ "type": "ipv6_addr",
+ "handle": 0,
+ "map": "limit",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "range": [
+ "dead::beef",
+ "dead::1:aced"
+ ]
+ },
+ "tarpit-pps"
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "limit": {
+ "map": {
+ "key": {
+ "concat": [
+ {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "th",
+ "field": "sport"
+ }
+ }
+ ]
+ },
+ "data": "@addr4limit"
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "limit": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "saddr"
+ }
+ },
+ "data": "@saddr6limit"
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/named_limits.nft b/tests/shell/testcases/maps/dumps/named_limits.nft
new file mode 100644
index 00000000..214df204
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/named_limits.nft
@@ -0,0 +1,55 @@
+table inet filter {
+ limit tarpit-pps {
+ rate 1/second
+ }
+
+ limit tarpit-bps {
+ rate 1 kbytes/second
+ }
+
+ limit http-bulk-rl-1m {
+ rate 1 mbytes/second
+ }
+
+ limit http-bulk-rl-10m {
+ rate 10 mbytes/second
+ }
+
+ set tarpit4 {
+ typeof ip saddr
+ size 10000
+ flags dynamic,timeout
+ timeout 1m
+ }
+
+ set tarpit6 {
+ typeof ip6 saddr
+ size 10000
+ flags dynamic,timeout
+ timeout 1m
+ }
+
+ map addr4limit {
+ typeof meta l4proto . ip saddr . tcp sport : limit
+ flags interval
+ elements = { tcp . 192.168.0.0/16 . 1-65535 : "tarpit-bps",
+ udp . 192.168.0.0/16 . 1-65535 : "tarpit-pps",
+ tcp . 127.0.0.1-127.1.2.3 . 1-1024 : "tarpit-pps",
+ tcp . 10.0.0.1-10.0.0.255 . 80 : "http-bulk-rl-1m",
+ tcp . 10.0.0.1-10.0.0.255 . 443 : "http-bulk-rl-1m",
+ tcp . 10.0.1.0/24 . 1024-65535 : "http-bulk-rl-10m",
+ tcp . 10.0.2.1 . 22 : "http-bulk-rl-10m" }
+ }
+
+ map saddr6limit {
+ typeof ip6 saddr : limit
+ flags interval
+ elements = { dead::beef-dead::1:aced : "tarpit-pps" }
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ limit name meta l4proto . ip saddr . th sport map @addr4limit
+ limit name ip6 saddr map @saddr6limit
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/named_snat_map_0.json-nft b/tests/shell/testcases/maps/dumps/named_snat_map_0.json-nft
new file mode 100644
index 00000000..ad9eb36e
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/named_snat_map_0.json-nft
@@ -0,0 +1,67 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "nat",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "nat",
+ "name": "postrouting",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "m",
+ "table": "nat",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "ipv4_addr",
+ "elem": [
+ [
+ "1.1.1.1",
+ "2.2.2.2"
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "nat",
+ "chain": "postrouting",
+ "handle": 0,
+ "expr": [
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": "@m"
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/nat_addr_port.nft b/tests/shell/testcases/maps/dumps/nat_addr_port.nft
new file mode 100644
index 00000000..c8493b3a
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/nat_addr_port.nft
@@ -0,0 +1,129 @@
+table ip ipfoo {
+ map t1 {
+ typeof numgen inc mod 2 : ip daddr
+ }
+
+ map t2 {
+ typeof numgen inc mod 2 : ip daddr . tcp dport
+ }
+
+ map x {
+ type ipv4_addr : ipv4_addr
+ }
+
+ map y {
+ type ipv4_addr : ipv4_addr . inet_service
+ elements = { 192.168.7.2 : 10.1.1.1 . 4242 }
+ }
+
+ map z {
+ type ipv4_addr . inet_service : ipv4_addr . inet_service
+ elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ iifname != "foobar" accept
+ dnat to ip daddr map @x
+ ip saddr 10.1.1.1 dnat to 10.2.3.4
+ ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+ meta l4proto tcp dnat ip to ip saddr map @y
+ dnat ip to ip saddr . tcp dport map @z
+ dnat to numgen inc mod 2 map @t1
+ meta l4proto tcp dnat ip to numgen inc mod 2 map @t2
+ }
+}
+table ip6 ip6foo {
+ map t1 {
+ typeof numgen inc mod 2 : ip6 daddr
+ }
+
+ map t2 {
+ typeof numgen inc mod 2 : ip6 daddr . tcp dport
+ }
+
+ map x {
+ type ipv6_addr : ipv6_addr
+ }
+
+ map y {
+ type ipv6_addr : ipv6_addr . inet_service
+ }
+
+ map z {
+ type ipv6_addr . inet_service : ipv6_addr . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ iifname != "foobar" accept
+ dnat to ip6 daddr map @x
+ ip6 saddr dead::1 dnat to feed::1
+ ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
+ meta l4proto tcp dnat ip6 to ip6 saddr map @y
+ dnat ip6 to ip6 saddr . tcp dport map @z
+ dnat to numgen inc mod 2 map @t1
+ meta l4proto tcp dnat ip6 to numgen inc mod 2 map @t2
+ }
+}
+table inet inetfoo {
+ map t1v4 {
+ typeof numgen inc mod 2 : ip daddr
+ }
+
+ map t2v4 {
+ typeof numgen inc mod 2 : ip daddr . tcp dport
+ }
+
+ map t1v6 {
+ typeof numgen inc mod 2 : ip6 daddr
+ }
+
+ map t2v6 {
+ typeof numgen inc mod 2 : ip6 daddr . tcp dport
+ }
+
+ map x4 {
+ type ipv4_addr : ipv4_addr
+ }
+
+ map y4 {
+ type ipv4_addr : ipv4_addr . inet_service
+ }
+
+ map z4 {
+ type ipv4_addr . inet_service : ipv4_addr . inet_service
+ elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+ }
+
+ map x6 {
+ type ipv6_addr : ipv6_addr
+ }
+
+ map y6 {
+ type ipv6_addr : ipv6_addr . inet_service
+ }
+
+ map z6 {
+ type ipv6_addr . inet_service : ipv6_addr . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ iifname != "foobar" accept
+ dnat ip to ip daddr map @x4
+ ip saddr 10.1.1.1 dnat ip to 10.2.3.4
+ ip saddr 10.1.1.2 tcp dport 42 dnat ip to 10.2.3.4:4242
+ meta l4proto tcp dnat ip to ip saddr map @y4
+ dnat ip to ip saddr . tcp dport map @z4
+ dnat ip to numgen inc mod 2 map @t1v4
+ meta l4proto tcp dnat ip to numgen inc mod 2 map @t2v4
+ dnat ip6 to ip6 daddr map @x6
+ ip6 saddr dead::1 dnat ip6 to feed::1
+ ip6 saddr dead::2 tcp dport 42 dnat ip6 to [c0::1a]:4242
+ meta l4proto tcp dnat ip6 to ip6 saddr map @y6
+ dnat ip6 to ip6 saddr . tcp dport map @z6
+ dnat ip6 to numgen inc mod 2 map @t1v6
+ meta l4proto tcp dnat ip6 to numgen inc mod 2 map @t2v6
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/pipapo_double_flush.json-nft b/tests/shell/testcases/maps/dumps/pipapo_double_flush.json-nft
new file mode 100644
index 00000000..ef8c3930
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/pipapo_double_flush.json-nft
@@ -0,0 +1,42 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "m",
+ "table": "t",
+ "type": [
+ "ipv4_addr",
+ "ipv4_addr"
+ ],
+ "handle": 0,
+ "map": "verdict",
+ "flags": [
+ "interval"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/pipapo_double_flush.nft b/tests/shell/testcases/maps/dumps/pipapo_double_flush.nft
new file mode 100644
index 00000000..cca569ea
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/pipapo_double_flush.nft
@@ -0,0 +1,9 @@
+table inet t {
+ map m {
+ type ipv4_addr . ipv4_addr : verdict
+ flags interval
+ }
+
+ chain c {
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_integer_0.nft b/tests/shell/testcases/maps/dumps/typeof_integer_0.nft
new file mode 100644
index 00000000..19c24feb
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_integer_0.nft
@@ -0,0 +1,20 @@
+table inet t {
+ map m1 {
+ typeof udp length . @ih,32,32 : verdict
+ flags interval
+ elements = { 20-80 . 0x14 : accept,
+ 1-10 . 0xa : drop }
+ }
+
+ map m2 {
+ typeof udp length . @ih,32,32 : verdict
+ elements = { 30 . 0x1e : drop,
+ 20 . 0x24 : accept }
+ }
+
+ chain c {
+ udp length . @nh,32,32 vmap @m1
+ udp length . @nh,32,32 vmap @m2
+ udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_0.nft b/tests/shell/testcases/maps/dumps/typeof_maps_0.nft
new file mode 100644
index 00000000..a5c0a609
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_0.nft
@@ -0,0 +1,36 @@
+table inet t {
+ map m1 {
+ typeof osf name : ct mark
+ elements = { "Linux" : 0x00000001 }
+ }
+
+ map m2 {
+ typeof vlan id : meta mark
+ elements = { 1 : 0x00000001, 4095 : 0x00004095 }
+ }
+
+ map m3 {
+ typeof ip saddr . ip daddr : meta mark
+ elements = { 1.2.3.4 . 5.6.7.8 : 0x00000001,
+ 2.3.4.5 . 6.7.8.9 : 0x00000002 }
+ }
+
+ map m4 {
+ typeof iifname . ip protocol . th dport : verdict
+ elements = { "eth0" . tcp . 22 : accept }
+ }
+
+ map m5 {
+ typeof ipsec in reqid . iifname : verdict
+ elements = { 23 . "eth0" : accept }
+ }
+
+ chain c {
+ ct mark set osf name map @m1
+ meta mark set vlan id map @m2
+ meta mark set ip saddr . ip daddr map @m3
+ iifname . ip protocol . th dport vmap @m4
+ iifname . ip protocol . th dport vmap { "eth0" . tcp . 22 : accept, "eth1" . udp . 67 : drop }
+ ipsec in reqid . iifname vmap @m5
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.json-nft b/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.json-nft
new file mode 100644
index 00000000..8130c46c
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.json-nft
@@ -0,0 +1,283 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "dynset",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "dynset",
+ "name": "test_ping",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "dynset",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "dynmark",
+ "table": "dynset",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "mark",
+ "size": 64,
+ "flags": [
+ "timeout"
+ ],
+ "timeout": 300,
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "dynset",
+ "chain": "test_ping",
+ "handle": 0,
+ "comment": "should not increment",
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@dynmark"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "dynset",
+ "chain": "test_ping",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "!=",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@dynmark"
+ }
+ },
+ {
+ "map": {
+ "op": "add",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": 1,
+ "map": "@dynmark"
+ }
+ },
+ {
+ "counter": {
+ "packets": 1,
+ "bytes": 84
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "dynset",
+ "chain": "test_ping",
+ "handle": 0,
+ "comment": "should increment",
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@dynmark"
+ }
+ },
+ {
+ "counter": {
+ "packets": 1,
+ "bytes": 84
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "dynset",
+ "chain": "test_ping",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@dynmark"
+ }
+ },
+ {
+ "map": {
+ "op": "delete",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": 1,
+ "map": "@dynmark"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "dynset",
+ "chain": "test_ping",
+ "handle": 0,
+ "comment": "delete should be instant but might fail under memory pressure",
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@dynmark"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "dynset",
+ "chain": "input",
+ "handle": 0,
+ "comment": "also check timeout-gc",
+ "expr": [
+ {
+ "map": {
+ "op": "add",
+ "elem": {
+ "elem": {
+ "val": "10.2.3.4",
+ "timeout": 1
+ }
+ },
+ "data": 2,
+ "map": "@dynmark"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "dynset",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": "icmp"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": "127.0.0.42"
+ }
+ },
+ {
+ "jump": {
+ "target": "test_ping"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.nft b/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.nft
new file mode 100644
index 00000000..9134673c
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_add_delete.nft
@@ -0,0 +1,22 @@
+table ip dynset {
+ map dynmark {
+ typeof ip daddr : meta mark
+ size 64
+ counter
+ timeout 5m
+ }
+
+ chain test_ping {
+ ip saddr @dynmark counter packets 0 bytes 0 comment "should not increment"
+ ip saddr != @dynmark add @dynmark { ip saddr : 0x00000001 } counter packets 1 bytes 84
+ ip saddr @dynmark counter packets 1 bytes 84 comment "should increment"
+ ip saddr @dynmark delete @dynmark { ip saddr : 0x00000001 }
+ ip saddr @dynmark counter packets 0 bytes 0 comment "delete should be instant but might fail under memory pressure"
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ add @dynmark { 10.2.3.4 timeout 1s : 0x00000002 } comment "also check timeout-gc"
+ meta l4proto icmp ip daddr 127.0.0.42 jump test_ping
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_concat.nft b/tests/shell/testcases/maps/dumps/typeof_maps_concat.nft
new file mode 100644
index 00000000..1ca98d81
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_concat.nft
@@ -0,0 +1,11 @@
+table netdev t {
+ map m {
+ typeof ether saddr . vlan id : meta mark
+ size 1234
+ flags dynamic,timeout
+ }
+
+ chain c {
+ ether type != 8021q update @m { ether daddr . 123 timeout 1m : 0x0000002a } counter packets 0 bytes 0 return
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_concat_update_0.nft b/tests/shell/testcases/maps/dumps/typeof_maps_concat_update_0.nft
new file mode 100644
index 00000000..f8b574f4
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_concat_update_0.nft
@@ -0,0 +1,13 @@
+table ip foo {
+ map pinned {
+ typeof ip saddr . ct original proto-dst : ip daddr . tcp dport
+ size 65535
+ flags dynamic,timeout
+ timeout 6m
+ }
+
+ chain pr {
+ update @pinned { ip saddr . ct original proto-dst timeout 1m30s : ip daddr . tcp dport }
+ update @pinned { ip saddr . ct original proto-dst timeout 1m30s : ip daddr . tcp dport }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_update_0.json-nft b/tests/shell/testcases/maps/dumps/typeof_maps_update_0.json-nft
new file mode 100644
index 00000000..1d50477d
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_update_0.json-nft
@@ -0,0 +1,110 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "kube-nfproxy-v4",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "kube-nfproxy-v4",
+ "name": "k8s-nfproxy-sep-TMVEFT7EX55F4T62",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "kube-nfproxy-v4",
+ "name": "k8s-nfproxy-sep-GMVEFT7EX55F4T62",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "sticky-set-svc-M53CN2XYVUHRQ7UB",
+ "table": "kube-nfproxy-v4",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "mark",
+ "size": 65535,
+ "flags": [
+ "timeout"
+ ],
+ "timeout": 360
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "sticky-set-svc-153CN2XYVUHRQ7UB",
+ "table": "kube-nfproxy-v4",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "mark",
+ "size": 65535,
+ "flags": [
+ "timeout"
+ ],
+ "timeout": 60
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "kube-nfproxy-v4",
+ "chain": "k8s-nfproxy-sep-TMVEFT7EX55F4T62",
+ "handle": 0,
+ "expr": [
+ {
+ "map": {
+ "op": "update",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": 2,
+ "map": "@sticky-set-svc-M53CN2XYVUHRQ7UB"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "kube-nfproxy-v4",
+ "chain": "k8s-nfproxy-sep-GMVEFT7EX55F4T62",
+ "handle": 0,
+ "expr": [
+ {
+ "map": {
+ "op": "update",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": 3,
+ "map": "@sticky-set-svc-153CN2XYVUHRQ7UB"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_update_0.nft b/tests/shell/testcases/maps/dumps/typeof_maps_update_0.nft
new file mode 100644
index 00000000..698219cb
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_update_0.nft
@@ -0,0 +1,21 @@
+table ip kube-nfproxy-v4 {
+ map sticky-set-svc-M53CN2XYVUHRQ7UB {
+ type ipv4_addr : mark
+ size 65535
+ timeout 6m
+ }
+
+ map sticky-set-svc-153CN2XYVUHRQ7UB {
+ typeof ip daddr : meta mark
+ size 65535
+ timeout 1m
+ }
+
+ chain k8s-nfproxy-sep-TMVEFT7EX55F4T62 {
+ update @sticky-set-svc-M53CN2XYVUHRQ7UB { ip saddr : 0x00000002 }
+ }
+
+ chain k8s-nfproxy-sep-GMVEFT7EX55F4T62 {
+ update @sticky-set-svc-153CN2XYVUHRQ7UB { ip saddr : 0x00000003 }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_raw_0.nft b/tests/shell/testcases/maps/dumps/typeof_raw_0.nft
new file mode 100644
index 00000000..476169f2
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_raw_0.nft
@@ -0,0 +1,13 @@
+table ip x {
+ map y {
+ typeof ip saddr . @ih,32,32 : verdict
+ elements = { 1.1.1.1 . 0x14 : accept,
+ 7.7.7.7 . 0x86 : accept,
+ 7.7.7.8 . 0x97 : drop }
+ }
+
+ chain y {
+ ip saddr . @nh,32,32 vmap @y
+ ip saddr . @nh,32,32 vmap { 4.4.4.4 . 0x34 : accept, 5.5.5.5 . 0x45 : drop }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/vmap_mark_bitwise_0.json-nft b/tests/shell/testcases/maps/dumps/vmap_mark_bitwise_0.json-nft
new file mode 100644
index 00000000..df156411
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/vmap_mark_bitwise_0.json-nft
@@ -0,0 +1,158 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "sctm_o0_0",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "sctm_o0_1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "SET_ctmark_RPLYroute",
+ "handle": 0
+ }
+ },
+ {
+ "counter": {
+ "family": "ip",
+ "name": "c_o0_0",
+ "table": "x",
+ "handle": 0,
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "sctm_o0",
+ "table": "x",
+ "type": "mark",
+ "handle": 0,
+ "map": "verdict",
+ "elem": [
+ [
+ 0,
+ {
+ "jump": {
+ "target": "sctm_o0_0"
+ }
+ }
+ ],
+ [
+ 1,
+ {
+ "jump": {
+ "target": "sctm_o0_1"
+ }
+ }
+ ]
+ ]
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "sctm_o1",
+ "table": "x",
+ "type": "mark",
+ "handle": 0,
+ "map": "counter",
+ "elem": [
+ [
+ 0,
+ "c_o0_0"
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "SET_ctmark_RPLYroute",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "&": [
+ {
+ ">>": [
+ {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ 8
+ ]
+ },
+ 15
+ ]
+ },
+ "data": "@sctm_o0"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "SET_ctmark_RPLYroute",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "map": {
+ "key": {
+ "&": [
+ {
+ ">>": [
+ {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ 8
+ ]
+ },
+ 15
+ ]
+ },
+ "data": "@sctm_o1"
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/vmap_mark_bitwise_0.nft b/tests/shell/testcases/maps/dumps/vmap_mark_bitwise_0.nft
new file mode 100644
index 00000000..beb5ffb0
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/vmap_mark_bitwise_0.nft
@@ -0,0 +1,26 @@
+table ip x {
+ counter c_o0_0 {
+ packets 0 bytes 0
+ }
+
+ map sctm_o0 {
+ type mark : verdict
+ elements = { 0x00000000 : jump sctm_o0_0, 0x00000001 : jump sctm_o0_1 }
+ }
+
+ map sctm_o1 {
+ type mark : counter
+ elements = { 0x00000000 : "c_o0_0" }
+ }
+
+ chain sctm_o0_0 {
+ }
+
+ chain sctm_o0_1 {
+ }
+
+ chain SET_ctmark_RPLYroute {
+ meta mark >> 8 & 0xf vmap @sctm_o0
+ counter name meta mark >> 8 & 0xf map @sctm_o1
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/vmap_timeout.json-nft b/tests/shell/testcases/maps/dumps/vmap_timeout.json-nft
new file mode 100644
index 00000000..1c3aa590
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/vmap_timeout.json-nft
@@ -0,0 +1,229 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "ssh_input",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "log_and_drop",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "other_input",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "wan_input",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "prerouting",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -300,
+ "policy": "accept"
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "portmap",
+ "table": "filter",
+ "type": "inet_service",
+ "handle": 0,
+ "map": "verdict",
+ "flags": [
+ "timeout"
+ ],
+ "gc-interval": 10,
+ "elem": [
+ [
+ 22,
+ {
+ "jump": {
+ "target": "ssh_input"
+ }
+ }
+ ]
+ ]
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "portaddrmap",
+ "table": "filter",
+ "type": [
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "map": "verdict",
+ "flags": [
+ "timeout"
+ ],
+ "gc-interval": 10,
+ "elem": [
+ [
+ {
+ "concat": [
+ "1.2.3.4",
+ 22
+ ]
+ },
+ {
+ "jump": {
+ "target": "ssh_input"
+ }
+ }
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "log_and_drop",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "other_input",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "log_and_drop"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "wan_input",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "data": "@portaddrmap"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "wan_input",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "data": "@portmap"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "prerouting",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "meta": {
+ "key": "iif"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "lo",
+ {
+ "jump": {
+ "target": "wan_input"
+ }
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/maps/dumps/vmap_timeout.nft b/tests/shell/testcases/maps/dumps/vmap_timeout.nft
new file mode 100644
index 00000000..095f894d
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/vmap_timeout.nft
@@ -0,0 +1,36 @@
+table inet filter {
+ map portmap {
+ type inet_service : verdict
+ flags timeout
+ gc-interval 10s
+ elements = { 22 : jump ssh_input }
+ }
+
+ map portaddrmap {
+ typeof ip daddr . th dport : verdict
+ flags timeout
+ gc-interval 10s
+ elements = { 1.2.3.4 . 22 : jump ssh_input }
+ }
+
+ chain ssh_input {
+ }
+
+ chain log_and_drop {
+ drop
+ }
+
+ chain other_input {
+ goto log_and_drop
+ }
+
+ chain wan_input {
+ ip daddr . tcp dport vmap @portaddrmap
+ tcp dport vmap @portmap
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority raw; policy accept;
+ iif vmap { "lo" : jump wan_input }
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/vmap_unary.nft b/tests/shell/testcases/maps/dumps/vmap_unary.nft
new file mode 100644
index 00000000..46c538b7
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/vmap_unary.nft
@@ -0,0 +1,11 @@
+table ip filter {
+ map ipsec_in {
+ typeof ipsec in reqid . iif : verdict
+ flags interval
+ }
+
+ chain INPUT {
+ type filter hook input priority filter; policy drop;
+ ipsec in reqid . iif vmap @ipsec_in
+ }
+}
diff --git a/tests/shell/testcases/maps/map_catchall_double_deactivate b/tests/shell/testcases/maps/map_catchall_double_deactivate
new file mode 100755
index 00000000..651c08a1
--- /dev/null
+++ b/tests/shell/testcases/maps/map_catchall_double_deactivate
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_catchall_element)
+
+$NFT "add table ip test ;
+ add map ip test testmap { type ipv4_addr : verdict; };
+ add chain ip test testchain;
+ add element ip test testmap { * : jump testchain }" || exit 1
+
+$NFT "flush map ip test testmap; delete map ip test testmap; delete map ip test testmap" 2>/dev/null && exit 1
+$NFT "flush map ip test testmap; delete map ip test testmap; delete element ip test testmap { * : jump testchain }" 2>/dev/null && exit 1
+
+$NFT "flush map ip test testmap; delete map ip test testmap" || exit 1
diff --git a/tests/shell/testcases/maps/map_catchall_double_free b/tests/shell/testcases/maps/map_catchall_double_free
new file mode 100755
index 00000000..d101256c
--- /dev/null
+++ b/tests/shell/testcases/maps/map_catchall_double_free
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_catchall_element)
+
+$NFT "add table ip test ;
+ add map ip test testmap { type ipv4_addr . ipv4_addr: verdict; flags interval,timeout; timeout 1s;};
+ add chain ip test testchain;
+ add element ip test testmap { * : jump testchain }" || exit 1
+
+sleep 2
+$NFT "add element ip test testmap { 1.2.3.4 . 5.6.7.8: jump testchain }" || exit 1
+sleep 2
+$NFT "add element ip test testmap { 2.3.4.5 . 6.7.8.9 timeout 1m: jump testchain }" || exit 1
diff --git a/tests/shell/testcases/maps/map_catchall_double_free_2 b/tests/shell/testcases/maps/map_catchall_double_free_2
new file mode 100755
index 00000000..5842fcb5
--- /dev/null
+++ b/tests/shell/testcases/maps/map_catchall_double_free_2
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_catchall_element)
+
+$NFT -f /dev/stdin <<EOF
+table ip test {
+ map testmap {
+ type ipv4_addr : verdict
+ elements = { * : jump testchain }
+ }
+
+ chain testchain { }
+}
+EOF
+
+# second attempt to delete the catchall element
+# musts trigger transaction abort
+$NFT -f /dev/stdin <<EOF
+delete element ip test testmap { * }
+delete element ip test testmap { * }
+EOF
+
+if [ $? -eq 1 ]; then
+ exit 0
+fi
+
+exit 1
diff --git a/tests/shell/testcases/maps/named_ct_objects b/tests/shell/testcases/maps/named_ct_objects
new file mode 100755
index 00000000..61b87c1a
--- /dev/null
+++ b/tests/shell/testcases/maps/named_ct_objects
@@ -0,0 +1,94 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_cttimeout)
+
+$NFT -f /dev/stdin <<EOF || exit 1
+table inet t {
+ ct expectation exp1 {
+ protocol tcp
+ dport 9876
+ timeout 1m
+ size 12
+ l3proto ip
+ }
+
+ ct expectation exp2 {
+ protocol tcp
+ dport 9876
+ timeout 3s
+ size 13
+ l3proto ip6
+ }
+
+ ct helper myftp {
+ type "ftp" protocol tcp
+ }
+
+ ct timeout dns {
+ protocol tcp
+ l3proto ip
+ policy = { established : 3, close : 1 }
+ }
+
+ map exp {
+ typeof ip saddr : ct expectation
+ elements = { 192.168.2.2 : "exp1" }
+ }
+
+ map exp6 {
+ typeof ip6 saddr : ct expectation
+ flags interval
+ elements = { dead:beef::/64 : "exp2" }
+ }
+
+ map helpobj {
+ typeof ip6 saddr : ct helper
+ flags interval
+ elements = { dead:beef::/64 : "myftp" }
+ }
+
+ map timeoutmap {
+ typeof ip daddr : ct timeout
+ elements = { 192.168.0.1 : "dns" }
+ }
+
+ set helpname {
+ typeof ct helper
+ elements = { "ftp", "sip" }
+ }
+
+ chain y {
+ ct expectation set ip saddr map @exp
+ ct expectation set ip6 saddr map { dead::beef : "exp2" }
+ ct expectation set ip6 daddr map { dead::beef : "exp2", feed::17 : "exp2" }
+ ct expectation set ip6 daddr . tcp dport map { dead::beef . 123 : "exp2", feed::17 . 512 : "exp2" }
+ ct helper set ip6 saddr map { dead::beef : "myftp", 1c3::c01d : "myftp" }
+ ct helper set ip6 saddr map @helpobj
+ ct timeout set ip daddr map @timeoutmap
+ ct timeout set ip daddr map { 1.2.3.4 : "dns", 5.6.7.8 : "dns", 192.168.8.0/24 : "dns" }
+ ct timeout set ip daddr map { 1.2.3.4-1.2.3.8 : "dns" }
+ ct timeout set ip6 daddr map { dead::beef : "dns", 1ce::/64 : "dns" }
+ ct helper @helpname accept
+ }
+}
+EOF
+
+must_fail()
+{
+ echo "Command should have failed: $1"
+ exit 111
+}
+
+
+must_work()
+{
+ echo "Command should have succeeded: $1"
+ exit 111
+}
+
+$NFT 'add rule inet t y ip saddr 192.168.1.1 ct timeout set "dns"' || must_work "dns timeout"
+
+$NFT 'add rule inet t y ct helper set ip saddr map @helpobj' && must_fail "helper assignment, map key is ipv6_addr"
+$NFT 'add rule inet t y ct helper set ip6 saddr map @helpname' && must_fail "helper assignment, not a map with objects"
+
+exit 0
diff --git a/tests/shell/testcases/maps/named_limits b/tests/shell/testcases/maps/named_limits
new file mode 100755
index 00000000..ac8e434c
--- /dev/null
+++ b/tests/shell/testcases/maps/named_limits
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile" || exit 1
+
+add_add_then_create()
+{
+ cmd="$@"
+
+ $NFT "add element inet filter $cmd" || exit 2
+
+ # again, kernel should suppress -EEXIST
+ $NFT "add element inet filter $cmd" || exit 3
+
+ # AGAIN, kernel should report -EEXIST
+ $NFT "create element inet filter $cmd" && echo "$cmd worked" 1>&2 && exit 4
+}
+
+add_create_dupe()
+{
+ cmd="$@"
+
+ $NFT "add element inet filter $cmd" && echo "$cmd worked" 1>&2 && exit 10
+ $NFT "create element inet filter $cmd" && echo "$cmd worked" 1>&2 && exit 11
+}
+
+delete()
+{
+ cmd="$@"
+
+ $NFT "delete element inet filter $cmd" || exit 30
+ $NFT "delete element inet filter $cmd" && echo "$cmd worked" 1>&2 && exit 31
+
+ # destroy should NOT report an error
+# $NFT "destroy element inet filter $cmd" || exit 40
+}
+
+add_add_then_create 'saddr6limit { fee1::dead : "tarpit-pps" }'
+add_add_then_create 'saddr6limit { c01a::/64 : "tarpit-bps" }'
+
+# test same with a diffent set type (concat + interval)
+add_add_then_create 'addr4limit { udp . 1.2.3.4 . 42 : "tarpit-pps", tcp . 1.2.3.4 . 42 : "tarpit-pps" }'
+
+# now test duplicate key with *DIFFERENT* limiter, should fail
+add_create_dupe 'saddr6limit { fee1::dead : "tarpit-bps" }'
+
+add_create_dupe 'addr4limit { udp . 1.2.3.4 . 42 : "tarpit-pps", tcp . 1.2.3.4 . 42 : "http-bulk-rl-10m" }'
+add_create_dupe 'addr4limit { udp . 1.2.3.4 . 43 : "tarpit-pps", tcp . 1.2.3.4 . 42 : "http-bulk-rl-10m" }'
+add_create_dupe 'addr4limit { udp . 1.2.3.5 . 42 : "tarpit-pps", tcp . 1.2.3.4 . 42 : "http-bulk-rl-10m" }'
+add_create_dupe 'addr4limit { udp . 1.2.3.4 . 42 : "tarpit-bps", tcp . 1.2.3.4 . 42 : "tarpit-pps" }'
+
+# delete keys again
+delete 'addr4limit { udp . 1.2.3.4 . 42 : "tarpit-pps", tcp . 1.2.3.4 . 42 :"tarpit-pps" }'
+
+delete 'saddr6limit { fee1::dead : "tarpit-pps" }'
+delete 'saddr6limit { c01a::/64 : "tarpit-bps" }'
+
+exit 0
diff --git a/tests/shell/testcases/maps/nat_addr_port b/tests/shell/testcases/maps/nat_addr_port
new file mode 100755
index 00000000..2804d48c
--- /dev/null
+++ b/tests/shell/testcases/maps/nat_addr_port
@@ -0,0 +1,207 @@
+#!/bin/bash
+
+# skeleton
+$NFT -f /dev/stdin <<EOF || exit 1
+table ip ipfoo {
+ map t1 {
+ typeof numgen inc mod 2 : ip daddr;
+ }
+
+ map t2 {
+ typeof numgen inc mod 2 : ip daddr . tcp dport
+ }
+
+ map x {
+ type ipv4_addr : ipv4_addr
+ }
+ map y {
+ type ipv4_addr : ipv4_addr . inet_service
+ elements = { 192.168.7.2 : 10.1.1.1 . 4242 }
+ }
+ map z {
+ type ipv4_addr . inet_service : ipv4_addr . inet_service
+ elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta iifname != "foobar" accept
+ dnat to ip daddr map @x
+ ip saddr 10.1.1.1 dnat to 10.2.3.4
+ ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+ meta l4proto tcp dnat ip addr . port to ip saddr map @y
+ meta l4proto tcp dnat ip addr . port to ip saddr . tcp dport map @z
+ dnat ip to numgen inc mod 2 map @t1
+ meta l4proto tcp dnat ip addr . port to numgen inc mod 2 map @t2
+ }
+}
+EOF
+
+# should fail: rule has no test for l4 protocol
+$NFT add rule 'ip ipfoo c ip saddr 10.1.1.2 dnat to 10.2.3.4:4242' && exit 1
+
+# should fail: rule has no test for l4 protocol, but map has inet_service
+$NFT add rule 'ip ipfoo c dnat to ip daddr map @y' && exit 1
+
+# skeleton 6
+$NFT -f /dev/stdin <<EOF || exit 1
+table ip6 ip6foo {
+ map t1 {
+ typeof numgen inc mod 2 : ip6 daddr;
+ }
+
+ map t2 {
+ typeof numgen inc mod 2 : ip6 daddr . tcp dport
+ }
+
+ map x {
+ type ipv6_addr : ipv6_addr
+ }
+ map y {
+ type ipv6_addr : ipv6_addr . inet_service
+ }
+ map z {
+ type ipv6_addr . inet_service : ipv6_addr . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta iifname != "foobar" accept
+ dnat to ip6 daddr map @x
+ ip6 saddr dead::1 dnat to feed::1
+ ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr map @y
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr . tcp dport map @z
+ dnat ip6 to numgen inc mod 2 map @t1
+ meta l4proto tcp dnat ip6 addr . port to numgen inc mod 2 map @t2
+ }
+}
+EOF
+
+# should fail: rule has no test for l4 protocol
+$NFT add rule 'ip6 ip6foo c ip6 saddr f0:0b::a3 dnat to [1c::3]:42' && exit 1
+
+# should fail: rule has no test for l4 protocol, but map has inet_service
+$NFT add rule 'ip6 ip6foo c dnat to ip daddr map @y' && exit 1
+
+# skeleton inet
+$NFT -f /dev/stdin <<EOF || exit 1
+table inet inetfoo {
+ map t1v4 {
+ typeof numgen inc mod 2 : ip daddr
+ }
+
+ map t2v4 {
+ typeof numgen inc mod 2 : ip daddr . tcp dport;
+ }
+
+ map t1v6 {
+ typeof numgen inc mod 2 : ip6 daddr;
+ }
+
+ map t2v6 {
+ typeof numgen inc mod 2 : ip6 daddr . tcp dport
+ }
+
+ map x4 {
+ type ipv4_addr : ipv4_addr
+ }
+ map y4 {
+ type ipv4_addr : ipv4_addr . inet_service
+ }
+ map z4 {
+ type ipv4_addr . inet_service : ipv4_addr . inet_service
+ elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+ }
+ map x6 {
+ type ipv6_addr : ipv6_addr
+ }
+ map y6 {
+ type ipv6_addr : ipv6_addr . inet_service
+ }
+ map z6 {
+ type ipv6_addr . inet_service : ipv6_addr . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta iifname != "foobar" accept
+ dnat ip to ip daddr map @x4
+ ip saddr 10.1.1.1 dnat to 10.2.3.4
+ ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+ meta l4proto tcp dnat ip addr . port to ip saddr map @y4
+ meta l4proto tcp dnat ip addr . port to ip saddr . tcp dport map @z4
+ dnat ip to numgen inc mod 2 map @t1v4
+ meta l4proto tcp dnat ip addr . port to numgen inc mod 2 map @t2v4
+ dnat ip6 to ip6 daddr map @x6
+ ip6 saddr dead::1 dnat to feed::1
+ ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr map @y6
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr . tcp dport map @z6
+ dnat ip6 to numgen inc mod 2 map @t1v6
+ meta l4proto tcp dnat ip6 addr . port to numgen inc mod 2 map @t2v6
+ }
+}
+EOF
+
+# should fail: map has wrong family: 4->6
+$NFT add rule 'inet inetfoo c dnat to ip daddr map @x6' && exit 1
+
+# should fail: map has wrong family: 6->4
+$NFT add rule 'inet inetfoo c dnat to ip6 daddr map @x4' && exit 1
+
+# should fail: rule has no test for l4 protocol
+$NFT add rule 'inet inetfoo c ip6 saddr f0:0b::a3 dnat to [1c::3]:42' && exit 1
+
+# should fail: rule has no test for l4 protocol, but map has inet_service
+$NFT add rule 'inet inetfoo c dnat to ip daddr map @y4' && exit 1
+
+# should fail: rule has test for l4 protocol, but map has wrong family: 4->6
+$NFT add rule 'inet inetfoo c meta l4proto tcp dnat to ip daddr map @y6' && exit 1
+
+# should fail: rule has test for l4 protocol, but map has wrong family: 6->4
+$NFT add rule 'inet inetfoo c meta l4proto tcp dnat to ip6 daddr map @y4' && exit 1
+
+# fail: inet_service, but expect ipv4_addr
+$NFT -f /dev/stdin <<EOF && exit 1
+table inet inetfoo {
+ map a {
+ type ipv4_addr : inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to ip saddr map @a
+ }
+}
+EOF
+
+# fail: maps to inet_service . inet_service, not addr . service
+$NFT -f /dev/stdin <<EOF && exit 1
+table inet inetfoo {
+ map b {
+ type ipv4_addr : inet_service . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to ip saddr map @a
+ }
+}
+EOF
+
+# fail: only accept exactly two sub-expressions: 'addr . service'
+$NFT -f /dev/stdin <<EOF && exit 1
+table inet inetfoo {
+ map b {
+ type ipv4_addr : inet_addr . inet_service . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to ip saddr map @a
+ }
+}
+EOF
+
+exit 0
diff --git a/tests/shell/testcases/maps/pipapo_double_flush b/tests/shell/testcases/maps/pipapo_double_flush
new file mode 100755
index 00000000..35ad0966
--- /dev/null
+++ b/tests/shell/testcases/maps/pipapo_double_flush
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+
+$NFT add table inet t
+$NFT add chain inet t c
+$NFT 'add map inet t m { type ipv4_addr . ipv4_addr : verdict; flags interval;}'
+
+for i in $(seq 1 10); do
+ $NFT "add element inet t m { 10.0.0.1 . 1.2.$i.1 - 1.2.$i.10 : jump c }"
+done
+
+$NFT -f /dev/stdin <<EOF
+add element inet t m { 10.1.1.1 . 1.1.1.4 : accept }
+add element inet t m { 10.1.1.6 . 1.1.1.4 : drop }
+add element inet t m { 10.1.1.7 . 1.1.1.4 : jump c }
+flush map inet t m
+add element inet t m { 10.1.1.1 . 1.1.1.4 : accept }
+add element inet t m { 10.1.1.6 . 1.1.1.4 : drop }
+add element inet t m { 10.1.1.7 . 1.1.1.4 : jump c }
+flush map inet t m
+flush map inet t m
+EOF
diff --git a/tests/shell/testcases/maps/typeof_integer_0 b/tests/shell/testcases/maps/typeof_integer_0
new file mode 100755
index 00000000..e93604e8
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_integer_0
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+EXPECTED="table inet t {
+ map m1 {
+ typeof udp length . @ih,32,32 : verdict
+ flags interval
+ elements = { 20-80 . 0x14 : accept, 1-10 . 0xa : drop }
+ }
+
+ map m2 {
+ typeof udp length . @ih,32,32 : verdict
+ elements = { 20 . 0x24 : accept, 30 . 0x1e : drop }
+ }
+
+ chain c {
+ udp length . @nh,32,32 vmap @m1
+ udp length . @nh,32,32 vmap @m2
+ udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : accept }
+ }
+}"
+
+$NFT add element inet t m1 { 90-100 . 40 : drop }
+$NFT delete element inet t m2 { 20 . 20 : accept }
+
+set -e
+$NFT -f - <<< $EXPECTED
+
diff --git a/tests/shell/testcases/maps/typeof_maps_0 b/tests/shell/testcases/maps/typeof_maps_0
new file mode 100755
index 00000000..98517fd5
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_0
@@ -0,0 +1,101 @@
+#!/bin/bash
+
+# support for strings and integers in named maps.
+# without typeof, this is 'type string' and 'type integer',
+# but neither could be used because it lacks size information.
+
+set -e
+
+die() {
+ printf '%s\n' "$*"
+ exit 1
+}
+
+INPUT_OSF_CT="
+ ct mark set osf name map @m1"
+if [ "$NFT_TEST_HAVE_osf" = n ] ; then
+ INPUT_OSF_CT=
+fi
+
+INPUT="table inet t {
+ map m1 {
+ typeof osf name : ct mark
+ elements = { Linux : 0x00000001 }
+ }
+
+ map m2 {
+ typeof vlan id : mark
+ elements = { 1 : 0x1,
+ 4095 : 0x4095 }
+ }
+
+ map m3 {
+ typeof ip saddr . ip daddr : meta mark
+ elements = { 1.2.3.4 . 5.6.7.8 : 0x00000001,
+ 2.3.4.5 . 6.7.8.9 : 0x00000002 }
+ }
+
+ map m4 {
+ typeof iifname . ip protocol . th dport : verdict
+ elements = { eth0 . tcp . 22 : accept }
+ }
+
+ map m5 {
+ typeof ipsec in reqid . meta iifname : verdict
+ elements = { 23 . eth0 : accept }
+ }
+
+ chain c {$INPUT_OSF_CT
+ ether type vlan meta mark set vlan id map @m2
+ meta mark set ip saddr . ip daddr map @m3
+ iifname . ip protocol . th dport vmap @m4
+ iifname . ip protocol . th dport vmap { \"eth0\" . tcp . 22 : accept, \"eth1\" . udp . 67 : drop }
+ ipsec in reqid . meta iifname vmap @m5
+ }
+}"
+
+EXPECTED="table inet t {
+ map m1 {
+ typeof osf name : ct mark
+ elements = { \"Linux\" : 0x00000001 }
+ }
+
+ map m2 {
+ typeof vlan id : meta mark
+ elements = { 1 : 0x00000001, 4095 : 0x00004095 }
+ }
+
+ map m3 {
+ typeof ip saddr . ip daddr : meta mark
+ elements = { 1.2.3.4 . 5.6.7.8 : 0x00000001,
+ 2.3.4.5 . 6.7.8.9 : 0x00000002 }
+ }
+
+ map m4 {
+ typeof iifname . ip protocol . th dport : verdict
+ elements = { \"eth0\" . tcp . 22 : accept }
+ }
+
+ map m5 {
+ typeof ipsec in reqid . iifname : verdict
+ elements = { 23 . \"eth0\" : accept }
+ }
+
+ chain c {$INPUT_OSF_CT
+ meta mark set vlan id map @m2
+ meta mark set ip saddr . ip daddr map @m3
+ iifname . ip protocol . th dport vmap @m4
+ iifname . ip protocol . th dport vmap { \"eth0\" . tcp . 22 : accept, \"eth1\" . udp . 67 : drop }
+ ipsec in reqid . iifname vmap @m5
+ }
+}"
+
+$NFT -f - <<< "$INPUT" || die $'nft command failed to process input:\n'">$INPUT<"
+
+$DIFF -u <($NFT list ruleset) - <<<"$EXPECTED" || die $'diff failed between ruleset and expected data.\nExpected:\n'">$EXPECTED<"
+
+
+if [ "$NFT_TEST_HAVE_osf" = n ] ; then
+ echo "Partial test due to NFT_TEST_HAVE_osf=n. Skip"
+ exit 77
+fi
diff --git a/tests/shell/testcases/maps/typeof_maps_add_delete b/tests/shell/testcases/maps/typeof_maps_add_delete
new file mode 100755
index 00000000..d2ac9f1c
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_add_delete
@@ -0,0 +1,56 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_dynset_op_delete)
+
+CONDMATCH="ip saddr @dynmark"
+NCONDMATCH="ip saddr != @dynmark"
+
+# use reduced feature set
+if [ "$NFT_TEST_HAVE_map_lookup" = n ] ; then
+ CONDMATCH=""
+ NCONDMATCH=""
+fi
+
+EXPECTED="table ip dynset {
+ map dynmark {
+ typeof ip daddr : meta mark
+ counter
+ size 64
+ timeout 5m
+ }
+
+ chain test_ping {
+ $CONDMATCH counter comment \"should not increment\"
+ $NCONDMATCH add @dynmark { ip saddr : 0x1 } counter
+ $CONDMATCH counter comment \"should increment\"
+ $CONDMATCH delete @dynmark { ip saddr : 0x1 }
+ $CONDMATCH counter comment \"delete should be instant but might fail under memory pressure\"
+ }
+
+ chain input {
+ type filter hook input priority 0; policy accept;
+
+ add @dynmark { 10.2.3.4 timeout 1s : 0x2 } comment \"also check timeout-gc\"
+ meta l4proto icmp ip daddr 127.0.0.42 jump test_ping
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
+$NFT list ruleset
+
+ip link set lo up
+ping -c 1 127.0.0.42
+
+$NFT get element ip dynset dynmark { 10.2.3.4 }
+
+# wait so that 10.2.3.4 times out.
+sleep 2
+
+set +e
+$NFT get element ip dynset dynmark { 10.2.3.4 } && exit 1
+
+if [ "$NFT_TEST_HAVE_map_lookup" = n ] ; then
+ echo "Only tested a subset due to NFT_TEST_HAVE_map_lookup=n. Skipped."
+ exit 77
+fi
diff --git a/tests/shell/testcases/maps/typeof_maps_concat b/tests/shell/testcases/maps/typeof_maps_concat
new file mode 100755
index 00000000..07820b7c
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_concat
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
diff --git a/tests/shell/testcases/maps/typeof_maps_concat_update_0 b/tests/shell/testcases/maps/typeof_maps_concat_update_0
new file mode 100755
index 00000000..2a52ea0e
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_concat_update_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# check update statement does print both concatentations (key and data).
+
+EXPECTED="table ip foo {
+ map pinned {
+ typeof ip saddr . ct original proto-dst : ip daddr . tcp dport
+ size 65535
+ flags dynamic,timeout
+ timeout 6m
+ }
+ chain pr {
+ update @pinned { ip saddr . ct original proto-dst timeout 1m30s : ip daddr . tcp dport }
+ meta l4proto tcp update @pinned { ip saddr . ct original proto-dst timeout 1m30s : ip daddr . tcp dport }
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/maps/typeof_maps_update_0 b/tests/shell/testcases/maps/typeof_maps_update_0
new file mode 100755
index 00000000..c233b13f
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_update_0
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# check update statement doesn't print "invalid dtype" on the data element.
+
+EXPECTED="table ip kube-nfproxy-v4 {
+ map sticky-set-svc-M53CN2XYVUHRQ7UB {
+ type ipv4_addr : mark
+ size 65535
+ timeout 6m
+ }
+
+ map sticky-set-svc-153CN2XYVUHRQ7UB {
+ typeof ip daddr : meta mark
+ size 65535
+ timeout 1m
+ }
+
+ chain k8s-nfproxy-sep-TMVEFT7EX55F4T62 {
+ update @sticky-set-svc-M53CN2XYVUHRQ7UB { ip saddr : 0x2 }
+ }
+ chain k8s-nfproxy-sep-GMVEFT7EX55F4T62 {
+ update @sticky-set-svc-153CN2XYVUHRQ7UB { ip saddr : 0x3 }
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
+
diff --git a/tests/shell/testcases/maps/typeof_raw_0 b/tests/shell/testcases/maps/typeof_raw_0
new file mode 100755
index 00000000..bcd2c6d8
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_raw_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+EXPECTED="table ip x {
+ map y {
+ typeof ip saddr . @ih,32,32: verdict
+ elements = { 1.1.1.1 . 0x14 : accept, 2.2.2.2 . 0x1e : drop }
+ }
+
+ chain y {
+ ip saddr . @nh,32,32 vmap @y
+ ip saddr . @nh,32,32 vmap { 4.4.4.4 . 0x34 : accept, 5.5.5.5 . 0x45 : drop}
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
+$NFT add element ip x y { 7.7.7.7 . 0x86 : accept, 7.7.7.8 . 0x97 : drop }
+$NFT delete element ip x y { 2.2.2.2 . 0x1e : drop }
diff --git a/tests/shell/testcases/maps/vmap_mark_bitwise_0 b/tests/shell/testcases/maps/vmap_mark_bitwise_0
new file mode 100755
index 00000000..2f305b27
--- /dev/null
+++ b/tests/shell/testcases/maps/vmap_mark_bitwise_0
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
+set -e
+
+RULESET="table ip x {
+ chain sctm_o0_0 {
+ }
+
+ chain sctm_o0_1 {
+ }
+
+ map sctm_o0 {
+ type mark : verdict
+ elements = {
+ 0x0 : jump sctm_o0_0,
+ 0x1 : jump sctm_o0_1,
+ }
+ }
+
+ counter c_o0_0 {}
+
+ map sctm_o1 {
+ type mark : counter
+ elements = {
+ 0x0 : \"c_o0_0\",
+ }
+ }
+
+ chain SET_ctmark_RPLYroute {
+ meta mark >> 8 & 0xf vmap @sctm_o0
+ }
+
+ chain SET_ctmark_RPLYroute {
+ counter name meta mark >> 8 & 0xf map @sctm_o1
+ }
+}"
+
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/maps/vmap_timeout b/tests/shell/testcases/maps/vmap_timeout
new file mode 100755
index 00000000..0cd965f7
--- /dev/null
+++ b/tests/shell/testcases/maps/vmap_timeout
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+
+set -e
+
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+$NFT -f $dumpfile
+
+port=23
+for i in $(seq 1 100) ; do
+ timeout=$((RANDOM%5))
+ timeout=$((timeout+1))
+ j=1
+
+ batched="{ $port timeout 3s : jump other_input "
+ batched_addr="{ 10.0.$((i%256)).$j . $port timeout ${timeout}s : jump other_input "
+ port=$((port + 1))
+ for j in $(seq 2 400); do
+ timeout=$((RANDOM%5))
+ timeout=$((timeout+1))
+
+ batched="$batched, $port timeout ${timeout}s : jump other_input "
+ batched_addr="$batched_addr, 10.0.$((i%256)).$((j%256)) . $port timeout ${timeout}s : jump other_input "
+ port=$((port + 1))
+ done
+
+ fail_addr="$batched_addr, 1.2.3.4 . 23 timeout 5m : jump other_input,
+ 1.2.3.4 . 23 timeout 3m : jump other_input }"
+ fail="$batched, 23 timeout 1m : jump other_input, 23 : jump other_input }"
+
+ batched="$batched }"
+ batched_addr="$batched_addr }"
+
+ if [ $i -gt 90 ]; then
+ # must fail, we create and $fail/$fail_addr contain one element twice.
+ $NFT create element inet filter portmap "$fail" && exit 111
+ $NFT create element inet filter portaddrmap "$fail_addr" && exit 112
+ fi
+
+ $NFT add element inet filter portmap "$batched"
+ $NFT add element inet filter portaddrmap "$batched_addr"
+done
+
+if [ "$NFT_TEST_HAVE_catchall_element" = n ] ; then
+ echo "Partial test due to NFT_TEST_HAVE_catchall_element=n."
+else
+ $NFT add element inet filter portaddrmap { "* timeout 2s : drop" }
+ $NFT add element inet filter portmap { "* timeout 3s : drop" }
+fi
+
+# wait for elements to time out
+sleep 5
diff --git a/tests/shell/testcases/maps/vmap_unary b/tests/shell/testcases/maps/vmap_unary
new file mode 100755
index 00000000..f4e1f012
--- /dev/null
+++ b/tests/shell/testcases/maps/vmap_unary
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+
+RULESET="table ip filter {
+ map ipsec_in {
+ typeof ipsec in reqid . iif : verdict
+ flags interval
+ }
+
+ chain INPUT {
+ type filter hook input priority 0; policy drop
+ ipsec in reqid . iif vmap @ipsec_in
+ }
+}"
+
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/netns/0001nft-f_0 b/tests/shell/testcases/netns/0001nft-f_0
index 81942263..a591f2cd 100755
--- a/tests/shell/testcases/netns/0001nft-f_0
+++ b/tests/shell/testcases/netns/0001nft-f_0
@@ -93,8 +93,7 @@ fi
KERNEL_RULESET="$($IP netns exec $NETNS_NAME $NFT list ruleset)"
$IP netns del $NETNS_NAME
if [ "$RULESET" != "$KERNEL_RULESET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
+ $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
exit 1
fi
exit 0
diff --git a/tests/shell/testcases/netns/0002loosecommands_0 b/tests/shell/testcases/netns/0002loosecommands_0
index 465c2e86..231f1fb7 100755
--- a/tests/shell/testcases/netns/0002loosecommands_0
+++ b/tests/shell/testcases/netns/0002loosecommands_0
@@ -56,7 +56,6 @@ RULESET="table ip t {
KERNEL_RULESET="$($IP netns exec $NETNS_NAME $NFT list ruleset)"
$IP netns del $NETNS_NAME
if [ "$RULESET" != "$KERNEL_RULESET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
+ $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
exit 1
fi
diff --git a/tests/shell/testcases/netns/0003many_0 b/tests/shell/testcases/netns/0003many_0
index a5fcb5d6..afe9117d 100755
--- a/tests/shell/testcases/netns/0003many_0
+++ b/tests/shell/testcases/netns/0003many_0
@@ -97,8 +97,7 @@ function test_netns()
KERNEL_RULESET="$($IP netns exec $NETNS_NAME $NFT list ruleset)"
if [ "$RULESET" != "$KERNEL_RULESET" ] ; then
echo "E: ruleset in netns $NETNS_NAME differs from the loaded" >&2
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
+ $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
$IP netns del $NETNS_NAME
exit 1
fi
diff --git a/tests/shell/testcases/netns/dumps/0001nft-f_0.json-nft b/tests/shell/testcases/netns/dumps/0001nft-f_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/netns/dumps/0001nft-f_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/netns/dumps/0001nft-f_0.nft b/tests/shell/testcases/netns/dumps/0001nft-f_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/netns/dumps/0001nft-f_0.nft
diff --git a/tests/shell/testcases/netns/dumps/0002loosecommands_0.json-nft b/tests/shell/testcases/netns/dumps/0002loosecommands_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/netns/dumps/0002loosecommands_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/netns/dumps/0002loosecommands_0.nft b/tests/shell/testcases/netns/dumps/0002loosecommands_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/netns/dumps/0002loosecommands_0.nft
diff --git a/tests/shell/testcases/netns/dumps/0003many_0.json-nft b/tests/shell/testcases/netns/dumps/0003many_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/netns/dumps/0003many_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/netns/dumps/0003many_0.nft b/tests/shell/testcases/netns/dumps/0003many_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/netns/dumps/0003many_0.nft
diff --git a/tests/shell/testcases/nft-f/0011manydefines_0 b/tests/shell/testcases/nft-f/0011manydefines_0
index 84664f46..aac06706 100755
--- a/tests/shell/testcases/nft-f/0011manydefines_0
+++ b/tests/shell/testcases/nft-f/0011manydefines_0
@@ -4,6 +4,15 @@
HOWMANY=20000
+if [ "$NFT_TEST_HAS_SOCKET_LIMITS" = y ] ; then
+ # The socket limit /proc/sys/net/core/wmem_max may be unsuitable for
+ # the test.
+ #
+ # Run only a subset of the test and mark as skipped at the end.
+ HOWMANY=2000
+fi
+
+
tmpfile=$(mktemp)
if [ ! -w $tmpfile ] ; then
echo "Failed to create tmp file" >&2
@@ -35,3 +44,10 @@ table t {
set -e
$NFT -f $tmpfile
+
+if [ "$HOWMANY" != 20000 ] ; then
+ echo "NFT_TEST_HAS_SOCKET_LIMITS indicates that the socket limit for"
+ echo "/proc/sys/net/core/wmem_max is too small for this test. Mark as SKIPPED"
+ echo "You may bump the limit and rerun with \`NFT_TEST_HAS_SOCKET_LIMITS=n\`."
+ exit 77
+fi
diff --git a/tests/shell/testcases/nft-f/0012different_defines_0 b/tests/shell/testcases/nft-f/0012different_defines_0
index 0bdbd1b5..fe228587 100755
--- a/tests/shell/testcases/nft-f/0012different_defines_0
+++ b/tests/shell/testcases/nft-f/0012different_defines_0
@@ -14,6 +14,8 @@ define d_ipv4_2 = 10.0.0.2
define d_ipv6 = fe0::1
define d_ipv6_2 = fe0::2
define d_ports = 100-222
+define d_qnum = 0
+define d_qnumr = 1-42
table inet t {
chain c {
@@ -29,6 +31,11 @@ table inet t {
ip daddr . meta iif vmap { \$d_ipv4 . \$d_iif : accept }
tcp dport \$d_ports
udp dport vmap { \$d_ports : accept }
+ tcp dport 1 tcp sport 1 meta oifname \"foobar\" queue num \$d_qnum bypass
+ tcp dport 1 tcp sport 1 meta oifname \"foobar\" queue num \$d_qnumr
+ tcp dport 1 tcp sport 1 meta oifname \"foobar\" queue flags bypass,fanout num \$d_qnumr
+ tcp dport 1 tcp sport 1 meta oifname \"foobar\" queue to symhash mod 2
+ tcp dport 1 tcp sport 1 meta oifname \"foobar\" queue flags bypass to jhash tcp dport . tcp sport mod 4
}
}"
diff --git a/tests/shell/testcases/nft-f/0016redefines_1 b/tests/shell/testcases/nft-f/0016redefines_1
index 4c26b379..1f59f6b8 100755
--- a/tests/shell/testcases/nft-f/0016redefines_1
+++ b/tests/shell/testcases/nft-f/0016redefines_1
@@ -26,8 +26,7 @@ $NFT -f - <<< "$RULESET"
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/nft-f/0017ct_timeout_obj_0 b/tests/shell/testcases/nft-f/0017ct_timeout_obj_0
index 4f407793..cfb78950 100755
--- a/tests/shell/testcases/nft-f/0017ct_timeout_obj_0
+++ b/tests/shell/testcases/nft-f/0017ct_timeout_obj_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_cttimeout)
+
EXPECTED='table ip filter {
ct timeout cttime{
protocol tcp
diff --git a/tests/shell/testcases/nft-f/0018ct_expectation_obj_0 b/tests/shell/testcases/nft-f/0018ct_expectation_obj_0
index 4f9872f6..b288457c 100755
--- a/tests/shell/testcases/nft-f/0018ct_expectation_obj_0
+++ b/tests/shell/testcases/nft-f/0018ct_expectation_obj_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_ctexpect)
+
EXPECTED='table ip filter {
ct expectation ctexpect{
protocol tcp
diff --git a/tests/shell/testcases/nft-f/0022variables_0 b/tests/shell/testcases/nft-f/0022variables_0
new file mode 100755
index 00000000..ee17a627
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0022variables_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+set -e
+
+RULESET="define test1 = @y
+
+table ip x {
+ set y {
+ type ipv4_addr
+ flags dynamic,timeout
+ }
+
+ chain z {
+ type filter hook input priority filter; policy accept;
+ add \$test1 { ip saddr }
+ update \$test1 { ip saddr timeout 30s }
+ ip saddr \$test1
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0023check_1 b/tests/shell/testcases/nft-f/0023check_1
new file mode 100755
index 00000000..42793b6e
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0023check_1
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+RULESET="table ip foo {
+ chain bar {
+ type filter hook prerouting priority 0;
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+
+$NFT -c add rule foo bar fib saddr . oif type local && exit 1
+exit 0
diff --git a/tests/shell/testcases/nft-f/0024priority_0 b/tests/shell/testcases/nft-f/0024priority_0
new file mode 100755
index 00000000..586f5c3f
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0024priority_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+RULESET="
+table inet statelessnat {
+ chain prerouting {
+ type filter hook prerouting priority -100;
+ ip daddr set numgen inc mod 16 map { 0-7 : 10.0.1.1, 8- 15 : 10.0.1.2 }
+ }
+ chain postrouting {
+ type filter hook postrouting priority 100
+ }
+}"
+
+exec $NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0025empty_dynset_0 b/tests/shell/testcases/nft-f/0025empty_dynset_0
new file mode 100755
index 00000000..fbdb5793
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0025empty_dynset_0
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip foo {
+ set inflows {
+ type ipv4_addr . inet_service . ifname . ipv4_addr . inet_service
+ flags dynamic
+ elements = { 10.1.0.3 . 39466 . \"veth1\" . 10.3.0.99 . 5201 counter packets 0 bytes 0 }
+ }
+
+ set inflows6 {
+ type ipv6_addr . inet_service . ifname . ipv6_addr . inet_service
+ flags dynamic
+ }
+
+ set inflows_ratelimit {
+ type ipv4_addr . inet_service . ifname . ipv4_addr . inet_service
+ flags dynamic
+ elements = { 10.1.0.3 . 39466 . \"veth1\" . 10.3.0.99 . 5201 limit rate 1/second counter packets 0 bytes 0 }
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+
+# inflows_ratelimit will be dumped without 'limit rate .. counter' on old kernels.
+if [ "$NFT_TEST_HAVE_set_with_two_expressions" = n ]; then
+ echo "Partial test due to NFT_TEST_HAVE_set_with_two_expressions=n."
+ exit 77
+fi
diff --git a/tests/shell/testcases/nft-f/0026listing_0 b/tests/shell/testcases/nft-f/0026listing_0
new file mode 100755
index 00000000..0f2f27c6
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0026listing_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# This is like "flush ruleset" except only flushes THIS ruleset, not ALL rulesets.
+# In particular, it leaves the dynamic sshguard/fail2ban deny lists untouched.
+RULESET="add table A
+delete table A
+table A {
+ chain B {
+ tcp dport {1,2} accept
+ }
+}
+list ruleset"
+
+exec $NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0027split_chains_0 b/tests/shell/testcases/nft-f/0027split_chains_0
new file mode 100755
index 00000000..de1e5a00
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0027split_chains_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table inet filter {
+ chain x {
+ }
+}
+table inet filter {
+ chain input {
+ type filter hook input priority filter; policy accept;
+ jump x
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 0
+exit 1
diff --git a/tests/shell/testcases/nft-f/0028variable_cmdline_0 b/tests/shell/testcases/nft-f/0028variable_cmdline_0
new file mode 100755
index 00000000..a2bbd5da
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0028variable_cmdline_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+
+RULESET="table inet filter {
+ set whitelist_v4 { type ipv4_addr; }
+}
+add element inet filter whitelist_v4 \$whitelist_v4
+"
+
+# this is intentional: exercise error path
+$NFT --define whitelist_v4="{ wrong }" -f - <<< "$RULESET"
+$NFT --define whitelist_v4="{ 1.1.1.1, \$wrong }" -f - <<< "$RULESET"
+
+set -e
+
+$NFT --define whitelist_v4="{ 1.1.1.1, 2.2.2.2 }" -f - <<< "$RULESET"
+$NFT --define x={5.5.5.5} --define whitelist_v4="{ 3.3.3.3, 4.4.4.4, \$x }" -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0029split_file_0 b/tests/shell/testcases/nft-f/0029split_file_0
new file mode 100755
index 00000000..0cc547ab
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0029split_file_0
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table inet filter {
+ set whitelist_v4 {
+ type ipv4_addr;
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority filter;
+ }
+}
+"
+
+$NFT -f - <<< "$RULESET"
+
+RULESET="table inet filter {
+ chain prerouting {
+ ip daddr @whitelist_v4
+ }
+}
+"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0030variable_reuse_0 b/tests/shell/testcases/nft-f/0030variable_reuse_0
new file mode 100755
index 00000000..8afc54aa
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0030variable_reuse_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+RULESET="define test = { 1.1.1.1 }
+
+table ip x {
+ set y {
+ type ipv4_addr
+ elements = { 2.2.2.2, \$test }
+ }
+
+ set z {
+ type ipv4_addr
+ elements = { 3.3.3.3, \$test }
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/0031vmap_string_0 b/tests/shell/testcases/nft-f/0031vmap_string_0
new file mode 100755
index 00000000..2af846a4
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0031vmap_string_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# Tests parse of corrupted verdicts
+
+set -e
+
+RULESET="
+table ip foo {
+ map bar {
+ type ipv4_addr : verdict
+ elements = {
+ 192.168.0.1 : ber
+ }
+ }
+
+ chain ber {
+ }
+}"
+
+$NFT -f - <<< "$RULESET" && exit 1
+exit 0
diff --git a/tests/shell/testcases/nft-f/0032pknock_0 b/tests/shell/testcases/nft-f/0032pknock_0
new file mode 100755
index 00000000..94fc8407
--- /dev/null
+++ b/tests/shell/testcases/nft-f/0032pknock_0
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+set -e
+
+RULESET="define guarded_ports = {ssh}
+
+table inet portknock {
+ set clients_ipv4 {
+ type ipv4_addr
+ flags timeout
+ }
+
+ set candidates_ipv4 {
+ type ipv4_addr . inet_service
+ flags timeout
+ }
+
+ chain input {
+ type filter hook input priority -10; policy accept;
+
+ tcp dport 10001 add @candidates_ipv4 {ip saddr . 10002 timeout 1s}
+ tcp dport 10002 ip saddr . tcp dport @candidates_ipv4 add @candidates_ipv4 {ip saddr . 10003 timeout 1s}
+ tcp dport 10003 ip saddr . tcp dport @candidates_ipv4 add @candidates_ipv4 {ip saddr . 10004 timeout 1s}
+ tcp dport 10004 ip saddr . tcp dport @candidates_ipv4 add @candidates_ipv4 {ip saddr . 10005 timeout 1s}
+ tcp dport 10005 ip saddr . tcp dport @candidates_ipv4 add @clients_ipv4 {ip saddr timeout 600s} log prefix \"Successful portknock: \"
+
+ tcp dport \$guarded_ports ip saddr @clients_ipv4 counter accept
+ tcp dport \$guarded_ports ct state established,related counter accept
+
+ tcp dport \$guarded_ports reject with tcp reset
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/nft-f/dumps/0001define_slash_0.json-nft b/tests/shell/testcases/nft-f/dumps/0001define_slash_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0001define_slash_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0001define_slash_0.nft b/tests/shell/testcases/nft-f/dumps/0001define_slash_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0001define_slash_0.nft
diff --git a/tests/shell/testcases/nft-f/dumps/0002rollback_rule_0.json-nft b/tests/shell/testcases/nft-f/dumps/0002rollback_rule_0.json-nft
new file mode 100644
index 00000000..99b0b28d
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0002rollback_rule_0.json-nft
@@ -0,0 +1,134 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "other",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "t",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "1.1.1.1"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "new"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 22222,
+ 33333
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@t"
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "other"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0003rollback_jump_0.json-nft b/tests/shell/testcases/nft-f/dumps/0003rollback_jump_0.json-nft
new file mode 100644
index 00000000..99b0b28d
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0003rollback_jump_0.json-nft
@@ -0,0 +1,134 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "other",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "t",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "1.1.1.1"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "new"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 22222,
+ 33333
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@t"
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "other"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0004rollback_set_0.json-nft b/tests/shell/testcases/nft-f/dumps/0004rollback_set_0.json-nft
new file mode 100644
index 00000000..99b0b28d
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0004rollback_set_0.json-nft
@@ -0,0 +1,134 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "other",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "t",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "1.1.1.1"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "new"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 22222,
+ 33333
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@t"
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "other"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0005rollback_map_0.json-nft b/tests/shell/testcases/nft-f/dumps/0005rollback_map_0.json-nft
new file mode 100644
index 00000000..99b0b28d
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0005rollback_map_0.json-nft
@@ -0,0 +1,134 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "other",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "t",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "1.1.1.1"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "new"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 22222,
+ 33333
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@t"
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "other"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0006action_object_0.json-nft b/tests/shell/testcases/nft-f/dumps/0006action_object_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0006action_object_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0006action_object_0.nft b/tests/shell/testcases/nft-f/dumps/0006action_object_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0006action_object_0.nft
diff --git a/tests/shell/testcases/nft-f/dumps/0007action_object_set_segfault_1.json-nft b/tests/shell/testcases/nft-f/dumps/0007action_object_set_segfault_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0007action_object_set_segfault_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0007action_object_set_segfault_1.nft b/tests/shell/testcases/nft-f/dumps/0007action_object_set_segfault_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0007action_object_set_segfault_1.nft
diff --git a/tests/shell/testcases/nft-f/dumps/0008split_tables_0.json-nft b/tests/shell/testcases/nft-f/dumps/0008split_tables_0.json-nft
new file mode 100644
index 00000000..05ebed5a
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0008split_tables_0.json-nft
@@ -0,0 +1,67 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "ssh",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 1,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "ssh",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0009variable_0.json-nft b/tests/shell/testcases/nft-f/dumps/0009variable_0.json-nft
new file mode 100644
index 00000000..41236dbe
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0009variable_0.json-nft
@@ -0,0 +1,44 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "forward",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "concat-set-variable",
+ "table": "forward",
+ "type": [
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "elem": [
+ {
+ "concat": [
+ "10.10.10.10",
+ 25
+ ]
+ },
+ {
+ "concat": [
+ "10.10.10.10",
+ 143
+ ]
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0010variable_0.json-nft b/tests/shell/testcases/nft-f/dumps/0010variable_0.json-nft
new file mode 100644
index 00000000..4b4ec4fb
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0010variable_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "whitelist_v4",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "1.1.1.1"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0011manydefines_0.nodump b/tests/shell/testcases/nft-f/dumps/0011manydefines_0.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0011manydefines_0.nodump
diff --git a/tests/shell/testcases/nft-f/dumps/0012different_defines_0.json-nft b/tests/shell/testcases/nft-f/dumps/0012different_defines_0.json-nft
new file mode 100644
index 00000000..1b2e3420
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0012different_defines_0.json-nft
@@ -0,0 +1,778 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "whatever"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "whatever"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iif"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oif"
+ }
+ },
+ "right": "lo"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": {
+ "set": [
+ "whatever"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iif"
+ }
+ },
+ "right": {
+ "set": [
+ "lo"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "right": 123
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "established",
+ "related",
+ "new"
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "!=",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": {
+ "|": [
+ "established",
+ "related",
+ "new"
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "10.0.0.0"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": "10.0.0.2"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "10.0.0.0"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "right": "fe0::1"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "saddr"
+ }
+ },
+ "right": "fe0::2"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "10.0.0.0",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "10.0.0.2",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "fe0::1",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "fe0::2",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip6",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip6",
+ "field": "nexthdr"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "fe0::2",
+ "tcp"
+ ]
+ },
+ {
+ "concat": [
+ "fe0::1",
+ "udp"
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "iif"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "10.0.0.0",
+ "lo"
+ ]
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "range": [
+ 100,
+ 222
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "range": [
+ 100,
+ 222
+ ]
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "sport"
+ }
+ },
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "foobar"
+ }
+ },
+ {
+ "queue": {
+ "num": 0,
+ "flags": "bypass"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "sport"
+ }
+ },
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "foobar"
+ }
+ },
+ {
+ "queue": {
+ "num": {
+ "range": [
+ 1,
+ 42
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "sport"
+ }
+ },
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "foobar"
+ }
+ },
+ {
+ "queue": {
+ "num": {
+ "range": [
+ 1,
+ 42
+ ]
+ },
+ "flags": [
+ "bypass",
+ "fanout"
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "sport"
+ }
+ },
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "foobar"
+ }
+ },
+ {
+ "queue": {
+ "num": {
+ "symhash": {
+ "mod": 2
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "sport"
+ }
+ },
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 1
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "foobar"
+ }
+ },
+ {
+ "queue": {
+ "num": {
+ "jhash": {
+ "mod": 4,
+ "expr": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "sport"
+ }
+ }
+ ]
+ }
+ }
+ },
+ "flags": "bypass"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0012different_defines_0.nft b/tests/shell/testcases/nft-f/dumps/0012different_defines_0.nft
index 7abced86..4734b2fd 100644
--- a/tests/shell/testcases/nft-f/dumps/0012different_defines_0.nft
+++ b/tests/shell/testcases/nft-f/dumps/0012different_defines_0.nft
@@ -8,9 +8,14 @@ table inet t {
ip6 daddr fe0::1 ip6 saddr fe0::2
ip saddr vmap { 10.0.0.0 : drop, 10.0.0.2 : accept }
ip6 daddr vmap { fe0::1 : drop, fe0::2 : accept }
- ip6 saddr . ip6 nexthdr { fe0::1 . udp, fe0::2 . tcp }
+ ip6 saddr . ip6 nexthdr { fe0::2 . tcp, fe0::1 . udp }
ip daddr . iif vmap { 10.0.0.0 . "lo" : accept }
tcp dport 100-222
udp dport vmap { 100-222 : accept }
+ tcp sport 1 tcp dport 1 oifname "foobar" queue flags bypass to 0
+ tcp sport 1 tcp dport 1 oifname "foobar" queue to 1-42
+ tcp sport 1 tcp dport 1 oifname "foobar" queue flags bypass,fanout to 1-42
+ tcp sport 1 tcp dport 1 oifname "foobar" queue to symhash mod 2
+ tcp sport 1 tcp dport 1 oifname "foobar" queue flags bypass to jhash tcp dport . tcp sport mod 4
}
}
diff --git a/tests/shell/testcases/nft-f/dumps/0013defines_1.json-nft b/tests/shell/testcases/nft-f/dumps/0013defines_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0013defines_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0013defines_1.nft b/tests/shell/testcases/nft-f/dumps/0013defines_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0013defines_1.nft
diff --git a/tests/shell/testcases/nft-f/dumps/0014defines_1.json-nft b/tests/shell/testcases/nft-f/dumps/0014defines_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0014defines_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0014defines_1.nft b/tests/shell/testcases/nft-f/dumps/0014defines_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0014defines_1.nft
diff --git a/tests/shell/testcases/nft-f/dumps/0015defines_1.json-nft b/tests/shell/testcases/nft-f/dumps/0015defines_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0015defines_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0015defines_1.nft b/tests/shell/testcases/nft-f/dumps/0015defines_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0015defines_1.nft
diff --git a/tests/shell/testcases/nft-f/dumps/0016redefines_1.json-nft b/tests/shell/testcases/nft-f/dumps/0016redefines_1.json-nft
new file mode 100644
index 00000000..40cdb000
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0016redefines_1.json-nft
@@ -0,0 +1,80 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": {
+ "set": [
+ "1.1.1.1",
+ "2.2.2.2"
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": {
+ "set": [
+ "3.3.3.3",
+ "4.4.4.4"
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0016redefines_1.nft b/tests/shell/testcases/nft-f/dumps/0016redefines_1.nft
new file mode 100644
index 00000000..65b7f491
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0016redefines_1.nft
@@ -0,0 +1,6 @@
+table ip x {
+ chain y {
+ ip saddr { 1.1.1.1, 2.2.2.2 }
+ ip saddr { 3.3.3.3, 4.4.4.4 }
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.json-nft b/tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.json-nft
new file mode 100644
index 00000000..b56240ea
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.json-nft
@@ -0,0 +1,53 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "ct timeout": {
+ "family": "ip",
+ "name": "cttime",
+ "table": "filter",
+ "handle": 0,
+ "protocol": "tcp",
+ "l3proto": "ip",
+ "policy": {
+ "established": 123,
+ "close": 12
+ }
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "ct timeout": "cttime"
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.nft b/tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.nft
index 7cff1ed5..c5d9649e 100644
--- a/tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.nft
+++ b/tests/shell/testcases/nft-f/dumps/0017ct_timeout_obj_0.nft
@@ -2,7 +2,7 @@ table ip filter {
ct timeout cttime {
protocol tcp
l3proto ip
- policy = { established : 123, close : 12 }
+ policy = { established : 2m3s, close : 12s }
}
chain c {
diff --git a/tests/shell/testcases/nft-f/dumps/0018ct_expectation_obj_0.json-nft b/tests/shell/testcases/nft-f/dumps/0018ct_expectation_obj_0.json-nft
new file mode 100644
index 00000000..21c97970
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0018ct_expectation_obj_0.json-nft
@@ -0,0 +1,52 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "ct expectation": {
+ "family": "ip",
+ "name": "ctexpect",
+ "table": "filter",
+ "handle": 0,
+ "protocol": "tcp",
+ "dport": 9876,
+ "timeout": 60000,
+ "size": 12,
+ "l3proto": "ip"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "ct expectation": "ctexpect"
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0018ct_expectation_obj_0.nft b/tests/shell/testcases/nft-f/dumps/0018ct_expectation_obj_0.nft
new file mode 100644
index 00000000..396185eb
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0018ct_expectation_obj_0.nft
@@ -0,0 +1,13 @@
+table ip filter {
+ ct expectation ctexpect {
+ protocol tcp
+ dport 9876
+ timeout 1m
+ size 12
+ l3proto ip
+ }
+
+ chain c {
+ ct expectation set "ctexpect"
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0018jump_variable_0.json-nft b/tests/shell/testcases/nft-f/dumps/0018jump_variable_0.json-nft
new file mode 100644
index 00000000..f62b48a3
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0018jump_variable_0.json-nft
@@ -0,0 +1,49 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "foo",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "foo",
+ "name": "bar",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "foo",
+ "name": "ber",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "ber"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0019jump_variable_1.json-nft b/tests/shell/testcases/nft-f/dumps/0019jump_variable_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0019jump_variable_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0019jump_variable_1.nft b/tests/shell/testcases/nft-f/dumps/0019jump_variable_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0019jump_variable_1.nft
diff --git a/tests/shell/testcases/nft-f/dumps/0020jump_variable_1.json-nft b/tests/shell/testcases/nft-f/dumps/0020jump_variable_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0020jump_variable_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0020jump_variable_1.nft b/tests/shell/testcases/nft-f/dumps/0020jump_variable_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0020jump_variable_1.nft
diff --git a/tests/shell/testcases/nft-f/dumps/0021list_ruleset_0.json-nft b/tests/shell/testcases/nft-f/dumps/0021list_ruleset_0.json-nft
new file mode 100644
index 00000000..f41b1b04
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0021list_ruleset_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "prerouting",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -50,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0022priority_variable_0.nft b/tests/shell/testcases/nft-f/dumps/0022priority_variable_0.nft
deleted file mode 100644
index 2e944599..00000000
--- a/tests/shell/testcases/nft-f/dumps/0022priority_variable_0.nft
+++ /dev/null
@@ -1,5 +0,0 @@
-table inet global {
- chain prerouting {
- type filter hook prerouting priority filter + 10; policy accept;
- }
-}
diff --git a/tests/shell/testcases/nft-f/dumps/0022variables_0.json-nft b/tests/shell/testcases/nft-f/dumps/0022variables_0.json-nft
new file mode 100644
index 00000000..09a4c1e3
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0022variables_0.json-nft
@@ -0,0 +1,115 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "z",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "set": "@y"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "set": {
+ "op": "update",
+ "elem": {
+ "elem": {
+ "val": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "timeout": 30
+ }
+ },
+ "set": "@y"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@y"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0022variables_0.nft b/tests/shell/testcases/nft-f/dumps/0022variables_0.nft
new file mode 100644
index 00000000..d30f4d53
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0022variables_0.nft
@@ -0,0 +1,14 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ }
+
+ chain z {
+ type filter hook input priority filter; policy accept;
+ add @y { ip saddr }
+ update @y { ip saddr timeout 30s }
+ ip saddr @y
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0023check_1.json-nft b/tests/shell/testcases/nft-f/dumps/0023check_1.json-nft
new file mode 100644
index 00000000..ddb2a057
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0023check_1.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "foo",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "foo",
+ "name": "bar",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0023check_1.nft b/tests/shell/testcases/nft-f/dumps/0023check_1.nft
new file mode 100644
index 00000000..04b9e70f
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0023check_1.nft
@@ -0,0 +1,5 @@
+table ip foo {
+ chain bar {
+ type filter hook prerouting priority filter; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0024priority_0.json-nft b/tests/shell/testcases/nft-f/dumps/0024priority_0.json-nft
new file mode 100644
index 00000000..cdc4b9d9
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0024priority_0.json-nft
@@ -0,0 +1,95 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "statelessnat",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "statelessnat",
+ "name": "prerouting",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -100,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "statelessnat",
+ "name": "postrouting",
+ "handle": 0,
+ "type": "filter",
+ "hook": "postrouting",
+ "prio": 100,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "statelessnat",
+ "chain": "prerouting",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "numgen": {
+ "mode": "inc",
+ "mod": 16,
+ "offset": 0
+ }
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "range": [
+ 0,
+ 7
+ ]
+ },
+ "10.0.1.1"
+ ],
+ [
+ {
+ "range": [
+ 8,
+ 15
+ ]
+ },
+ "10.0.1.2"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0024priority_0.nft b/tests/shell/testcases/nft-f/dumps/0024priority_0.nft
new file mode 100644
index 00000000..cd7fc504
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0024priority_0.nft
@@ -0,0 +1,10 @@
+table inet statelessnat {
+ chain prerouting {
+ type filter hook prerouting priority dstnat; policy accept;
+ ip daddr set numgen inc mod 16 map { 0-7 : 10.0.1.1, 8-15 : 10.0.1.2 }
+ }
+
+ chain postrouting {
+ type filter hook postrouting priority srcnat; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.json-nft b/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.json-nft
new file mode 100644
index 00000000..0cde23b0
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.json-nft
@@ -0,0 +1,111 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "foo",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "inflows",
+ "table": "foo",
+ "type": [
+ "ipv4_addr",
+ "inet_service",
+ "ifname",
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "flags": [
+ "dynamic"
+ ],
+ "elem": [
+ {
+ "elem": {
+ "val": {
+ "concat": [
+ "10.1.0.3",
+ 39466,
+ "veth1",
+ "10.3.0.99",
+ 5201
+ ]
+ },
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "inflows6",
+ "table": "foo",
+ "type": [
+ "ipv6_addr",
+ "inet_service",
+ "ifname",
+ "ipv6_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "flags": [
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "inflows_ratelimit",
+ "table": "foo",
+ "type": [
+ "ipv4_addr",
+ "inet_service",
+ "ifname",
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "flags": [
+ "dynamic"
+ ],
+ "elem": [
+ {
+ "elem": {
+ "val": {
+ "concat": [
+ "10.1.0.3",
+ 39466,
+ "veth1",
+ "10.3.0.99",
+ 5201
+ ]
+ },
+ "limit": {
+ "rate": 1,
+ "burst": 5,
+ "per": "second"
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.nft b/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.nft
new file mode 100644
index 00000000..33b9e4ff
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.nft
@@ -0,0 +1,18 @@
+table ip foo {
+ set inflows {
+ type ipv4_addr . inet_service . ifname . ipv4_addr . inet_service
+ flags dynamic
+ elements = { 10.1.0.3 . 39466 . "veth1" . 10.3.0.99 . 5201 counter packets 0 bytes 0 }
+ }
+
+ set inflows6 {
+ type ipv6_addr . inet_service . ifname . ipv6_addr . inet_service
+ flags dynamic
+ }
+
+ set inflows_ratelimit {
+ type ipv4_addr . inet_service . ifname . ipv4_addr . inet_service
+ flags dynamic
+ elements = { 10.1.0.3 . 39466 . "veth1" . 10.3.0.99 . 5201 limit rate 1/second burst 5 packets counter packets 0 bytes 0 }
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0026listing_0.json-nft b/tests/shell/testcases/nft-f/dumps/0026listing_0.json-nft
new file mode 100644
index 00000000..8acdcdf4
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0026listing_0.json-nft
@@ -0,0 +1,56 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "A",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "A",
+ "name": "B",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "A",
+ "chain": "B",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 1,
+ 2
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0026listing_0.nft b/tests/shell/testcases/nft-f/dumps/0026listing_0.nft
new file mode 100644
index 00000000..fd0bb686
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0026listing_0.nft
@@ -0,0 +1,5 @@
+table ip A {
+ chain B {
+ tcp dport { 1, 2 } accept
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0027split_chains_0.json-nft b/tests/shell/testcases/nft-f/dumps/0027split_chains_0.json-nft
new file mode 100644
index 00000000..bda8bfc9
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0027split_chains_0.json-nft
@@ -0,0 +1,53 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "x"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0027split_chains_0.nft b/tests/shell/testcases/nft-f/dumps/0027split_chains_0.nft
new file mode 100644
index 00000000..39198be1
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0027split_chains_0.nft
@@ -0,0 +1,9 @@
+table inet filter {
+ chain x {
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ jump x
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0028variable_cmdline_0.json-nft b/tests/shell/testcases/nft-f/dumps/0028variable_cmdline_0.json-nft
new file mode 100644
index 00000000..69d826df
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0028variable_cmdline_0.json-nft
@@ -0,0 +1,34 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "whitelist_v4",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "1.1.1.1",
+ "2.2.2.2",
+ "3.3.3.3",
+ "4.4.4.4",
+ "5.5.5.5"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0028variable_cmdline_0.nft b/tests/shell/testcases/nft-f/dumps/0028variable_cmdline_0.nft
new file mode 100644
index 00000000..aa081122
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0028variable_cmdline_0.nft
@@ -0,0 +1,8 @@
+table inet filter {
+ set whitelist_v4 {
+ type ipv4_addr
+ elements = { 1.1.1.1, 2.2.2.2,
+ 3.3.3.3, 4.4.4.4,
+ 5.5.5.5 }
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0029split_file_0.json-nft b/tests/shell/testcases/nft-f/dumps/0029split_file_0.json-nft
new file mode 100644
index 00000000..ab680af8
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0029split_file_0.json-nft
@@ -0,0 +1,61 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "prerouting",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "whitelist_v4",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "prerouting",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": "@whitelist_v4"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0029split_file_0.nft b/tests/shell/testcases/nft-f/dumps/0029split_file_0.nft
new file mode 100644
index 00000000..32d5c0e9
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0029split_file_0.nft
@@ -0,0 +1,10 @@
+table inet filter {
+ set whitelist_v4 {
+ type ipv4_addr
+ }
+
+ chain prerouting {
+ type filter hook prerouting priority filter; policy accept;
+ ip daddr @whitelist_v4
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.json-nft b/tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.json-nft
new file mode 100644
index 00000000..e0704b7d
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.json-nft
@@ -0,0 +1,44 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "1.1.1.1",
+ "2.2.2.2"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "z",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "1.1.1.1",
+ "3.3.3.3"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.nft b/tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.nft
new file mode 100644
index 00000000..635901f4
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0030variable_reuse_0.nft
@@ -0,0 +1,11 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ elements = { 1.1.1.1, 2.2.2.2 }
+ }
+
+ set z {
+ type ipv4_addr
+ elements = { 1.1.1.1, 3.3.3.3 }
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0031vmap_string_0.json-nft b/tests/shell/testcases/nft-f/dumps/0031vmap_string_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0031vmap_string_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0031vmap_string_0.nft b/tests/shell/testcases/nft-f/dumps/0031vmap_string_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0031vmap_string_0.nft
diff --git a/tests/shell/testcases/nft-f/dumps/0032pknock_0.json-nft b/tests/shell/testcases/nft-f/dumps/0032pknock_0.json-nft
new file mode 100644
index 00000000..4c7d2bbe
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0032pknock_0.json-nft
@@ -0,0 +1,484 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "portknock",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "portknock",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": -10,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "clients_ipv4",
+ "table": "portknock",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "candidates_ipv4",
+ "table": "portknock",
+ "type": [
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "portknock",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 10001
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "elem": {
+ "val": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ 10002
+ ]
+ },
+ "timeout": 1
+ }
+ },
+ "set": "@candidates_ipv4"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "portknock",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 10002
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "right": "@candidates_ipv4"
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "elem": {
+ "val": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ 10003
+ ]
+ },
+ "timeout": 1
+ }
+ },
+ "set": "@candidates_ipv4"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "portknock",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 10003
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "right": "@candidates_ipv4"
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "elem": {
+ "val": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ 10004
+ ]
+ },
+ "timeout": 1
+ }
+ },
+ "set": "@candidates_ipv4"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "portknock",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 10004
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "right": "@candidates_ipv4"
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "elem": {
+ "val": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ 10005
+ ]
+ },
+ "timeout": 1
+ }
+ },
+ "set": "@candidates_ipv4"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "portknock",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 10005
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "right": "@candidates_ipv4"
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "elem": {
+ "val": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "timeout": 600
+ }
+ },
+ "set": "@clients_ipv4"
+ }
+ },
+ {
+ "log": {
+ "prefix": "Successful portknock: "
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "portknock",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@clients_ipv4"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "portknock",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "established",
+ "related"
+ ]
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "portknock",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-f/dumps/0032pknock_0.nft b/tests/shell/testcases/nft-f/dumps/0032pknock_0.nft
new file mode 100644
index 00000000..f29dfb28
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0032pknock_0.nft
@@ -0,0 +1,25 @@
+table inet portknock {
+ set clients_ipv4 {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ }
+
+ set candidates_ipv4 {
+ type ipv4_addr . inet_service
+ size 65535
+ flags dynamic,timeout
+ }
+
+ chain input {
+ type filter hook input priority filter - 10; policy accept;
+ tcp dport 10001 add @candidates_ipv4 { ip saddr . 10002 timeout 1s }
+ tcp dport 10002 ip saddr . tcp dport @candidates_ipv4 add @candidates_ipv4 { ip saddr . 10003 timeout 1s }
+ tcp dport 10003 ip saddr . tcp dport @candidates_ipv4 add @candidates_ipv4 { ip saddr . 10004 timeout 1s }
+ tcp dport 10004 ip saddr . tcp dport @candidates_ipv4 add @candidates_ipv4 { ip saddr . 10005 timeout 1s }
+ tcp dport 10005 ip saddr . tcp dport @candidates_ipv4 add @clients_ipv4 { ip saddr timeout 10m } log prefix "Successful portknock: "
+ tcp dport 22 ip saddr @clients_ipv4 counter packets 0 bytes 0 accept
+ tcp dport 22 ct state established,related counter packets 0 bytes 0 accept
+ tcp dport 22 reject with tcp reset
+ }
+}
diff --git a/tests/shell/testcases/nft-f/dumps/sample-ruleset.nft b/tests/shell/testcases/nft-f/dumps/sample-ruleset.nft
new file mode 100644
index 00000000..1a9f4e7a
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/sample-ruleset.nft
@@ -0,0 +1,239 @@
+table inet filter {
+ map if_input {
+ type ifname : verdict
+ elements = { "eth0" : jump public_input,
+ "eth1" : jump home_input,
+ "eth2.10" : jump home_input,
+ "eth2.20" : jump home_input }
+ }
+
+ map if_forward {
+ type ifname : verdict
+ elements = { "eth0" : jump public_forward,
+ "eth1" : jump trusted_forward,
+ "eth2.10" : jump voip_forward,
+ "eth2.20" : jump guest_forward }
+ }
+
+ map if_output {
+ type ifname : verdict
+ elements = { "eth0" : jump public_output,
+ "eth1" : jump home_output,
+ "eth2.10" : jump home_output,
+ "eth2.20" : jump home_output }
+ }
+
+ set ipv4_blacklist {
+ type ipv4_addr
+ flags interval
+ auto-merge
+ }
+
+ set ipv6_blacklist {
+ type ipv6_addr
+ flags interval
+ auto-merge
+ }
+
+ set limit_src_ip {
+ type ipv4_addr
+ size 1024
+ flags dynamic,timeout
+ }
+
+ set limit_src_ip6 {
+ type ipv6_addr
+ size 1024
+ flags dynamic,timeout
+ }
+
+ chain PREROUTING_RAW {
+ type filter hook prerouting priority raw; policy accept;
+ meta l4proto != { icmp, tcp, udp, ipv6-icmp } counter packets 0 bytes 0 drop
+ tcp flags syn jump {
+ tcp option maxseg size 1-500 counter packets 0 bytes 0 drop
+ tcp sport 0 counter packets 0 bytes 0 drop
+ }
+ rt type 0 counter packets 0 bytes 0 drop
+ }
+
+ chain PREROUTING_MANGLE {
+ type filter hook prerouting priority mangle; policy accept;
+ ct state vmap { invalid : jump ct_invalid_pre, related : jump rpfilter, new : jump ct_new_pre, untracked : jump ct_untracked_pre }
+ }
+
+ chain ct_invalid_pre {
+ counter packets 0 bytes 0 drop
+ }
+
+ chain ct_untracked_pre {
+ icmpv6 type { mld-listener-query, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld2-listener-report } return
+ counter packets 0 bytes 0 drop
+ }
+
+ chain ct_new_pre {
+ jump rpfilter
+ tcp flags & (fin | syn | rst | ack) != syn counter packets 0 bytes 0 drop
+ iifname "eth0" meta nfproto vmap { ipv4 : jump blacklist_input_ipv4, ipv6 : jump blacklist_input_ipv6 }
+ }
+
+ chain rpfilter {
+ ip saddr 0.0.0.0 ip daddr 255.255.255.255 udp sport 68 udp dport 67 return
+ ip6 saddr :: ip6 daddr . icmpv6 type { ff02::1:ff00:0/104 . nd-neighbor-solicit, ff02::16 . mld2-listener-report } return
+ fib saddr . iif oif 0 counter packets 0 bytes 0 drop
+ }
+
+ chain blacklist_input_ipv4 {
+ ip saddr { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/3 } counter packets 0 bytes 0 drop
+ ip saddr @ipv4_blacklist counter packets 0 bytes 0 drop
+ }
+
+ chain blacklist_input_ipv6 {
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 saddr fe80::/64 return
+ udp sport 547 ip6 saddr fe80::/64 return
+ ip6 saddr { ::/3, 2001::/32, 2001:2::/48, 2001:3::/32, 2001:10::-2001:2f:ffff:ffff:ffff:ffff:ffff:ffff, 2001:db8::/32, 2002::/16, 3000::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff } counter packets 0 bytes 0 drop
+ ip6 saddr @ipv6_blacklist counter packets 0 bytes 0 drop
+ }
+
+ chain INPUT {
+ type filter hook input priority filter; policy drop;
+ iif "lo" accept
+ ct state established,related accept
+ iifname vmap @if_input
+ log prefix "NFT REJECT IN " flags ip options flags ether limit rate 5/second burst 10 packets reject
+ }
+
+ chain public_input {
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 saddr fe80::/64 ip6 hoplimit 255 accept
+ udp sport 547 udp dport 546 ip6 saddr fe80::/64 accept
+ fib daddr type { broadcast, anycast, multicast } counter packets 0 bytes 0 drop
+ counter packets 0 bytes 0 drop
+ }
+
+ chain home_input {
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
+ icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept
+ udp sport 68 udp dport 67 accept
+ udp sport 546 udp dport 547 iifname { "eth1", "eth2.10", "eth2.20" } accept
+ fib daddr type { broadcast, anycast, multicast } counter packets 0 bytes 0 drop
+ icmp type echo-request accept
+ icmpv6 type echo-request accept
+ tcp dport 22 iifname "eth1" accept
+ meta l4proto { tcp, udp } th dport 53 jump {
+ ip6 saddr != { fd00::/8, fe80::/64 } counter packets 0 bytes 0 reject with icmpv6 port-unreachable
+ accept
+ }
+ udp dport 123 accept
+ tcp dport 8443 accept
+ }
+
+ chain FORWARD_MANGLE {
+ type filter hook forward priority mangle; policy accept;
+ oifname "eth0" jump {
+ ct state new meta nfproto vmap { ipv4 : jump blacklist_output_ipv4, ipv6 : jump blacklist_output_ipv6 }
+ tcp flags & (syn | rst) == syn tcp option maxseg size set rt mtu
+ }
+ }
+
+ chain blacklist_output_ipv4 {
+ ip daddr { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/3 } goto log_blacklist
+ ip daddr @ipv4_blacklist goto log_blacklist
+ }
+
+ chain blacklist_output_ipv6 {
+ icmpv6 type . ip6 daddr { nd-router-solicit . ff02::2, nd-neighbor-solicit . ff02::1:ff00:0/104, nd-neighbor-advert . fe80::/64, nd-neighbor-advert . ff02::1, nd-neighbor-advert . ff02::1:ff00:0/104, mld2-listener-report . ff02::16 } return
+ udp dport 547 ip6 daddr ff02::1:2 return
+ ip6 daddr { ::/3, 2001::/32, 2001:2::/48, 2001:3::/32, 2001:10::-2001:2f:ffff:ffff:ffff:ffff:ffff:ffff, 2001:db8::/32, 2002::/16, 3000::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff } goto log_blacklist
+ ip6 daddr @ipv6_blacklist goto log_blacklist
+ }
+
+ chain log_blacklist {
+ log prefix "NFT BLACKLIST " flags ip options flags ether limit rate 5/minute burst 10 packets drop
+ counter packets 0 bytes 0 drop
+ }
+
+ chain FORWARD {
+ type filter hook forward priority filter; policy drop;
+ ct state established,related accept
+ fib daddr type { broadcast, anycast, multicast } counter packets 0 bytes 0 drop
+ iifname vmap @if_forward
+ log prefix "NFT REJECT FWD " flags ip options flags ether limit rate 5/second burst 10 packets reject
+ }
+
+ chain public_forward {
+ udp dport { 5060, 7078-7097 } oifname "eth2.10" jump {
+ ip6 saddr { 2001:db8::1-2001:db8::2 } accept
+ meta nfproto ipv6 log prefix "NFT DROP SIP " flags ip options flags ether limit rate 5/second burst 10 packets drop
+ }
+ counter packets 0 bytes 0 drop
+ }
+
+ chain trusted_forward {
+ oifname "eth0" accept
+ icmp type echo-request accept
+ icmpv6 type echo-request accept
+ ip daddr { 192.168.3.30, 192.168.4.40 } tcp dport vmap { 22 : accept, 80 : drop, 443 : accept }
+ ip daddr 192.168.2.20 jump {
+ tcp dport { 80, 443, 515, 631, 9100 } accept
+ udp dport 161 accept
+ }
+ }
+
+ chain voip_forward {
+ icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } oifname "eth0" accept
+ ip6 daddr { 2001:db8::1-2001:db8::2 } jump {
+ udp dport { 3478, 5060 } accept
+ udp sport 7078-7097 accept
+ tcp dport 5061 accept
+ }
+ tcp dport 587 ip daddr 10.0.0.1 accept
+ tcp dport 80 oifname "eth0" counter packets 0 bytes 0 reject
+ }
+
+ chain guest_forward {
+ oifname "eth0" accept
+ }
+
+ chain OUTPUT {
+ type filter hook output priority filter; policy drop;
+ oif "lo" accept
+ ct state vmap { invalid : jump ct_invalid_out, established : accept, related : accept, untracked : jump ct_untracked_out }
+ oifname vmap @if_output
+ log prefix "NFT REJECT OUT " flags ip options flags ether limit rate 5/second burst 10 packets reject
+ }
+
+ chain ct_invalid_out {
+ counter packets 0 bytes 0 drop
+ }
+
+ chain ct_untracked_out {
+ icmpv6 type { mld-listener-query, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld2-listener-report } return
+ counter packets 0 bytes 0 drop
+ }
+
+ chain public_output {
+ ct state new meta nfproto vmap { ipv4 : jump blacklist_output_ipv4, ipv6 : jump blacklist_output_ipv6 }
+ icmp type { destination-unreachable, echo-request, time-exceeded, parameter-problem } accept
+ icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } accept
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
+ icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept
+ udp dport 547 ip6 saddr fe80::/64 ip6 daddr ff02::1:2 accept
+ udp dport { 53, 123 } accept
+ tcp dport { 443, 587, 853 } accept
+ }
+
+ chain home_output {
+ icmp type { destination-unreachable, echo-request, time-exceeded, parameter-problem } accept
+ icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } accept
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
+ icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept
+ udp sport 547 udp dport 546 ip6 saddr fe80::/64 oifname { "eth1", "eth2.10", "eth2.20" } accept
+ udp sport 67 udp dport 68 ip saddr { 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 } accept
+ tcp dport 22 ip daddr 192.168.1.10 accept
+ }
+
+ chain POSTROUTING_SRCNAT {
+ type nat hook postrouting priority srcnat; policy accept;
+ ip saddr { 192.168.1.0-192.168.4.255 } oifname "eth0" masquerade
+ }
+}
diff --git a/tests/shell/testcases/nft-f/sample-ruleset b/tests/shell/testcases/nft-f/sample-ruleset
new file mode 100755
index 00000000..763e41a1
--- /dev/null
+++ b/tests/shell/testcases/nft-f/sample-ruleset
@@ -0,0 +1,262 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_chain_binding)
+
+$NFT -f /dev/stdin <<"EOF"
+define public_if = eth0
+define trusted_if = eth1
+define voip_if = eth2.10
+define guest_if = eth2.20
+define home_if = { $trusted_if, $voip_if, $guest_if }
+define home_ipv6_if = { $trusted_if, $voip_if, $guest_if }
+
+define masq_ip = { 192.168.1.0/24, 192.168.2.0/24, 192.168.3.0/24, 192.168.4.0/24 }
+define masq_if = $public_if
+
+define host1_ip = 192.168.1.10
+define host2_ip = 192.168.2.20
+define host3_ip = 192.168.3.30
+define host4_ip = 192.168.4.40
+
+define proxy_port = 8443
+
+define private_ip = { 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 }
+define private_ip6 = { fe80::/64, fd00::/8 }
+define bogons_ip = { 0.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 127.0.0.0/8, 169.254.0.0/16, 172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 192.168.0.0/16, 198.18.0.0/15, 198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/3 }
+define bogons_ip6 = { ::/3, 2001:0002::/48, 2001:0003::/32, 2001:10::/28, 2001:20::/28, 2001::/32, 2001:db8::/32, 2002::/16, 3000::/4, 4000::/2, 8000::/1 }
+
+define sip_whitelist_ip6 = { 2001:db8::1/128, 2001:db8::2/128 }
+define smtps_whitelist_ip = 10.0.0.1
+define protocol_whitelist = { tcp, udp, icmp, ipv6-icmp }
+
+table inet filter {
+ map if_input {
+ type ifname : verdict;
+ elements = { $public_if : jump public_input, $trusted_if : jump home_input, $voip_if : jump home_input, $guest_if : jump home_input }
+ }
+ map if_forward {
+ type ifname : verdict;
+ elements = { $public_if : jump public_forward, $trusted_if : jump trusted_forward, $voip_if : jump voip_forward, $guest_if : jump guest_forward }
+ }
+ map if_output {
+ type ifname : verdict;
+ elements = { $public_if : jump public_output, $trusted_if : jump home_output, $voip_if : jump home_output, $guest_if : jump home_output }
+ }
+
+ set ipv4_blacklist { type ipv4_addr; flags interval; auto-merge; }
+ set ipv6_blacklist { type ipv6_addr; flags interval; auto-merge; }
+ set limit_src_ip { type ipv4_addr; flags dynamic, timeout; size 1024; }
+ set limit_src_ip6 { type ipv6_addr; flags dynamic, timeout; size 1024; }
+
+ chain PREROUTING_RAW {
+ type filter hook prerouting priority raw;
+
+ meta l4proto != $protocol_whitelist counter drop
+ tcp flags syn jump {
+ tcp option maxseg size 1-500 counter drop
+ tcp sport 0 counter drop
+ }
+ rt type 0 counter drop
+ }
+
+ chain PREROUTING_MANGLE {
+ type filter hook prerouting priority mangle;
+
+ ct state vmap { invalid : jump ct_invalid_pre, untracked : jump ct_untracked_pre, new : jump ct_new_pre, related : jump rpfilter }
+ }
+ chain ct_invalid_pre {
+ counter drop
+ }
+ chain ct_untracked_pre {
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld-listener-query, mld2-listener-report } return
+ counter drop
+ }
+ chain ct_new_pre {
+ jump rpfilter
+
+ tcp flags & (fin|syn|rst|ack) != syn counter drop
+
+ iifname $public_if meta nfproto vmap { ipv4 : jump blacklist_input_ipv4, ipv6 : jump blacklist_input_ipv6 }
+ }
+ chain rpfilter {
+ ip saddr 0.0.0.0 ip daddr 255.255.255.255 udp sport bootpc udp dport bootps return
+ ip6 saddr ::/128 ip6 daddr . icmpv6 type { ff02::1:ff00:0/104 . nd-neighbor-solicit, ff02::16 . mld2-listener-report } return
+
+ fib saddr . iif oif eq 0 counter drop
+ }
+ chain blacklist_input_ipv4{
+ ip saddr $bogons_ip counter drop
+ ip saddr @ipv4_blacklist counter drop
+ }
+ chain blacklist_input_ipv6{
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 saddr fe80::/64 return
+ udp sport dhcpv6-server ip6 saddr fe80::/64 return
+
+ ip6 saddr $bogons_ip6 counter drop
+ ip6 saddr @ipv6_blacklist counter drop
+ }
+
+ chain INPUT {
+ type filter hook input priority filter; policy drop;
+
+ iif lo accept
+
+ ct state established,related accept
+
+ iifname vmap @if_input
+
+ log prefix "NFT REJECT IN " flags ether flags ip options limit rate 5/second burst 10 packets reject
+ }
+ chain public_input {
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 saddr fe80::/64 ip6 hoplimit 255 accept
+
+ udp sport dhcpv6-server udp dport dhcpv6-client ip6 saddr fe80::/64 accept
+ fib daddr type { broadcast, multicast, anycast } counter drop
+
+ counter drop
+ }
+ chain home_input {
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
+ icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept
+
+ udp sport bootpc udp dport bootps accept
+ udp sport dhcpv6-client udp dport dhcpv6-server iifname $home_ipv6_if accept
+
+ fib daddr type { broadcast, multicast, anycast } counter drop
+
+ icmp type echo-request accept
+ icmpv6 type echo-request accept
+
+ tcp dport ssh iifname $trusted_if accept
+
+ meta l4proto { tcp, udp } th dport domain jump {
+ ip6 saddr != $private_ip6 counter reject
+ accept
+ }
+
+ udp dport ntp accept
+
+ tcp dport $proxy_port accept
+ }
+
+ chain FORWARD_MANGLE {
+ type filter hook forward priority mangle;
+
+ oifname $public_if jump {
+ ct state new meta nfproto vmap { ipv4 : jump blacklist_output_ipv4, ipv6 : jump blacklist_output_ipv6 }
+ tcp flags & (syn|rst) == syn tcp option maxseg size set rt mtu
+ }
+ }
+ chain blacklist_output_ipv4 {
+ ip daddr $bogons_ip goto log_blacklist
+ ip daddr @ipv4_blacklist goto log_blacklist
+ }
+ chain blacklist_output_ipv6 {
+ icmpv6 type . ip6 daddr { nd-router-solicit . ff02::2/128, nd-neighbor-solicit . ff02::1:ff00:0/104, nd-neighbor-advert . fe80::/64, nd-neighbor-advert . ff02::1/128, nd-neighbor-advert . ff02::1:ff00:0/104, mld2-listener-report . ff02::16/128 } return
+ udp dport dhcpv6-server ip6 daddr ff02::1:2 return
+
+ ip6 daddr $bogons_ip6 goto log_blacklist
+ ip6 daddr @ipv6_blacklist goto log_blacklist
+ }
+ chain log_blacklist {
+ log prefix "NFT BLACKLIST " flags ether flags ip options limit rate 5/minute burst 10 packets drop
+ counter drop
+ }
+
+ chain FORWARD {
+ type filter hook forward priority filter; policy drop;
+
+ ct state established,related accept
+
+ fib daddr type { broadcast, multicast, anycast } counter drop
+
+ iifname vmap @if_forward
+
+ log prefix "NFT REJECT FWD " flags ether flags ip options limit rate 5/second burst 10 packets reject
+ }
+ chain public_forward {
+ udp dport { 5060, 7078-7097 } oifname $voip_if jump {
+ ip6 saddr $sip_whitelist_ip6 accept
+ meta nfproto ipv6 log prefix "NFT DROP SIP " flags ether flags ip options limit rate 5/second burst 10 packets drop
+ }
+
+ counter drop
+ }
+ chain trusted_forward {
+ oifname $public_if accept
+
+ icmp type echo-request accept
+ icmpv6 type echo-request accept
+
+ ip daddr { $host3_ip, $host4_ip } tcp dport vmap { ssh : accept, https : accept, http : drop }
+
+ ip daddr $host2_ip jump {
+ tcp dport { http, https, printer, ipp, 9100 } accept
+ udp dport snmp accept
+ }
+ }
+ chain voip_forward {
+ icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } oifname $public_if accept
+
+ ip6 daddr $sip_whitelist_ip6 jump {
+ udp dport { 3478, 5060 } accept
+ udp sport { 7078-7097 } accept
+ tcp dport 5061 accept
+ }
+
+ tcp dport 587 ip daddr $smtps_whitelist_ip accept
+ tcp dport http oifname $public_if counter reject
+ }
+ chain guest_forward {
+ oifname $public_if accept
+ }
+
+ chain OUTPUT {
+ type filter hook output priority filter; policy drop;
+
+ oif lo accept
+
+ ct state vmap { established : accept, related : accept, invalid : jump ct_invalid_out, untracked : jump ct_untracked_out }
+
+ oifname vmap @if_output
+
+ log prefix "NFT REJECT OUT " flags ether flags ip options limit rate 5/second burst 10 packets reject
+ }
+ chain ct_invalid_out {
+ counter drop
+ }
+ chain ct_untracked_out {
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, mld-listener-query, mld2-listener-report } return
+ counter drop
+ }
+ chain public_output {
+ ct state new meta nfproto vmap { ipv4 : jump blacklist_output_ipv4, ipv6 : jump blacklist_output_ipv6 }
+
+ icmp type { destination-unreachable, time-exceeded, parameter-problem, echo-request } accept
+ icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } accept
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
+ icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept
+
+ udp dport dhcpv6-server ip6 saddr fe80::/64 ip6 daddr ff02::1:2 accept
+
+ udp dport { domain, ntp } accept
+ tcp dport { https, 587, domain-s } accept
+ }
+ chain home_output {
+ icmp type { destination-unreachable, time-exceeded, parameter-problem, echo-request } accept
+ icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request } accept
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } ip6 hoplimit 255 accept
+ icmpv6 type { mld-listener-query, mld2-listener-report } ip6 hoplimit 1 accept
+
+ udp sport dhcpv6-server udp dport dhcpv6-client ip6 saddr fe80::/64 oifname $home_ipv6_if accept
+ udp sport bootps udp dport bootpc ip saddr $private_ip accept
+ tcp dport ssh ip daddr $host1_ip accept
+ }
+
+ chain POSTROUTING_SRCNAT {
+ type nat hook postrouting priority srcnat;
+
+ meta nfproto ipv4 ip saddr $masq_ip oifname $masq_if masquerade
+ }
+}
+EOF
diff --git a/tests/shell/testcases/nft-i/0001define_0 b/tests/shell/testcases/nft-i/0001define_0
new file mode 100755
index 00000000..62e1b6de
--- /dev/null
+++ b/tests/shell/testcases/nft-i/0001define_0
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -e
+
+# test if using defines in interactive nft sessions works
+
+$NFT -i >/dev/null <<EOF
+add table inet t
+add chain inet t c
+define ports = { 22, 443 }
+add rule inet t c tcp dport \$ports accept
+add rule inet t c udp dport \$ports accept
+EOF
+
+$NFT -i >/dev/null <<EOF
+define port = 22
+flush chain inet t c
+redefine port = 443
+delete chain inet t c
+undefine port
+delete table inet t
+EOF
diff --git a/tests/shell/testcases/nft-i/dumps/0001define_0.json-nft b/tests/shell/testcases/nft-i/dumps/0001define_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/nft-i/dumps/0001define_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/nft-i/dumps/0001define_0.nft b/tests/shell/testcases/nft-i/dumps/0001define_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/nft-i/dumps/0001define_0.nft
diff --git a/tests/shell/testcases/optimizations/dependency_kill b/tests/shell/testcases/optimizations/dependency_kill
new file mode 100755
index 00000000..904eecf8
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dependency_kill
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table bridge foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table ip foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table ip6 foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table netdev foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table inet foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ meta nfproto ipv4 udp dport 67
+ meta nfproto ipv6 udp dport 67
+ }
+}"
+
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/dumps/dependency_kill.json-nft b/tests/shell/testcases/optimizations/dumps/dependency_kill.json-nft
new file mode 100644
index 00000000..712182e9
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/dependency_kill.json-nft
@@ -0,0 +1,776 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "bridge",
+ "name": "foo",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "bridge",
+ "table": "foo",
+ "name": "bar",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "bridge",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "bridge",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "bridge",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ether",
+ "field": "type"
+ }
+ },
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "bridge",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ether",
+ "field": "type"
+ }
+ },
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "foo",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "foo",
+ "name": "bar",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ether",
+ "field": "type"
+ }
+ },
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "foo",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "foo",
+ "name": "bar",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ether",
+ "field": "type"
+ }
+ },
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "netdev",
+ "name": "foo",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "foo",
+ "name": "bar",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "netdev",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "netdev",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "netdev",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ether",
+ "field": "type"
+ }
+ },
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "netdev",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ether",
+ "field": "type"
+ }
+ },
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "foo",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "foo",
+ "name": "bar",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "protocol"
+ }
+ },
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ether",
+ "field": "type"
+ }
+ },
+ "right": "ip"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ether",
+ "field": "type"
+ }
+ },
+ "right": "ip6"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "nfproto"
+ }
+ },
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "foo",
+ "chain": "bar",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "nfproto"
+ }
+ },
+ "right": "ipv6"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 67
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/dependency_kill.nft b/tests/shell/testcases/optimizations/dumps/dependency_kill.nft
new file mode 100644
index 00000000..1781f7be
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/dependency_kill.nft
@@ -0,0 +1,42 @@
+table bridge foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table ip foo {
+ chain bar {
+ udp dport 67
+ meta protocol ip6 udp dport 67
+ udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table ip6 foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ udp dport 67
+ ether type ip udp dport 67
+ udp dport 67
+ }
+}
+table netdev foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ }
+}
+table inet foo {
+ chain bar {
+ meta protocol ip udp dport 67
+ meta protocol ip6 udp dport 67
+ ether type ip udp dport 67
+ ether type ip6 udp dport 67
+ meta nfproto ipv4 udp dport 67
+ meta nfproto ipv6 udp dport 67
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_nat.json-nft b/tests/shell/testcases/optimizations/dumps/merge_nat.json-nft
new file mode 100644
index 00000000..a6cf1bfc
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_nat.json-nft
@@ -0,0 +1,379 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test1",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test1",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oif"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test1",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "dnat": {
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "4.4.4.4",
+ "1.1.1.1"
+ ],
+ [
+ "5.5.5.5",
+ "2.2.2.2"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test2",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test2",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test2",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oif"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test2",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "dnat": {
+ "family": "ip",
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 80,
+ {
+ "concat": [
+ "1.1.1.1",
+ 8001
+ ]
+ }
+ ],
+ [
+ 81,
+ {
+ "concat": [
+ "2.2.2.2",
+ 9001
+ ]
+ }
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test2",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": {
+ "set": [
+ {
+ "prefix": {
+ "addr": "10.141.11.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "10.141.13.0",
+ "len": 24
+ }
+ }
+ ]
+ }
+ }
+ },
+ {
+ "masquerade": null
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test4",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test4",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test4",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oif"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test4",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "dnat": {
+ "family": "ip",
+ "addr": {
+ "map": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "1.1.1.1",
+ 80
+ ]
+ },
+ {
+ "concat": [
+ "4.4.4.4",
+ 8000
+ ]
+ }
+ ],
+ [
+ {
+ "concat": [
+ "2.2.2.2",
+ 81
+ ]
+ },
+ {
+ "concat": [
+ "3.3.3.3",
+ 9000
+ ]
+ }
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test4",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "redirect": {
+ "port": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 83,
+ 8083
+ ],
+ [
+ 84,
+ 8084
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test4",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 85
+ }
+ },
+ {
+ "redirect": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_nat.nft b/tests/shell/testcases/optimizations/dumps/merge_nat.nft
new file mode 100644
index 00000000..f6c119ec
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_nat.nft
@@ -0,0 +1,21 @@
+table ip test1 {
+ chain y {
+ oif "lo" accept
+ dnat to ip saddr map { 4.4.4.4 : 1.1.1.1, 5.5.5.5 : 2.2.2.2 }
+ }
+}
+table ip test2 {
+ chain y {
+ oif "lo" accept
+ dnat ip to tcp dport map { 80 : 1.1.1.1 . 8001, 81 : 2.2.2.2 . 9001 }
+ ip saddr { 10.141.11.0/24, 10.141.13.0/24 } masquerade
+ }
+}
+table ip test4 {
+ chain y {
+ oif "lo" accept
+ dnat ip to ip daddr . tcp dport map { 1.1.1.1 . 80 : 4.4.4.4 . 8000, 2.2.2.2 . 81 : 3.3.3.3 . 9000 }
+ redirect to :tcp dport map { 83 : 8083, 84 : 8084 }
+ tcp dport 85 redirect
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_nat_concat.json-nft b/tests/shell/testcases/optimizations/dumps/merge_nat_concat.json-nft
new file mode 100644
index 00000000..dc67feec
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_nat_concat.json-nft
@@ -0,0 +1,200 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test3",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test3",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test3",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oif"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test3",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "sport"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "1.1.1.1",
+ {
+ "range": [
+ 1024,
+ 65535
+ ]
+ }
+ ]
+ },
+ "3.3.3.3"
+ ],
+ [
+ {
+ "concat": [
+ "2.2.2.2",
+ {
+ "range": [
+ 1024,
+ 65535
+ ]
+ }
+ ]
+ },
+ "4.4.4.4"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test3",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "enp2s0"
+ }
+ },
+ {
+ "snat": {
+ "family": "ip",
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "prefix": {
+ "addr": "10.1.1.0",
+ "len": 24
+ }
+ },
+ {
+ "range": [
+ "72.2.3.66",
+ "72.2.3.78"
+ ]
+ }
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test3",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 8888,
+ 9999
+ ]
+ }
+ }
+ },
+ {
+ "redirect": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_nat_concat.nft b/tests/shell/testcases/optimizations/dumps/merge_nat_concat.nft
new file mode 100644
index 00000000..0faddfd1
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_nat_concat.nft
@@ -0,0 +1,8 @@
+table ip test3 {
+ chain y {
+ oif "lo" accept
+ snat to ip saddr . tcp sport map { 1.1.1.1 . 1024-65535 : 3.3.3.3, 2.2.2.2 . 1024-65535 : 4.4.4.4 }
+ oifname "enp2s0" snat ip to ip saddr map { 10.1.1.0/24 : 72.2.3.66-72.2.3.78 }
+ tcp dport { 8888, 9999 } redirect
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_nat_inet.json-nft b/tests/shell/testcases/optimizations/dumps/merge_nat_inet.json-nft
new file mode 100644
index 00000000..99930f11
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_nat_inet.json-nft
@@ -0,0 +1,208 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "nat",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "nat",
+ "name": "prerouting",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "nat",
+ "name": "postrouting",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "nat",
+ "chain": "prerouting",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oif"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "nat",
+ "chain": "prerouting",
+ "handle": 0,
+ "expr": [
+ {
+ "dnat": {
+ "family": "ip",
+ "addr": {
+ "map": {
+ "key": {
+ "concat": [
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "enp2s0",
+ "72.2.3.70",
+ 80
+ ]
+ },
+ {
+ "concat": [
+ "10.1.1.52",
+ 80
+ ]
+ }
+ ],
+ [
+ {
+ "concat": [
+ "enp2s0",
+ "72.2.3.66",
+ 53122
+ ]
+ },
+ {
+ "concat": [
+ "10.1.1.10",
+ 22
+ ]
+ }
+ ],
+ [
+ {
+ "concat": [
+ "enp2s0",
+ "72.2.3.66",
+ 443
+ ]
+ },
+ {
+ "concat": [
+ "10.1.1.52",
+ 443
+ ]
+ }
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "nat",
+ "chain": "postrouting",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oif"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "nat",
+ "chain": "postrouting",
+ "handle": 0,
+ "expr": [
+ {
+ "snat": {
+ "family": "ip",
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "72.2.3.66",
+ "10.2.2.2"
+ ],
+ [
+ "72.2.3.67",
+ "10.2.3.3"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_nat_inet.nft b/tests/shell/testcases/optimizations/dumps/merge_nat_inet.nft
new file mode 100644
index 00000000..a1a11354
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_nat_inet.nft
@@ -0,0 +1,11 @@
+table inet nat {
+ chain prerouting {
+ oif "lo" accept
+ dnat ip to iifname . ip daddr . tcp dport map { "enp2s0" . 72.2.3.70 . 80 : 10.1.1.52 . 80, "enp2s0" . 72.2.3.66 . 53122 : 10.1.1.10 . 22, "enp2s0" . 72.2.3.66 . 443 : 10.1.1.52 . 443 }
+ }
+
+ chain postrouting {
+ oif "lo" accept
+ snat ip to ip daddr map { 72.2.3.66 : 10.2.2.2, 72.2.3.67 : 10.2.3.3 }
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_reject.json-nft b/tests/shell/testcases/optimizations/dumps/merge_reject.json-nft
new file mode 100644
index 00000000..46ed0677
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_reject.json-nft
@@ -0,0 +1,320 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": "172.30.33.70"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 3306
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "tcp",
+ "172.30.238.117",
+ 8080
+ ]
+ },
+ {
+ "concat": [
+ "tcp",
+ "172.30.33.71",
+ 3306
+ ]
+ },
+ {
+ "concat": [
+ "tcp",
+ "172.30.254.251",
+ 3306
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "reject": {
+ "type": "icmp",
+ "expr": "port-unreachable"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": "172.30.254.252"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 3306
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "tcp",
+ "aaaa::3",
+ 8080
+ ]
+ },
+ {
+ "concat": [
+ "tcp",
+ "aaaa::2",
+ 3306
+ ]
+ },
+ {
+ "concat": [
+ "tcp",
+ "aaaa::4",
+ 3306
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "reject": {
+ "type": "icmpv6",
+ "expr": "port-unreachable"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "right": "aaaa::5"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 3306
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "reject": {
+ "type": "tcp reset"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_reject.nft b/tests/shell/testcases/optimizations/dumps/merge_reject.nft
new file mode 100644
index 00000000..c29ad6d5
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_reject.nft
@@ -0,0 +1,13 @@
+table ip x {
+ chain y {
+ ip daddr 172.30.33.70 tcp dport 3306 counter packets 0 bytes 0 drop
+ meta l4proto . ip daddr . tcp dport { tcp . 172.30.238.117 . 8080, tcp . 172.30.33.71 . 3306, tcp . 172.30.254.251 . 3306 } counter packets 0 bytes 0 reject
+ ip daddr 172.30.254.252 tcp dport 3306 counter packets 0 bytes 0 reject with tcp reset
+ }
+}
+table ip6 x {
+ chain y {
+ meta l4proto . ip6 daddr . tcp dport { tcp . aaaa::3 . 8080, tcp . aaaa::2 . 3306, tcp . aaaa::4 . 3306 } counter packets 0 bytes 0 reject
+ ip6 daddr aaaa::5 tcp dport 3306 counter packets 0 bytes 0 reject with tcp reset
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_stmts.json-nft b/tests/shell/testcases/optimizations/dumps/merge_stmts.json-nft
new file mode 100644
index 00000000..c392b76a
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts.json-nft
@@ -0,0 +1,63 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "set": [
+ "192.168.0.1",
+ "192.168.0.2",
+ "192.168.0.3"
+ ]
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_stmts.nft b/tests/shell/testcases/optimizations/dumps/merge_stmts.nft
new file mode 100644
index 00000000..b56ea3ed
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts.nft
@@ -0,0 +1,5 @@
+table ip x {
+ chain y {
+ ip daddr { 192.168.0.1, 192.168.0.2, 192.168.0.3 } counter packets 0 bytes 0 accept
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.json-nft b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.json-nft
new file mode 100644
index 00000000..267d84ef
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.json-nft
@@ -0,0 +1,374 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "c2",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "c3",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "eth1",
+ "1.1.1.1",
+ "2.2.2.3"
+ ]
+ },
+ {
+ "concat": [
+ "eth1",
+ "1.1.1.2",
+ "2.2.2.4"
+ ]
+ },
+ {
+ "concat": [
+ "eth1",
+ "1.1.1.2",
+ {
+ "prefix": {
+ "addr": "2.2.3.0",
+ "len": 24
+ }
+ }
+ ]
+ },
+ {
+ "concat": [
+ "eth1",
+ "1.1.1.2",
+ {
+ "range": [
+ "2.2.4.0",
+ "2.2.4.10"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ "eth2",
+ "1.1.1.3",
+ "2.2.2.5"
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "protocol"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "th",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "tcp",
+ 22
+ ]
+ },
+ {
+ "concat": [
+ "udp",
+ 67
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "c1",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ 51820,
+ "foo"
+ ]
+ },
+ {
+ "concat": [
+ 514,
+ "bar"
+ ]
+ },
+ {
+ "concat": [
+ 67,
+ "bar"
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "c2",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ 100,
+ "foo"
+ ]
+ },
+ {
+ "concat": [
+ 51820,
+ "foo"
+ ]
+ },
+ {
+ "concat": [
+ 514,
+ "bar"
+ ]
+ },
+ {
+ "concat": [
+ 67,
+ "bar"
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "c3",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ 100,
+ "foo"
+ ]
+ },
+ {
+ "concat": [
+ 51820,
+ "foo"
+ ]
+ },
+ {
+ "concat": [
+ 514,
+ "bar"
+ ]
+ },
+ {
+ "concat": [
+ 67,
+ "bar"
+ ]
+ },
+ {
+ "concat": [
+ 100,
+ "test"
+ ]
+ },
+ {
+ "concat": [
+ 51820,
+ "test"
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft
new file mode 100644
index 00000000..f56cea1c
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft
@@ -0,0 +1,18 @@
+table ip x {
+ chain y {
+ iifname . ip saddr . ip daddr { "eth1" . 1.1.1.1 . 2.2.2.3, "eth1" . 1.1.1.2 . 2.2.2.4, "eth1" . 1.1.1.2 . 2.2.3.0/24, "eth1" . 1.1.1.2 . 2.2.4.0-2.2.4.10, "eth2" . 1.1.1.3 . 2.2.2.5 } accept
+ ip protocol . th dport { tcp . 22, udp . 67 }
+ }
+
+ chain c1 {
+ udp dport . iifname { 51820 . "foo", 514 . "bar", 67 . "bar" } accept
+ }
+
+ chain c2 {
+ udp dport . iifname { 100 . "foo", 51820 . "foo", 514 . "bar", 67 . "bar" } accept
+ }
+
+ chain c3 {
+ udp dport . iifname { 100 . "foo", 51820 . "foo", 514 . "bar", 67 . "bar", 100 . "test", 51820 . "test" } accept
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.json-nft b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.json-nft
new file mode 100644
index 00000000..5dfa40a8
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.json-nft
@@ -0,0 +1,167 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "x",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "meta": {
+ "key": "pkttype"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "broadcast",
+ 547
+ ]
+ },
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "broadcast",
+ 67
+ ]
+ },
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "multicast",
+ 1900
+ ]
+ },
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ "1.1.1.1",
+ "2.2.2.2"
+ ]
+ },
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "2.2.2.2",
+ "3.3.3.3"
+ ]
+ },
+ {
+ "drop": null
+ }
+ ],
+ [
+ {
+ "concat": [
+ "4.4.4.4",
+ "5.5.5.5"
+ ]
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.nft b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.nft
new file mode 100644
index 00000000..780aa09a
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.nft
@@ -0,0 +1,9 @@
+table ip x {
+ chain x {
+ meta pkttype . udp dport vmap { broadcast . 547 : accept, broadcast . 67 : accept, multicast . 1900 : drop }
+ }
+
+ chain y {
+ ip saddr . ip daddr vmap { 1.1.1.1 . 2.2.2.2 : accept, 2.2.2.2 . 3.3.3.3 : drop, 4.4.4.4 . 5.5.5.5 : accept }
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.json-nft b/tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.json-nft
new file mode 100644
index 00000000..17d57b8f
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.json-nft
@@ -0,0 +1,182 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "z",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "w",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "invalid",
+ {
+ "drop": null
+ }
+ ],
+ [
+ "established",
+ {
+ "accept": null
+ }
+ ],
+ [
+ "related",
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 1,
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "range": [
+ 2,
+ 3
+ ]
+ },
+ {
+ "drop": null
+ }
+ ],
+ [
+ 4,
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "w",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "elem": {
+ "val": "1.1.1.1",
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "elem": {
+ "val": "1.1.1.2",
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.nft b/tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.nft
new file mode 100644
index 00000000..8ecbd927
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.nft
@@ -0,0 +1,13 @@
+table ip x {
+ chain y {
+ ct state vmap { invalid : drop, established : accept, related : accept }
+ }
+
+ chain z {
+ tcp dport vmap { 1 : accept, 2-3 : drop, 4 : accept }
+ }
+
+ chain w {
+ ip saddr vmap { 1.1.1.1 counter packets 0 bytes 0 : accept, 1.1.1.2 counter packets 0 bytes 0 : drop }
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_vmap_raw.json-nft b/tests/shell/testcases/optimizations/dumps/merge_vmap_raw.json-nft
new file mode 100644
index 00000000..b8ad126c
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_vmap_raw.json-nft
@@ -0,0 +1,438 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "nat_dns_dnstc",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "nat_dns_this_5301",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "nat_dns_saturn_5301",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "nat_dns_saturn_5302",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "nat_dns_saturn_5303",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "nat_dns_acme",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "nat_dns_dnstc",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": "udp"
+ }
+ },
+ {
+ "redirect": {
+ "port": 5300
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "nat_dns_dnstc",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "nat_dns_this_5301",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": "udp"
+ }
+ },
+ {
+ "redirect": {
+ "port": 5301
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "nat_dns_this_5301",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "nat_dns_saturn_5301",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "nfproto"
+ }
+ },
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": "udp"
+ }
+ },
+ {
+ "dnat": {
+ "family": "ip",
+ "addr": "240.0.1.2",
+ "port": 5301
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "nat_dns_saturn_5301",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "nat_dns_saturn_5302",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "nfproto"
+ }
+ },
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": "udp"
+ }
+ },
+ {
+ "dnat": {
+ "family": "ip",
+ "addr": "240.0.1.2",
+ "port": 5302
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "nat_dns_saturn_5302",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "nat_dns_saturn_5303",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "nfproto"
+ }
+ },
+ "right": "ipv4"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": "udp"
+ }
+ },
+ {
+ "dnat": {
+ "family": "ip",
+ "addr": "240.0.1.2",
+ "port": 5303
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "nat_dns_saturn_5303",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "nat_dns_acme",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "udp",
+ "field": "length"
+ }
+ },
+ {
+ "payload": {
+ "base": "th",
+ "offset": 160,
+ "len": 128
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ {
+ "range": [
+ 47,
+ 63
+ ]
+ },
+ "0xe373135363130333131303735353203"
+ ]
+ },
+ {
+ "goto": {
+ "target": "nat_dns_dnstc"
+ }
+ }
+ ],
+ [
+ {
+ "concat": [
+ {
+ "range": [
+ 62,
+ 78
+ ]
+ },
+ "0xe31393032383939353831343037320e"
+ ]
+ },
+ {
+ "goto": {
+ "target": "nat_dns_this_5301"
+ }
+ }
+ ],
+ [
+ {
+ "concat": [
+ {
+ "range": [
+ 62,
+ 78
+ ]
+ },
+ "0xe31363436323733373931323934300e"
+ ]
+ },
+ {
+ "goto": {
+ "target": "nat_dns_saturn_5301"
+ }
+ }
+ ],
+ [
+ {
+ "concat": [
+ {
+ "range": [
+ 62,
+ 78
+ ]
+ },
+ "0xe32393535373539353636383732310e"
+ ]
+ },
+ {
+ "goto": {
+ "target": "nat_dns_saturn_5302"
+ }
+ }
+ ],
+ [
+ {
+ "concat": [
+ {
+ "range": [
+ 62,
+ 78
+ ]
+ },
+ "0xe38353439353637323038363633390e"
+ ]
+ },
+ {
+ "goto": {
+ "target": "nat_dns_saturn_5303"
+ }
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "nat_dns_acme",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_vmap_raw.nft b/tests/shell/testcases/optimizations/dumps/merge_vmap_raw.nft
new file mode 100644
index 00000000..18847116
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_vmap_raw.nft
@@ -0,0 +1,31 @@
+table inet x {
+ chain nat_dns_dnstc {
+ meta l4proto udp redirect to :5300
+ drop
+ }
+
+ chain nat_dns_this_5301 {
+ meta l4proto udp redirect to :5301
+ drop
+ }
+
+ chain nat_dns_saturn_5301 {
+ meta nfproto ipv4 meta l4proto udp dnat ip to 240.0.1.2:5301
+ drop
+ }
+
+ chain nat_dns_saturn_5302 {
+ meta nfproto ipv4 meta l4proto udp dnat ip to 240.0.1.2:5302
+ drop
+ }
+
+ chain nat_dns_saturn_5303 {
+ meta nfproto ipv4 meta l4proto udp dnat ip to 240.0.1.2:5303
+ drop
+ }
+
+ chain nat_dns_acme {
+ udp length . @th,160,128 vmap { 47-63 . 0xe373135363130333131303735353203 : goto nat_dns_dnstc, 62-78 . 0xe31393032383939353831343037320e : goto nat_dns_this_5301, 62-78 . 0xe31363436323733373931323934300e : goto nat_dns_saturn_5301, 62-78 . 0xe32393535373539353636383732310e : goto nat_dns_saturn_5302, 62-78 . 0xe38353439353637323038363633390e : goto nat_dns_saturn_5303 }
+ drop
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_vmaps.json-nft b/tests/shell/testcases/optimizations/dumps/merge_vmaps.json-nft
new file mode 100644
index 00000000..e87f1c4c
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_vmaps.json-nft
@@ -0,0 +1,205 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "filter_in_tcp",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "filter_in_udp",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "set": {
+ "op": "update",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "set": "@s",
+ "stmt": [
+ {
+ "limit": {
+ "rate": 12,
+ "burst": 30,
+ "per": "minute"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 80,
+ {
+ "accept": null
+ }
+ ],
+ [
+ 81,
+ {
+ "accept": null
+ }
+ ],
+ [
+ 443,
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "range": [
+ 8000,
+ 8100
+ ]
+ },
+ {
+ "accept": null
+ }
+ ],
+ [
+ {
+ "range": [
+ 24000,
+ 25000
+ ]
+ },
+ {
+ "accept": null
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "tcp",
+ {
+ "goto": {
+ "target": "filter_in_tcp"
+ }
+ }
+ ],
+ [
+ "udp",
+ {
+ "goto": {
+ "target": "filter_in_udp"
+ }
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "log": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/merge_vmaps.nft b/tests/shell/testcases/optimizations/dumps/merge_vmaps.nft
new file mode 100644
index 00000000..c981acf0
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/merge_vmaps.nft
@@ -0,0 +1,20 @@
+table ip x {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ }
+
+ chain filter_in_tcp {
+ }
+
+ chain filter_in_udp {
+ }
+
+ chain y {
+ update @s { ip saddr limit rate 12/minute burst 30 packets } accept
+ tcp dport vmap { 80 : accept, 81 : accept, 443 : accept, 8000-8100 : accept, 24000-25000 : accept }
+ meta l4proto vmap { tcp : goto filter_in_tcp, udp : goto filter_in_udp }
+ log
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/not_mergeable.json-nft b/tests/shell/testcases/optimizations/dumps/not_mergeable.json-nft
new file mode 100644
index 00000000..8e64ba1e
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/not_mergeable.json-nft
@@ -0,0 +1,140 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "t1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "t2",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "t3",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "t4",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "jump": {
+ "target": "t1"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "jump": {
+ "target": "t2"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "version"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 4,
+ {
+ "jump": {
+ "target": "t3"
+ }
+ }
+ ],
+ [
+ 6,
+ {
+ "jump": {
+ "target": "t4"
+ }
+ }
+ ]
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/not_mergeable.nft b/tests/shell/testcases/optimizations/dumps/not_mergeable.nft
new file mode 100644
index 00000000..02b89207
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/not_mergeable.nft
@@ -0,0 +1,19 @@
+table ip x {
+ chain t1 {
+ }
+
+ chain t2 {
+ }
+
+ chain t3 {
+ }
+
+ chain t4 {
+ }
+
+ chain y {
+ counter packets 0 bytes 0 jump t1
+ counter packets 0 bytes 0 jump t2
+ ip version vmap { 4 : jump t3, 6 : jump t4 }
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/ruleset.json-nft b/tests/shell/testcases/optimizations/dumps/ruleset.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/ruleset.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/ruleset.nft b/tests/shell/testcases/optimizations/dumps/ruleset.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/ruleset.nft
diff --git a/tests/shell/testcases/optimizations/dumps/single_anon_set.json-nft b/tests/shell/testcases/optimizations/dumps/single_anon_set.json-nft
new file mode 100644
index 00000000..26634134
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/single_anon_set.json-nft
@@ -0,0 +1,360 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "127.0.0.1"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iif"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "!=",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": {
+ "prefix": {
+ "addr": "127.0.0.0",
+ "len": 8
+ }
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": {
+ "range": [
+ "127.0.0.1",
+ "192.168.7.3"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "sport"
+ }
+ },
+ "right": {
+ "range": [
+ 1,
+ 1023
+ ]
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "set": [
+ "192.168.7.1",
+ "192.168.7.5"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 80,
+ 443
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "192.168.0.1",
+ 22
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "192.168.0.1",
+ 1
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": {
+ "set": [
+ "established",
+ "related"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/single_anon_set.nft b/tests/shell/testcases/optimizations/dumps/single_anon_set.nft
new file mode 100644
index 00000000..35e3f36e
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/single_anon_set.nft
@@ -0,0 +1,15 @@
+table ip test {
+ chain test {
+ ip saddr 127.0.0.1 accept
+ iif "lo" accept
+ tcp dport != 22 drop
+ ip saddr 127.0.0.0/8 accept
+ ip saddr 127.0.0.1-192.168.7.3 accept
+ tcp sport 1-1023 drop
+ ip daddr { 192.168.7.1, 192.168.7.5 } accept
+ tcp dport { 80, 443 } accept
+ ip daddr . tcp dport { 192.168.0.1 . 22 } accept
+ meta mark set ip daddr map { 192.168.0.1 : 0x00000001 }
+ ct state { established, related } accept
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/single_anon_set_expr.json-nft b/tests/shell/testcases/optimizations/dumps/single_anon_set_expr.json-nft
new file mode 100644
index 00000000..c8adddb1
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/single_anon_set_expr.json-nft
@@ -0,0 +1,59 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "right": {
+ "set": [
+ {
+ "elem": {
+ "val": 10,
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/single_anon_set_expr.nft b/tests/shell/testcases/optimizations/dumps/single_anon_set_expr.nft
new file mode 100644
index 00000000..54880b92
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/single_anon_set_expr.nft
@@ -0,0 +1,5 @@
+table ip test {
+ chain test {
+ meta mark { 0x0000000a counter packets 0 bytes 0 }
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/skip_merge.json-nft b/tests/shell/testcases/optimizations/dumps/skip_merge.json-nft
new file mode 100644
index 00000000..7bb6c656
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/skip_merge.json-nft
@@ -0,0 +1,235 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "udp_input",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "tcp_input",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "udp_accepted",
+ "table": "filter",
+ "type": "inet_service",
+ "handle": 0,
+ "elem": [
+ 500,
+ 4500
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "tcp_accepted",
+ "table": "filter",
+ "type": "inet_service",
+ "handle": 0,
+ "elem": [
+ 80,
+ 443
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "udp_input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "range": [
+ 1,
+ 128
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "udp_input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": "@udp_accepted"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "udp_input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 53
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "tcp_input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ {
+ "range": [
+ 1,
+ 128
+ ]
+ },
+ {
+ "range": [
+ 8888,
+ 9999
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "tcp_input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": "@tcp_accepted"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "tcp_input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "range": [
+ 1024,
+ 65535
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/skip_merge.nft b/tests/shell/testcases/optimizations/dumps/skip_merge.nft
new file mode 100644
index 00000000..9c10b74b
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/skip_merge.nft
@@ -0,0 +1,23 @@
+table inet filter {
+ set udp_accepted {
+ type inet_service
+ elements = { 500, 4500 }
+ }
+
+ set tcp_accepted {
+ type inet_service
+ elements = { 80, 443 }
+ }
+
+ chain udp_input {
+ udp dport 1-128 accept
+ udp dport @udp_accepted accept
+ udp dport 53 accept
+ }
+
+ chain tcp_input {
+ tcp dport { 1-128, 8888-9999 } accept
+ tcp dport @tcp_accepted accept
+ tcp dport 1024-65535 accept
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/skip_non_eq.json-nft b/tests/shell/testcases/optimizations/dumps/skip_non_eq.json-nft
new file mode 100644
index 00000000..19296d02
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/skip_non_eq.json-nft
@@ -0,0 +1,108 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "op": "!=",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "eth0"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "eth0"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "eth0"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/skip_non_eq.nft b/tests/shell/testcases/optimizations/dumps/skip_non_eq.nft
new file mode 100644
index 00000000..6df38655
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/skip_non_eq.nft
@@ -0,0 +1,6 @@
+table inet x {
+ chain y {
+ iifname "eth0" oifname != "eth0" counter packets 0 bytes 0 accept
+ iifname "eth0" oifname "eth0" counter packets 0 bytes 0 accept
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/skip_unsupported.json-nft b/tests/shell/testcases/optimizations/dumps/skip_unsupported.json-nft
new file mode 100644
index 00000000..d6347b1e
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/skip_unsupported.json-nft
@@ -0,0 +1,256 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "GEOIP_CC_wan-lan_120",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "1.32.128.0",
+ "len": 18
+ }
+ },
+ {
+ "range": [
+ "1.32.200.0",
+ "1.32.204.128"
+ ]
+ },
+ {
+ "prefix": {
+ "addr": "1.32.207.0",
+ "len": 24
+ }
+ },
+ {
+ "range": [
+ "1.32.216.118",
+ "1.32.216.255"
+ ]
+ },
+ {
+ "range": [
+ "1.32.219.0",
+ "1.32.222.255"
+ ]
+ },
+ {
+ "prefix": {
+ "addr": "1.32.226.0",
+ "len": 23
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.32.231.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.32.233.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.32.238.0",
+ "len": 23
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.32.240.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "223.223.220.0",
+ "len": 22
+ }
+ },
+ {
+ "prefix": {
+ "addr": "223.255.254.0",
+ "len": 24
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 80
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": 10
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "1.2.3.4"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 81
+ }
+ },
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": 11
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.2.3.5",
+ 81
+ ]
+ },
+ {
+ "concat": [
+ "1.2.3.5",
+ 82
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/skip_unsupported.nft b/tests/shell/testcases/optimizations/dumps/skip_unsupported.nft
new file mode 100644
index 00000000..f24855e7
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/skip_unsupported.nft
@@ -0,0 +1,18 @@
+table inet x {
+ set GEOIP_CC_wan-lan_120 {
+ type ipv4_addr
+ flags interval
+ elements = { 1.32.128.0/18, 1.32.200.0-1.32.204.128,
+ 1.32.207.0/24, 1.32.216.118-1.32.216.255,
+ 1.32.219.0-1.32.222.255, 1.32.226.0/23,
+ 1.32.231.0/24, 1.32.233.0/24,
+ 1.32.238.0/23, 1.32.240.0/24,
+ 223.223.220.0/22, 223.255.254.0/24 }
+ }
+
+ chain y {
+ ip saddr 1.2.3.4 tcp dport 80 meta mark set 0x0000000a accept
+ ip saddr 1.2.3.4 tcp dport 81 meta mark set 0x0000000b accept
+ ip saddr . tcp dport { 1.2.3.5 . 81, 1.2.3.5 . 82 } accept
+ }
+}
diff --git a/tests/shell/testcases/optimizations/dumps/variables.json-nft b/tests/shell/testcases/optimizations/dumps/variables.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/variables.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optimizations/dumps/variables.nft b/tests/shell/testcases/optimizations/dumps/variables.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/optimizations/dumps/variables.nft
diff --git a/tests/shell/testcases/optimizations/merge_nat b/tests/shell/testcases/optimizations/merge_nat
new file mode 100755
index 00000000..3ffcbd57
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_nat
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip test1 {
+ chain y {
+ oif lo accept
+ ip saddr 4.4.4.4 dnat to 1.1.1.1
+ ip saddr 5.5.5.5 dnat to 2.2.2.2
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
+
+RULESET="table ip test2 {
+ chain y {
+ oif lo accept
+ tcp dport 80 dnat to 1.1.1.1:8001
+ tcp dport 81 dnat to 2.2.2.2:9001
+ ip saddr 10.141.11.0/24 masquerade
+ ip saddr 10.141.13.0/24 masquerade
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
+
+RULESET="table ip test4 {
+ chain y {
+ oif lo accept
+ ip daddr 1.1.1.1 tcp dport 80 dnat to 4.4.4.4:8000
+ ip daddr 2.2.2.2 tcp dport 81 dnat to 3.3.3.3:9000
+ tcp dport 83 redirect to :8083
+ tcp dport 84 redirect to :8084
+ tcp dport 85 redirect
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_nat_concat b/tests/shell/testcases/optimizations/merge_nat_concat
new file mode 100755
index 00000000..2e0a91a3
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_nat_concat
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+
+RULESET="table ip test3 {
+ chain y {
+ oif lo accept
+ ip saddr 1.1.1.1 tcp sport 1024-65535 snat to 3.3.3.3
+ ip saddr 2.2.2.2 tcp sport 1024-65535 snat to 4.4.4.4
+ oifname enp2s0 snat ip to ip saddr map { 10.1.1.0/24 : 72.2.3.66-72.2.3.78 }
+ tcp dport 8888 redirect
+ tcp dport 9999 redirect
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_nat_inet b/tests/shell/testcases/optimizations/merge_nat_inet
new file mode 100755
index 00000000..ff1916d3
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_nat_inet
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_inet_nat)
+
+set -e
+
+RULESET="table inet nat {
+ chain prerouting {
+ oif lo accept
+ iifname enp2s0 ip daddr 72.2.3.66 tcp dport 53122 dnat to 10.1.1.10:22
+ iifname enp2s0 ip daddr 72.2.3.66 tcp dport 443 dnat to 10.1.1.52:443
+ iifname enp2s0 ip daddr 72.2.3.70 tcp dport 80 dnat to 10.1.1.52:80
+ }
+ chain postrouting {
+ oif lo accept
+ ip daddr 72.2.3.66 snat to 10.2.2.2
+ ip daddr 72.2.3.67 snat to 10.2.3.3
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_reject b/tests/shell/testcases/optimizations/merge_reject
new file mode 100755
index 00000000..c0ef9cac
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_reject
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain y {
+ meta l4proto tcp ip daddr 172.30.33.70 tcp dport 3306 counter packets 0 bytes 0 drop
+ meta l4proto tcp ip daddr 172.30.33.71 tcp dport 3306 counter packets 0 bytes 0 reject
+ meta l4proto tcp ip daddr 172.30.238.117 tcp dport 8080 counter packets 0 bytes 0 reject
+ meta l4proto tcp ip daddr 172.30.254.251 tcp dport 3306 counter packets 0 bytes 0 reject
+ meta l4proto tcp ip daddr 172.30.254.252 tcp dport 3306 counter packets 0 bytes 0 reject with tcp reset
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
+
+RULESET="table ip6 x {
+ chain y {
+ meta l4proto tcp ip6 daddr aaaa::2 tcp dport 3306 counter packets 0 bytes 0 reject
+ meta l4proto tcp ip6 daddr aaaa::3 tcp dport 8080 counter packets 0 bytes 0 reject
+ meta l4proto tcp ip6 daddr aaaa::4 tcp dport 3306 counter packets 0 bytes 0 reject
+ meta l4proto tcp ip6 daddr aaaa::5 tcp dport 3306 counter packets 0 bytes 0 reject with tcp reset
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_stmts b/tests/shell/testcases/optimizations/merge_stmts
new file mode 100755
index 00000000..ec7a9dd6
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_stmts
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain y {
+ ip daddr 192.168.0.1 counter accept comment "test1"
+ ip daddr 192.168.0.2 counter accept comment "test2"
+ ip daddr 192.168.0.3 counter accept comment "test3"
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_stmts_concat b/tests/shell/testcases/optimizations/merge_stmts_concat
new file mode 100755
index 00000000..4db4a6f9
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_stmts_concat
@@ -0,0 +1,37 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+
+RULESET="table ip x {
+ chain y {
+ meta iifname eth1 ip saddr 1.1.1.1 ip daddr 2.2.2.3 accept
+ meta iifname eth1 ip saddr 1.1.1.2 ip daddr 2.2.2.4 accept
+ meta iifname eth1 ip saddr 1.1.1.2 ip daddr 2.2.3.0/24 accept
+ meta iifname eth1 ip saddr 1.1.1.2 ip daddr 2.2.4.0-2.2.4.10 accept
+ meta iifname eth2 ip saddr 1.1.1.3 ip daddr 2.2.2.5 accept
+ ip protocol . th dport { tcp . 22, udp . 67 }
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
+
+RULESET="table ip x {
+ chain c1 {
+ udp dport 51820 iifname "foo" accept
+ udp dport { 67, 514 } iifname "bar" accept
+ }
+
+ chain c2 {
+ udp dport { 51820, 100 } iifname "foo" accept
+ udp dport { 67, 514 } iifname "bar" accept
+ }
+
+ chain c3 {
+ udp dport { 51820, 100 } iifname { "foo", "test" } accept
+ udp dport { 67, 514 } iifname "bar" accept
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_stmts_concat_vmap b/tests/shell/testcases/optimizations/merge_stmts_concat_vmap
new file mode 100755
index 00000000..657d0aea
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_stmts_concat_vmap
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain x {
+ meta pkttype broadcast udp dport { 67, 547 } accept
+ meta pkttype multicast udp dport 1900 drop
+ }
+ chain y {
+ ip saddr 1.1.1.1 ip daddr 2.2.2.2 accept
+ ip saddr 4.4.4.4 ip daddr 5.5.5.5 accept
+ ip saddr 2.2.2.2 ip daddr 3.3.3.3 drop
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_stmts_vmap b/tests/shell/testcases/optimizations/merge_stmts_vmap
new file mode 100755
index 00000000..e5357c0f
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_stmts_vmap
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
+set -e
+
+RULESET="table ip x {
+ chain y {
+ ct state invalid drop
+ ct state established,related accept
+ }
+ chain z {
+ tcp dport { 1 } accept
+ tcp dport 2-3 drop
+ tcp dport 4 accept
+ }
+ chain w {
+ ip saddr 1.1.1.1 counter accept
+ ip saddr 1.1.1.2 counter drop
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_vmap_raw b/tests/shell/testcases/optimizations/merge_vmap_raw
new file mode 100755
index 00000000..eb04bec3
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_vmap_raw
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+
+RULESET="table inet x {
+ chain nat_dns_dnstc { meta l4proto udp redirect to :5300 ; drop ; }
+ chain nat_dns_this_5301 { meta l4proto udp redirect to :5301 ; drop ; }
+ chain nat_dns_saturn_5301 { meta nfproto ipv4 meta l4proto udp dnat to 240.0.1.2:5301 ; drop ; }
+ chain nat_dns_saturn_5302 { meta nfproto ipv4 meta l4proto udp dnat to 240.0.1.2:5302 ; drop ; }
+ chain nat_dns_saturn_5303 { meta nfproto ipv4 meta l4proto udp dnat to 240.0.1.2:5303 ; drop ; }
+
+ chain nat_dns_acme {
+ udp length 47-63 @th,160,128 0x0e373135363130333131303735353203 \
+ goto nat_dns_dnstc
+
+ udp length 62-78 @th,160,128 0x0e31393032383939353831343037320e \
+ goto nat_dns_this_5301
+
+ udp length 62-78 @th,160,128 0x0e31363436323733373931323934300e \
+ goto nat_dns_saturn_5301
+
+ udp length 62-78 @th,160,128 0x0e32393535373539353636383732310e \
+ goto nat_dns_saturn_5302
+
+ udp length 62-78 @th,160,128 0x0e38353439353637323038363633390e \
+ goto nat_dns_saturn_5303
+
+ drop
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/merge_vmaps b/tests/shell/testcases/optimizations/merge_vmaps
new file mode 100755
index 00000000..e2e4be15
--- /dev/null
+++ b/tests/shell/testcases/optimizations/merge_vmaps
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ set s {
+ type ipv4_addr
+ flags dynamic
+ }
+ chain filter_in_tcp {
+ }
+ chain filter_in_udp {
+ }
+ chain y {
+ update @s { ip saddr limit rate 12/minute burst 30 packets } accept
+ tcp dport vmap {
+ 80 : accept,
+ 81 : accept,
+ 443 : accept,
+ }
+ tcp dport vmap {
+ 8000-8100 : accept,
+ 24000-25000 : accept,
+ }
+ meta l4proto tcp goto filter_in_tcp
+ meta l4proto udp goto filter_in_udp
+ log
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/not_mergeable b/tests/shell/testcases/optimizations/not_mergeable
new file mode 100755
index 00000000..ddb2f0fd
--- /dev/null
+++ b/tests/shell/testcases/optimizations/not_mergeable
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain t1 {
+ }
+ chain t2 {
+ }
+ chain t3 {
+ }
+ chain t4 {
+ }
+ chain y {
+ counter jump t1
+ counter jump t2
+ ip version 4 jump t3
+ ip version 6 jump t4
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/ruleset b/tests/shell/testcases/optimizations/ruleset
new file mode 100755
index 00000000..2b2d80ff
--- /dev/null
+++ b/tests/shell/testcases/optimizations/ruleset
@@ -0,0 +1,170 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_prerouting_reject)
+
+RULESET="table inet uni {
+ chain gtfo {
+ reject with icmpx type host-unreachable
+ drop
+ }
+
+ chain filter_in_tcp {
+ tcp dport vmap {
+ 80 : accept,
+ 81 : accept,
+ 443 : accept,
+ 931 : accept,
+ 5001 : accept,
+ 5201 : accept,
+ }
+ tcp dport vmap {
+ 6800-6999 : accept,
+ 33434-33499 : accept,
+ }
+
+ drop
+ }
+
+ chain filter_in_udp {
+ udp dport vmap {
+ 53 : accept,
+ 123 : accept,
+ 846 : accept,
+ 849 : accept,
+ 5001 : accept,
+ 5201 : accept,
+ }
+ udp dport vmap {
+ 5300-5399 : accept,
+ 6800-6999 : accept,
+ 33434-33499 : accept,
+ }
+
+ drop
+ }
+
+ chain filter_in {
+ type filter hook input priority 0; policy drop;
+
+ ct state vmap {
+ invalid : drop,
+ established : accept,
+ related : accept,
+ untracked : accept,
+ }
+
+ ct status vmap {
+ dnat : accept,
+ snat : accept,
+ }
+
+ iif lo accept
+
+ meta iifgroup {100-199} accept
+
+ meta l4proto tcp goto filter_in_tcp
+ meta l4proto udp goto filter_in_udp
+
+ icmp type vmap {
+ echo-request : accept,
+ }
+ ip6 nexthdr icmpv6 icmpv6 type vmap {
+ echo-request : accept,
+ }
+ }
+
+ chain filter_fwd_ifgroup {
+ meta iifgroup . oifgroup vmap {
+ 100 . 10 : accept,
+ 100 . 100 : accept,
+ 100 . 101 : accept,
+ 101 . 101 : accept,
+ }
+ goto gtfo
+ }
+
+ chain filter_fwd {
+ type filter hook forward priority 0; policy drop;
+
+ fib daddr type broadcast drop
+
+ ct state vmap {
+ invalid : drop,
+ established : accept,
+ related : accept,
+ untracked : accept,
+ }
+
+ ct status vmap {
+ dnat : accept,
+ snat : accept,
+ }
+
+ meta iifgroup {100-199} goto filter_fwd_ifgroup
+ }
+
+ chain nat_fwd_tun {
+ meta l4proto tcp redirect to :15
+ udp dport 53 redirect to :13
+ goto gtfo
+ }
+
+ chain nat_dns_dnstc { meta l4proto udp redirect to :5300 ; drop ; }
+ chain nat_dns_this_5301 { meta l4proto udp redirect to :5301 ; drop ; }
+ chain nat_dns_moon_5301 { meta nfproto ipv4 meta l4proto udp dnat to 240.0.1.2:5301 ; drop ; }
+ chain nat_dns_moon_5302 { meta nfproto ipv4 meta l4proto udp dnat to 240.0.1.2:5302 ; drop ; }
+ chain nat_dns_moon_5303 { meta nfproto ipv4 meta l4proto udp dnat to 240.0.1.2:5303 ; drop ; }
+
+ chain nat_dns_acme {
+ udp length 47-63 @th,160,128 0x0e373135363130333131303735353203 \
+ goto nat_dns_dnstc
+
+ udp length 62-78 @th,160,128 0x0e31393032383939353831343037320e \
+ goto nat_dns_this_5301
+
+ udp length 62-78 @th,160,128 0x0e31363436323733373931323934300e \
+ goto nat_dns_moon_5301
+
+ udp length 62-78 @th,160,128 0x0e32393535373539353636383732310e \
+ goto nat_dns_moon_5302
+
+ udp length 62-78 @th,160,128 0x0e38353439353637323038363633390e \
+ goto nat_dns_moon_5303
+
+ drop
+ }
+
+ chain nat_prerouting {
+ type nat hook prerouting priority -100; policy accept;
+
+ iifgroup 10 udp dport 53 goto nat_dns_acme
+ iifgroup 10 accept
+
+ ip daddr 198.19.0.0/16 goto nat_fwd_tun
+ ip6 daddr fc00::/8 goto nat_fwd_tun
+
+ tcp dport 53 redirect to :25302
+ udp dport 53 redirect to :25302
+ }
+
+ chain nat_output {
+ type nat hook output priority -100; policy accept;
+
+ ip daddr 198.19.0.0/16 goto nat_fwd_tun
+ ip6 daddr fc00::/8 goto nat_fwd_tun
+ }
+
+ chain nat_postrouting {
+ type nat hook postrouting priority 100; policy accept;
+
+ oif != lo masquerade
+ }
+
+ chain mangle_forward {
+ type filter hook forward priority -150; policy accept;
+
+ tcp flags & (syn | rst) == syn tcp option maxseg size set rt mtu
+ }
+}"
+
+$NFT -o -c -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/single_anon_set b/tests/shell/testcases/optimizations/single_anon_set
new file mode 100755
index 00000000..632e965f
--- /dev/null
+++ b/tests/shell/testcases/optimizations/single_anon_set
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+set -e
+
+test -d "$NFT_TEST_TESTTMPDIR"
+
+# Input file contains rules with anon sets that contain
+# one element, plus extra rule with two elements (that should be
+# left alone).
+
+# Dump file has the simplified rules where anon sets have been
+# replaced by equality tests where possible.
+file_input1="$NFT_TEST_TESTTMPDIR/input1.nft"
+
+cat <<EOF > "$file_input1"
+table ip test {
+ chain test {
+ # Test cases where anon set can be removed:
+ ip saddr { 127.0.0.1 } accept
+ iif { "lo" } accept
+
+ # negation, can change to != 22.
+ tcp dport != { 22 } drop
+
+ # single prefix, can remove anon set.
+ ip saddr { 127.0.0.0/8 } accept
+
+ # range, can remove anon set.
+ ip saddr { 127.0.0.1-192.168.7.3 } accept
+ tcp sport { 1-1023 } drop
+
+ # Test cases where anon set must be kept.
+
+ # 2 elements, cannot remove the anon set.
+ ip daddr { 192.168.7.1, 192.168.7.5 } accept
+ tcp dport { 80, 443 } accept
+
+ # single element, but concatenation which is not
+ # supported outside of set/map context at this time.
+ ip daddr . tcp dport { 192.168.0.1 . 22 } accept
+
+ # single element, but a map.
+ meta mark set ip daddr map { 192.168.0.1 : 1 }
+
+ # 2 elements. This could be converted because
+ # ct state cannot be both established and related
+ # at the same time, but this needs extra work.
+ ct state { established, related } accept
+ }
+}
+EOF
+
+$NFT -f "$file_input1"
diff --git a/tests/shell/testcases/optimizations/single_anon_set_expr b/tests/shell/testcases/optimizations/single_anon_set_expr
new file mode 100755
index 00000000..81b7ceba
--- /dev/null
+++ b/tests/shell/testcases/optimizations/single_anon_set_expr
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
+set -e
+
+test -d "$NFT_TEST_TESTTMPDIR"
+
+# Input file contains rules with anon sets that contain
+# one element, plus extra rule with two elements (that should be
+# left alone).
+
+# Dump file has the simplified rules where anon sets have been
+# replaced by equality tests where possible.
+file_input1="$NFT_TEST_TESTTMPDIR/input1.nft"
+
+cat <<EOF > "$file_input1"
+table ip test {
+ chain test {
+ # with stateful statement
+ meta mark { 0x0000000a counter }
+ }
+}
+EOF
+
+$NFT -f "$file_input1"
diff --git a/tests/shell/testcases/optimizations/skip_merge b/tests/shell/testcases/optimizations/skip_merge
new file mode 100755
index 00000000..8af976ca
--- /dev/null
+++ b/tests/shell/testcases/optimizations/skip_merge
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table inet filter {
+ set udp_accepted {
+ type inet_service;
+ elements = {
+ isakmp, ipsec-nat-t
+ }
+ }
+
+ set tcp_accepted {
+ type inet_service;
+ elements = {
+ http, https
+ }
+ }
+
+ chain udp_input {
+ udp dport 1-128 accept
+ udp dport @udp_accepted accept
+ udp dport domain accept
+ }
+
+ chain tcp_input {
+ tcp dport 1-128 accept
+ tcp dport 8888-9999 accept
+ tcp dport @tcp_accepted accept
+ tcp dport 1024-65535 accept
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/skip_non_eq b/tests/shell/testcases/optimizations/skip_non_eq
new file mode 100755
index 00000000..431ed0ad
--- /dev/null
+++ b/tests/shell/testcases/optimizations/skip_non_eq
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table inet x {
+ chain y {
+ iifname "eth0" oifname != "eth0" counter packets 0 bytes 0 accept
+ iifname "eth0" oifname "eth0" counter packets 0 bytes 0 accept
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/skip_unsupported b/tests/shell/testcases/optimizations/skip_unsupported
new file mode 100755
index 00000000..6baa8280
--- /dev/null
+++ b/tests/shell/testcases/optimizations/skip_unsupported
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table inet x {
+ set GEOIP_CC_wan-lan_120 {
+ type ipv4_addr
+ flags interval
+ elements = { 1.32.128.0/18, 1.32.200.0-1.32.204.128,
+ 1.32.207.0/24, 1.32.216.118-1.32.216.255,
+ 1.32.219.0-1.32.222.255, 1.32.226.0/23,
+ 1.32.231.0/24, 1.32.233.0/24,
+ 1.32.238.0/23, 1.32.240.0/24,
+ 223.223.220.0/22, 223.255.254.0/24 }
+ }
+
+ chain y {
+ ip saddr 1.2.3.4 tcp dport 80 meta mark set 10 accept
+ ip saddr 1.2.3.4 tcp dport 81 meta mark set 11 accept
+ ip saddr 1.2.3.5 tcp dport 81 accept comment \"test\"
+ ip saddr 1.2.3.5 tcp dport 82 accept
+ }
+}"
+
+$NFT -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optimizations/variables b/tests/shell/testcases/optimizations/variables
new file mode 100755
index 00000000..fa986065
--- /dev/null
+++ b/tests/shell/testcases/optimizations/variables
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+set -e
+
+RULESET="define addrv4_vpnnet = 10.1.0.0/16
+
+table ip nat {
+ chain postrouting {
+ type nat hook postrouting priority 0; policy accept;
+
+ ip saddr \$addrv4_vpnnet counter masquerade fully-random comment \"masquerade ipv4\"
+ }
+}"
+
+$NFT -c -o -f - <<< $RULESET
diff --git a/tests/shell/testcases/optionals/comments_0 b/tests/shell/testcases/optionals/comments_0
index 29b85062..ab859365 100755
--- a/tests/shell/testcases/optionals/comments_0
+++ b/tests/shell/testcases/optionals/comments_0
@@ -5,4 +5,4 @@
$NFT add table test
$NFT add chain test test
$NFT add rule test test tcp dport 22 counter accept comment test_comment
-$NFT list table test -a | grep 'accept comment \"test_comment\"' >/dev/null
+$NFT -a list table test | grep 'accept comment \"test_comment\"' >/dev/null
diff --git a/tests/shell/testcases/optionals/comments_chain_0 b/tests/shell/testcases/optionals/comments_chain_0
new file mode 100755
index 00000000..1a84cfa6
--- /dev/null
+++ b/tests/shell/testcases/optionals/comments_chain_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_comment)
+
+EXPECTED='table ip test_table {
+ chain test_chain {
+ comment "test"
+ }
+}
+'
+
+set -e
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/optionals/comments_handles_0 b/tests/shell/testcases/optionals/comments_handles_0
index 30539bf0..a01df1df 100755
--- a/tests/shell/testcases/optionals/comments_handles_0
+++ b/tests/shell/testcases/optionals/comments_handles_0
@@ -6,5 +6,5 @@ $NFT add table test
$NFT add chain test test
$NFT add rule test test tcp dport 22 counter accept comment test_comment
set -e
-$NFT list table test -a | grep 'accept comment \"test_comment\" # handle '[[:digit:]]$ >/dev/null
+$NFT -a list table test | grep 'accept comment \"test_comment\" # handle '[[:digit:]]$ >/dev/null
$NFT list table test | grep 'accept comment \"test_comment\"' | grep -v '# handle '[[:digit:]]$ >/dev/null
diff --git a/tests/shell/testcases/optionals/comments_objects_0 b/tests/shell/testcases/optionals/comments_objects_0
new file mode 100755
index 00000000..28041ebd
--- /dev/null
+++ b/tests/shell/testcases/optionals/comments_objects_0
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_comment)
+
+set -e
+
+COMMENT128="12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678"
+
+# test for pass with comment that is 128 bytes long.
+rc=0
+$NFT add table ip filter \{ quota foo1 \{ comment "\"${COMMENT128}\"" \}\; \}\; || rc="$?"
+test "$rc" = 0
+
+# test for failure with comment that is 128+1 bytes long.
+rc=0
+$NFT add table ip filter \{ quota foo2 \{ comment "\"${COMMENT128}x\"" \}\; \}\; || rc="$?"
+test "$rc" = 1
+
+RULESET='table ip filter {
+ quota q {
+ over 1200 bytes
+ comment "'"$COMMENT128"'"
+ }
+
+ counter c {
+ packets 0 bytes 0
+ comment "test2"
+ }
+
+ ct helper h {
+ type "sip" protocol tcp
+ l3proto ip
+ comment "test3"
+ }
+
+ ct expectation e {
+ protocol tcp
+ dport 666
+ timeout 100ms
+ size 96
+ l3proto ip
+ comment "test4"
+ }
+
+ limit l {
+ rate 400/hour
+ comment "test5"
+ }
+
+ synproxy s {
+ mss 1460
+ wscale 2
+ comment "test6"
+ }
+}
+'
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/optionals/comments_objects_dup_0 b/tests/shell/testcases/optionals/comments_objects_dup_0
new file mode 100755
index 00000000..79d975a2
--- /dev/null
+++ b/tests/shell/testcases/optionals/comments_objects_dup_0
@@ -0,0 +1,97 @@
+#!/bin/bash
+
+EXPECTED='table ip filter {
+ quota q {
+ over 1200 bytes
+ comment "test1"
+ comment "test1"
+ }
+}
+'
+
+$NFT -f - <<< "$EXPECTED"
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+EXPECTED='table ip filter {
+ counter c {
+ packets 0 bytes 0
+ comment "test2"
+ comment "test2"
+ }
+}
+'
+
+$NFT -f - <<< "$EXPECTED"
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+EXPECTED='table ip filter {
+ ct helper h {
+ type "sip" protocol tcp
+ l3proto ip
+ comment "test3"
+ comment "test3"
+ }
+}
+'
+
+$NFT -f - <<< "$EXPECTED"
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+EXPECTED='table ip filter {
+ ct expectation e {
+ protocol tcp
+ dport 666
+ timeout 100ms
+ size 96
+ l3proto ip
+ comment "test4"
+ comment "test4"
+ }
+}
+'
+
+$NFT -f - <<< "$EXPECTED"
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+EXPECTED='table ip filter {
+ limit l {
+ rate 400/hour
+ comment "test5"
+ comment "test5"
+ }
+}
+'
+
+$NFT -f - <<< "$EXPECTED"
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+EXPECTED='table ip filter {
+ synproxy s {
+ mss 1460
+ wscale 2
+ comment "test6"
+ comment "test6"
+ }
+}
+'
+
+$NFT -f - <<< "$EXPECTED"
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
diff --git a/tests/shell/testcases/optionals/comments_table_0 b/tests/shell/testcases/optionals/comments_table_0
new file mode 100755
index 00000000..56bb206b
--- /dev/null
+++ b/tests/shell/testcases/optionals/comments_table_0
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_comment)
+
+# comments are shown
+
+$NFT add table test { comment \"test_comment\"\; }
diff --git a/tests/shell/testcases/optionals/delete_object_handles_0 b/tests/shell/testcases/optionals/delete_object_handles_0
index d5d96547..9b65e677 100755
--- a/tests/shell/testcases/optionals/delete_object_handles_0
+++ b/tests/shell/testcases/optionals/delete_object_handles_0
@@ -10,8 +10,8 @@ $NFT add quota ip6 test-ip6 http-quota over 25 mbytes
$NFT add counter ip6 test-ip6 http-traffic
$NFT add quota ip6 test-ip6 ssh-quota 10 mbytes
-counter_handle=$($NFT list ruleset -a | awk '/https-traffic/{print $NF}')
-quota_handle=$($NFT list ruleset -a | awk '/ssh-quota/{print $NF}')
+counter_handle=$($NFT -a list ruleset | awk '/https-traffic/{print $NF}')
+quota_handle=$($NFT -a list ruleset | awk '/ssh-quota/{print $NF}')
$NFT delete counter test-ip handle $counter_handle
$NFT delete quota ip6 test-ip6 handle $quota_handle
@@ -37,7 +37,6 @@ table ip6 test-ip6 {
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/optionals/dumps/comments_0.json-nft b/tests/shell/testcases/optionals/dumps/comments_0.json-nft
new file mode 100644
index 00000000..aef4b3e4
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_0.json-nft
@@ -0,0 +1,58 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "comment": "test_comment",
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optionals/dumps/comments_chain_0.json-nft b/tests/shell/testcases/optionals/dumps/comments_chain_0.json-nft
new file mode 100644
index 00000000..4c752e80
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_chain_0.json-nft
@@ -0,0 +1,27 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test_table",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test_table",
+ "name": "test_chain",
+ "handle": 0,
+ "comment": "test"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optionals/dumps/comments_chain_0.nft b/tests/shell/testcases/optionals/dumps/comments_chain_0.nft
new file mode 100644
index 00000000..be3d8f33
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_chain_0.nft
@@ -0,0 +1,5 @@
+table ip test_table {
+ chain test_chain {
+ comment "test"
+ }
+}
diff --git a/tests/shell/testcases/optionals/dumps/comments_handles_0.json-nft b/tests/shell/testcases/optionals/dumps/comments_handles_0.json-nft
new file mode 100644
index 00000000..aef4b3e4
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_handles_0.json-nft
@@ -0,0 +1,58 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "comment": "test_comment",
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optionals/dumps/comments_objects_0.json-nft b/tests/shell/testcases/optionals/dumps/comments_objects_0.json-nft
new file mode 100644
index 00000000..b5359d8b
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_objects_0.json-nft
@@ -0,0 +1,102 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "quota": {
+ "family": "ip",
+ "name": "foo1",
+ "table": "filter",
+ "handle": 0,
+ "comment": "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678",
+ "bytes": 0,
+ "used": 0,
+ "inv": false
+ }
+ },
+ {
+ "quota": {
+ "family": "ip",
+ "name": "q",
+ "table": "filter",
+ "handle": 0,
+ "comment": "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678",
+ "bytes": 1200,
+ "used": 0,
+ "inv": true
+ }
+ },
+ {
+ "counter": {
+ "family": "ip",
+ "name": "c",
+ "table": "filter",
+ "handle": 0,
+ "comment": "test2",
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "ct helper": {
+ "family": "ip",
+ "name": "h",
+ "table": "filter",
+ "handle": 0,
+ "comment": "test3",
+ "type": "sip",
+ "protocol": "tcp",
+ "l3proto": "ip"
+ }
+ },
+ {
+ "ct expectation": {
+ "family": "ip",
+ "name": "e",
+ "table": "filter",
+ "handle": 0,
+ "comment": "test4",
+ "protocol": "tcp",
+ "dport": 666,
+ "timeout": 100,
+ "size": 96,
+ "l3proto": "ip"
+ }
+ },
+ {
+ "limit": {
+ "family": "ip",
+ "name": "l",
+ "table": "filter",
+ "handle": 0,
+ "comment": "test5",
+ "rate": 400,
+ "per": "hour",
+ "burst": 5
+ }
+ },
+ {
+ "synproxy": {
+ "family": "ip",
+ "name": "s",
+ "table": "filter",
+ "handle": 0,
+ "comment": "test6",
+ "mss": 1460,
+ "wscale": 2
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optionals/dumps/comments_objects_0.nft b/tests/shell/testcases/optionals/dumps/comments_objects_0.nft
new file mode 100644
index 00000000..13822209
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_objects_0.nft
@@ -0,0 +1,42 @@
+table ip filter {
+ quota foo1 {
+ comment "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678"
+ 0 bytes
+ }
+
+ quota q {
+ comment "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678"
+ over 1200 bytes
+ }
+
+ counter c {
+ comment "test2"
+ packets 0 bytes 0
+ }
+
+ ct helper h {
+ comment "test3"
+ type "sip" protocol tcp
+ l3proto ip
+ }
+
+ ct expectation e {
+ comment "test4"
+ protocol tcp
+ dport 666
+ timeout 100ms
+ size 96
+ l3proto ip
+ }
+
+ limit l {
+ comment "test5"
+ rate 400/hour
+ }
+
+ synproxy s {
+ comment "test6"
+ mss 1460
+ wscale 2
+ }
+}
diff --git a/tests/shell/testcases/optionals/dumps/comments_objects_dup_0.json-nft b/tests/shell/testcases/optionals/dumps/comments_objects_dup_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_objects_dup_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optionals/dumps/comments_objects_dup_0.nft b/tests/shell/testcases/optionals/dumps/comments_objects_dup_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_objects_dup_0.nft
diff --git a/tests/shell/testcases/optionals/dumps/comments_table_0.json-nft b/tests/shell/testcases/optionals/dumps/comments_table_0.json-nft
new file mode 100644
index 00000000..8512c7de
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_table_0.json-nft
@@ -0,0 +1,19 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0,
+ "comment": "test_comment"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optionals/dumps/comments_table_0.nft b/tests/shell/testcases/optionals/dumps/comments_table_0.nft
new file mode 100644
index 00000000..32ae3c2d
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/comments_table_0.nft
@@ -0,0 +1,3 @@
+table ip test {
+ comment "test_comment"
+}
diff --git a/tests/shell/testcases/optionals/dumps/delete_object_handles_0.json-nft b/tests/shell/testcases/optionals/dumps/delete_object_handles_0.json-nft
new file mode 100644
index 00000000..583ce528
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/delete_object_handles_0.json-nft
@@ -0,0 +1,67 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test-ip",
+ "handle": 0
+ }
+ },
+ {
+ "quota": {
+ "family": "ip",
+ "name": "https-quota",
+ "table": "test-ip",
+ "handle": 0,
+ "bytes": 26214400,
+ "used": 0,
+ "inv": false
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "ports",
+ "table": "test-ip",
+ "type": "inet_service",
+ "handle": 0,
+ "map": "quota"
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "test-ip6",
+ "handle": 0
+ }
+ },
+ {
+ "quota": {
+ "family": "ip6",
+ "name": "http-quota",
+ "table": "test-ip6",
+ "handle": 0,
+ "bytes": 26214400,
+ "used": 0,
+ "inv": true
+ }
+ },
+ {
+ "counter": {
+ "family": "ip6",
+ "name": "http-traffic",
+ "table": "test-ip6",
+ "handle": 0,
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optionals/dumps/delete_object_handles_0.nft b/tests/shell/testcases/optionals/dumps/delete_object_handles_0.nft
new file mode 100644
index 00000000..aac03cc5
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/delete_object_handles_0.nft
@@ -0,0 +1,18 @@
+table ip test-ip {
+ quota https-quota {
+ 25 mbytes
+ }
+
+ map ports {
+ type inet_service : quota
+ }
+}
+table ip6 test-ip6 {
+ quota http-quota {
+ over 25 mbytes
+ }
+
+ counter http-traffic {
+ packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/optionals/dumps/handles_0.json-nft b/tests/shell/testcases/optionals/dumps/handles_0.json-nft
new file mode 100644
index 00000000..ff06af30
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/handles_0.json-nft
@@ -0,0 +1,57 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optionals/dumps/handles_1.json-nft b/tests/shell/testcases/optionals/dumps/handles_1.json-nft
new file mode 100644
index 00000000..ff06af30
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/handles_1.json-nft
@@ -0,0 +1,57 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optionals/dumps/handles_1.nft b/tests/shell/testcases/optionals/dumps/handles_1.nft
new file mode 100644
index 00000000..085c6cf1
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/handles_1.nft
@@ -0,0 +1,5 @@
+table ip test {
+ chain test {
+ tcp dport 22 counter packets 0 bytes 0 accept
+ }
+}
diff --git a/tests/shell/testcases/optionals/dumps/log_prefix_0.json-nft b/tests/shell/testcases/optionals/dumps/log_prefix_0.json-nft
new file mode 100644
index 00000000..161a58d4
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/log_prefix_0.json-nft
@@ -0,0 +1,52 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "invalid"
+ }
+ },
+ {
+ "log": {
+ "prefix": "invalid state match, logging:"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optionals/dumps/log_prefix_0.nft b/tests/shell/testcases/optionals/dumps/log_prefix_0.nft
new file mode 100644
index 00000000..8c11d697
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/log_prefix_0.nft
@@ -0,0 +1,5 @@
+table ip x {
+ chain y {
+ ct state invalid log prefix "invalid state match, logging:"
+ }
+}
diff --git a/tests/shell/testcases/optionals/dumps/update_object_handles_0.json-nft b/tests/shell/testcases/optionals/dumps/update_object_handles_0.json-nft
new file mode 100644
index 00000000..ba78f8d7
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/update_object_handles_0.json-nft
@@ -0,0 +1,39 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test-ip",
+ "handle": 0
+ }
+ },
+ {
+ "counter": {
+ "family": "ip",
+ "name": "traffic-counter",
+ "table": "test-ip",
+ "handle": 0,
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "quota": {
+ "family": "ip",
+ "name": "traffic-quota",
+ "table": "test-ip",
+ "handle": 0,
+ "bytes": 52428800,
+ "used": 0,
+ "inv": false
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/optionals/dumps/update_object_handles_0.nft b/tests/shell/testcases/optionals/dumps/update_object_handles_0.nft
new file mode 100644
index 00000000..f391b631
--- /dev/null
+++ b/tests/shell/testcases/optionals/dumps/update_object_handles_0.nft
@@ -0,0 +1,9 @@
+table ip test-ip {
+ counter traffic-counter {
+ packets 0 bytes 0
+ }
+
+ quota traffic-quota {
+ 50 mbytes
+ }
+}
diff --git a/tests/shell/testcases/optionals/handles_0 b/tests/shell/testcases/optionals/handles_0
index 7c6a437c..80f3c5b2 100755
--- a/tests/shell/testcases/optionals/handles_0
+++ b/tests/shell/testcases/optionals/handles_0
@@ -5,4 +5,4 @@
$NFT add table test
$NFT add chain test test
$NFT add rule test test tcp dport 22 counter accept
-$NFT list table test -a | grep 'accept # handle '[[:digit:]]$ >/dev/null
+$NFT -a list table test | grep 'accept # handle '[[:digit:]]$ >/dev/null
diff --git a/tests/shell/testcases/optionals/log_prefix_0 b/tests/shell/testcases/optionals/log_prefix_0
new file mode 100755
index 00000000..513a9e74
--- /dev/null
+++ b/tests/shell/testcases/optionals/log_prefix_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+TMP=$(mktemp)
+
+RULESET='define test = "state"
+define foo = "match, logging"
+
+table x {
+ chain y {
+ ct state invalid log prefix "invalid $test $foo:"
+ }
+}'
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/optionals/update_object_handles_0 b/tests/shell/testcases/optionals/update_object_handles_0
new file mode 100755
index 00000000..ccd96779
--- /dev/null
+++ b/tests/shell/testcases/optionals/update_object_handles_0
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_stateful_object_update)
+
+set -e
+$NFT add table test-ip
+$NFT add counter test-ip traffic-counter
+$NFT add counter test-ip traffic-counter
+$NFT add quota test-ip traffic-quota 25 mbytes
+$NFT add quota test-ip traffic-quota 50 mbytes
+
+EXPECTED="table ip test-ip {
+ counter traffic-counter {
+ packets 0 bytes 0
+ }
+
+ quota traffic-quota {
+ 50 mbytes
+ }
+}"
+
+GET="$($NFT list ruleset)"
+if [ "$EXPECTED" != "$GET" ] ; then
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ exit 1
+fi
diff --git a/tests/shell/testcases/owner/0001-flowtable-uaf b/tests/shell/testcases/owner/0001-flowtable-uaf
new file mode 100755
index 00000000..c07e8d6a
--- /dev/null
+++ b/tests/shell/testcases/owner/0001-flowtable-uaf
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_table_flag_owner)
+
+set -e
+
+$NFT -f - <<EOF
+table t {
+ flags owner
+ flowtable f {
+ hook ingress priority 0
+ devices = { lo }
+ }
+}
+EOF
+
+# trigger uaf.
+$NFT -f - <<EOF
+table t {
+ flags owner
+ flowtable f {
+ hook ingress priority 0
+ devices = { lo }
+ }
+}
+EOF
diff --git a/tests/shell/testcases/owner/dumps/0001-flowtable-uaf.json-nft b/tests/shell/testcases/owner/dumps/0001-flowtable-uaf.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/owner/dumps/0001-flowtable-uaf.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/owner/dumps/0001-flowtable-uaf.nft b/tests/shell/testcases/owner/dumps/0001-flowtable-uaf.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/owner/dumps/0001-flowtable-uaf.nft
diff --git a/tests/shell/testcases/owner/dumps/0002-persist.json-nft b/tests/shell/testcases/owner/dumps/0002-persist.json-nft
new file mode 100644
index 00000000..f0c336a8
--- /dev/null
+++ b/tests/shell/testcases/owner/dumps/0002-persist.json-nft
@@ -0,0 +1,19 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0,
+ "flags": "persist"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/owner/dumps/0002-persist.nft b/tests/shell/testcases/owner/dumps/0002-persist.nft
new file mode 100644
index 00000000..b47027d3
--- /dev/null
+++ b/tests/shell/testcases/owner/dumps/0002-persist.nft
@@ -0,0 +1,3 @@
+table ip t {
+ flags persist
+}
diff --git a/tests/shell/testcases/packetpath/dumps/payload.nodump b/tests/shell/testcases/packetpath/dumps/payload.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/packetpath/dumps/payload.nodump
diff --git a/tests/shell/testcases/packetpath/dumps/set_lookups.json-nft b/tests/shell/testcases/packetpath/dumps/set_lookups.json-nft
new file mode 100644
index 00000000..24363f90
--- /dev/null
+++ b/tests/shell/testcases/packetpath/dumps/set_lookups.json-nft
@@ -0,0 +1,674 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": [
+ "ipv4_addr",
+ "iface_index"
+ ],
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "concat": [
+ "127.0.0.1",
+ "lo"
+ ]
+ },
+ {
+ "concat": [
+ "127.0.0.2",
+ "lo"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s2",
+ "table": "t",
+ "type": [
+ "ipv4_addr",
+ "iface_index"
+ ],
+ "handle": 0,
+ "elem": [
+ {
+ "concat": [
+ "127.0.0.1",
+ "lo"
+ ]
+ },
+ {
+ "concat": [
+ "127.0.0.2",
+ "lo"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s3",
+ "table": "t",
+ "type": "iface_index",
+ "handle": 0,
+ "elem": [
+ "lo"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s4",
+ "table": "t",
+ "type": "iface_index",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ "lo"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "nomatch",
+ "table": "t",
+ "type": [
+ "ipv4_addr",
+ "iface_index"
+ ],
+ "handle": 0,
+ "elem": [
+ {
+ "concat": [
+ "127.0.0.3",
+ "lo"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "nomatch2",
+ "table": "t",
+ "type": [
+ "ipv4_addr",
+ "iface_index"
+ ],
+ "handle": 0,
+ "elem": [
+ {
+ "concat": [
+ "127.0.0.2",
+ "90000"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "type"
+ }
+ },
+ "right": "echo-request"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "iif"
+ }
+ }
+ ]
+ },
+ "right": "@s"
+ }
+ },
+ {
+ "counter": {
+ "packets": 1,
+ "bytes": 84
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "type"
+ }
+ },
+ "right": "echo-request"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "lo"
+ ]
+ },
+ "right": "@s"
+ }
+ },
+ {
+ "counter": {
+ "packets": 1,
+ "bytes": 84
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "type"
+ }
+ },
+ "right": "echo-request"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "lo"
+ ]
+ },
+ "right": "@s"
+ }
+ },
+ {
+ "counter": {
+ "packets": 1,
+ "bytes": 84
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "type"
+ }
+ },
+ "right": "echo-request"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "iif"
+ }
+ }
+ ]
+ },
+ "right": "@s2"
+ }
+ },
+ {
+ "counter": {
+ "packets": 1,
+ "bytes": 84
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "type"
+ }
+ },
+ "right": "echo-request"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "lo"
+ ]
+ },
+ "right": "@s2"
+ }
+ },
+ {
+ "counter": {
+ "packets": 1,
+ "bytes": 84
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "type"
+ }
+ },
+ "right": "echo-request"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "lo"
+ ]
+ },
+ "right": "@s2"
+ }
+ },
+ {
+ "counter": {
+ "packets": 1,
+ "bytes": 84
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "type"
+ }
+ },
+ "right": "echo-request"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "lo"
+ ]
+ },
+ "right": "@s"
+ }
+ },
+ {
+ "counter": {
+ "packets": 1,
+ "bytes": 84
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "type"
+ }
+ },
+ "right": "echo-request"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "lo"
+ ]
+ },
+ "right": "@s2"
+ }
+ },
+ {
+ "counter": {
+ "packets": 1,
+ "bytes": 84
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "type"
+ }
+ },
+ "right": "echo-request"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iif"
+ }
+ },
+ "right": "@s3"
+ }
+ },
+ {
+ "counter": {
+ "packets": 1,
+ "bytes": 84
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "type"
+ }
+ },
+ "right": "echo-request"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iif"
+ }
+ },
+ "right": "@s4"
+ }
+ },
+ {
+ "counter": {
+ "packets": 1,
+ "bytes": 84
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "lo"
+ ]
+ },
+ "right": "@nomatch"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "iif"
+ }
+ }
+ ]
+ },
+ "right": "@nomatch2"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/packetpath/dumps/set_lookups.nft b/tests/shell/testcases/packetpath/dumps/set_lookups.nft
new file mode 100644
index 00000000..7566f557
--- /dev/null
+++ b/tests/shell/testcases/packetpath/dumps/set_lookups.nft
@@ -0,0 +1,51 @@
+table ip t {
+ set s {
+ type ipv4_addr . iface_index
+ flags interval
+ elements = { 127.0.0.1 . "lo",
+ 127.0.0.2 . "lo" }
+ }
+
+ set s2 {
+ typeof ip saddr . iif
+ elements = { 127.0.0.1 . "lo",
+ 127.0.0.2 . "lo" }
+ }
+
+ set s3 {
+ type iface_index
+ elements = { "lo" }
+ }
+
+ set s4 {
+ type iface_index
+ flags interval
+ elements = { "lo" }
+ }
+
+ set nomatch {
+ typeof ip saddr . iif
+ elements = { 127.0.0.3 . "lo" }
+ }
+
+ set nomatch2 {
+ type ipv4_addr . iface_index
+ elements = { 127.0.0.2 . 90000 }
+ }
+
+ chain c {
+ type filter hook input priority filter; policy accept;
+ icmp type echo-request ip saddr . iif @s counter packets 1 bytes 84
+ icmp type echo-request ip saddr . "lo" @s counter packets 1 bytes 84
+ icmp type echo-request ip saddr . "lo" @s counter packets 1 bytes 84
+ icmp type echo-request ip saddr . iif @s2 counter packets 1 bytes 84
+ icmp type echo-request ip saddr . "lo" @s2 counter packets 1 bytes 84
+ icmp type echo-request ip saddr . "lo" @s2 counter packets 1 bytes 84
+ icmp type echo-request ip daddr . "lo" @s counter packets 1 bytes 84
+ icmp type echo-request ip daddr . "lo" @s2 counter packets 1 bytes 84
+ icmp type echo-request iif @s3 counter packets 1 bytes 84
+ icmp type echo-request iif @s4 counter packets 1 bytes 84
+ ip daddr . "lo" @nomatch counter packets 0 bytes 0 drop
+ ip daddr . iif @nomatch2 counter packets 0 bytes 0 drop
+ }
+}
diff --git a/tests/shell/testcases/packetpath/dumps/tcp_options.nodump b/tests/shell/testcases/packetpath/dumps/tcp_options.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/packetpath/dumps/tcp_options.nodump
diff --git a/tests/shell/testcases/packetpath/dumps/vlan_8021ad_tag.nodump b/tests/shell/testcases/packetpath/dumps/vlan_8021ad_tag.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/packetpath/dumps/vlan_8021ad_tag.nodump
diff --git a/tests/shell/testcases/packetpath/flowtables b/tests/shell/testcases/packetpath/flowtables
new file mode 100755
index 00000000..ec7dfeb7
--- /dev/null
+++ b/tests/shell/testcases/packetpath/flowtables
@@ -0,0 +1,96 @@
+#! /bin/bash -x
+
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+
+rnd=$(mktemp -u XXXXXXXX)
+R="flowtable-router-$rnd"
+C="flowtable-client-$rnd"
+S="flowtbale-server-$rnd"
+
+cleanup()
+{
+ for i in $R $C $S;do
+ kill $(ip netns pid $i) 2>/dev/null
+ ip netns del $i
+ done
+}
+
+trap cleanup EXIT
+
+ip netns add $R
+ip netns add $S
+ip netns add $C
+
+ip link add s_r netns $S type veth peer name r_s netns $R
+ip netns exec $S ip link set s_r up
+ip netns exec $R ip link set r_s up
+ip link add c_r netns $C type veth peer name r_c netns $R
+ip netns exec $R ip link set r_c up
+ip netns exec $C ip link set c_r up
+
+ip netns exec $S ip -6 addr add 2001:db8:ffff:22::1/64 dev s_r
+ip netns exec $C ip -6 addr add 2001:db8:ffff:21::2/64 dev c_r
+ip netns exec $R ip -6 addr add 2001:db8:ffff:22::fffe/64 dev r_s
+ip netns exec $R ip -6 addr add 2001:db8:ffff:21::fffe/64 dev r_c
+ip netns exec $R sysctl -w net.ipv6.conf.all.forwarding=1
+ip netns exec $C ip route add 2001:db8:ffff:22::/64 via 2001:db8:ffff:21::fffe dev c_r
+ip netns exec $S ip route add 2001:db8:ffff:21::/64 via 2001:db8:ffff:22::fffe dev s_r
+ip netns exec $S ethtool -K s_r tso off
+ip netns exec $C ethtool -K c_r tso off
+
+sleep 3
+ip netns exec $C ping -6 2001:db8:ffff:22::1 -c1 || exit 1
+
+ip netns exec $R nft -f - <<EOF
+table ip6 filter {
+ flowtable f1 {
+ hook ingress priority -100
+ devices = { r_c, r_s }
+ }
+
+ chain forward {
+ type filter hook forward priority filter; policy accept;
+ ip6 nexthdr tcp ct state established,related counter packets 0 bytes 0 flow add @f1 counter packets 0 bytes 0
+ ip6 nexthdr tcp ct state invalid counter packets 0 bytes 0 drop
+ tcp flags fin,rst counter packets 0 bytes 0 accept
+ meta l4proto tcp meta length < 100 counter packets 0 bytes 0 accept
+ ip6 nexthdr tcp counter packets 0 bytes 0 log drop
+ }
+}
+EOF
+
+if [ ! -r /proc/net/nf_conntrack ]
+then
+ echo "E: nf_conntrack unreadable, skipping" >&2
+ exit 77
+fi
+
+ip netns exec $R nft list ruleset
+ip netns exec $R sysctl -w net.netfilter.nf_flowtable_tcp_timeout=5 || {
+ echo "E: set net.netfilter.nf_flowtable_tcp_timeout fail, skipping" >&2
+ exit 77
+}
+ip netns exec $R sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established=86400 || {
+ echo "E: set net.netfilter.nf_conntrack_tcp_timeout_established fail, skipping" >&2
+ exit 77
+
+}
+
+# A trick to control the timing to send a packet
+ip netns exec $S socat TCP6-LISTEN:10001 GOPEN:/tmp/pipefile-$rnd,ignoreeof &
+sleep 1
+ip netns exec $C socat -b 2048 PIPE:/tmp/pipefile-$rnd 'TCP:[2001:db8:ffff:22::1]:10001' &
+sleep 1
+ip netns exec $R grep 'OFFLOAD' /proc/net/nf_conntrack || { echo "check [OFFLOAD] tag (failed)"; exit 1; }
+ip netns exec $R cat /proc/net/nf_conntrack
+sleep 6
+ip netns exec $R grep 'OFFLOAD' /proc/net/nf_conntrack && { echo "CT OFFLOAD timeout, fail back to classical path (failed)"; exit 1; }
+ip netns exec $R grep '8639[0-9]' /proc/net/nf_conntrack || { echo "check nf_conntrack_tcp_timeout_established (failed)"; exit 1; }
+ip netns exec $C echo "send sth" >> /tmp/pipefile-$rnd
+ip netns exec $R grep 'OFFLOAD' /proc/net/nf_conntrack || { echo "traffic seen, back to OFFLOAD path (failed)"; exit 1; }
+ip netns exec $C sleep 3
+ip netns exec $C echo "send sth" >> /tmp/pipefile-$rnd
+ip netns exec $C sleep 3
+ip netns exec $R grep 'OFFLOAD' /proc/net/nf_conntrack || { echo "Traffic seen in 5s (nf_flowtable_tcp_timeout), so stay in OFFLOAD (failed)"; exit 1; }
+
+exit 0
diff --git a/tests/shell/testcases/packetpath/payload b/tests/shell/testcases/packetpath/payload
new file mode 100755
index 00000000..4c5c42da
--- /dev/null
+++ b/tests/shell/testcases/packetpath/payload
@@ -0,0 +1,182 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_netdev_egress)
+
+rnd=$(mktemp -u XXXXXXXX)
+ns1="nft1payload-$rnd"
+ns2="nft2payload-$rnd"
+
+cleanup()
+{
+ ip netns del "$ns1"
+ ip netns del "$ns2"
+}
+
+trap cleanup EXIT
+
+run_test()
+{
+ ns1_addr=$2
+ ns2_addr=$3
+ cidr=$4
+
+ # socat needs square brackets, ie. [abcd::2]
+ if [ $1 -eq 6 ]; then
+ nsx1_addr="["$ns1_addr"]"
+ nsx2_addr="["$ns2_addr"]"
+ else
+ nsx1_addr="$ns1_addr"
+ nsx2_addr="$ns2_addr"
+ fi
+
+ ip netns add "$ns1" || exit 111
+ ip netns add "$ns2" || exit 111
+
+ ip -net "$ns1" link set lo up
+ ip -net "$ns2" link set lo up
+
+ ip link add veth0 netns $ns1 type veth peer name veth0 netns $ns2
+
+ ip -net "$ns1" link set veth0 up
+ ip -net "$ns2" link set veth0 up
+ ip -net "$ns1" addr add $ns1_addr/$cidr dev veth0
+ ip -net "$ns2" addr add $ns2_addr/$cidr dev veth0
+
+RULESET="table netdev payload_netdev {
+ counter ingress {}
+ counter egress {}
+ counter mangle_ingress {}
+ counter mangle_egress {}
+ counter mangle_ingress_match {}
+ counter mangle_egress_match {}
+
+ chain ingress {
+ type filter hook ingress device veth0 priority 0;
+ tcp dport 7777 counter name ingress
+ tcp dport 7778 tcp dport set 7779 counter name mangle_ingress
+ tcp dport 7779 counter name mangle_ingress_match
+ }
+
+ chain egress {
+ type filter hook egress device veth0 priority 0;
+ tcp dport 8887 counter name egress
+ tcp dport 8888 tcp dport set 8889 counter name mangle_egress
+ tcp dport 8889 counter name mangle_egress_match
+ }
+}
+
+table inet payload_inet {
+ counter input {}
+ counter output {}
+ counter mangle_input {}
+ counter mangle_output {}
+ counter mangle_input_match {}
+ counter mangle_output_match {}
+
+ chain in {
+ type filter hook input priority 0;
+ tcp dport 7770 counter name input
+ tcp dport 7771 tcp dport set 7772 counter name mangle_input
+ tcp dport 7772 counter name mangle_input_match
+ }
+
+ chain out {
+ type filter hook output priority 0;
+ tcp dport 8880 counter name output
+ tcp dport 8881 tcp dport set 8882 counter name mangle_output
+ tcp dport 8882 counter name mangle_output_match
+ }
+}"
+
+ ip netns exec "$ns1" $NFT -f - <<< "$RULESET" || exit 1
+
+ ip netns exec "$ns1" socat -u STDIN TCP:$nsx2_addr:8887,connect-timeout=2 < /dev/null > /dev/null
+ ip netns exec "$ns1" socat -u STDIN TCP:$nsx2_addr:8888,connect-timeout=2 < /dev/null > /dev/null
+
+ ip netns exec "$ns1" socat -u STDIN TCP:$nsx2_addr:8880,connect-timeout=2 < /dev/null > /dev/null
+ ip netns exec "$ns1" socat -u STDIN TCP:$nsx2_addr:8881,connect-timeout=2 < /dev/null > /dev/null
+
+ ip netns exec "$ns2" socat -u STDIN TCP:$nsx1_addr:7777,connect-timeout=2 < /dev/null > /dev/null
+ ip netns exec "$ns2" socat -u STDIN TCP:$nsx1_addr:7778,connect-timeout=2 < /dev/null > /dev/null
+
+ ip netns exec "$ns2" socat -u STDIN TCP:$nsx1_addr:7770,connect-timeout=2 < /dev/null > /dev/null
+ ip netns exec "$ns2" socat -u STDIN TCP:$nsx1_addr:7771,connect-timeout=2 < /dev/null > /dev/null
+
+ ip netns exec "$ns1" $NFT list ruleset
+
+ ip netns exec "$ns1" $NFT list counter netdev payload_netdev ingress | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter netdev payload_netdev mangle_ingress | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter netdev payload_netdev mangle_ingress_match | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter netdev payload_netdev egress | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter netdev payload_netdev mangle_egress | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter netdev payload_netdev mangle_egress_match | grep -v "packets 0" > /dev/null || exit 1
+
+ ip netns exec "$ns1" $NFT list counter inet payload_inet input | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter inet payload_inet mangle_input | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter inet payload_inet mangle_input_match | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter inet payload_inet output | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter inet payload_inet mangle_output | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter inet payload_inet mangle_output_match | grep -v "packets 0" > /dev/null || exit 1
+
+ #
+ # ... next stage
+ #
+
+ ip netns exec "$ns1" $NFT flush ruleset
+
+ #
+ # bridge
+ #
+
+ ip -net "$ns1" addr del $ns1_addr/$cidr dev veth0
+
+ ip -net "$ns1" link add name br0 type bridge
+ ip -net "$ns1" link set veth0 master br0
+ ip -net "$ns1" addr add $ns1_addr/$cidr dev br0
+ ip -net "$ns1" link set up dev br0
+
+RULESET="table bridge payload_bridge {
+ counter input {}
+ counter output {}
+ counter mangle_input {}
+ counter mangle_output {}
+ counter mangle_input_match {}
+ counter mangle_output_match {}
+
+ chain in {
+ type filter hook input priority 0;
+ tcp dport 7770 counter name input
+ tcp dport 7771 tcp dport set 7772 counter name mangle_input
+ tcp dport 7772 counter name mangle_input_match
+ }
+
+ chain out {
+ type filter hook output priority 0;
+ tcp dport 8880 counter name output
+ tcp dport 8881 tcp dport set 8882 counter name mangle_output
+ tcp dport 8882 counter name mangle_output_match
+ }
+}"
+
+ ip netns exec "$ns1" $NFT -f - <<< "$RULESET" || exit 1
+
+ ip netns exec "$ns1" socat -u STDIN TCP:$nsx2_addr:8880,connect-timeout=2 < /dev/null > /dev/null
+ ip netns exec "$ns1" socat -u STDIN TCP:$nsx2_addr:8881,connect-timeout=2 < /dev/null > /dev/null
+
+ ip netns exec "$ns2" socat -u STDIN TCP:$nsx1_addr:7770,connect-timeout=2 < /dev/null > /dev/null
+ ip netns exec "$ns2" socat -u STDIN TCP:$nsx1_addr:7771,connect-timeout=2 < /dev/null > /dev/null
+
+ ip netns exec "$ns1" $NFT list ruleset
+
+ ip netns exec "$ns1" $NFT list counter bridge payload_bridge input | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter bridge payload_bridge mangle_input | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter bridge payload_bridge mangle_input_match | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter bridge payload_bridge output | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter bridge payload_bridge mangle_output | grep -v "packets 0" > /dev/null || exit 1
+ ip netns exec "$ns1" $NFT list counter bridge payload_bridge mangle_output_match | grep -v "packets 0" > /dev/null || exit 1
+}
+
+run_test "4" "10.141.10.2" "10.141.10.3" "24"
+cleanup
+run_test 6 "abcd::2" "abcd::3" "64"
+# trap calls cleanup
diff --git a/tests/shell/testcases/packetpath/set_lookups b/tests/shell/testcases/packetpath/set_lookups
new file mode 100755
index 00000000..85159858
--- /dev/null
+++ b/tests/shell/testcases/packetpath/set_lookups
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+
+$NFT -f /dev/stdin <<"EOF"
+table ip t {
+ set s {
+ type ipv4_addr . iface_index
+ flags interval
+ elements = { 127.0.0.1 . 1 }
+ }
+
+ set s2 {
+ typeof ip saddr . meta iif
+ elements = { 127.0.0.1 . 1 }
+ }
+
+ set s3 {
+ type iface_index
+ elements = { "lo" }
+ }
+
+ set s4 {
+ type iface_index
+ flags interval
+ elements = { "lo" }
+ }
+
+ set nomatch {
+ typeof ip saddr . meta iif
+ elements = { 127.0.0.3 . 1 }
+ }
+
+ set nomatch2 {
+ type ipv4_addr . iface_index
+ elements = { 127.0.0.2 . 90000 }
+ }
+
+ chain c {
+ type filter hook input priority filter;
+ icmp type echo-request ip saddr . meta iif @s counter
+ icmp type echo-request ip saddr . 1 @s counter
+ icmp type echo-request ip saddr . "lo" @s counter
+ icmp type echo-request ip saddr . meta iif @s2 counter
+ icmp type echo-request ip saddr . 1 @s2 counter
+ icmp type echo-request ip saddr . "lo" @s2 counter
+
+ icmp type echo-request ip daddr . "lo" @s counter
+ icmp type echo-request ip daddr . "lo" @s2 counter
+
+ icmp type echo-request meta iif @s3 counter
+ icmp type echo-request meta iif @s4 counter
+
+ ip daddr . 1 @nomatch counter drop
+ ip daddr . meta iif @nomatch2 counter drop
+ }
+}
+EOF
+
+$NFT add element t s { 127.0.0.2 . 1 }
+$NFT add element t s2 { 127.0.0.2 . "lo" }
+
+ip link set lo up
+ping -q -c 1 127.0.0.2 > /dev/null
diff --git a/tests/shell/testcases/packetpath/tcp_options b/tests/shell/testcases/packetpath/tcp_options
new file mode 100755
index 00000000..57e228c5
--- /dev/null
+++ b/tests/shell/testcases/packetpath/tcp_options
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_reset_tcp_options)
+
+have_socat="no"
+socat -h > /dev/null && have_socat="yes"
+
+ip link set lo up
+
+$NFT -f /dev/stdin <<EOF
+table inet t {
+ counter nomatchc {}
+ counter sackpermc {}
+ counter maxsegc {}
+ counter nopc {}
+
+ chain c {
+ type filter hook output priority 0;
+ tcp dport != 22345 accept
+ tcp flags & (fin | syn | rst | ack ) == syn tcp option 254 length ge 4 counter name nomatchc drop
+ tcp flags & (fin | syn | rst | ack ) == syn tcp option fastopen length ge 2 reset tcp option fastopen counter name nomatchc
+ tcp flags & (fin | syn | rst | ack ) == syn tcp option sack-perm missing counter name nomatchc
+ tcp flags & (fin | syn | rst | ack) == syn tcp option sack-perm exists counter name sackpermc
+ tcp flags & (fin | syn | rst | ack) == syn tcp option maxseg size gt 1400 counter name maxsegc
+ tcp flags & (fin | syn | rst | ack) == syn tcp option nop missing counter name nomatchc
+ tcp flags & (fin | syn | rst | ack) == syn tcp option nop exists counter name nopc
+ tcp flags & (fin | syn | rst | ack) == syn drop
+ }
+}
+EOF
+
+if [ $? -ne 0 ]; then
+ exit 1
+fi
+
+if [ $have_socat != "yes" ]; then
+ echo "Ran partial test, socat not available (skipped)"
+ exit 77
+fi
+
+# This will fail (drop in output -> connect fails with eperm)
+socat -u STDIN TCP:127.0.0.1:22345,connect-timeout=1 < /dev/null > /dev/null
+
+# can't validate via dump file, syn rexmit can cause counters to be > 1 in rare cases.
+
+$NFT list counter inet t nomatchc
+
+# nomatchc must be 0.
+$NFT list counter inet t nomatchc | grep -q "packets 0" || exit 1
+
+# these counters must not be 0.
+for nz in sackpermc maxsegc nopc; do
+ $NFT list counter inet t $nz
+ $NFT list counter inet t $nz | grep -q "packets 0" && exit 1
+done
+
+exit 0
diff --git a/tests/shell/testcases/packetpath/vlan_8021ad_tag b/tests/shell/testcases/packetpath/vlan_8021ad_tag
new file mode 100755
index 00000000..379a5710
--- /dev/null
+++ b/tests/shell/testcases/packetpath/vlan_8021ad_tag
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+rnd=$(mktemp -u XXXXXXXX)
+ns1="nft1ifname-$rnd"
+ns2="nft2ifname-$rnd"
+
+cleanup()
+{
+ ip netns del "$ns1"
+ ip netns del "$ns2"
+}
+
+trap cleanup EXIT
+
+set -e
+
+ip netns add "$ns1"
+ip netns add "$ns2"
+ip -net "$ns1" link set lo up
+ip -net "$ns2" link set lo up
+
+ip link add veth0 netns $ns1 type veth peer name veth0 netns $ns2
+
+ip -net "$ns1" link set veth0 addr da:d3:00:01:02:03
+
+ip -net "$ns1" link add vlan123 link veth0 type vlan id 123 proto 802.1ad
+ip -net "$ns2" link add vlan123 link veth0 type vlan id 123 proto 802.1ad
+
+
+for dev in veth0 vlan123; do
+ ip -net "$ns1" link set $dev up
+ ip -net "$ns2" link set $dev up
+done
+
+ip -net "$ns1" addr add 10.1.1.1/24 dev vlan123
+ip -net "$ns2" addr add 10.1.1.2/24 dev vlan123
+
+ip netns exec "$ns2" $NFT -f /dev/stdin <<"EOF"
+table netdev t {
+ chain c {
+ type filter hook ingress device veth0 priority filter;
+ ether saddr da:d3:00:01:02:03 ether type 8021ad vlan id 123 ip daddr 10.1.1.2 icmp type echo-request counter
+ }
+}
+EOF
+
+ip netns exec "$ns1" ping -c 1 10.1.1.2
+
+ip netns exec "$ns2" $NFT list ruleset
+ip netns exec "$ns2" $NFT list chain netdev t c | grep 'counter packets 1 bytes 84'
diff --git a/tests/shell/testcases/parsing/describe b/tests/shell/testcases/parsing/describe
new file mode 100755
index 00000000..2ee072e8
--- /dev/null
+++ b/tests/shell/testcases/parsing/describe
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+errmsg='Error: unknown ip option type/field'
+
+str=$($NFT describe ip option rr value 2>&1 | head -n 1)
+
+[ "$str" = "$errmsg" ] && exit 0
diff --git a/tests/shell/testcases/parsing/dumps/describe.json-nft b/tests/shell/testcases/parsing/dumps/describe.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/parsing/dumps/describe.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/parsing/dumps/describe.nft b/tests/shell/testcases/parsing/dumps/describe.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/parsing/dumps/describe.nft
diff --git a/tests/shell/testcases/parsing/dumps/large_rule_pipe.json-nft b/tests/shell/testcases/parsing/dumps/large_rule_pipe.json-nft
new file mode 100644
index 00000000..bf5dc65f
--- /dev/null
+++ b/tests/shell/testcases/parsing/dumps/large_rule_pipe.json-nft
@@ -0,0 +1,4079 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "firewalld",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PREROUTING",
+ "handle": 0,
+ "type": "nat",
+ "hook": "prerouting",
+ "prio": -90,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PREROUTING_ZONES_SOURCE",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PREROUTING_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POSTROUTING",
+ "handle": 0,
+ "type": "nat",
+ "hook": "postrouting",
+ "prio": 110,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POSTROUTING_ZONES_SOURCE",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POSTROUTING_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_home",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_home_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_home_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_home_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_home",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_home_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_home_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_home_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PREROUTING_ZONES_SOURCE"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PREROUTING_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "enp0s25"
+ }
+ },
+ {
+ "goto": {
+ "target": "nat_PRE_home"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "nat_PRE_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POSTROUTING_ZONES_SOURCE"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POSTROUTING_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "enp0s25"
+ }
+ },
+ {
+ "goto": {
+ "target": "nat_POST_home"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "nat_POST_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_home_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_home_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_home_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_home_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_home_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_home_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "firewalld",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PREROUTING",
+ "handle": 0,
+ "type": "nat",
+ "hook": "prerouting",
+ "prio": -90,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PREROUTING_ZONES_SOURCE",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PREROUTING_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POSTROUTING",
+ "handle": 0,
+ "type": "nat",
+ "hook": "postrouting",
+ "prio": 110,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POSTROUTING_ZONES_SOURCE",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POSTROUTING_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_home",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_home_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_home_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_home_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_home",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_home_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_home_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_home_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PREROUTING_ZONES_SOURCE"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PREROUTING_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "enp0s25"
+ }
+ },
+ {
+ "goto": {
+ "target": "nat_PRE_home"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "nat_PRE_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POSTROUTING_ZONES_SOURCE"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POSTROUTING_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "enp0s25"
+ }
+ },
+ {
+ "goto": {
+ "target": "nat_POST_home"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "nat_POST_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_home_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_home_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_home_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_home_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_home_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_home_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "firewalld",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PREROUTING",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PREROUTING_ZONES_SOURCE",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PREROUTING_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PREROUTING",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PREROUTING_ZONES_SOURCE",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PREROUTING_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_INPUT",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FORWARD",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_INPUT_ZONES_SOURCE",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_INPUT_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FORWARD_IN_ZONES_SOURCE",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FORWARD_IN_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FORWARD_OUT_ZONES_SOURCE",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FORWARD_OUT_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_home",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_home_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_home_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_home_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_home",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_home_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_home_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_home_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_home",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_home_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_home_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_home_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_home",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_home_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_home_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_home_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_home",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_home_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_home_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_home_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmpv6",
+ "field": "type"
+ }
+ },
+ "right": {
+ "set": [
+ "nd-router-advert",
+ "nd-neighbor-solicit"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "nfproto"
+ }
+ },
+ "right": "ipv6"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "fib": {
+ "result": "oif",
+ "flags": [
+ "saddr",
+ "iif"
+ ]
+ }
+ },
+ "right": false
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PREROUTING_ZONES_SOURCE"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PREROUTING_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "enp0s25"
+ }
+ },
+ {
+ "goto": {
+ "target": "raw_PRE_home"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "raw_PRE_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PREROUTING_ZONES_SOURCE"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PREROUTING_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "enp0s25"
+ }
+ },
+ {
+ "goto": {
+ "target": "mangle_PRE_home"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "mangle_PRE_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "established",
+ "related"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_INPUT_ZONES_SOURCE"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_INPUT_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "invalid"
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "reject": {
+ "type": "icmpx",
+ "expr": "admin-prohibited"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "established",
+ "related"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FORWARD_IN_ZONES_SOURCE"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FORWARD_IN_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FORWARD_OUT_ZONES_SOURCE"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FORWARD_OUT_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "invalid"
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "reject": {
+ "type": "icmpx",
+ "expr": "admin-prohibited"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "enp0s25"
+ }
+ },
+ {
+ "goto": {
+ "target": "filter_IN_home"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "filter_IN_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD_IN_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "enp0s25"
+ }
+ },
+ {
+ "goto": {
+ "target": "filter_FWDI_home"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD_IN_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "filter_FWDI_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD_OUT_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "enp0s25"
+ }
+ },
+ {
+ "goto": {
+ "target": "filter_FWDO_home"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD_OUT_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "filter_FWDO_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": {
+ "set": [
+ "icmp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "prefix": {
+ "addr": "fe80::",
+ "len": 64
+ }
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 546
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_public",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": {
+ "set": [
+ "icmp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_home_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_home_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_home_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_home_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 137
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "ct": {
+ "key": "helper"
+ }
+ },
+ "right": "netbios-ns"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_home_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_home_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_home_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": {
+ "set": [
+ "icmp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": "224.0.0.251"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 5353
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "right": "ff02::fb"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 5353
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "range": [
+ 1714,
+ 1764
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "range": [
+ 1714,
+ 1764
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "prefix": {
+ "addr": "fe80::",
+ "len": 64
+ }
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 546
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 137
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 138
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 139
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_home_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 445
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_home_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_home_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_home_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_home",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": {
+ "set": [
+ "icmp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_home_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_home_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_home_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_home_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_home_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_home",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_home_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": {
+ "set": [
+ "icmp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "prefix": {
+ "addr": "fe80::",
+ "len": 64
+ }
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 546
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "new",
+ "untracked"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_work",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": {
+ "set": [
+ "icmp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_work_allow"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/parsing/dumps/large_rule_pipe.nft b/tests/shell/testcases/parsing/dumps/large_rule_pipe.nft
new file mode 100644
index 00000000..15832752
--- /dev/null
+++ b/tests/shell/testcases/parsing/dumps/large_rule_pipe.nft
@@ -0,0 +1,561 @@
+table ip firewalld {
+ chain nat_PREROUTING {
+ type nat hook prerouting priority dstnat + 10; policy accept;
+ jump nat_PREROUTING_ZONES_SOURCE
+ jump nat_PREROUTING_ZONES
+ }
+
+ chain nat_PREROUTING_ZONES_SOURCE {
+ }
+
+ chain nat_PREROUTING_ZONES {
+ iifname "enp0s25" goto nat_PRE_home
+ goto nat_PRE_public
+ }
+
+ chain nat_POSTROUTING {
+ type nat hook postrouting priority srcnat + 10; policy accept;
+ jump nat_POSTROUTING_ZONES_SOURCE
+ jump nat_POSTROUTING_ZONES
+ }
+
+ chain nat_POSTROUTING_ZONES_SOURCE {
+ }
+
+ chain nat_POSTROUTING_ZONES {
+ oifname "enp0s25" goto nat_POST_home
+ goto nat_POST_public
+ }
+
+ chain nat_PRE_public {
+ jump nat_PRE_public_log
+ jump nat_PRE_public_deny
+ jump nat_PRE_public_allow
+ }
+
+ chain nat_PRE_public_log {
+ }
+
+ chain nat_PRE_public_deny {
+ }
+
+ chain nat_PRE_public_allow {
+ }
+
+ chain nat_POST_public {
+ jump nat_POST_public_log
+ jump nat_POST_public_deny
+ jump nat_POST_public_allow
+ }
+
+ chain nat_POST_public_log {
+ }
+
+ chain nat_POST_public_deny {
+ }
+
+ chain nat_POST_public_allow {
+ }
+
+ chain nat_PRE_home {
+ jump nat_PRE_home_log
+ jump nat_PRE_home_deny
+ jump nat_PRE_home_allow
+ }
+
+ chain nat_PRE_home_log {
+ }
+
+ chain nat_PRE_home_deny {
+ }
+
+ chain nat_PRE_home_allow {
+ }
+
+ chain nat_POST_home {
+ jump nat_POST_home_log
+ jump nat_POST_home_deny
+ jump nat_POST_home_allow
+ }
+
+ chain nat_POST_home_log {
+ }
+
+ chain nat_POST_home_deny {
+ }
+
+ chain nat_POST_home_allow {
+ }
+
+ chain nat_PRE_work {
+ jump nat_PRE_work_log
+ jump nat_PRE_work_deny
+ jump nat_PRE_work_allow
+ }
+
+ chain nat_PRE_work_log {
+ }
+
+ chain nat_PRE_work_deny {
+ }
+
+ chain nat_PRE_work_allow {
+ }
+
+ chain nat_POST_work {
+ jump nat_POST_work_log
+ jump nat_POST_work_deny
+ jump nat_POST_work_allow
+ }
+
+ chain nat_POST_work_log {
+ }
+
+ chain nat_POST_work_deny {
+ }
+
+ chain nat_POST_work_allow {
+ }
+}
+table ip6 firewalld {
+ chain nat_PREROUTING {
+ type nat hook prerouting priority dstnat + 10; policy accept;
+ jump nat_PREROUTING_ZONES_SOURCE
+ jump nat_PREROUTING_ZONES
+ }
+
+ chain nat_PREROUTING_ZONES_SOURCE {
+ }
+
+ chain nat_PREROUTING_ZONES {
+ iifname "enp0s25" goto nat_PRE_home
+ goto nat_PRE_public
+ }
+
+ chain nat_POSTROUTING {
+ type nat hook postrouting priority srcnat + 10; policy accept;
+ jump nat_POSTROUTING_ZONES_SOURCE
+ jump nat_POSTROUTING_ZONES
+ }
+
+ chain nat_POSTROUTING_ZONES_SOURCE {
+ }
+
+ chain nat_POSTROUTING_ZONES {
+ oifname "enp0s25" goto nat_POST_home
+ goto nat_POST_public
+ }
+
+ chain nat_PRE_public {
+ jump nat_PRE_public_log
+ jump nat_PRE_public_deny
+ jump nat_PRE_public_allow
+ }
+
+ chain nat_PRE_public_log {
+ }
+
+ chain nat_PRE_public_deny {
+ }
+
+ chain nat_PRE_public_allow {
+ }
+
+ chain nat_POST_public {
+ jump nat_POST_public_log
+ jump nat_POST_public_deny
+ jump nat_POST_public_allow
+ }
+
+ chain nat_POST_public_log {
+ }
+
+ chain nat_POST_public_deny {
+ }
+
+ chain nat_POST_public_allow {
+ }
+
+ chain nat_PRE_home {
+ jump nat_PRE_home_log
+ jump nat_PRE_home_deny
+ jump nat_PRE_home_allow
+ }
+
+ chain nat_PRE_home_log {
+ }
+
+ chain nat_PRE_home_deny {
+ }
+
+ chain nat_PRE_home_allow {
+ }
+
+ chain nat_POST_home {
+ jump nat_POST_home_log
+ jump nat_POST_home_deny
+ jump nat_POST_home_allow
+ }
+
+ chain nat_POST_home_log {
+ }
+
+ chain nat_POST_home_deny {
+ }
+
+ chain nat_POST_home_allow {
+ }
+
+ chain nat_PRE_work {
+ jump nat_PRE_work_log
+ jump nat_PRE_work_deny
+ jump nat_PRE_work_allow
+ }
+
+ chain nat_PRE_work_log {
+ }
+
+ chain nat_PRE_work_deny {
+ }
+
+ chain nat_PRE_work_allow {
+ }
+
+ chain nat_POST_work {
+ jump nat_POST_work_log
+ jump nat_POST_work_deny
+ jump nat_POST_work_allow
+ }
+
+ chain nat_POST_work_log {
+ }
+
+ chain nat_POST_work_deny {
+ }
+
+ chain nat_POST_work_allow {
+ }
+}
+table inet firewalld {
+ chain raw_PREROUTING {
+ type filter hook prerouting priority raw + 10; policy accept;
+ icmpv6 type { nd-router-advert, nd-neighbor-solicit } accept
+ meta nfproto ipv6 fib saddr . iif oif missing drop
+ jump raw_PREROUTING_ZONES_SOURCE
+ jump raw_PREROUTING_ZONES
+ }
+
+ chain raw_PREROUTING_ZONES_SOURCE {
+ }
+
+ chain raw_PREROUTING_ZONES {
+ iifname "enp0s25" goto raw_PRE_home
+ goto raw_PRE_public
+ }
+
+ chain mangle_PREROUTING {
+ type filter hook prerouting priority mangle + 10; policy accept;
+ jump mangle_PREROUTING_ZONES_SOURCE
+ jump mangle_PREROUTING_ZONES
+ }
+
+ chain mangle_PREROUTING_ZONES_SOURCE {
+ }
+
+ chain mangle_PREROUTING_ZONES {
+ iifname "enp0s25" goto mangle_PRE_home
+ goto mangle_PRE_public
+ }
+
+ chain filter_INPUT {
+ type filter hook input priority filter + 10; policy accept;
+ ct state established,related accept
+ iifname "lo" accept
+ jump filter_INPUT_ZONES_SOURCE
+ jump filter_INPUT_ZONES
+ ct state invalid drop
+ reject with icmpx admin-prohibited
+ }
+
+ chain filter_FORWARD {
+ type filter hook forward priority filter + 10; policy accept;
+ ct state established,related accept
+ iifname "lo" accept
+ jump filter_FORWARD_IN_ZONES_SOURCE
+ jump filter_FORWARD_IN_ZONES
+ jump filter_FORWARD_OUT_ZONES_SOURCE
+ jump filter_FORWARD_OUT_ZONES
+ ct state invalid drop
+ reject with icmpx admin-prohibited
+ }
+
+ chain filter_INPUT_ZONES_SOURCE {
+ }
+
+ chain filter_INPUT_ZONES {
+ iifname "enp0s25" goto filter_IN_home
+ goto filter_IN_public
+ }
+
+ chain filter_FORWARD_IN_ZONES_SOURCE {
+ }
+
+ chain filter_FORWARD_IN_ZONES {
+ iifname "enp0s25" goto filter_FWDI_home
+ goto filter_FWDI_public
+ }
+
+ chain filter_FORWARD_OUT_ZONES_SOURCE {
+ }
+
+ chain filter_FORWARD_OUT_ZONES {
+ oifname "enp0s25" goto filter_FWDO_home
+ goto filter_FWDO_public
+ }
+
+ chain raw_PRE_public {
+ jump raw_PRE_public_log
+ jump raw_PRE_public_deny
+ jump raw_PRE_public_allow
+ }
+
+ chain raw_PRE_public_log {
+ }
+
+ chain raw_PRE_public_deny {
+ }
+
+ chain raw_PRE_public_allow {
+ }
+
+ chain filter_IN_public {
+ jump filter_IN_public_log
+ jump filter_IN_public_deny
+ jump filter_IN_public_allow
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_IN_public_log {
+ }
+
+ chain filter_IN_public_deny {
+ }
+
+ chain filter_IN_public_allow {
+ tcp dport 22 ct state new,untracked accept
+ ip6 daddr fe80::/64 udp dport 546 ct state new,untracked accept
+ }
+
+ chain filter_FWDI_public {
+ jump filter_FWDI_public_log
+ jump filter_FWDI_public_deny
+ jump filter_FWDI_public_allow
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_FWDI_public_log {
+ }
+
+ chain filter_FWDI_public_deny {
+ }
+
+ chain filter_FWDI_public_allow {
+ }
+
+ chain mangle_PRE_public {
+ jump mangle_PRE_public_log
+ jump mangle_PRE_public_deny
+ jump mangle_PRE_public_allow
+ }
+
+ chain mangle_PRE_public_log {
+ }
+
+ chain mangle_PRE_public_deny {
+ }
+
+ chain mangle_PRE_public_allow {
+ }
+
+ chain filter_FWDO_public {
+ jump filter_FWDO_public_log
+ jump filter_FWDO_public_deny
+ jump filter_FWDO_public_allow
+ }
+
+ chain filter_FWDO_public_log {
+ }
+
+ chain filter_FWDO_public_deny {
+ }
+
+ chain filter_FWDO_public_allow {
+ }
+
+ chain raw_PRE_home {
+ jump raw_PRE_home_log
+ jump raw_PRE_home_deny
+ jump raw_PRE_home_allow
+ }
+
+ chain raw_PRE_home_log {
+ }
+
+ chain raw_PRE_home_deny {
+ }
+
+ chain raw_PRE_home_allow {
+ udp dport 137 ct helper "netbios-ns"
+ }
+
+ chain filter_IN_home {
+ jump filter_IN_home_log
+ jump filter_IN_home_deny
+ jump filter_IN_home_allow
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_IN_home_log {
+ }
+
+ chain filter_IN_home_deny {
+ }
+
+ chain filter_IN_home_allow {
+ tcp dport 22 ct state new,untracked accept
+ ip daddr 224.0.0.251 udp dport 5353 ct state new,untracked accept
+ ip6 daddr ff02::fb udp dport 5353 ct state new,untracked accept
+ udp dport 1714-1764 ct state new,untracked accept
+ tcp dport 1714-1764 ct state new,untracked accept
+ ip6 daddr fe80::/64 udp dport 546 ct state new,untracked accept
+ udp dport 137 ct state new,untracked accept
+ udp dport 138 ct state new,untracked accept
+ tcp dport 139 ct state new,untracked accept
+ tcp dport 445 ct state new,untracked accept
+ }
+
+ chain filter_FWDI_home {
+ jump filter_FWDI_home_log
+ jump filter_FWDI_home_deny
+ jump filter_FWDI_home_allow
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_FWDI_home_log {
+ }
+
+ chain filter_FWDI_home_deny {
+ }
+
+ chain filter_FWDI_home_allow {
+ }
+
+ chain mangle_PRE_home {
+ jump mangle_PRE_home_log
+ jump mangle_PRE_home_deny
+ jump mangle_PRE_home_allow
+ }
+
+ chain mangle_PRE_home_log {
+ }
+
+ chain mangle_PRE_home_deny {
+ }
+
+ chain mangle_PRE_home_allow {
+ }
+
+ chain filter_FWDO_home {
+ jump filter_FWDO_home_log
+ jump filter_FWDO_home_deny
+ jump filter_FWDO_home_allow
+ }
+
+ chain filter_FWDO_home_log {
+ }
+
+ chain filter_FWDO_home_deny {
+ }
+
+ chain filter_FWDO_home_allow {
+ }
+
+ chain raw_PRE_work {
+ jump raw_PRE_work_log
+ jump raw_PRE_work_deny
+ jump raw_PRE_work_allow
+ }
+
+ chain raw_PRE_work_log {
+ }
+
+ chain raw_PRE_work_deny {
+ }
+
+ chain raw_PRE_work_allow {
+ }
+
+ chain filter_IN_work {
+ jump filter_IN_work_log
+ jump filter_IN_work_deny
+ jump filter_IN_work_allow
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_IN_work_log {
+ }
+
+ chain filter_IN_work_deny {
+ }
+
+ chain filter_IN_work_allow {
+ tcp dport 22 ct state new,untracked accept
+ ip6 daddr fe80::/64 udp dport 546 ct state new,untracked accept
+ }
+
+ chain filter_FWDI_work {
+ jump filter_FWDI_work_log
+ jump filter_FWDI_work_deny
+ jump filter_FWDI_work_allow
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_FWDI_work_log {
+ }
+
+ chain filter_FWDI_work_deny {
+ }
+
+ chain filter_FWDI_work_allow {
+ }
+
+ chain mangle_PRE_work {
+ jump mangle_PRE_work_log
+ jump mangle_PRE_work_deny
+ jump mangle_PRE_work_allow
+ }
+
+ chain mangle_PRE_work_log {
+ }
+
+ chain mangle_PRE_work_deny {
+ }
+
+ chain mangle_PRE_work_allow {
+ }
+
+ chain filter_FWDO_work {
+ jump filter_FWDO_work_log
+ jump filter_FWDO_work_deny
+ jump filter_FWDO_work_allow
+ }
+
+ chain filter_FWDO_work_log {
+ }
+
+ chain filter_FWDO_work_deny {
+ }
+
+ chain filter_FWDO_work_allow {
+ }
+}
diff --git a/tests/shell/testcases/parsing/dumps/log.json-nft b/tests/shell/testcases/parsing/dumps/log.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/parsing/dumps/log.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/parsing/dumps/log.nft b/tests/shell/testcases/parsing/dumps/log.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/parsing/dumps/log.nft
diff --git a/tests/shell/testcases/parsing/dumps/octal.json-nft b/tests/shell/testcases/parsing/dumps/octal.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/parsing/dumps/octal.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/parsing/dumps/octal.nft b/tests/shell/testcases/parsing/dumps/octal.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/parsing/dumps/octal.nft
diff --git a/tests/shell/testcases/parsing/large_rule_pipe b/tests/shell/testcases/parsing/large_rule_pipe
new file mode 100755
index 00000000..b6760c01
--- /dev/null
+++ b/tests/shell/testcases/parsing/large_rule_pipe
@@ -0,0 +1,571 @@
+#!/bin/bash
+
+set -e
+
+RULESET="#!/sbin/nft -f
+flush ruleset;
+table ip firewalld {
+ chain nat_PREROUTING {
+ type nat hook prerouting priority -90; policy accept;
+ jump nat_PREROUTING_ZONES_SOURCE
+ jump nat_PREROUTING_ZONES
+ }
+
+ chain nat_PREROUTING_ZONES_SOURCE {
+ }
+
+ chain nat_PREROUTING_ZONES {
+ iifname "enp0s25" goto nat_PRE_home
+ goto nat_PRE_public
+ }
+
+ chain nat_POSTROUTING {
+ type nat hook postrouting priority 110; policy accept;
+ jump nat_POSTROUTING_ZONES_SOURCE
+ jump nat_POSTROUTING_ZONES
+ }
+
+ chain nat_POSTROUTING_ZONES_SOURCE {
+ }
+
+ chain nat_POSTROUTING_ZONES {
+ oifname "enp0s25" goto nat_POST_home
+ goto nat_POST_public
+ }
+
+ chain nat_PRE_public {
+ jump nat_PRE_public_log
+ jump nat_PRE_public_deny
+ jump nat_PRE_public_allow
+ }
+
+ chain nat_PRE_public_log {
+ }
+
+ chain nat_PRE_public_deny {
+ }
+
+ chain nat_PRE_public_allow {
+ }
+
+ chain nat_POST_public {
+ jump nat_POST_public_log
+ jump nat_POST_public_deny
+ jump nat_POST_public_allow
+ }
+
+ chain nat_POST_public_log {
+ }
+
+ chain nat_POST_public_deny {
+ }
+
+ chain nat_POST_public_allow {
+ }
+
+ chain nat_PRE_home {
+ jump nat_PRE_home_log
+ jump nat_PRE_home_deny
+ jump nat_PRE_home_allow
+ }
+
+ chain nat_PRE_home_log {
+ }
+
+ chain nat_PRE_home_deny {
+ }
+
+ chain nat_PRE_home_allow {
+ }
+
+ chain nat_POST_home {
+ jump nat_POST_home_log
+ jump nat_POST_home_deny
+ jump nat_POST_home_allow
+ }
+
+ chain nat_POST_home_log {
+ }
+
+ chain nat_POST_home_deny {
+ }
+
+ chain nat_POST_home_allow {
+ }
+
+ chain nat_PRE_work {
+ jump nat_PRE_work_log
+ jump nat_PRE_work_deny
+ jump nat_PRE_work_allow
+ }
+
+ chain nat_PRE_work_log {
+ }
+
+ chain nat_PRE_work_deny {
+ }
+
+ chain nat_PRE_work_allow {
+ }
+
+ chain nat_POST_work {
+ jump nat_POST_work_log
+ jump nat_POST_work_deny
+ jump nat_POST_work_allow
+ }
+
+ chain nat_POST_work_log {
+ }
+
+ chain nat_POST_work_deny {
+ }
+
+ chain nat_POST_work_allow {
+ }
+}
+table ip6 firewalld {
+ chain nat_PREROUTING {
+ type nat hook prerouting priority -90; policy accept;
+ jump nat_PREROUTING_ZONES_SOURCE
+ jump nat_PREROUTING_ZONES
+ }
+
+ chain nat_PREROUTING_ZONES_SOURCE {
+ }
+
+ chain nat_PREROUTING_ZONES {
+ iifname "enp0s25" goto nat_PRE_home
+ goto nat_PRE_public
+ }
+
+ chain nat_POSTROUTING {
+ type nat hook postrouting priority 110; policy accept;
+ jump nat_POSTROUTING_ZONES_SOURCE
+ jump nat_POSTROUTING_ZONES
+ }
+
+ chain nat_POSTROUTING_ZONES_SOURCE {
+ }
+
+ chain nat_POSTROUTING_ZONES {
+ oifname "enp0s25" goto nat_POST_home
+ goto nat_POST_public
+ }
+
+ chain nat_PRE_public {
+ jump nat_PRE_public_log
+ jump nat_PRE_public_deny
+ jump nat_PRE_public_allow
+ }
+
+ chain nat_PRE_public_log {
+ }
+
+ chain nat_PRE_public_deny {
+ }
+
+ chain nat_PRE_public_allow {
+ }
+
+ chain nat_POST_public {
+ jump nat_POST_public_log
+ jump nat_POST_public_deny
+ jump nat_POST_public_allow
+ }
+
+ chain nat_POST_public_log {
+ }
+
+ chain nat_POST_public_deny {
+ }
+
+ chain nat_POST_public_allow {
+ }
+
+ chain nat_PRE_home {
+ jump nat_PRE_home_log
+ jump nat_PRE_home_deny
+ jump nat_PRE_home_allow
+ }
+
+ chain nat_PRE_home_log {
+ }
+
+ chain nat_PRE_home_deny {
+ }
+
+ chain nat_PRE_home_allow {
+ }
+
+ chain nat_POST_home {
+ jump nat_POST_home_log
+ jump nat_POST_home_deny
+ jump nat_POST_home_allow
+ }
+
+ chain nat_POST_home_log {
+ }
+
+ chain nat_POST_home_deny {
+ }
+
+ chain nat_POST_home_allow {
+ }
+
+ chain nat_PRE_work {
+ jump nat_PRE_work_log
+ jump nat_PRE_work_deny
+ jump nat_PRE_work_allow
+ }
+
+ chain nat_PRE_work_log {
+ }
+
+ chain nat_PRE_work_deny {
+ }
+
+ chain nat_PRE_work_allow {
+ }
+
+ chain nat_POST_work {
+ jump nat_POST_work_log
+ jump nat_POST_work_deny
+ jump nat_POST_work_allow
+ }
+
+ chain nat_POST_work_log {
+ }
+
+ chain nat_POST_work_deny {
+ }
+
+ chain nat_POST_work_allow {
+ }
+}
+table inet firewalld {
+ chain raw_PREROUTING {
+ type filter hook prerouting priority -290; policy accept;
+ icmpv6 type { nd-router-advert, nd-neighbor-solicit } accept
+ meta nfproto ipv6 fib saddr . iif oif missing drop
+ jump raw_PREROUTING_ZONES_SOURCE
+ jump raw_PREROUTING_ZONES
+ }
+
+ chain raw_PREROUTING_ZONES_SOURCE {
+ }
+
+ chain raw_PREROUTING_ZONES {
+ iifname "enp0s25" goto raw_PRE_home
+ goto raw_PRE_public
+ }
+
+ chain mangle_PREROUTING {
+ type filter hook prerouting priority -140; policy accept;
+ jump mangle_PREROUTING_ZONES_SOURCE
+ jump mangle_PREROUTING_ZONES
+ }
+
+ chain mangle_PREROUTING_ZONES_SOURCE {
+ }
+
+ chain mangle_PREROUTING_ZONES {
+ iifname "enp0s25" goto mangle_PRE_home
+ goto mangle_PRE_public
+ }
+
+ chain filter_INPUT {
+ type filter hook input priority 10; policy accept;
+ ct state established,related accept
+ iifname "lo" accept
+ jump filter_INPUT_ZONES_SOURCE
+ jump filter_INPUT_ZONES
+ ct state invalid drop
+ reject with icmpx type admin-prohibited
+ }
+
+ chain filter_FORWARD {
+ type filter hook forward priority 10; policy accept;
+ ct state established,related accept
+ iifname "lo" accept
+ jump filter_FORWARD_IN_ZONES_SOURCE
+ jump filter_FORWARD_IN_ZONES
+ jump filter_FORWARD_OUT_ZONES_SOURCE
+ jump filter_FORWARD_OUT_ZONES
+ ct state invalid drop
+ reject with icmpx type admin-prohibited
+ }
+
+ chain filter_INPUT_ZONES_SOURCE {
+ }
+
+ chain filter_INPUT_ZONES {
+ iifname "enp0s25" goto filter_IN_home
+ goto filter_IN_public
+ }
+
+ chain filter_FORWARD_IN_ZONES_SOURCE {
+ }
+
+ chain filter_FORWARD_IN_ZONES {
+ iifname "enp0s25" goto filter_FWDI_home
+ goto filter_FWDI_public
+ }
+
+ chain filter_FORWARD_OUT_ZONES_SOURCE {
+ }
+
+ chain filter_FORWARD_OUT_ZONES {
+ oifname "enp0s25" goto filter_FWDO_home
+ goto filter_FWDO_public
+ }
+
+ chain raw_PRE_public {
+ jump raw_PRE_public_log
+ jump raw_PRE_public_deny
+ jump raw_PRE_public_allow
+ }
+
+ chain raw_PRE_public_log {
+ }
+
+ chain raw_PRE_public_deny {
+ }
+
+ chain raw_PRE_public_allow {
+ }
+
+ chain filter_IN_public {
+ jump filter_IN_public_log
+ jump filter_IN_public_deny
+ jump filter_IN_public_allow
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_IN_public_log {
+ }
+
+ chain filter_IN_public_deny {
+ }
+
+ chain filter_IN_public_allow {
+ tcp dport ssh ct state new,untracked accept
+ ip6 daddr fe80::/64 udp dport dhcpv6-client ct state new,untracked accept
+ }
+
+ chain filter_FWDI_public {
+ jump filter_FWDI_public_log
+ jump filter_FWDI_public_deny
+ jump filter_FWDI_public_allow
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_FWDI_public_log {
+ }
+
+ chain filter_FWDI_public_deny {
+ }
+
+ chain filter_FWDI_public_allow {
+ }
+
+ chain mangle_PRE_public {
+ jump mangle_PRE_public_log
+ jump mangle_PRE_public_deny
+ jump mangle_PRE_public_allow
+ }
+
+ chain mangle_PRE_public_log {
+ }
+
+ chain mangle_PRE_public_deny {
+ }
+
+ chain mangle_PRE_public_allow {
+ }
+
+ chain filter_FWDO_public {
+ jump filter_FWDO_public_log
+ jump filter_FWDO_public_deny
+ jump filter_FWDO_public_allow
+ }
+
+ chain filter_FWDO_public_log {
+ }
+
+ chain filter_FWDO_public_deny {
+ }
+
+ chain filter_FWDO_public_allow {
+ }
+
+ chain raw_PRE_home {
+ jump raw_PRE_home_log
+ jump raw_PRE_home_deny
+ jump raw_PRE_home_allow
+ }
+
+ chain raw_PRE_home_log {
+ }
+
+ chain raw_PRE_home_deny {
+ }
+
+ chain raw_PRE_home_allow {
+ udp dport netbios-ns ct helper "netbios-ns"
+ }
+
+ chain filter_IN_home {
+ jump filter_IN_home_log
+ jump filter_IN_home_deny
+ jump filter_IN_home_allow
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_IN_home_log {
+ }
+
+ chain filter_IN_home_deny {
+ }
+
+ chain filter_IN_home_allow {
+ tcp dport ssh ct state new,untracked accept
+ ip daddr 224.0.0.251 udp dport mdns ct state new,untracked accept
+ ip6 daddr ff02::fb udp dport mdns ct state new,untracked accept
+ udp dport 1714-1764 ct state new,untracked accept
+ tcp dport 1714-1764 ct state new,untracked accept
+ ip6 daddr fe80::/64 udp dport dhcpv6-client ct state new,untracked accept
+ udp dport netbios-ns ct state new,untracked accept
+ udp dport netbios-dgm ct state new,untracked accept
+ tcp dport netbios-ssn ct state new,untracked accept
+ tcp dport microsoft-ds ct state new,untracked accept
+ }
+
+ chain filter_FWDI_home {
+ jump filter_FWDI_home_log
+ jump filter_FWDI_home_deny
+ jump filter_FWDI_home_allow
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_FWDI_home_log {
+ }
+
+ chain filter_FWDI_home_deny {
+ }
+
+ chain filter_FWDI_home_allow {
+ }
+
+ chain mangle_PRE_home {
+ jump mangle_PRE_home_log
+ jump mangle_PRE_home_deny
+ jump mangle_PRE_home_allow
+ }
+
+ chain mangle_PRE_home_log {
+ }
+
+ chain mangle_PRE_home_deny {
+ }
+
+ chain mangle_PRE_home_allow {
+ }
+
+ chain filter_FWDO_home {
+ jump filter_FWDO_home_log
+ jump filter_FWDO_home_deny
+ jump filter_FWDO_home_allow
+ }
+
+ chain filter_FWDO_home_log {
+ }
+
+ chain filter_FWDO_home_deny {
+ }
+
+ chain filter_FWDO_home_allow {
+ }
+
+ chain raw_PRE_work {
+ jump raw_PRE_work_log
+ jump raw_PRE_work_deny
+ jump raw_PRE_work_allow
+ }
+
+ chain raw_PRE_work_log {
+ }
+
+ chain raw_PRE_work_deny {
+ }
+
+ chain raw_PRE_work_allow {
+ }
+
+ chain filter_IN_work {
+ jump filter_IN_work_log
+ jump filter_IN_work_deny
+ jump filter_IN_work_allow
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_IN_work_log {
+ }
+
+ chain filter_IN_work_deny {
+ }
+
+ chain filter_IN_work_allow {
+ tcp dport ssh ct state new,untracked accept
+ ip6 daddr fe80::/64 udp dport dhcpv6-client ct state new,untracked accept
+ }
+
+ chain filter_FWDI_work {
+ jump filter_FWDI_work_log
+ jump filter_FWDI_work_deny
+ jump filter_FWDI_work_allow
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_FWDI_work_log {
+ }
+
+ chain filter_FWDI_work_deny {
+ }
+
+ chain filter_FWDI_work_allow {
+ }
+
+ chain mangle_PRE_work {
+ jump mangle_PRE_work_log
+ jump mangle_PRE_work_deny
+ jump mangle_PRE_work_allow
+ }
+
+ chain mangle_PRE_work_log {
+ }
+
+ chain mangle_PRE_work_deny {
+ }
+
+ chain mangle_PRE_work_allow {
+ }
+
+ chain filter_FWDO_work {
+ jump filter_FWDO_work_log
+ jump filter_FWDO_work_deny
+ jump filter_FWDO_work_allow
+ }
+
+ chain filter_FWDO_work_log {
+ }
+
+ chain filter_FWDO_work_deny {
+ }
+
+ chain filter_FWDO_work_allow {
+ }
+}"
+
+( echo "flush ruleset;"; echo "${RULESET}" ) | $NFT -f -
+
+exit 0
diff --git a/tests/shell/testcases/parsing/log b/tests/shell/testcases/parsing/log
new file mode 100755
index 00000000..0b89d589
--- /dev/null
+++ b/tests/shell/testcases/parsing/log
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+$NFT add table t || exit 1
+$NFT add chain t c || exit 1
+$NFT add rule t c 'iif != lo ip daddr 127.0.0.1/8 counter limit rate 1/second log flags all prefix "nft_lo4 " drop' || exit 1
+$NFT add rule t c 'iif != lo ip daddr 127.0.0.1/8 counter limit rate 1/second log flags all level debug drop' || exit 1
+$NFT delete table t || exit 1
+
+exit 0
+
diff --git a/tests/shell/testcases/parsing/octal b/tests/shell/testcases/parsing/octal
new file mode 100755
index 00000000..09ac26e7
--- /dev/null
+++ b/tests/shell/testcases/parsing/octal
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+$NFT add table t || exit 1
+$NFT add chain t c || exit 1
+$NFT add rule t c 'ip saddr 01 continue comment "0.0.0.1"' || exit 1
+$NFT add rule t c 'ip saddr 08 continue comment "error"' && {
+ echo "'"ip saddr 08"'" not rejected 1>&2
+ exit 1
+}
+$NFT delete table t || exit 1
+
+exit 0
+
diff --git a/tests/shell/testcases/rule_management/0001addinsertposition_0 b/tests/shell/testcases/rule_management/0001addinsertposition_0
index bb3fda51..237e9e32 100755
--- a/tests/shell/testcases/rule_management/0001addinsertposition_0
+++ b/tests/shell/testcases/rule_management/0001addinsertposition_0
@@ -30,8 +30,7 @@ for arg in "position 2" "handle 2" "index 0"; do
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
done
@@ -42,8 +41,7 @@ for arg in "position 3" "handle 3" "index 1"; do
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
done
@@ -62,8 +60,7 @@ for arg in "position 3" "handle 3" "index 1"; do
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
done
@@ -82,8 +79,7 @@ for arg in "position 2" "handle 2" "index 0"; do
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
done
diff --git a/tests/shell/testcases/rule_management/0003insert_0 b/tests/shell/testcases/rule_management/0003insert_0
index 329ccc20..c343d579 100755
--- a/tests/shell/testcases/rule_management/0003insert_0
+++ b/tests/shell/testcases/rule_management/0003insert_0
@@ -9,3 +9,7 @@ $NFT add chain t c
$NFT insert rule t c accept
$NFT insert rule t c drop
$NFT insert rule t c masquerade
+
+# check 'evaluate: un-break rule insert with intervals'
+
+$NFT insert rule t c tcp sport { 3478-3497, 16384-16387 }
diff --git a/tests/shell/testcases/rule_management/0010replace_0 b/tests/shell/testcases/rule_management/0010replace_0
index 251cebb2..cd69a89d 100755
--- a/tests/shell/testcases/rule_management/0010replace_0
+++ b/tests/shell/testcases/rule_management/0010replace_0
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
# test for kernel commit ca08987885a147643817d02bf260bc4756ce8cd4
# ("netfilter: nf_tables: deactivate expressions in rule replecement routine")
diff --git a/tests/shell/testcases/rule_management/0011reset_0 b/tests/shell/testcases/rule_management/0011reset_0
new file mode 100755
index 00000000..33eadd9e
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0011reset_0
@@ -0,0 +1,170 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_reset_rule)
+
+set -e
+
+echo "loading ruleset"
+$NFT -f - <<EOF
+table ip t {
+ set s {
+ type ipv4_addr
+ counter
+ elements = { 1.1.1.1 counter packets 1 bytes 11 }
+ }
+ chain c {
+ counter packets 1 bytes 11 update @s { ip saddr } accept
+ counter packets 2 bytes 12 drop
+ }
+
+ chain c2 {
+ counter packets 3 bytes 13 accept
+ counter packets 4 bytes 14 drop
+ }
+}
+table inet t {
+ chain c {
+ counter packets 5 bytes 15 accept
+ counter packets 6 bytes 16 drop
+ }
+}
+table ip t2 {
+ chain c2 {
+ counter packets 7 bytes 17 accept
+ counter packets 8 bytes 18 drop
+ }
+}
+EOF
+
+echo "resetting specific rule"
+handle=$($NFT -a list chain t c | sed -n 's/.*accept # handle \([0-9]*\)$/\1/p')
+$NFT reset rule t c handle $handle
+EXPECT='table ip t {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter
+ elements = { 1.1.1.1 counter packets 1 bytes 11 }
+ }
+
+ chain c {
+ counter packets 0 bytes 0 update @s { ip saddr } accept
+ counter packets 2 bytes 12 drop
+ }
+
+ chain c2 {
+ counter packets 3 bytes 13 accept
+ counter packets 4 bytes 14 drop
+ }
+}
+table inet t {
+ chain c {
+ counter packets 5 bytes 15 accept
+ counter packets 6 bytes 16 drop
+ }
+}
+table ip t2 {
+ chain c2 {
+ counter packets 7 bytes 17 accept
+ counter packets 8 bytes 18 drop
+ }
+}'
+$DIFF -u <(echo "$EXPECT") <($NFT list ruleset)
+
+echo "resetting specific chain"
+EXPECT='table ip t {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter
+ }
+
+ chain c2 {
+ counter packets 3 bytes 13 accept
+ counter packets 4 bytes 14 drop
+ }
+}'
+$DIFF -u <(echo "$EXPECT") <($NFT reset rules chain t c2)
+
+echo "resetting specific table"
+EXPECT='table ip t {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter
+ }
+
+ chain c {
+ counter packets 0 bytes 0 update @s { ip saddr } accept
+ counter packets 2 bytes 12 drop
+ }
+
+ chain c2 {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}'
+$DIFF -u <(echo "$EXPECT") <($NFT reset rules table t)
+
+echo "resetting specific family"
+EXPECT='table ip t {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter
+ }
+
+ chain c {
+ counter packets 0 bytes 0 update @s { ip saddr } accept
+ counter packets 0 bytes 0 drop
+ }
+
+ chain c2 {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}
+table ip t2 {
+ chain c2 {
+ counter packets 7 bytes 17 accept
+ counter packets 8 bytes 18 drop
+ }
+}'
+$DIFF -u <(echo "$EXPECT") <($NFT reset rules ip)
+
+echo "resetting whole ruleset"
+EXPECT='table ip t {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter
+ }
+
+ chain c {
+ counter packets 0 bytes 0 update @s { ip saddr } accept
+ counter packets 0 bytes 0 drop
+ }
+
+ chain c2 {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}
+table inet t {
+ chain c {
+ counter packets 5 bytes 15 accept
+ counter packets 6 bytes 16 drop
+ }
+}
+table ip t2 {
+ chain c2 {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}'
+$DIFF -u <(echo "$EXPECT") <($NFT reset rules)
diff --git a/tests/shell/testcases/rule_management/0012destroy_0 b/tests/shell/testcases/rule_management/0012destroy_0
new file mode 100755
index 00000000..a058150f
--- /dev/null
+++ b/tests/shell/testcases/rule_management/0012destroy_0
@@ -0,0 +1,14 @@
+#!/bin/bash -e
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_destroy)
+
+$NFT add table t
+$NFT add chain t c
+
+# pass for non-existent rule
+$NFT destroy rule t c handle 3333
+
+# successfully delete existing rule
+handle=$($NFT -a -e insert rule t c accept | \
+ sed -n 's/.*handle \([0-9]*\)$/\1/p')
+$NFT destroy rule t c handle "$handle"
diff --git a/tests/shell/testcases/rule_management/dumps/0001addinsertposition_0.json-nft b/tests/shell/testcases/rule_management/dumps/0001addinsertposition_0.json-nft
new file mode 100644
index 00000000..83dfee0d
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0001addinsertposition_0.json-nft
@@ -0,0 +1,65 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0001addinsertposition_0.nft b/tests/shell/testcases/rule_management/dumps/0001addinsertposition_0.nft
new file mode 100644
index 00000000..527d79d6
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0001addinsertposition_0.nft
@@ -0,0 +1,7 @@
+table ip t {
+ chain c {
+ drop
+ accept
+ accept
+ }
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0002addinsertlocation_1.json-nft b/tests/shell/testcases/rule_management/dumps/0002addinsertlocation_1.json-nft
new file mode 100644
index 00000000..b3808ce2
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0002addinsertlocation_1.json-nft
@@ -0,0 +1,52 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0002addinsertlocation_1.nft b/tests/shell/testcases/rule_management/dumps/0002addinsertlocation_1.nft
new file mode 100644
index 00000000..b76cd930
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0002addinsertlocation_1.nft
@@ -0,0 +1,6 @@
+table ip t {
+ chain c {
+ accept
+ accept
+ }
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0003insert_0.json-nft b/tests/shell/testcases/rule_management/dumps/0003insert_0.json-nft
new file mode 100644
index 00000000..9216cabf
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0003insert_0.json-nft
@@ -0,0 +1,102 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "sport"
+ }
+ },
+ "right": {
+ "set": [
+ {
+ "range": [
+ 3478,
+ 3497
+ ]
+ },
+ {
+ "range": [
+ 16384,
+ 16387
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "masquerade": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0003insert_0.nft b/tests/shell/testcases/rule_management/dumps/0003insert_0.nft
index 9421f4ae..b1875aba 100644
--- a/tests/shell/testcases/rule_management/dumps/0003insert_0.nft
+++ b/tests/shell/testcases/rule_management/dumps/0003insert_0.nft
@@ -1,5 +1,6 @@
table ip t {
chain c {
+ tcp sport { 3478-3497, 16384-16387 }
masquerade
drop
accept
diff --git a/tests/shell/testcases/rule_management/dumps/0004replace_0.json-nft b/tests/shell/testcases/rule_management/dumps/0004replace_0.json-nft
new file mode 100644
index 00000000..5d0b7d06
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0004replace_0.json-nft
@@ -0,0 +1,39 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0005replace_1.json-nft b/tests/shell/testcases/rule_management/dumps/0005replace_1.json-nft
new file mode 100644
index 00000000..db64cdbc
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0005replace_1.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0005replace_1.nft b/tests/shell/testcases/rule_management/dumps/0005replace_1.nft
new file mode 100644
index 00000000..1e0d1d60
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0005replace_1.nft
@@ -0,0 +1,4 @@
+table ip t {
+ chain c {
+ }
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0006replace_1.json-nft b/tests/shell/testcases/rule_management/dumps/0006replace_1.json-nft
new file mode 100644
index 00000000..db64cdbc
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0006replace_1.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0006replace_1.nft b/tests/shell/testcases/rule_management/dumps/0006replace_1.nft
new file mode 100644
index 00000000..1e0d1d60
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0006replace_1.nft
@@ -0,0 +1,4 @@
+table ip t {
+ chain c {
+ }
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0007delete_0.json-nft b/tests/shell/testcases/rule_management/dumps/0007delete_0.json-nft
new file mode 100644
index 00000000..5d0b7d06
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0007delete_0.json-nft
@@ -0,0 +1,39 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0008delete_1.json-nft b/tests/shell/testcases/rule_management/dumps/0008delete_1.json-nft
new file mode 100644
index 00000000..db64cdbc
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0008delete_1.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0008delete_1.nft b/tests/shell/testcases/rule_management/dumps/0008delete_1.nft
new file mode 100644
index 00000000..1e0d1d60
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0008delete_1.nft
@@ -0,0 +1,4 @@
+table ip t {
+ chain c {
+ }
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0009delete_1.json-nft b/tests/shell/testcases/rule_management/dumps/0009delete_1.json-nft
new file mode 100644
index 00000000..db64cdbc
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0009delete_1.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0009delete_1.nft b/tests/shell/testcases/rule_management/dumps/0009delete_1.nft
new file mode 100644
index 00000000..1e0d1d60
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0009delete_1.nft
@@ -0,0 +1,4 @@
+table ip t {
+ chain c {
+ }
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0010replace_0.json-nft b/tests/shell/testcases/rule_management/dumps/0010replace_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0010replace_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0010replace_0.nft b/tests/shell/testcases/rule_management/dumps/0010replace_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0010replace_0.nft
diff --git a/tests/shell/testcases/rule_management/dumps/0011reset_0.json-nft b/tests/shell/testcases/rule_management/dumps/0011reset_0.json-nft
new file mode 100644
index 00000000..bc242467
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0011reset_0.json-nft
@@ -0,0 +1,257 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c2",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "dynamic"
+ ],
+ "elem": [
+ {
+ "elem": {
+ "val": "1.1.1.1",
+ "counter": {
+ "packets": 1,
+ "bytes": 11
+ }
+ }
+ }
+ ],
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "set": {
+ "op": "update",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "set": "@s"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c2",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c2",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t2",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t2",
+ "name": "c2",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t2",
+ "chain": "c2",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t2",
+ "chain": "c2",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0011reset_0.nft b/tests/shell/testcases/rule_management/dumps/0011reset_0.nft
new file mode 100644
index 00000000..3b4f5a11
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0011reset_0.nft
@@ -0,0 +1,31 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter
+ elements = { 1.1.1.1 counter packets 1 bytes 11 }
+ }
+
+ chain c {
+ counter packets 0 bytes 0 update @s { ip saddr } accept
+ counter packets 0 bytes 0 drop
+ }
+
+ chain c2 {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}
+table inet t {
+ chain c {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}
+table ip t2 {
+ chain c2 {
+ counter packets 0 bytes 0 accept
+ counter packets 0 bytes 0 drop
+ }
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0012destroy_0.json-nft b/tests/shell/testcases/rule_management/dumps/0012destroy_0.json-nft
new file mode 100644
index 00000000..db64cdbc
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0012destroy_0.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/rule_management/dumps/0012destroy_0.nft b/tests/shell/testcases/rule_management/dumps/0012destroy_0.nft
new file mode 100644
index 00000000..1e0d1d60
--- /dev/null
+++ b/tests/shell/testcases/rule_management/dumps/0012destroy_0.nft
@@ -0,0 +1,4 @@
+table ip t {
+ chain c {
+ }
+}
diff --git a/tests/shell/testcases/sets/0011add_many_elements_0 b/tests/shell/testcases/sets/0011add_many_elements_0
index ba23f90f..c37b2f0d 100755
--- a/tests/shell/testcases/sets/0011add_many_elements_0
+++ b/tests/shell/testcases/sets/0011add_many_elements_0
@@ -3,6 +3,14 @@
# test adding many sets elements
HOWMANY=255
+if [ "$NFT_TEST_HAS_SOCKET_LIMITS" = y ] ; then
+ # The socket limit /proc/sys/net/core/wmem_max may be unsuitable for
+ # the test.
+ #
+ # Run only a subset of the test and mark as skipped at the end.
+ HOWMANY=30
+fi
+
tmpfile=$(mktemp)
if [ ! -w $tmpfile ] ; then
@@ -30,3 +38,10 @@ add element x y $(generate)" > $tmpfile
set -e
$NFT -f $tmpfile
+
+if [ "$HOWMANY" != 255 ] ; then
+ echo "NFT_TEST_HAS_SOCKET_LIMITS indicates that the socket limit for"
+ echo "/proc/sys/net/core/wmem_max is too small for this test. Mark as SKIPPED"
+ echo "You may bump the limit and rerun with \`NFT_TEST_HAS_SOCKET_LIMITS=n\`."
+ exit 77
+fi
diff --git a/tests/shell/testcases/sets/0012add_delete_many_elements_0 b/tests/shell/testcases/sets/0012add_delete_many_elements_0
index 7e7beebd..64451604 100755
--- a/tests/shell/testcases/sets/0012add_delete_many_elements_0
+++ b/tests/shell/testcases/sets/0012add_delete_many_elements_0
@@ -3,6 +3,13 @@
# test adding and deleting many sets elements
HOWMANY=255
+if [ "$NFT_TEST_HAS_SOCKET_LIMITS" = y ] ; then
+ # The socket limit /proc/sys/net/core/wmem_max may be unsuitable for
+ # the test.
+ #
+ # Run only a subset of the test and mark as skipped at the end.
+ HOWMANY=30
+fi
tmpfile=$(mktemp)
if [ ! -w $tmpfile ] ; then
@@ -31,3 +38,10 @@ delete element x y $(generate)" > $tmpfile
set -e
$NFT -f $tmpfile
+
+if [ "$HOWMANY" != 255 ] ; then
+ echo "NFT_TEST_HAS_SOCKET_LIMITS indicates that the socket limit for"
+ echo "/proc/sys/net/core/wmem_max is too small for this test. Mark as SKIPPED"
+ echo "You may bump the limit and rerun with \`NFT_TEST_HAS_SOCKET_LIMITS=n\`."
+ exit 77
+fi
diff --git a/tests/shell/testcases/sets/0013add_delete_many_elements_0 b/tests/shell/testcases/sets/0013add_delete_many_elements_0
index 5774317b..c0925dd5 100755
--- a/tests/shell/testcases/sets/0013add_delete_many_elements_0
+++ b/tests/shell/testcases/sets/0013add_delete_many_elements_0
@@ -3,6 +3,13 @@
# test adding and deleting many sets elements in two nft -f runs.
HOWMANY=255
+if [ "$NFT_TEST_HAS_SOCKET_LIMITS" = y ] ; then
+ # The socket limit /proc/sys/net/core/wmem_max may be unsuitable for
+ # the test.
+ #
+ # Run only a subset of the test and mark as skipped at the end.
+ HOWMANY=30
+fi
tmpfile=$(mktemp)
if [ ! -w $tmpfile ] ; then
@@ -32,3 +39,10 @@ add element x y $(generate)" > $tmpfile
$NFT -f $tmpfile
echo "delete element x y $(generate)" > $tmpfile
$NFT -f $tmpfile
+
+if [ "$HOWMANY" != 255 ] ; then
+ echo "NFT_TEST_HAS_SOCKET_LIMITS indicates that the socket limit for"
+ echo "/proc/sys/net/core/wmem_max is too small for this test. Mark as SKIPPED"
+ echo "You may bump the limit and rerun with \`NFT_TEST_HAS_SOCKET_LIMITS=n\`."
+ exit 77
+fi
diff --git a/tests/shell/testcases/sets/0020comments_0 b/tests/shell/testcases/sets/0020comments_0
index 44d451a8..1df38326 100755
--- a/tests/shell/testcases/sets/0020comments_0
+++ b/tests/shell/testcases/sets/0020comments_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_comment)
+
# Test that comments are added to set elements in standard sets.
# Explicitly test bitmap backend set implementation.
diff --git a/tests/shell/testcases/sets/0022type_selective_flush_0 b/tests/shell/testcases/sets/0022type_selective_flush_0
index 6062913b..48f6875b 100755
--- a/tests/shell/testcases/sets/0022type_selective_flush_0
+++ b/tests/shell/testcases/sets/0022type_selective_flush_0
@@ -16,7 +16,7 @@ $NFT -f - <<< "$RULESET"
# Commands that should be invalid
declare -a cmds=(
- "flush set t m" "flush set t f"
+ "flush set t m"
"flush map t s" "flush map t f"
"flush meter t s" "flush meter t m"
)
diff --git a/tests/shell/testcases/sets/0024synproxy_0 b/tests/shell/testcases/sets/0024synproxy_0
new file mode 100755
index 00000000..0c7da572
--- /dev/null
+++ b/tests/shell/testcases/sets/0024synproxy_0
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_synproxy)
+
+# * creating valid named objects
+# * referencing them from a valid rule
+
+RULESET="
+table inet x {
+ synproxy https-synproxy {
+ mss 1460
+ wscale 7
+ timestamp sack-perm
+ }
+ synproxy other-synproxy {
+ mss 1460
+ wscale 5
+ }
+ map test2 {
+ type ipv4_addr : synproxy
+ flags interval
+ elements = { 192.168.1.0/24 : "https-synproxy", 192.168.2.0/24 : "other-synproxy" }
+ }
+ chain y {
+ type filter hook input priority 0; policy accept;
+ synproxy name ip saddr map { 192.168.1.0/24 : "https-synproxy", 192.168.2.0/24 : "other-synproxy" }
+ }
+}"
+
+set -e
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/sets/0025anonymous_set_0 b/tests/shell/testcases/sets/0025anonymous_set_0
index 93a7c022..74777d8e 100755
--- a/tests/shell/testcases/sets/0025anonymous_set_0
+++ b/tests/shell/testcases/sets/0025anonymous_set_0
@@ -14,4 +14,4 @@ $NFT add rule t c ip daddr { \
}
#set : tcp ports
-$NFT add rule t c tcp dport { 22, 23 } counter
+$NFT add rule t c meta oifname \"doesntexist\" tcp dport { 22, 23 } counter
diff --git a/tests/shell/testcases/sets/0028delete_handle_0 b/tests/shell/testcases/sets/0028delete_handle_0
index 4e8b3228..c6d12534 100755
--- a/tests/shell/testcases/sets/0028delete_handle_0
+++ b/tests/shell/testcases/sets/0028delete_handle_0
@@ -7,7 +7,7 @@ $NFT add set test-ip y { type inet_service \; timeout 3h45s \;}
$NFT add set test-ip z { type ipv4_addr\; flags constant , interval\;}
$NFT add set test-ip c {type ipv4_addr \; flags timeout \; elements={192.168.1.1 timeout 10s, 192.168.1.2 timeout 30s} \;}
-set_handle=$($NFT list ruleset -a | awk '/set c/{print $NF}')
+set_handle=$($NFT -a list ruleset | awk '/set c/{print $NF}')
$NFT delete set test-ip handle $set_handle
EXPECTED="table ip test-ip {
@@ -29,7 +29,6 @@ EXPECTED="table ip test-ip {
GET="$($NFT list ruleset)"
if [ "$EXPECTED" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
+ $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/sets/0029named_ifname_dtype_0 b/tests/shell/testcases/sets/0029named_ifname_dtype_0
index 39b3c90c..2dbcd22b 100755
--- a/tests/shell/testcases/sets/0029named_ifname_dtype_0
+++ b/tests/shell/testcases/sets/0029named_ifname_dtype_0
@@ -13,12 +13,53 @@ EXPECTED="table inet t {
elements = { \"ssh\" . \"eth0\" }
}
+ set nv {
+ type ifname . mark
+ }
+
+ set z {
+ typeof ct zone
+ elements = { 1 }
+ }
+
+ set m {
+ typeof meta mark
+ elements = { 1 }
+ }
+
+ map cz {
+ typeof meta iifname : ct zone
+ elements = { \"veth4\" : 1 }
+ }
+
+ map cm {
+ typeof meta iifname : ct mark
+ elements = { \"veth4\" : 1 }
+ }
+
chain c {
iifname @s accept
oifname @s accept
tcp dport . meta iifname @sc accept
+ meta iifname . meta mark @nv accept
}
}"
set -e
$NFT -f - <<< "$EXPECTED"
+$NFT add element inet t s '{ "eth1" }'
+$NFT add element inet t s '{ "eth2", "eth3", "veth1" }'
+
+$NFT add element inet t sc '{ 80 . "eth0" }'
+$NFT add element inet t sc '{ 80 . "eth0" }' || true
+$NFT add element inet t sc '{ 80 . "eth1" }'
+$NFT add element inet t sc '{ 81 . "eth0" }'
+
+$NFT add element inet t nv '{ "eth0" . 1 }'
+$NFT add element inet t nv '{ "eth0" . 2 }'
+
+$NFT add element inet t z '{ 2, 3, 4, 5, 6 }'
+$NFT add element inet t cz '{ "eth0" : 1, "eth1" : 2 }'
+
+$NFT add element inet t m '{ 2, 3, 4, 5, 6 }'
+$NFT add element inet t cm '{ "eth0" : 1, "eth1" : 2 }'
diff --git a/tests/shell/testcases/sets/0030add_many_elements_interval_0 b/tests/shell/testcases/sets/0030add_many_elements_interval_0
index 059ade9a..32a705bf 100755
--- a/tests/shell/testcases/sets/0030add_many_elements_interval_0
+++ b/tests/shell/testcases/sets/0030add_many_elements_interval_0
@@ -1,6 +1,13 @@
#!/bin/bash
HOWMANY=255
+if [ "$NFT_TEST_HAS_SOCKET_LIMITS" = y ] ; then
+ # The socket limit /proc/sys/net/core/wmem_max may be unsuitable for
+ # the test.
+ #
+ # Run only a subset of the test and mark as skipped at the end.
+ HOWMANY=30
+fi
tmpfile=$(mktemp)
if [ ! -w $tmpfile ] ; then
@@ -28,3 +35,10 @@ add element x y $(generate)" > $tmpfile
set -e
$NFT -f $tmpfile
+
+if [ "$HOWMANY" != 255 ] ; then
+ echo "NFT_TEST_HAS_SOCKET_LIMITS indicates that the socket limit for"
+ echo "/proc/sys/net/core/wmem_max is too small for this test. Mark as SKIPPED"
+ echo "You may bump the limit and rerun with \`NFT_TEST_HAS_SOCKET_LIMITS=n\`."
+ exit 77
+fi
diff --git a/tests/shell/testcases/sets/0031set_timeout_size_0 b/tests/shell/testcases/sets/0031set_timeout_size_0
index 9edd5f6f..9a4a27f6 100755
--- a/tests/shell/testcases/sets/0031set_timeout_size_0
+++ b/tests/shell/testcases/sets/0031set_timeout_size_0
@@ -3,10 +3,10 @@
RULESET="add table x
add set x y { type ipv4_addr; size 128; timeout 30s; flags dynamic; }
add chain x test
-add rule x test set update ip saddr timeout 1d2h3m4s8ms @y
+add rule x test set update ip saddr timeout 1d2h3m4s10ms @y
add rule x test set update ip daddr timeout 100ms @y"
set -e
$NFT -f - <<< "$RULESET"
-$NFT list chain x test | grep -q 'update @y { ip saddr timeout 1d2h3m4s8ms }'
+$NFT list chain x test | grep -q 'update @y { ip saddr timeout 1d2h3m4s\(10\|8\)ms }'
$NFT list chain x test | grep -q 'update @y { ip daddr timeout 100ms }'
diff --git a/tests/shell/testcases/sets/0034get_element_0 b/tests/shell/testcases/sets/0034get_element_0
index c7e7298a..32375b9f 100755
--- a/tests/shell/testcases/sets/0034get_element_0
+++ b/tests/shell/testcases/sets/0034get_element_0
@@ -1,44 +1,72 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
RC=0
-check() { # (elems, expected)
- out=$($NFT get element ip t s "{ $1 }" 2>/dev/null)
+check() { # (set, elems, expected)
+ out=$($NFT get element ip t $1 "{ $2 }")
out=$(grep "elements =" <<< "$out")
out="${out#* \{ }"
out="${out% \}}"
- [[ "$out" == "$2" ]] && return
- echo "ERROR: asked for '$1', expecting '$2' but got '$out'"
+ [[ "$out" == "$3" ]] && return
+ echo "ERROR: asked for '$2' in set $1, expecting '$3' but got '$out'"
((RC++))
}
RULESET="add table ip t
add set ip t s { type inet_service; flags interval; }
add element ip t s { 10, 20-30, 40, 50-60 }
+add set ip t ips { type ipv4_addr; flags interval; }
+add element ip t ips { 10.0.0.1, 10.0.0.5-10.0.0.8 }
+add element ip t ips { 10.0.0.128/25, 10.0.1.0/24, 10.0.2.3-10.0.2.12 }
+add set ip t cs { type ipv4_addr . inet_service; flags interval; }
+add element ip t cs { 10.0.0.1 . 22, 10.1.0.0/16 . 1-1024 }
+add element ip t cs { 10.2.0.1-10.2.0.8 . 1024-65535 }
"
$NFT -f - <<< "$RULESET"
# simple cases, (non-)existing values and ranges
-check 10 10
-check 11 ""
-check 20-30 20-30
-check 15-18 ""
+check s 10 10
+check s 11 ""
+check s 20-30 20-30
+check s 15-18 ""
# multiple single elements, ranges smaller than present
-check "10, 40" "10, 40"
-check "22-24, 26-28" "20-30, 20-30"
-check 21-29 20-30
+check s "10, 40" "10, 40"
+check s "22-24, 26-28" "20-30, 20-30"
+check s 21-29 20-30
# mixed single elements and ranges
-check "10, 20" "10, 20-30"
-check "10, 22" "10, 20-30"
-check "10, 22-24" "10, 20-30"
+check s "10, 20" "10, 20-30"
+check s "10, 22" "10, 20-30"
+check s "10, 22-24" "10, 20-30"
# non-existing ranges matching elements
-check 10-40 ""
-check 10-20 ""
-check 10-25 ""
-check 25-55 ""
+check s 10-40 ""
+check s 10-20 ""
+check s 10-25 ""
+check s 25-55 ""
+
+# playing with IPs, ranges and prefixes
+check ips 10.0.0.1 10.0.0.1
+check ips 10.0.0.2 ""
+check ips 10.0.1.0/24 10.0.1.0/24
+check ips 10.0.1.2/31 10.0.1.0/24
+check ips 10.0.1.0 10.0.1.0/24
+check ips 10.0.1.3 10.0.1.0/24
+check ips 10.0.1.255 10.0.1.0/24
+check ips 10.0.2.3-10.0.2.12 10.0.2.3-10.0.2.12
+check ips 10.0.2.10 10.0.2.3-10.0.2.12
+check ips 10.0.2.12 10.0.2.3-10.0.2.12
+
+# test concatenated ranges, i.e. Pi, Pa and Po
+check cs "10.0.0.1 . 22" "10.0.0.1 . 22"
+check cs "10.0.0.1 . 23" ""
+check cs "10.0.0.2 . 22" ""
+check cs "10.1.0.1 . 42" "10.1.0.0/16 . 1-1024"
+check cs "10.1.1.0/24 . 10-20" "10.1.0.0/16 . 1-1024"
+check cs "10.2.0.3 . 20000" "10.2.0.1-10.2.0.8 . 1024-65535"
exit $RC
diff --git a/tests/shell/testcases/sets/0036add_set_element_expiration_0 b/tests/shell/testcases/sets/0036add_set_element_expiration_0
index 8dfed6c1..d961ffd4 100755
--- a/tests/shell/testcases/sets/0036add_set_element_expiration_0
+++ b/tests/shell/testcases/sets/0036add_set_element_expiration_0
@@ -1,13 +1,26 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_setelem_expiration)
+
set -e
+drop_seconds() {
+ sed -E 's/m[0-9]*s([0-9]*ms)?/m/g'
+}
+
RULESET="add table ip x
+add set ip x y { type ipv4_addr; flags dynamic,timeout; }
+add element ip x y { 1.1.1.1 timeout 30m expires 15m59s }"
+
+EXPECTED="add table ip x
add set ip x y { type ipv4_addr; flags dynamic,timeout; }
-add element ip x y { 1.1.1.1 timeout 30s expires 15s }"
+add element ip x y { 1.1.1.1 timeout 30m expires 15m }"
-test_output=$($NFT -e -f - <<< "$RULESET" 2>&1)
+test_output=$($NFT -e -f - <<< "$RULESET" 2>&1 | grep -v '# new generation' | drop_seconds)
-diff -u <(echo "$test_output") <(echo "$RULESET")
+if [ "$test_output" != "$EXPECTED" ] ; then
+ $DIFF -u <(echo "$test_output") <(echo "$EXPECTED")
+ exit 1
+fi
$NFT "add chain ip x c; add rule ip x c ip saddr @y"
diff --git a/tests/shell/testcases/sets/0038meter_list_0 b/tests/shell/testcases/sets/0038meter_list_0
new file mode 100755
index 00000000..7c37c1d8
--- /dev/null
+++ b/tests/shell/testcases/sets/0038meter_list_0
@@ -0,0 +1,34 @@
+#!/bin/bash
+
+#
+# Listing meters should not include dynamic sets in the output
+#
+
+set -e
+
+RULESET="
+ add table t
+ add set t s { type ipv4_addr; size 256; flags dynamic,timeout; }
+ add chain t c
+ add rule t c tcp dport 80 meter m size 128 { ip saddr limit rate 10/second }
+"
+
+expected_output="table ip t {
+ set s {
+ type ipv4_addr
+ size 256
+ flags dynamic,timeout
+ }
+ set m {
+ type ipv4_addr
+ size 128
+ flags dynamic
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+
+test_output=$($NFT list meters)
+
+test "$test_output" = "$expected_output"
+
diff --git a/tests/shell/testcases/sets/0039delete_interval_0 b/tests/shell/testcases/sets/0039delete_interval_0
new file mode 100755
index 00000000..19df16ec
--- /dev/null
+++ b/tests/shell/testcases/sets/0039delete_interval_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+# Make sure nft allows to delete existing ranges only
+
+RULESET="
+table t {
+ set s {
+ type ipv4_addr
+ flags interval
+ elements = { 192.168.1.0-192.168.1.254, 192.168.1.255 }
+ }
+}"
+
+$NFT -f - <<< "$RULESET" || { echo "E: Can't load basic ruleset" 1>&2; exit 1; }
+
+$NFT delete element t s '{ 192.168.1.0/24 }' 2>/dev/null || exit 0
+echo "E: Deletion of non-existing range allowed" 1>&2
diff --git a/tests/shell/testcases/sets/0040get_host_endian_elements_0 b/tests/shell/testcases/sets/0040get_host_endian_elements_0
new file mode 100755
index 00000000..caf6a4af
--- /dev/null
+++ b/tests/shell/testcases/sets/0040get_host_endian_elements_0
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+RULESET="table ip t {
+ set s {
+ type mark
+ flags interval
+ elements = {
+ 0x23-0x42, 0x1337
+ }
+ }
+}"
+
+$NFT -f - <<< "$RULESET" || { echo "can't apply basic ruleset"; exit 1; }
+
+$NFT get element ip t s '{ 0x23-0x42 }' || {
+ echo "can't find existing range 0x23-0x42"
+ exit 1
+}
+
+$NFT get element ip t s '{ 0x26-0x28 }' || {
+ echo "can't find existing sub-range 0x26-0x28"
+ exit 1
+}
+
+$NFT get element ip t s '{ 0x26-0x99 }' && {
+ echo "found non-existing range 0x26-0x99"
+ exit 1
+}
+
+$NFT get element ip t s '{ 0x55-0x99 }' && {
+ echo "found non-existing range 0x55-0x99"
+ exit 1
+}
+
+$NFT get element ip t s '{ 0x55 }' && {
+ echo "found non-existing element 0x55"
+ exit 1
+}
+
+$NFT get element ip t s '{ 0x1337 }' || {
+ echo "can't find existing element 0x1337"
+ exit 1
+}
diff --git a/tests/shell/testcases/sets/0041interval_0 b/tests/shell/testcases/sets/0041interval_0
new file mode 100755
index 00000000..42fc6ccf
--- /dev/null
+++ b/tests/shell/testcases/sets/0041interval_0
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+set -e
+
+RULESET="
+table ip t {
+ set s {
+ type ipv4_addr
+ flags interval
+ elements = { 192.168.2.195, 192.168.2.196,
+ 192.168.2.197, 192.168.2.198 }
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
+
+$NFT 'delete element t s { 192.168.2.195, 192.168.2.196 }; add element t s { 192.168.2.196 }' 2>/dev/null
+$NFT get element t s { 192.168.2.196, 192.168.2.197, 192.168.2.198 } 1>/dev/null
+$NFT 'delete element t s { 192.168.2.196, 192.168.2.197 }; add element t s { 192.168.2.197 }' 2>/dev/null
+$NFT get element t s { 192.168.2.197, 192.168.2.198 } 1>/dev/null
+$NFT 'delete element t s { 192.168.2.198, 192.168.2.197 }; add element t s { 192.168.2.196, 192.168.2.197, 192.168.2.195 }' 1>/dev/null
+$NFT get element t s { 192.168.2.196, 192.168.2.197, 192.168.2.195 } 1>/dev/null
+$NFT delete element t s { 192.168.2.196, 192.168.2.197, 192.168.2.195 } 2>/dev/null
+$NFT create element t s { 192.168.2.196} 2>/dev/null
+$NFT get element t s { 192.168.2.196 } 1>/dev/null
diff --git a/tests/shell/testcases/sets/0042update_set_0 b/tests/shell/testcases/sets/0042update_set_0
new file mode 100755
index 00000000..a8e9e05f
--- /dev/null
+++ b/tests/shell/testcases/sets/0042update_set_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip t {
+ set set1 {
+ type ether_addr
+ }
+
+ set set2 {
+ type ether_addr
+ size 65535
+ flags dynamic
+ }
+
+ chain c {
+ ether daddr @set1 add @set2 { ether daddr counter }
+ }
+}"
+
+$NFT -f - <<< "$RULESET" || { echo "can't apply basic ruleset"; exit 1; }
diff --git a/tests/shell/testcases/sets/0043concatenated_ranges_0 b/tests/shell/testcases/sets/0043concatenated_ranges_0
new file mode 100755
index 00000000..a3dbf5bf
--- /dev/null
+++ b/tests/shell/testcases/sets/0043concatenated_ranges_0
@@ -0,0 +1,195 @@
+#!/bin/bash -e
+#
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+#
+# 0043concatenated_ranges_0 - Add, get, list, timeout for concatenated ranges
+#
+# Cycle over supported data types, forming concatenations of three fields, for
+# all possible permutations, and:
+# - add entries to set
+# - list them
+# - get entries by specifying a value matching ranges for all fields
+# - delete them
+# - check that they can't be deleted again
+# - add them with 1s timeout
+# - check that they are not listed after 1s, just once, for the first entry
+# - delete them
+# - make sure they can't be deleted again
+
+TYPES="ipv4_addr ipv6_addr ether_addr inet_proto inet_service mark"
+
+RULESPEC_ipv4_addr="ip saddr"
+ELEMS_ipv4_addr="192.0.2.1 198.51.100.0/25 203.0.113.0-203.0.113.129"
+ADD_ipv4_addr="192.0.2.252/31"
+GET_ipv4_addr="198.51.100.127 198.51.100.0/25"
+
+RULESPEC_ipv6_addr="ip6 daddr"
+ELEMS_ipv6_addr="2001:db8:c0c:c0de::1-2001:db8:cacc::a 2001:db8::1 2001:db8:dada:da::/64"
+ADD_ipv6_addr="2001:db8::d1ca:d1ca"
+GET_ipv6_addr="2001:db8::1 2001:db8::1"
+
+RULESPEC_ether_addr="ether saddr"
+ELEMS_ether_addr="00:0a:c1:d1:f1:ed-00:0a:c1:dd:ec:af 00:0b:0c:ca:cc:10-c1:a0:c1:cc:10:00 f0:ca:cc:1a:b0:1a"
+ADD_ether_addr="00:be:1d:ed:ab:e1"
+GET_ether_addr="ac:c1:ac:c0:ce:c0 00:0b:0c:ca:cc:10-c1:a0:c1:cc:10:00"
+
+RULESPEC_inet_proto="meta l4proto"
+ELEMS_inet_proto="tcp udp icmp"
+ADD_inet_proto="sctp"
+GET_inet_proto="udp udp"
+
+RULESPEC_inet_service="tcp dport"
+ELEMS_inet_service="22-23 1024-32768 31337"
+ADD_inet_service="32769-65535"
+GET_inet_service="32768 1024-32768"
+
+RULESPEC_mark="mark"
+ELEMS_mark="0x00000064-0x000000c8 0x0000006f 0x0000fffd-0x0000ffff"
+ADD_mark="0x0000002a"
+GET_mark="0x0000006f 0x0000006f"
+
+tmp="$(mktemp)"
+trap "rm -f ${tmp}" EXIT
+
+render() {
+ eval "echo \"$(cat ${1})\""
+}
+
+cat <<'EOF' > "${tmp}"
+flush ruleset
+
+table inet filter {
+ ${setmap} test {
+ type ${ta} . ${tb} . ${tc} ${mapt}
+ flags interval,timeout
+ elements = { ${a1} . ${b1} . ${c1} ${mapv},
+ ${a2} . ${b2} . ${c2} ${mapv},
+ ${a3} . ${b3} . ${c3} ${mapv}, }
+ }
+
+ chain output {
+ type filter hook output priority 0; policy accept;
+ ${rule} @test counter
+ }
+}
+EOF
+
+timeout_tested=0
+run_test()
+{
+setmap="$1"
+for ta in ${TYPES}; do
+ eval a=\$ELEMS_${ta}
+ a1=${a%% *}; a2=$(expr "$a" : ".* \(.*\) .*"); a3=${a##* }
+ eval sa=\$RULESPEC_${ta}
+
+ mark=0
+ for tb in ${TYPES}; do
+ [ "${tb}" = "${ta}" ] && continue
+ if [ "${tb}" = "ipv6_addr" ]; then
+ [ "${ta}" = "ipv4_addr" ] && continue
+ elif [ "${tb}" = "ipv4_addr" ]; then
+ [ "${ta}" = "ipv6_addr" ] && continue
+ fi
+
+ eval b=\$ELEMS_${tb}
+ b1=${b%% *}; b2=$(expr "$b" : ".* \(.*\) .*"); b3=${b##* }
+ eval sb=\$RULESPEC_${tb}
+
+ for tc in ${TYPES}; do
+ [ "${tc}" = "${ta}" ] && continue
+ [ "${tc}" = "${tb}" ] && continue
+ if [ "${tc}" = "ipv6_addr" ]; then
+ [ "${ta}" = "ipv4_addr" ] && continue
+ [ "${tb}" = "ipv4_addr" ] && continue
+ elif [ "${tc}" = "ipv4_addr" ]; then
+ [ "${ta}" = "ipv6_addr" ] && continue
+ [ "${tb}" = "ipv6_addr" ] && continue
+ fi
+
+ echo "$setmap TYPE: ${ta} ${tb} ${tc}"
+
+ eval c=\$ELEMS_${tc}
+ c1=${c%% *}; c2=$(expr "$c" : ".* \(.*\) .*"); c3=${c##* }
+ eval sc=\$RULESPEC_${tc}
+
+ case "${setmap}" in
+ "set")
+ mapt=""
+ mapv=""
+ rule="${sa} . ${sb} . ${sc}"
+ ;;
+ "map")
+ mapt=": mark"
+ mark=42
+ mapv=$(printf " : 0x%08x" ${mark})
+ rule="meta mark set ${sa} . ${sb} . ${sc} map"
+ ;;
+ esac
+
+ render ${tmp} | ${NFT} -f -
+
+ [ $(${NFT} list ${setmap} inet filter test | \
+ grep -c -e "${a1} . ${b1} . ${c1}${mapv}" \
+ -e "${a2} . ${b2} . ${c2}${mapv}" \
+ -e "${a3} . ${b3} . ${c3}${mapv}") -eq 3 ]
+
+ ${NFT} delete element inet filter test \
+ "{ ${a1} . ${b1} . ${c1}${mapv} }"
+ ${NFT} delete element inet filter test \
+ "{ ${a1} . ${b1} . ${c1}${mapv} }" \
+ 2>/dev/null && exit 1
+
+ eval add_a=\$ADD_${ta}
+ eval add_b=\$ADD_${tb}
+ eval add_c=\$ADD_${tc}
+ ${NFT} add element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} timeout 2m${mapv}}"
+ [ $(${NFT} list ${setmap} inet filter test | \
+ grep -c "${add_a} . ${add_b} . ${add_c}") -eq 1 ]
+
+ eval get_a=\$GET_${ta}
+ eval get_b=\$GET_${tb}
+ eval get_c=\$GET_${tc}
+ exp_a=${get_a##* }; get_a=${get_a%% *}
+ exp_b=${get_b##* }; get_b=${get_b%% *}
+ exp_c=${get_c##* }; get_c=${get_c%% *}
+ [ $(${NFT} get element inet filter test \
+ "{ ${get_a} . ${get_b} . ${get_c}${mapv} }" | \
+ grep -c "${exp_a} . ${exp_b} . ${exp_c}") -eq 1 ]
+
+ ${NFT} "delete element inet filter test \
+ { ${a2} . ${b2} . ${c2}${mapv} };
+ delete element inet filter test \
+ { ${a3} . ${b3} . ${c3}${mapv} }"
+ ${NFT} "delete element inet filter test \
+ { ${a2} . ${b2} . ${c2}${mapv} };
+ delete element inet filter test \
+ { ${a3} . ${b3} . ${c3} ${mapv} }" \
+ 2>/dev/null && exit 1
+
+ if [ ${timeout_tested} -eq 1 ]; then
+ ${NFT} delete element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} ${mapv} }"
+ ${NFT} delete element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} ${mapv} }" \
+ 2>/dev/null && exit 1
+ continue
+ fi
+
+ ${NFT} delete element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} ${mapv}}"
+ ${NFT} add element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} timeout 1s${mapv}}"
+ sleep 1
+ [ $(${NFT} list ${setmap} inet filter test | \
+ grep -c "${add_a} . ${add_b} . ${add_c} ${mapv}") -eq 0 ]
+ timeout_tested=1
+ done
+ done
+done
+}
+
+run_test "set"
+run_test "map"
diff --git a/tests/shell/testcases/sets/0043concatenated_ranges_1 b/tests/shell/testcases/sets/0043concatenated_ranges_1
new file mode 100755
index 00000000..bb3bf6b2
--- /dev/null
+++ b/tests/shell/testcases/sets/0043concatenated_ranges_1
@@ -0,0 +1,25 @@
+#!/bin/bash -e
+#
+# 0043concatenated_ranges_1 - Insert and list subnets of different sizes
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+check() {
+ $NFT add element "${1}" t s "{ ${2} . ${3} }"
+ [ "$( $NFT list set "${1}" t s | grep -c "${2} . ${3}" )" = 1 ]
+}
+
+$NFT add table ip6 t
+$NFT add table ip t
+
+$NFT add set ip6 t s '{ type ipv6_addr . ipv6_addr ; flags interval ; }'
+$NFT add set ip t s '{ type ipv4_addr . ipv4_addr ; flags interval ; }'
+
+for n in $(seq 32 127); do
+ h="$(printf %x "${n}")"
+ check ip6 "2001:db8::/${n}" "2001:db8:${h}::-2001:db8:${h}::${h}:1"
+done
+
+for n in $(seq 24 31); do
+ check ip "192.0.2.0/${n}" "192.0.2.$((n * 3))-192.0.2.$((n * 3 + 2))"
+done
diff --git a/tests/shell/testcases/sets/0044interval_overlap_0 b/tests/shell/testcases/sets/0044interval_overlap_0
new file mode 100755
index 00000000..b0f51cc8
--- /dev/null
+++ b/tests/shell/testcases/sets/0044interval_overlap_0
@@ -0,0 +1,174 @@
+#!/bin/bash -e
+#
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+#
+# 0044interval_overlap_0 - Add overlapping and non-overlapping intervals
+#
+# Check that adding overlapping intervals to a set returns an error, unless:
+# - the inserted element overlaps entirely, that is, it's identical to an
+# existing one
+# - for concatenated ranges, the new element is less specific than any existing
+# overlapping element, as elements are evaluated in order of insertion
+#
+# Then, repeat the test with a set configured with a timeout, checking that:
+# - we can insert all the elements as described above
+# - once the timeout has expired, we can insert all the elements again, and old
+# elements are not present
+# - before the timeout expires again, we can re-add elements that are not
+# expected to fail, but old elements might be present
+#
+# If $NFT points to a libtool wrapper, and we're running on a slow machine or
+# kernel (e.g. KASan enabled), it might not be possible to execute hundreds of
+# commands within an otherwise reasonable 1 second timeout. Estimate a usable
+# timeout first, by counting commands and measuring against one nft rule timeout
+# itself, so that we can keep this fast for a binary $NFT on a reasonably fast
+# kernel.
+
+# Accept Interval List
+intervals_simple="
+ y 0 - 2 0-2
+ y 0 - 2 0-2
+ n 0 - 1 0-2
+ n 0 - 3 0-2
+ y 3 - 10 0-2, 3-10
+ n 3 - 9 0-2, 3-10
+ n 4 - 10 0-2, 3-10
+ n 4 - 9 0-2, 3-10
+ y 20 - 30 0-2, 3-10, 20-30
+ y 11 - 12 0-2, 3-10, 11-12, 20-30
+ y 13 - 19 0-2, 3-10, 11-12, 13-19, 20-30
+ n 25 - 40 0-2, 3-10, 11-12, 13-19, 20-30
+ y 50 - 60 0-2, 3-10, 11-12, 13-19, 20-30, 50-60
+ y 31 - 49 0-2, 3-10, 11-12, 13-19, 20-30, 31-49, 50-60
+ n 59 - 60 0-2, 3-10, 11-12, 13-19, 20-30, 31-49, 50-60
+"
+
+intervals_concat="
+ y 0-2 . 0-3 0-2 . 0-3
+ y 0-2 . 0-3 0-2 . 0-3
+ n 0-1 . 0-2 0-2 . 0-3
+ y 10-20 . 30-40 0-2 . 0-3, 10-20 . 30-40
+ y 15-20 . 50-60 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60
+ y 3-9 . 4-29 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29
+ y 3-9 . 4-29 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29
+ n 11-19 . 30-40 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29
+ y 15-20 . 49-61 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29, 15-20 . 49-61
+"
+
+count_elements() {
+ pass=
+ interval=
+ elements=0
+ for t in ${intervals_simple} ${intervals_concat}; do
+ [ -z "${pass}" ] && pass="${t}" && continue
+ [ -z "${interval}" ] && interval="${t}" && continue
+ unset IFS
+
+ elements=$((elements + 1))
+
+ IFS='
+'
+ done
+ unset IFS
+}
+
+match_elements() {
+ skip=0
+ n=0
+ out=
+ for a in $($NFT list set t ${1})}; do
+ [ ${n} -eq 0 ] && { [ "${a}" = "elements" ] && n=1; continue; }
+ [ ${n} -eq 1 ] && { [ "${a}" = "=" ] && n=2; continue; }
+ [ ${n} -eq 2 ] && { [ "${a}" = "{" ] && n=3; continue; }
+
+ [ "${a}" = "}" ] && break
+
+ [ ${skip} -eq 1 ] && skip=0 && out="${out}," && continue
+ [ "${a}" = "expires" ] && skip=1 && continue
+
+ [ -n "${out}" ] && out="${out} ${a}" || out="${a}"
+
+ done
+
+ if [ "${out%,}" != "${2}" ]; then
+ echo "Expected: ${2}, got: ${out%,}"
+ return 1
+ fi
+}
+
+estimate_timeout() {
+ count_elements
+
+ $NFT add table t
+ $NFT add set t s '{ type inet_service ; flags timeout; timeout 1s; gc-interval 1s; }'
+ execs_1s=1
+ $NFT add element t s "{ 0 }"
+ while match_elements s "0" >/dev/null; do
+ execs_1s=$((execs_1s + 1))
+ done
+
+ timeout="$((elements / execs_1s * 3 / 2 + 1))"
+}
+
+add_elements() {
+ set="s"
+ pass=
+ interval=
+ IFS='
+'
+ for t in ${intervals_simple} switch ${intervals_concat}; do
+if [ "$NFT_TEST_HAVE_pipapo" = y ] ; then
+ [ "${t}" = "switch" ] && set="c" && continue
+else
+ break
+fi
+ [ -z "${pass}" ] && pass="${t}" && continue
+ [ -z "${interval}" ] && interval="${t}" && continue
+ unset IFS
+
+ if [ "${pass}" = "y" ]; then
+ if ! $NFT add element t ${set} "{ ${interval} }"; then
+ echo "Failed to insert ${interval} given:"
+ $NFT list ruleset
+ exit 1
+ fi
+ else
+ if $NFT add element t ${set} "{ ${interval} }" 2>/dev/null; then
+ echo "Could insert ${interval} given:"
+ $NFT list ruleset
+ exit 1
+ fi
+ fi
+
+ [ "${1}" != "nomatch" ] && match_elements "${set}" "${t}"
+
+ pass=
+ interval=
+ IFS='
+'
+ done
+ unset IFS
+}
+
+$NFT add table t
+$NFT add set t s '{ type inet_service ; flags interval ; }'
+if [ "$NFT_TEST_HAVE_pipapo" = y ] ; then
+ $NFT add set t c '{ type inet_service . inet_service ; flags interval ; }'
+fi
+add_elements
+
+$NFT flush ruleset
+estimate_timeout
+
+$NFT flush ruleset
+$NFT add table t
+$NFT add set t s "{ type inet_service ; flags interval,timeout; timeout ${timeout}s; gc-interval ${timeout}s; }"
+if [ "$NFT_TEST_HAVE_pipapo" = y ] ; then
+ $NFT add set t c "{ type inet_service . inet_service ; flags interval,timeout ; timeout ${timeout}s; gc-interval ${timeout}s; }"
+fi
+add_elements
+
+sleep $((timeout * 3 / 2))
+add_elements
+
+add_elements nomatch
diff --git a/tests/shell/testcases/sets/0044interval_overlap_1 b/tests/shell/testcases/sets/0044interval_overlap_1
new file mode 100755
index 00000000..cdd0c844
--- /dev/null
+++ b/tests/shell/testcases/sets/0044interval_overlap_1
@@ -0,0 +1,38 @@
+#!/bin/bash -e
+#
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+#
+# 0044interval_overlap_1 - Single-sized intervals can never overlap partially
+#
+# Check that inserting, deleting, and inserting single-sized intervals again
+# never leads to a partial overlap. Specifically trigger rbtree rebalancing in
+# the process, to ensure different tree shapes of equivalent sets don't lead to
+# false positives, by deleting every second inserted item.
+
+xorshift() {
+ # Adaptation of Xorshift algorithm from:
+ # Marsaglia, G. (2003). Xorshift RNGs.
+ # Journal of Statistical Software, 8(14), 1 - 6.
+ # doi:http://dx.doi.org/10.18637/jss.v008.i14
+ # with triplet (5, 3, 1), suitable for 16-bit ranges.
+
+ : $((port ^= port << 5))
+ : $((port ^= port >> 3))
+ : $((port ^= port << 1))
+}
+
+$NFT add table t
+$NFT add set t s '{ type inet_service ; flags interval ; }'
+
+for op in add delete add; do
+ port=1
+ skip=0
+ for i in $(seq 1 500); do
+ xorshift
+ if [ "${op}" = "delete" ]; then
+ [ ${skip} -eq 0 ] && skip=1 && continue
+ skip=0
+ fi
+ $NFT ${op} element t s "{ { $((port % 32768 + 32768)) } }"
+ done
+done
diff --git a/tests/shell/testcases/sets/0045concat_ipv4_service b/tests/shell/testcases/sets/0045concat_ipv4_service
new file mode 100755
index 00000000..5b40f973
--- /dev/null
+++ b/tests/shell/testcases/sets/0045concat_ipv4_service
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+$NFT -f - <<EOF
+table inet t {
+ set s {
+ type ipv4_addr . inet_service
+ size 65536
+ flags dynamic,timeout
+ elements = { 192.168.7.1 . 22 }
+ }
+
+ chain c {
+ tcp dport 21 add @s { ip saddr . 22 timeout 60s }
+ }
+}
+EOF
diff --git a/tests/shell/testcases/sets/0046netmap_0 b/tests/shell/testcases/sets/0046netmap_0
new file mode 100755
index 00000000..7533623e
--- /dev/null
+++ b/tests/shell/testcases/sets/0046netmap_0
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_netmap)
+
+EXPECTED="table ip x {
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24,
+ 10.141.12.0/24 : 192.168.3.0/24,
+ 10.141.13.0/24 : 192.168.4.0/24 }
+ }
+ }
+ table ip6 x {
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip6 prefix to ip6 saddr map { 2001:db8:1111::/64 : 2001:db8:2222::/64 }
+ }
+ }
+"
+
+set -e
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/sets/0047nat_0 b/tests/shell/testcases/sets/0047nat_0
new file mode 100755
index 00000000..757605ee
--- /dev/null
+++ b/tests/shell/testcases/sets/0047nat_0
@@ -0,0 +1,42 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+EXPECTED="table ip x {
+ map y {
+ type ipv4_addr : interval ipv4_addr
+ flags interval
+ elements = { 10.141.10.0/24 : 192.168.2.2-192.168.2.4,
+ 10.141.11.0/24 : 192.168.4.2-192.168.4.3 }
+ }
+
+ chain x {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to iifname . ip saddr map { enp2s0 . 10.1.1.136 : 1.1.2.69 . 22, enp2s0 . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 }
+ dnat ip to iifname . ip saddr map { enp2s0 . 10.1.1.136 : 1.1.2.69, enp2s0 . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 }
+ }
+
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat to ip saddr map @y
+ }
+ }
+"
+
+set -e
+$NFT -f - <<< $EXPECTED
+$NFT add element x y { 10.141.12.0/24 : 192.168.5.10-192.168.5.20 }
+
+EXPECTED="table inet x {
+ chain x {
+ type nat hook prerouting priority dstnat; policy accept;
+ dnat to ip daddr . tcp dport map { 10.141.10.1 . 22 : 192.168.2.2, 10.141.11.2 . 2222 : 192.168.4.2 }
+ }
+
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat to ip saddr map { 10.141.10.0/24 : 192.168.2.2-192.168.2.4, 10.141.11.0/24 : 192.168.4.2-192.168.4.3 }
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/sets/0048set_counters_0 b/tests/shell/testcases/sets/0048set_counters_0
new file mode 100755
index 00000000..95babdc9
--- /dev/null
+++ b/tests/shell/testcases/sets/0048set_counters_0
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
+set -e
+
+EXPECTED="table ip x {
+ set y {
+ typeof ip saddr
+ counter
+ elements = { 192.168.10.35, 192.168.10.101, 192.168.10.135 }
+ }
+
+ chain z {
+ type filter hook output priority filter; policy accept;
+ ip daddr @y
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/sets/0049set_define_0 b/tests/shell/testcases/sets/0049set_define_0
new file mode 100755
index 00000000..756afdc1
--- /dev/null
+++ b/tests/shell/testcases/sets/0049set_define_0
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="define BASE_ALLOWED_INCOMING_TCP_PORTS = {22, 80, 443}
+define EXTRA_ALLOWED_INCOMING_TCP_PORTS = {}
+
+table inet filter {
+ chain input {
+ type filter hook input priority 0; policy drop;
+ tcp dport {\$BASE_ALLOWED_INCOMING_TCP_PORTS, \$EXTRA_ALLOWED_INCOMING_TCP_PORTS} ct state new counter accept
+ }
+}
+"
+
+$NFT -f - <<< "$EXPECTED"
+
+EXPECTED="define ip-block-4 = { 1.1.1.1 }
+
+ create set inet filter ip-block-4-test {
+ type ipv4_addr
+ flags interval
+ auto-merge
+ elements = \$ip-block-4
+ }
+"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/sets/0050set_define_1 b/tests/shell/testcases/sets/0050set_define_1
new file mode 100755
index 00000000..c12de177
--- /dev/null
+++ b/tests/shell/testcases/sets/0050set_define_1
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="define BASE_ALLOWED_INCOMING_TCP_PORTS = {}
+
+table inet filter {
+ chain input {
+ type filter hook input priority 0; policy drop;
+ tcp dport {\$BASE_ALLOWED_INCOMING_TCP_PORTS} ct state new counter accept
+ }
+}
+"
+
+$NFT -f - <<< "$EXPECTED" &> /dev/null || exit 0
+echo "E: Accepted empty set" 1>&2
+exit 1
diff --git a/tests/shell/testcases/sets/0051set_interval_counter_0 b/tests/shell/testcases/sets/0051set_interval_counter_0
new file mode 100755
index 00000000..6e67a43c
--- /dev/null
+++ b/tests/shell/testcases/sets/0051set_interval_counter_0
@@ -0,0 +1,21 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
+set -e
+
+EXPECTED="table ip x {
+ set s {
+ type ipv4_addr
+ flags interval
+ counter
+ elements = { 192.168.2.0/24 }
+ }
+
+ chain y {
+ type filter hook output priority filter; policy accept;
+ ip daddr @s
+ }
+}"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/sets/0052overlap_0 b/tests/shell/testcases/sets/0052overlap_0
new file mode 100755
index 00000000..c2960945
--- /dev/null
+++ b/tests/shell/testcases/sets/0052overlap_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="add table ip filter
+add set ip filter w_all {type ipv4_addr; flags interval; auto-merge}
+add element ip filter w_all {10.10.10.10, 10.10.10.11}
+"
+
+$NFT -f - <<< "$EXPECTED"
+
+EXPECTED="flush set ip filter w_all
+add element ip filter w_all {10.10.10.10, 10.10.10.253}
+"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/sets/0053echo_0 b/tests/shell/testcases/sets/0053echo_0
new file mode 100755
index 00000000..6bb03c28
--- /dev/null
+++ b/tests/shell/testcases/sets/0053echo_0
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="add table inet filter
+delete table inet filter
+
+table inet filter {
+ chain input {
+ type filter hook input priority filter; policy drop;
+ iifname { lo } ip saddr { 10.0.0.0/8 } ip daddr { 192.168.100.62 } tcp dport { 2001 } counter accept
+ }
+}
+"
+
+$NFT -ef - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/sets/0054comments_set_0 b/tests/shell/testcases/sets/0054comments_set_0
new file mode 100755
index 00000000..9c8f7875
--- /dev/null
+++ b/tests/shell/testcases/sets/0054comments_set_0
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -e
+
+# Test that comments are added to sets
+
+$NFT add table t
+$NFT add set t s {type ipv4_addr \; flags interval \; comment "test" \;}
+$NFT add map t m {type ipv4_addr : ipv4_addr \; flags interval \; comment \"another test\" \;}
diff --git a/tests/shell/testcases/sets/0055tcpflags_0 b/tests/shell/testcases/sets/0055tcpflags_0
new file mode 100755
index 00000000..a2b24eb2
--- /dev/null
+++ b/tests/shell/testcases/sets/0055tcpflags_0
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+EXPECTED="add table ip test
+
+add set ip test tcp_good_flags { type tcp_flag ; flags constant ; elements = {
+ ( 0 | 0 | 0 |ack| 0 | 0 ), \
+ ( 0 | 0 | 0 |ack| 0 |urg), \
+ ( 0 | 0 | 0 |ack|psh| 0 ), \
+ ( 0 | 0 | 0 |ack|psh|urg), \
+ ( 0 | 0 |rst| 0 | 0 | 0 ), \
+ ( 0 | 0 |rst|ack| 0 | 0 ), \
+ ( 0 | 0 |rst|ack| 0 |urg), \
+ ( 0 | 0 |rst|ack|psh| 0 ), \
+ ( 0 | 0 |rst|ack|psh|urg), \
+ ( 0 |syn| 0 | 0 | 0 | 0 ), \
+ ( 0 |syn| 0 |ack| 0 | 0 ), \
+ ( 0 |syn| 0 |ack| 0 |urg), \
+ ( 0 |syn| 0 |ack|psh| 0 ), \
+ ( 0 |syn| 0 |ack|psh|urg), \
+ (fin| 0 | 0 |ack| 0 | 0 ), \
+ (fin| 0 | 0 |ack| 0 |urg), \
+ (fin| 0 | 0 |ack|psh| 0 ), \
+ (fin| 0 | 0 |ack|psh|urg) \
+} ; }"
+
+set -e
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/sets/0056dynamic_limit_0 b/tests/shell/testcases/sets/0056dynamic_limit_0
new file mode 100755
index 00000000..21fa0bff
--- /dev/null
+++ b/tests/shell/testcases/sets/0056dynamic_limit_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+RULESET="table inet filter {
+ set ssh_meter {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ timeout 1m
+ elements = { 127.0.0.1 expires 52s44ms limit rate over 1/minute }
+ }
+
+ chain output {
+ type filter hook output priority filter; policy accept;
+ ip protocol icmp add @ssh_meter { ip saddr timeout 1m limit rate over 1/minute }
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/sets/0057set_create_fails_0 b/tests/shell/testcases/sets/0057set_create_fails_0
new file mode 100755
index 00000000..5f0149a3
--- /dev/null
+++ b/tests/shell/testcases/sets/0057set_create_fails_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+RULESET="table inet filter {
+ set test {
+ type ipv4_addr
+ size 65535
+ elements = { 1.1.1.1 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+CMD="create element inet filter test { 1.1.1.1, 1.1.1.2, 1.1.1.3, 1.1.1.4, 1.1.1.5, 1.1.1.6, 1.1.1.7, 1.1.1.8, 1.1.1.9, 1.1.1.10, 1.1.1.11, 1.1.1.12, 1.1.1.13, 1.1.1.14, 1.1.1.15, 1.1.1.16, 1.1.1.17, 1.1.1.18, 1.1.1.19, 1.1.1.20, 1.1.1.21, 1.1.1.22, 1.1.1.23, 1.1.1.24, 1.1.1.25, 1.1.1.26, 1.1.1.27, 1.1.1.28, 1.1.1.29, 1.1.1.30, 1.1.1.31, 1.1.1.32, 1.1.1.33, 1.1.1.34, 1.1.1.35, 1.1.1.36, 1.1.1.37, 1.1.1.38, 1.1.1.39, 1.1.1.40, 1.1.1.41, 1.1.1.42, 1.1.1.43, 1.1.1.44, 1.1.1.45, 1.1.1.46, 1.1.1.47, 1.1.1.48, 1.1.1.49, 1.1.1.50, 1.1.1.51, 1.1.1.52, 1.1.1.53, 1.1.1.54, 1.1.1.55, 1.1.1.56, 1.1.1.57, 1.1.1.58, 1.1.1.59, 1.1.1.60, 1.1.1.61, 1.1.1.62, 1.1.1.63, 1.1.1.64, 1.1.1.65, 1.1.1.66, 1.1.1.67, 1.1.1.68, 1.1.1.69, 1.1.1.70, 1.1.1.71, 1.1.1.72, 1.1.1.73, 1.1.1.74, 1.1.1.75, 1.1.1.76, 1.1.1.77, 1.1.1.78, 1.1.1.79, 1.1.1.80, 1.1.1.81, 1.1.1.82, 1.1.1.83, 1.1.1.84, 1.1.1.85, 1.1.1.86, 1.1.1.87, 1.1.1.88, 1.1.1.89, 1.1.1.90, 1.1.1.91, 1.1.1.92, 1.1.1.93, 1.1.1.94, 1.1.1.95, 1.1.1.96, 1.1.1.97, 1.1.1.98, 1.1.1.99, 1.1.1.100, 1.1.1.101, 1.1.1.102, 1.1.1.103, 1.1.1.104, 1.1.1.105, 1.1.1.106, 1.1.1.107, 1.1.1.108, 1.1.1.109, 1.1.1.110, 1.1.1.111, 1.1.1.112, 1.1.1.113, 1.1.1.114, 1.1.1.115, 1.1.1.116, 1.1.1.117, 1.1.1.118, 1.1.1.119, 1.1.1.120, 1.1.1.121, 1.1.1.122, 1.1.1.123, 1.1.1.124, 1.1.1.125, 1.1.1.126, 1.1.1.127, 1.1.1.128, 1.1.1.129, 1.1.1.130, 1.1.1.131, 1.1.1.132, 1.1.1.133, 1.1.1.134, 1.1.1.135, 1.1.1.136, 1.1.1.137, 1.1.1.138, 1.1.1.139, 1.1.1.140, 1.1.1.141, 1.1.1.142, 1.1.1.143, 1.1.1.144, 1.1.1.145, 1.1.1.146, 1.1.1.147, 1.1.1.148, 1.1.1.149, 1.1.1.150, 1.1.1.151, 1.1.1.152, 1.1.1.153, 1.1.1.154, 1.1.1.155, 1.1.1.156, 1.1.1.157, 1.1.1.158, 1.1.1.159, 1.1.1.160, 1.1.1.161, 1.1.1.162, 1.1.1.163, 1.1.1.164, 1.1.1.165, 1.1.1.166, 1.1.1.167, 1.1.1.168, 1.1.1.169, 1.1.1.170, 1.1.1.171, 1.1.1.172, 1.1.1.173, 1.1.1.174, 1.1.1.175, 1.1.1.176, 1.1.1.177, 1.1.1.178, 1.1.1.179, 1.1.1.180, 1.1.1.181, 1.1.1.182, 1.1.1.183, 1.1.1.184, 1.1.1.185, 1.1.1.186, 1.1.1.187, 1.1.1.188, 1.1.1.189, 1.1.1.190, 1.1.1.191, 1.1.1.192, 1.1.1.193, 1.1.1.194, 1.1.1.195, 1.1.1.196, 1.1.1.197, 1.1.1.198, 1.1.1.199, 1.1.1.200, 1.1.1.201, 1.1.1.202, 1.1.1.203, 1.1.1.204, 1.1.1.205, 1.1.1.206, 1.1.1.207, 1.1.1.208, 1.1.1.209, 1.1.1.210, 1.1.1.211, 1.1.1.212, 1.1.1.213, 1.1.1.214, 1.1.1.215, 1.1.1.216, 1.1.1.217, 1.1.1.218, 1.1.1.219, 1.1.1.220, 1.1.1.221, 1.1.1.222, 1.1.1.223, 1.1.1.224, 1.1.1.225, 1.1.1.226, 1.1.1.227, 1.1.1.228, 1.1.1.229, 1.1.1.230, 1.1.1.231, 1.1.1.232, 1.1.1.233, 1.1.1.234, 1.1.1.235, 1.1.1.236, 1.1.1.237, 1.1.1.238, 1.1.1.239, 1.1.1.240, 1.1.1.241, 1.1.1.242, 1.1.1.243, 1.1.1.244, 1.1.1.245, 1.1.1.246, 1.1.1.247, 1.1.1.248, 1.1.1.249, 1.1.1.250, 1.1.1.251, 1.1.1.252, 1.1.1.253 }"
+
+# If this returns ENOSPC, then nft is sending a netlink message that is larger
+# than NFT_MNL_ACK_MAXSIZE. Make sure this returns EEXIST.
+$NFT -f - <<< $CMD 2>&1 >/dev/null | grep "File exists"
+[ "$?" -eq 0 ] && exit 0
diff --git a/tests/shell/testcases/sets/0058_setupdate_timeout_0 b/tests/shell/testcases/sets/0058_setupdate_timeout_0
new file mode 100755
index 00000000..52a658e1
--- /dev/null
+++ b/tests/shell/testcases/sets/0058_setupdate_timeout_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+RULESET="table inet filter {
+ set ssh_meter {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ timeout 30d
+ }
+
+ chain test {
+ add @ssh_meter { ip saddr timeout 30d }
+ }
+}"
+
+set -e
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/sets/0059set_update_multistmt_0 b/tests/shell/testcases/sets/0059set_update_multistmt_0
new file mode 100755
index 00000000..2aeba2c5
--- /dev/null
+++ b/tests/shell/testcases/sets/0059set_update_multistmt_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_with_two_expressions)
+
+RULESET="table x {
+ set y {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ timeout 1h
+ }
+ chain z {
+ type filter hook output priority 0;
+ update @y { ip daddr limit rate 1/second counter }
+ }
+}"
+
+set -e
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/sets/0060set_multistmt_0 b/tests/shell/testcases/sets/0060set_multistmt_0
new file mode 100755
index 00000000..8e17444e
--- /dev/null
+++ b/tests/shell/testcases/sets/0060set_multistmt_0
@@ -0,0 +1,52 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_with_two_expressions)
+
+RULESET="table x {
+ set y {
+ type ipv4_addr
+ limit rate 1/second counter
+ elements = { 5.5.5.5 limit rate 1/second counter packets 0 bytes 0 }
+ }
+ chain y {
+ type filter hook output priority filter; policy accept;
+ ip daddr @y
+ }
+}"
+
+$NFT -f - <<< $RULESET
+# should work
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+# should work
+$NFT add element x y { 1.1.1.1 limit rate 1/second counter }
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+# should fail
+$NFT add element x y { 2.2.2.2 limit rate 1/second }
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+# should fail
+$NFT add element x y { 3.3.3.3 counter limit rate 1/second }
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+# should work
+$NFT add element x y { 4.4.4.4 }
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+exit 0
diff --git a/tests/shell/testcases/sets/0060set_multistmt_1 b/tests/shell/testcases/sets/0060set_multistmt_1
new file mode 100755
index 00000000..04ef047c
--- /dev/null
+++ b/tests/shell/testcases/sets/0060set_multistmt_1
@@ -0,0 +1,40 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_with_two_expressions)
+
+RULESET="table x {
+ set y {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter quota 500 bytes
+ elements = { 1.2.3.4 counter packets 9 bytes 756 quota 500 bytes used 500 bytes }
+ }
+ chain y {
+ type filter hook output priority filter; policy accept;
+ update @y { ip daddr }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+# should work
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+# should work
+$NFT add element x y { 1.1.1.1 }
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+# should work
+$NFT add element x y { 2.2.2.2 counter quota 1000 bytes }
+if [ $? -ne 0 ]
+then
+ exit 1
+fi
+
+exit 0
diff --git a/tests/shell/testcases/sets/0061anonymous_automerge_0 b/tests/shell/testcases/sets/0061anonymous_automerge_0
new file mode 100755
index 00000000..2dfb800e
--- /dev/null
+++ b/tests/shell/testcases/sets/0061anonymous_automerge_0
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain y {
+ ip saddr { 1.1.1.1-1.1.1.2, 1.1.1.1 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/sets/0062set_connlimit_0 b/tests/shell/testcases/sets/0062set_connlimit_0
new file mode 100755
index 00000000..48aa6fce
--- /dev/null
+++ b/tests/shell/testcases/sets/0062set_connlimit_0
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
+set -e
+
+RULESET="table ip x {
+ set est-connlimit {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ elements = { 84.245.120.167 ct count over 20 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+RULESET="table ip x {
+ set new-connlimit {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ ct count over 20
+ elements = { 84.245.120.167 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+$NFT flush set ip x est-connlimit
+$NFT flush set ip x new-connlimit
diff --git a/tests/shell/testcases/sets/0063set_catchall_0 b/tests/shell/testcases/sets/0063set_catchall_0
new file mode 100755
index 00000000..edd015d0
--- /dev/null
+++ b/tests/shell/testcases/sets/0063set_catchall_0
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_catchall_element)
+
+set -e
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ counter
+ elements = { 1.1.1.1, * }
+ }
+ set z {
+ type ipv4_addr
+ flags interval
+ counter
+ elements = { 1.1.1.0/24 , * }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+$NFT delete element x y { \* }
+$NFT add element x y { \* }
diff --git a/tests/shell/testcases/sets/0064map_catchall_0 b/tests/shell/testcases/sets/0064map_catchall_0
new file mode 100755
index 00000000..fd289372
--- /dev/null
+++ b/tests/shell/testcases/sets/0064map_catchall_0
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_catchall_element)
+
+set -e
+
+RULESET="table ip x {
+ map y {
+ type ipv4_addr : ipv4_addr
+ elements = { 10.141.0.1 : 192.168.0.2, * : 192.168.0.3 }
+ }
+ map z {
+ type ipv4_addr : ipv4_addr
+ flags interval
+ elements = { 10.141.0.0/24 : 192.168.0.2, * : 192.168.0.3 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+$NFT delete element x y { \* : 192.168.0.3 }
+$NFT add element x y { \* : 192.168.0.4 }
+
+$NFT add chain x y
+$NFT add rule x y snat to ip saddr map @z
+$NFT 'add rule x y snat to ip saddr map { 10.141.0.0/24 : 192.168.0.2, * : 192.168.0.3 }'
+$NFT 'add rule x y snat to ip saddr . ip daddr map { 10.141.0.0/24 . 10.0.0.0/8 : 192.168.0.2, 192.168.9.0/24 . 192.168.10.0/24 : 192.168.0.4, * : 192.168.0.3 }'
diff --git a/tests/shell/testcases/sets/0065_icmp_postprocessing b/tests/shell/testcases/sets/0065_icmp_postprocessing
new file mode 100755
index 00000000..f838c3ef
--- /dev/null
+++ b/tests/shell/testcases/sets/0065_icmp_postprocessing
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ chain foo {
+ icmp id 42
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+$NFT insert rule ip x foo index 0 accept
diff --git a/tests/shell/testcases/sets/0067nat_concat_interval_0 b/tests/shell/testcases/sets/0067nat_concat_interval_0
new file mode 100755
index 00000000..81621957
--- /dev/null
+++ b/tests/shell/testcases/sets/0067nat_concat_interval_0
@@ -0,0 +1,58 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+
+EXPECTED="table ip nat {
+ map ipportmap2 {
+ type ipv4_addr . ipv4_addr : interval ipv4_addr . inet_service
+ flags interval
+ elements = { 192.168.1.2 . 192.168.2.2 : 127.0.0.1/8 . 42 - 43 }
+ }
+
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ ip protocol tcp dnat ip to ip saddr . ip daddr map @ipportmap2
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+
+EXPECTED="table ip nat {
+ map fwdtoip_th {
+ type ipv4_addr . inet_service : interval ipv4_addr . inet_service
+ flags interval
+ elements = { 1.2.3.4 . 10000-20000 : 192.168.3.4 . 30000-40000 }
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+$NFT add rule ip nat prerouting meta l4proto { tcp, udp } dnat to ip daddr . th dport map @fwdtoip_th
+
+EXPECTED="table ip nat {
+ map ipportmap4 {
+ typeof iifname . ip saddr : interval ip daddr
+ flags interval
+ elements = { enp2s0 . 10.1.1.136 : 1.1.2.69, enp2s0 . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 }
+ }
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ dnat to iifname . ip saddr map @ipportmap4
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+EXPECTED="table ip nat {
+ map ipportmap5 {
+ typeof iifname . ip saddr : interval ip daddr . tcp dport
+ flags interval
+ elements = { enp2s0 . 10.1.1.136 : 1.1.2.69 . 22, enp2s0 . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 }
+ }
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to iifname . ip saddr map @ipportmap5
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/sets/0067nat_interval_0 b/tests/shell/testcases/sets/0067nat_interval_0
new file mode 100755
index 00000000..c90203d0
--- /dev/null
+++ b/tests/shell/testcases/sets/0067nat_interval_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="table ip nat {
+ map ipportmap {
+ type ipv4_addr : interval ipv4_addr . inet_service
+ flags interval
+ elements = { 192.168.1.2 : 10.141.10.1-10.141.10.3 . 8888-8999 }
+ }
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ ip protocol tcp dnat ip to ip saddr map @ipportmap
+ }
+}"
+
+$NFT -f - <<< $EXPECTED
+$NFT add element ip nat ipportmap { 192.168.2.0/24 : 10.141.11.5-10.141.11.20 . 8888-8999 }
diff --git a/tests/shell/testcases/sets/0068interval_stack_overflow_0 b/tests/shell/testcases/sets/0068interval_stack_overflow_0
new file mode 100755
index 00000000..e61010c7
--- /dev/null
+++ b/tests/shell/testcases/sets/0068interval_stack_overflow_0
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+set -e
+
+ruleset_file=$(mktemp)
+
+trap 'rm -f "$ruleset_file"' EXIT
+
+HOWMANY=255
+if [ "$NFT_TEST_HAS_SOCKET_LIMITS" = y ] ; then
+ # The socket limit /proc/sys/net/core/wmem_max may be unsuitable for
+ # the test.
+ #
+ # Run only a subset of the test and mark as skipped at the end.
+ HOWMANY=30
+fi
+
+{
+ echo 'define big_set = {'
+ for ((i = 1; i < $HOWMANY; i++)); do
+ for ((j = 1; j < 255; j++)); do
+ echo "10.0.$i.$j,"
+ done
+ done
+ echo '10.1.0.0/24 }'
+} >"$ruleset_file"
+
+cat >>"$ruleset_file" <<\EOF
+table inet test68_table {
+ set test68_set {
+ type ipv4_addr
+ flags interval
+ elements = { $big_set }
+ }
+}
+EOF
+
+( ulimit -s 400 && $NFT -f "$ruleset_file" )
+
+if [ "$HOWMANY" != 255 ] ; then
+ echo "NFT_TEST_HAS_SOCKET_LIMITS indicates that the socket limit for"
+ echo "/proc/sys/net/core/wmem_max is too small for this test. Mark as SKIPPED"
+ echo "You may bump the limit and rerun with \`NFT_TEST_HAS_SOCKET_LIMITS=n\`."
+ exit 77
+fi
diff --git a/tests/shell/testcases/sets/0069interval_merge_0 b/tests/shell/testcases/sets/0069interval_merge_0
new file mode 100755
index 00000000..edb6422a
--- /dev/null
+++ b/tests/shell/testcases/sets/0069interval_merge_0
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ auto-merge
+ elements = { 1.2.3.0, 1.2.3.255, 1.2.3.0/24, 3.3.3.3, 4.4.4.4, 4.4.4.4-4.4.4.8, 3.3.3.4, 3.3.3.5 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ auto-merge
+ elements = { 1.2.4.0, 3.3.3.6, 4.4.4.0/24 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+$NFT add element ip x y { 1.2.3.0-1.2.4.255, 3.3.3.5, 4.4.4.1 }
+$NFT add element ip x y { 1.2.3.0-1.2.4.255, 3.3.3.5, 4.4.5.0 }
diff --git a/tests/shell/testcases/sets/0070stacked_l2_headers b/tests/shell/testcases/sets/0070stacked_l2_headers
new file mode 100755
index 00000000..07820b7c
--- /dev/null
+++ b/tests/shell/testcases/sets/0070stacked_l2_headers
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
diff --git a/tests/shell/testcases/sets/0071unclosed_prefix_interval_0 b/tests/shell/testcases/sets/0071unclosed_prefix_interval_0
new file mode 100755
index 00000000..79e3ca7d
--- /dev/null
+++ b/tests/shell/testcases/sets/0071unclosed_prefix_interval_0
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+set -e
+
+RULESET="
+table inet t {
+ set s1 {
+ type ipv4_addr
+ flags interval
+ elements = { 192.0.0.0/2, 10.0.0.0/8 }
+ }
+ set s2 {
+ type ipv6_addr
+ flags interval
+ elements = { ff00::/8, fe80::/10 }
+ }
+ chain c {
+ ip saddr @s1 accept
+ ip6 daddr @s2 accept
+ }
+}"
+
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/sets/0072destroy_0 b/tests/shell/testcases/sets/0072destroy_0
new file mode 100755
index 00000000..9886a9b0
--- /dev/null
+++ b/tests/shell/testcases/sets/0072destroy_0
@@ -0,0 +1,12 @@
+#!/bin/bash -e
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_destroy)
+
+$NFT add table x
+
+# pass for non-existent set
+$NFT destroy set x s
+
+# successfully delete existing set
+$NFT add set x s '{type ipv4_addr; size 2;}'
+$NFT destroy set x s
diff --git a/tests/shell/testcases/sets/0073flat_interval_set b/tests/shell/testcases/sets/0073flat_interval_set
new file mode 100755
index 00000000..0630595f
--- /dev/null
+++ b/tests/shell/testcases/sets/0073flat_interval_set
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+set -e
+
+EXPECTED="flush ruleset
+add table inet filter
+add map inet filter testmap { type ipv4_addr : counter; flags interval;}
+add counter inet filter TEST
+add element inet filter testmap { 192.168.0.0/24 : \"TEST\" }"
+
+$NFT -f - <<< "$EXPECTED"
diff --git a/tests/shell/testcases/sets/0074nested_interval_set b/tests/shell/testcases/sets/0074nested_interval_set
new file mode 100755
index 00000000..e7f65fc5
--- /dev/null
+++ b/tests/shell/testcases/sets/0074nested_interval_set
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+$NFT -f "$dumpfile"
diff --git a/tests/shell/testcases/sets/automerge_0 b/tests/shell/testcases/sets/automerge_0
new file mode 100755
index 00000000..1dbac0b7
--- /dev/null
+++ b/tests/shell/testcases/sets/automerge_0
@@ -0,0 +1,131 @@
+#!/bin/bash
+
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+
+set -e
+
+RULESET="table inet x {
+ set y {
+ type inet_service
+ flags interval
+ auto-merge
+ }
+}"
+
+HOWMANY=65535
+if [ "$NFT_TEST_HAS_SOCKET_LIMITS" = y ] ; then
+ # The socket limit /proc/sys/net/core/wmem_max may be unsuitable for
+ # the test.
+ #
+ # Run only a subset of the test and mark as skipped at the end.
+ HOWMANY=5000
+fi
+
+$NFT -f - <<< $RULESET
+
+tmpfile=$(mktemp)
+echo -n "add element inet x y { " > $tmpfile
+for ((i=0;i<$HOWMANY;i+=2))
+do
+ echo -n "$i, " >> $tmpfile
+ if [ $i -eq $((HOWMANY-1)) ]
+ then
+ echo -n "$i" >> $tmpfile
+ fi
+done
+echo "}" >> $tmpfile
+
+$NFT -f $tmpfile
+
+tmpfile2=$(mktemp)
+for ((i=1;i<$HOWMANY;i+=2))
+do
+ echo "$i" >> $tmpfile2
+done
+
+tmpfile3=$(mktemp)
+shuf "$tmpfile2" --random-source=<("$NFT_TEST_BASEDIR/helpers/random-source.sh" "automerge-shuf-tmpfile2" "$NFT_TEST_RANDOM_SEED") > "$tmpfile3"
+i=0
+cat $tmpfile3 | while read line && [ $i -lt 10 ]
+do
+ $NFT add element inet x y { $line }
+ if [ $? -ne 0 ]
+ then
+ echo "failed to add $line"
+ exit 1
+ fi
+ i=$((i+1))
+done
+
+for ((i=0;i<10;i++))
+do
+ from=$(($RANDOM%$HOWMANY))
+ to=$(($from+100))
+ $NFT add element inet x y { $from-$to }
+ if [ $? -ne 0 ]
+ then
+ echo "failed to add $from-$to"
+ exit 1
+ fi
+
+ $NFT get element inet x y { $from-$to } 1>/dev/null
+ if [ $? -ne 0 ]
+ then
+ echo "failed to get $from-$to"
+ exit 1
+ fi
+
+ # partial removals in the previous random range
+ from2=$(($from+10))
+ to2=$(($to-10))
+ $NFT delete element inet x y { $from, $to, $from2-$to2 }
+ if [ $? -ne 0 ]
+ then
+ echo "failed to delete $from, $to, $from2-$to2"
+ exit 1
+ fi
+
+ # check deletions are correct
+ from=$(($from+1))
+ $NFT get element inet x y { $from } 1>/dev/null
+ if [ $? -ne 0 ]
+ then
+ echo "failed to get $from"
+ exit 1
+ fi
+
+ to=$(($to-1))
+ $NFT get element inet x y { $to } 1>/dev/null
+ if [ $? -ne 0 ]
+ then
+ echo "failed to get $to"
+ exit 1
+ fi
+
+ from2=$(($from2-1))
+ $NFT get element inet x y { $from2 } 1>/dev/null
+ if [ $? -ne 0 ]
+ then
+ echo "failed to get $from2"
+ exit 1
+ fi
+ to2=$(($to2+1))
+
+ $NFT get element inet x y { $to2 } 1>/dev/null
+ if [ $? -ne 0 ]
+ then
+ echo "failed to get $to2"
+ exit 1
+ fi
+done
+
+rm -f $tmpfile
+rm -f $tmpfile2
+rm -f $tmpfile3
+
+if [ "$HOWMANY" != 65535 ] ; then
+ echo "NFT_TEST_HAS_SOCKET_LIMITS indicates that the socket limit for"
+ echo "/proc/sys/net/core/wmem_max is too small for this test. Mark as SKIPPED"
+ echo "You may bump the limit and rerun with \`NFT_TEST_HAS_SOCKET_LIMITS=n\`."
+ exit 77
+fi
diff --git a/tests/shell/testcases/sets/collapse_elem_0 b/tests/shell/testcases/sets/collapse_elem_0
new file mode 100755
index 00000000..7699e9da
--- /dev/null
+++ b/tests/shell/testcases/sets/collapse_elem_0
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip a {
+ set x {
+ type inet_service;
+ }
+}
+table ip6 a {
+ set x {
+ type inet_service;
+ }
+}
+add element ip a x { 1 }
+add element ip a x { 2 }
+add element ip6 a x { 2 }"
+
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/sets/concat_interval_0 b/tests/shell/testcases/sets/concat_interval_0
new file mode 100755
index 00000000..36138ae0
--- /dev/null
+++ b/tests/shell/testcases/sets/concat_interval_0
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+
+RULESET="table ip t {
+ set s {
+ type ipv4_addr . inet_proto . inet_service
+ flags interval
+ counter
+ elements = { 1.0.0.1 . udp . 53 }
+ }
+ set s2 {
+ type ipv4_addr . mark
+ flags interval
+ elements = { 10.10.10.10 . 0x00000100,
+ 20.20.20.20 . 0x00000200 }
+ }
+}"
+
+$NFT -f - <<< $RULESET
+
+$NFT delete element t s { 1.0.0.1 . udp . 53}
+
+exit 0
diff --git a/tests/shell/testcases/sets/dumps/0001named_interval_0.json-nft b/tests/shell/testcases/sets/dumps/0001named_interval_0.json-nft
new file mode 100644
index 00000000..b9c66a21
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0001named_interval_0.json-nft
@@ -0,0 +1,261 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s1",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "range": [
+ "10.0.0.0",
+ "11.0.0.0"
+ ]
+ },
+ {
+ "prefix": {
+ "addr": "172.16.0.0",
+ "len": 16
+ }
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s2",
+ "table": "t",
+ "type": "ipv6_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "fe00::",
+ "len": 64
+ }
+ },
+ {
+ "range": [
+ "fe11::",
+ "fe22::"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s3",
+ "table": "t",
+ "type": "inet_proto",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "range": [
+ 10,
+ 20
+ ]
+ },
+ {
+ "range": [
+ 50,
+ 60
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s4",
+ "table": "t",
+ "type": "inet_service",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "range": [
+ 0,
+ 1024
+ ]
+ },
+ {
+ "range": [
+ 8080,
+ 8082
+ ]
+ },
+ {
+ "range": [
+ 10000,
+ 40000
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@s1"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "right": "@s2"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "protocol"
+ }
+ },
+ "right": "@s3"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "nexthdr"
+ }
+ },
+ "right": "@s3"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": "@s4"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0002named_interval_automerging_0.json-nft b/tests/shell/testcases/sets/dumps/0002named_interval_automerging_0.json-nft
new file mode 100644
index 00000000..4c0be670
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0002named_interval_automerging_0.json-nft
@@ -0,0 +1,44 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "192.168.0.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "192.168.1.0",
+ "len": 24
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0003named_interval_missing_flag_0.json-nft b/tests/shell/testcases/sets/dumps/0003named_interval_missing_flag_0.json-nft
new file mode 100644
index 00000000..b6173e9f
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0003named_interval_missing_flag_0.json-nft
@@ -0,0 +1,27 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0004named_interval_shadow_0.json-nft b/tests/shell/testcases/sets/dumps/0004named_interval_shadow_0.json-nft
new file mode 100644
index 00000000..c55858fa
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0004named_interval_shadow_0.json-nft
@@ -0,0 +1,38 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s",
+ "table": "t",
+ "type": "ipv6_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "fe00::",
+ "len": 64
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0005named_interval_shadow_0.json-nft b/tests/shell/testcases/sets/dumps/0005named_interval_shadow_0.json-nft
new file mode 100644
index 00000000..a75681f3
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0005named_interval_shadow_0.json-nft
@@ -0,0 +1,38 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s",
+ "table": "t",
+ "type": "ipv6_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "fe00::",
+ "len": 48
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0006create_set_0.json-nft b/tests/shell/testcases/sets/dumps/0006create_set_0.json-nft
new file mode 100644
index 00000000..b6173e9f
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0006create_set_0.json-nft
@@ -0,0 +1,27 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0007create_element_0.json-nft b/tests/shell/testcases/sets/dumps/0007create_element_0.json-nft
new file mode 100644
index 00000000..f5a9ac19
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0007create_element_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "1.1.1.1"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0008comments_interval_0.json-nft b/tests/shell/testcases/sets/dumps/0008comments_interval_0.json-nft
new file mode 100644
index 00000000..c6f5aa68
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0008comments_interval_0.json-nft
@@ -0,0 +1,38 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "elem": {
+ "val": "1.1.1.1",
+ "comment": "test"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0008create_verdict_map_0.json-nft b/tests/shell/testcases/sets/dumps/0008create_verdict_map_0.json-nft
new file mode 100644
index 00000000..fa5dcb25
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0008create_verdict_map_0.json-nft
@@ -0,0 +1,78 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "postrouting",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "sourcemap",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "verdict",
+ "elem": [
+ [
+ "100.123.10.2",
+ {
+ "jump": {
+ "target": "c"
+ }
+ }
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "postrouting",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": "@sourcemap"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0009comments_timeout_0.json-nft b/tests/shell/testcases/sets/dumps/0009comments_timeout_0.json-nft
new file mode 100644
index 00000000..2418b39a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0009comments_timeout_0.json-nft
@@ -0,0 +1,38 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "timeout"
+ ],
+ "elem": [
+ {
+ "elem": {
+ "val": "1.1.1.1",
+ "comment": "test"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0010comments_0.json-nft b/tests/shell/testcases/sets/dumps/0010comments_0.json-nft
new file mode 100644
index 00000000..7ea3c602
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0010comments_0.json-nft
@@ -0,0 +1,35 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s",
+ "table": "t",
+ "type": "ipv6_addr",
+ "handle": 0,
+ "elem": [
+ {
+ "elem": {
+ "val": "::1",
+ "comment": "test"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0011add_many_elements_0.nodump b/tests/shell/testcases/sets/dumps/0011add_many_elements_0.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0011add_many_elements_0.nodump
diff --git a/tests/shell/testcases/sets/dumps/0012add_delete_many_elements_0.json-nft b/tests/shell/testcases/sets/dumps/0012add_delete_many_elements_0.json-nft
new file mode 100644
index 00000000..c1b7639d
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0012add_delete_many_elements_0.json-nft
@@ -0,0 +1,27 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0013add_delete_many_elements_0.json-nft b/tests/shell/testcases/sets/dumps/0013add_delete_many_elements_0.json-nft
new file mode 100644
index 00000000..c1b7639d
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0013add_delete_many_elements_0.json-nft
@@ -0,0 +1,27 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0014malformed_set_is_not_defined_0.json-nft b/tests/shell/testcases/sets/dumps/0014malformed_set_is_not_defined_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0014malformed_set_is_not_defined_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0014malformed_set_is_not_defined_0.nft b/tests/shell/testcases/sets/dumps/0014malformed_set_is_not_defined_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0014malformed_set_is_not_defined_0.nft
diff --git a/tests/shell/testcases/sets/dumps/0015rulesetflush_0.json-nft b/tests/shell/testcases/sets/dumps/0015rulesetflush_0.json-nft
new file mode 100644
index 00000000..6268e216
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0015rulesetflush_0.json-nft
@@ -0,0 +1,53 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "blacklist_v4",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "192.168.0.0",
+ "len": 24
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0016element_leak_0.json-nft b/tests/shell/testcases/sets/dumps/0016element_leak_0.json-nft
new file mode 100644
index 00000000..96b9714a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0016element_leak_0.json-nft
@@ -0,0 +1,31 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 2,
+ "elem": [
+ "1.1.1.1"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0017add_after_flush_0.json-nft b/tests/shell/testcases/sets/dumps/0017add_after_flush_0.json-nft
new file mode 100644
index 00000000..96b9714a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0017add_after_flush_0.json-nft
@@ -0,0 +1,31 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 2,
+ "elem": [
+ "1.1.1.1"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0018set_check_size_1.json-nft b/tests/shell/testcases/sets/dumps/0018set_check_size_1.json-nft
new file mode 100644
index 00000000..d226811c
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0018set_check_size_1.json-nft
@@ -0,0 +1,32 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 2,
+ "elem": [
+ "1.1.1.1",
+ "1.1.1.2"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0018set_check_size_1.nft b/tests/shell/testcases/sets/dumps/0018set_check_size_1.nft
new file mode 100644
index 00000000..8cd37076
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0018set_check_size_1.nft
@@ -0,0 +1,7 @@
+table ip x {
+ set s {
+ type ipv4_addr
+ size 2
+ elements = { 1.1.1.1, 1.1.1.2 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0019set_check_size_0.json-nft b/tests/shell/testcases/sets/dumps/0019set_check_size_0.json-nft
new file mode 100644
index 00000000..d226811c
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0019set_check_size_0.json-nft
@@ -0,0 +1,32 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 2,
+ "elem": [
+ "1.1.1.1",
+ "1.1.1.2"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0020comments_0.json-nft b/tests/shell/testcases/sets/dumps/0020comments_0.json-nft
new file mode 100644
index 00000000..401a8f23
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0020comments_0.json-nft
@@ -0,0 +1,35 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s",
+ "table": "t",
+ "type": "inet_service",
+ "handle": 0,
+ "elem": [
+ {
+ "elem": {
+ "val": 22,
+ "comment": "test"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0021nesting_0.json-nft b/tests/shell/testcases/sets/dumps/0021nesting_0.json-nft
new file mode 100644
index 00000000..5ed089dc
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0021nesting_0.json-nft
@@ -0,0 +1,69 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": {
+ "set": [
+ {
+ "prefix": {
+ "addr": "1.1.1.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2.2.2.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "3.3.3.0",
+ "len": 24
+ }
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.json-nft b/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.json-nft
new file mode 100644
index 00000000..c6171392
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.json-nft
@@ -0,0 +1,101 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "m",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "inet_service"
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "f",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 1024,
+ "flags": [
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 80
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "set": "@f",
+ "stmt": [
+ {
+ "limit": {
+ "rate": 10,
+ "burst": 5,
+ "per": "second"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.nft b/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.nft
index 5a6e3261..38987ded 100644
--- a/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.nft
+++ b/tests/shell/testcases/sets/dumps/0022type_selective_flush_0.nft
@@ -7,7 +7,13 @@ table ip t {
type ipv4_addr : inet_service
}
+ set f {
+ type ipv4_addr
+ size 1024
+ flags dynamic
+ }
+
chain c {
- tcp dport 80 meter f size 1024 { ip saddr limit rate 10/second }
+ tcp dport 80 add @f { ip saddr limit rate 10/second burst 5 packets }
}
}
diff --git a/tests/shell/testcases/sets/dumps/0023incomplete_add_set_command_0.json-nft b/tests/shell/testcases/sets/dumps/0023incomplete_add_set_command_0.json-nft
new file mode 100644
index 00000000..e0e56fec
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0023incomplete_add_set_command_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0024named_objects_0.json-nft b/tests/shell/testcases/sets/dumps/0024named_objects_0.json-nft
new file mode 100644
index 00000000..b4521333
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0024named_objects_0.json-nft
@@ -0,0 +1,165 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "counter": {
+ "family": "inet",
+ "name": "user123",
+ "table": "x",
+ "handle": 0,
+ "packets": 12,
+ "bytes": 1433
+ }
+ },
+ {
+ "counter": {
+ "family": "inet",
+ "name": "user321",
+ "table": "x",
+ "handle": 0,
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "quota": {
+ "family": "inet",
+ "name": "user123",
+ "table": "x",
+ "handle": 0,
+ "bytes": 2000,
+ "used": 0,
+ "inv": true
+ }
+ },
+ {
+ "quota": {
+ "family": "inet",
+ "name": "user124",
+ "table": "x",
+ "handle": 0,
+ "bytes": 2000,
+ "used": 0,
+ "inv": true
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "test",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "quota",
+ "elem": [
+ [
+ "192.168.2.2",
+ "user124"
+ ],
+ [
+ "192.168.2.3",
+ "user124"
+ ]
+ ]
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "counter": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ "1.1.1.1",
+ "user123"
+ ],
+ [
+ "2.2.2.2",
+ "user123"
+ ],
+ [
+ "192.168.2.2",
+ "user123"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "quota": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": "@test"
+ }
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0024synproxy_0.json-nft b/tests/shell/testcases/sets/dumps/0024synproxy_0.json-nft
new file mode 100644
index 00000000..0af61333
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0024synproxy_0.json-nft
@@ -0,0 +1,131 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "synproxy": {
+ "family": "inet",
+ "name": "https-synproxy",
+ "table": "x",
+ "handle": 0,
+ "mss": 1460,
+ "wscale": 7,
+ "flags": [
+ "timestamp",
+ "sack-perm"
+ ]
+ }
+ },
+ {
+ "synproxy": {
+ "family": "inet",
+ "name": "other-synproxy",
+ "table": "x",
+ "handle": 0,
+ "mss": 1460,
+ "wscale": 5
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "test2",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "synproxy",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "prefix": {
+ "addr": "192.168.1.0",
+ "len": 24
+ }
+ },
+ "https-synproxy"
+ ],
+ [
+ {
+ "prefix": {
+ "addr": "192.168.2.0",
+ "len": 24
+ }
+ },
+ "other-synproxy"
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "synproxy": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "prefix": {
+ "addr": "192.168.1.0",
+ "len": 24
+ }
+ },
+ "https-synproxy"
+ ],
+ [
+ {
+ "prefix": {
+ "addr": "192.168.2.0",
+ "len": 24
+ }
+ },
+ "other-synproxy"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0024synproxy_0.nft b/tests/shell/testcases/sets/dumps/0024synproxy_0.nft
new file mode 100644
index 00000000..e0ee86db
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0024synproxy_0.nft
@@ -0,0 +1,23 @@
+table inet x {
+ synproxy https-synproxy {
+ mss 1460
+ wscale 7
+ timestamp sack-perm
+ }
+
+ synproxy other-synproxy {
+ mss 1460
+ wscale 5
+ }
+
+ map test2 {
+ type ipv4_addr : synproxy
+ flags interval
+ elements = { 192.168.1.0/24 : "https-synproxy", 192.168.2.0/24 : "other-synproxy" }
+ }
+
+ chain y {
+ type filter hook input priority filter; policy accept;
+ synproxy name ip saddr map { 192.168.1.0/24 : "https-synproxy", 192.168.2.0/24 : "other-synproxy" }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0025anonymous_set_0.json-nft b/tests/shell/testcases/sets/dumps/0025anonymous_set_0.json-nft
new file mode 100644
index 00000000..9d56d025
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0025anonymous_set_0.json-nft
@@ -0,0 +1,102 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "set": [
+ "192.168.0.1",
+ "192.168.0.2",
+ "192.168.0.3"
+ ]
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "doesntexist"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 22,
+ 23
+ ]
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft b/tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft
index 6204b00c..59636994 100644
--- a/tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft
+++ b/tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft
@@ -2,6 +2,6 @@ table ip t {
chain c {
type filter hook output priority filter; policy accept;
ip daddr { 192.168.0.1, 192.168.0.2, 192.168.0.3 }
- tcp dport { 22, 23 } counter packets 0 bytes 0
+ oifname "doesntexist" tcp dport { 22, 23 } counter packets 0 bytes 0
}
}
diff --git a/tests/shell/testcases/sets/dumps/0026named_limit_0.json-nft b/tests/shell/testcases/sets/dumps/0026named_limit_0.json-nft
new file mode 100644
index 00000000..5d21f26c
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0026named_limit_0.json-nft
@@ -0,0 +1,75 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "limit": {
+ "family": "ip",
+ "name": "http-traffic",
+ "table": "filter",
+ "handle": 0,
+ "rate": 1,
+ "per": "second",
+ "burst": 5
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "limit": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ 80,
+ "http-traffic"
+ ],
+ [
+ 443,
+ "http-traffic"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0027ipv6_maps_ipv4_0.json-nft b/tests/shell/testcases/sets/dumps/0027ipv6_maps_ipv4_0.json-nft
new file mode 100644
index 00000000..b9251ffa
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0027ipv6_maps_ipv4_0.json-nft
@@ -0,0 +1,38 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s",
+ "table": "t",
+ "type": "ipv6_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "::ffff:0.0.0.0",
+ "len": 96
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0028autoselect_0.json-nft b/tests/shell/testcases/sets/dumps/0028autoselect_0.json-nft
new file mode 100644
index 00000000..5968b2e0
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0028autoselect_0.json-nft
@@ -0,0 +1,168 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s1",
+ "table": "t",
+ "type": "inet_proto",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s2",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s3",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 1024,
+ "flags": [
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "foobar"
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "protocol"
+ }
+ },
+ "set": "@s1"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "foobar"
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "set": "@s2"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "foobar"
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "set": "@s3"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0028autoselect_0.nft b/tests/shell/testcases/sets/dumps/0028autoselect_0.nft
new file mode 100644
index 00000000..0c604927
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0028autoselect_0.nft
@@ -0,0 +1,26 @@
+table ip t {
+ set s1 {
+ type inet_proto
+ size 65535
+ flags dynamic
+ }
+
+ set s2 {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ }
+
+ set s3 {
+ type ipv4_addr
+ size 1024
+ flags dynamic
+ }
+
+ chain c {
+ type filter hook input priority filter; policy accept;
+ iifname "foobar" add @s1 { ip protocol }
+ iifname "foobar" add @s2 { ip daddr }
+ iifname "foobar" add @s3 { ip daddr }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0028delete_handle_0.json-nft b/tests/shell/testcases/sets/dumps/0028delete_handle_0.json-nft
new file mode 100644
index 00000000..96314141
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0028delete_handle_0.json-nft
@@ -0,0 +1,53 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test-ip",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "x",
+ "table": "test-ip",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "test-ip",
+ "type": "inet_service",
+ "handle": 0,
+ "flags": [
+ "timeout"
+ ],
+ "timeout": 10845
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "z",
+ "table": "test-ip",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "constant",
+ "interval"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0028delete_handle_0.nft b/tests/shell/testcases/sets/dumps/0028delete_handle_0.nft
new file mode 100644
index 00000000..0f25c763
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0028delete_handle_0.nft
@@ -0,0 +1,15 @@
+table ip test-ip {
+ set x {
+ type ipv4_addr
+ }
+
+ set y {
+ type inet_service
+ timeout 3h45s
+ }
+
+ set z {
+ type ipv4_addr
+ flags constant,interval
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0029named_ifname_dtype_0.nft b/tests/shell/testcases/sets/dumps/0029named_ifname_dtype_0.nft
index 23ff89bb..55cd4f26 100644
--- a/tests/shell/testcases/sets/dumps/0029named_ifname_dtype_0.nft
+++ b/tests/shell/testcases/sets/dumps/0029named_ifname_dtype_0.nft
@@ -1,17 +1,57 @@
table inet t {
set s {
type ifname
- elements = { "eth0" }
+ elements = { "eth0",
+ "eth1",
+ "eth2",
+ "eth3",
+ "veth1" }
}
set sc {
type inet_service . ifname
- elements = { 22 . "eth0" }
+ elements = { 22 . "eth0",
+ 80 . "eth0",
+ 81 . "eth0",
+ 80 . "eth1" }
+ }
+
+ set nv {
+ type ifname . mark
+ elements = { "eth0" . 0x00000001,
+ "eth0" . 0x00000002 }
+ }
+
+ set z {
+ typeof ct zone
+ elements = { 1, 2, 3, 4, 5,
+ 6 }
+ }
+
+ set m {
+ typeof meta mark
+ elements = { 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005,
+ 0x00000006 }
+ }
+
+ map cz {
+ typeof iifname : ct zone
+ elements = { "eth0" : 1,
+ "eth1" : 2,
+ "veth4" : 1 }
+ }
+
+ map cm {
+ typeof iifname : ct mark
+ elements = { "eth0" : 0x00000001,
+ "eth1" : 0x00000002,
+ "veth4" : 0x00000001 }
}
chain c {
iifname @s accept
oifname @s accept
tcp dport . iifname @sc accept
+ iifname . meta mark @nv accept
}
}
diff --git a/tests/shell/testcases/sets/dumps/0030add_many_elements_interval_0.nodump b/tests/shell/testcases/sets/dumps/0030add_many_elements_interval_0.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0030add_many_elements_interval_0.nodump
diff --git a/tests/shell/testcases/sets/dumps/0031set_timeout_size_0.nodump b/tests/shell/testcases/sets/dumps/0031set_timeout_size_0.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0031set_timeout_size_0.nodump
diff --git a/tests/shell/testcases/sets/dumps/0032restore_set_simple_0.json-nft b/tests/shell/testcases/sets/dumps/0032restore_set_simple_0.json-nft
new file mode 100644
index 00000000..4d194bff
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0032restore_set_simple_0.json-nft
@@ -0,0 +1,49 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "setA",
+ "table": "filter",
+ "type": [
+ "ipv4_addr",
+ "inet_service",
+ "ipv4_addr"
+ ],
+ "handle": 0,
+ "flags": [
+ "timeout"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "setB",
+ "table": "filter",
+ "type": [
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "flags": [
+ "timeout"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.json-nft b/tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.json-nft
new file mode 100644
index 00000000..16684438
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.json-nft
@@ -0,0 +1,49 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "setA",
+ "table": "x",
+ "type": [
+ "ipv4_addr",
+ "inet_service",
+ "ipv4_addr"
+ ],
+ "handle": 0,
+ "flags": [
+ "timeout"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "setB",
+ "table": "x",
+ "type": [
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "flags": [
+ "timeout"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.nft b/tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.nft
new file mode 100644
index 00000000..d6174c51
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0033add_set_simple_flat_0.nft
@@ -0,0 +1,11 @@
+table ip x {
+ set setA {
+ type ipv4_addr . inet_service . ipv4_addr
+ flags timeout
+ }
+
+ set setB {
+ type ipv4_addr . inet_service
+ flags timeout
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0034get_element_0.json-nft b/tests/shell/testcases/sets/dumps/0034get_element_0.json-nft
new file mode 100644
index 00000000..bfc0e4a0
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0034get_element_0.json-nft
@@ -0,0 +1,140 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "inet_service",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ 10,
+ {
+ "range": [
+ 20,
+ 30
+ ]
+ },
+ 40,
+ {
+ "range": [
+ 50,
+ 60
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "ips",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ "10.0.0.1",
+ {
+ "range": [
+ "10.0.0.5",
+ "10.0.0.8"
+ ]
+ },
+ {
+ "prefix": {
+ "addr": "10.0.0.128",
+ "len": 25
+ }
+ },
+ {
+ "prefix": {
+ "addr": "10.0.1.0",
+ "len": 24
+ }
+ },
+ {
+ "range": [
+ "10.0.2.3",
+ "10.0.2.12"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "cs",
+ "table": "t",
+ "type": [
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "concat": [
+ "10.0.0.1",
+ 22
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "10.1.0.0",
+ "len": 16
+ }
+ },
+ {
+ "range": [
+ 1,
+ 1024
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "range": [
+ "10.2.0.1",
+ "10.2.0.8"
+ ]
+ },
+ {
+ "range": [
+ 1024,
+ 65535
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0034get_element_0.nft b/tests/shell/testcases/sets/dumps/0034get_element_0.nft
new file mode 100644
index 00000000..1c1dd977
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0034get_element_0.nft
@@ -0,0 +1,23 @@
+table ip t {
+ set s {
+ type inet_service
+ flags interval
+ elements = { 10, 20-30, 40, 50-60 }
+ }
+
+ set ips {
+ type ipv4_addr
+ flags interval
+ elements = { 10.0.0.1, 10.0.0.5-10.0.0.8,
+ 10.0.0.128/25, 10.0.1.0/24,
+ 10.0.2.3-10.0.2.12 }
+ }
+
+ set cs {
+ type ipv4_addr . inet_service
+ flags interval
+ elements = { 10.0.0.1 . 22,
+ 10.1.0.0/16 . 1-1024,
+ 10.2.0.1-10.2.0.8 . 1024-65535 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.json-nft b/tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.json-nft
new file mode 100644
index 00000000..e4c77147
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.nft b/tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.nft
new file mode 100644
index 00000000..ca69cee2
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0035add_set_elements_flat_0.nft
@@ -0,0 +1,6 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0036add_set_element_expiration_0.nodump b/tests/shell/testcases/sets/dumps/0036add_set_element_expiration_0.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0036add_set_element_expiration_0.nodump
diff --git a/tests/shell/testcases/sets/dumps/0037_set_with_inet_service_0.json-nft b/tests/shell/testcases/sets/dumps/0037_set_with_inet_service_0.json-nft
new file mode 100644
index 00000000..1c3b559d
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0037_set_with_inet_service_0.json-nft
@@ -0,0 +1,159 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "forward",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 0,
+ "policy": "drop"
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "myset",
+ "table": "filter",
+ "type": [
+ "ipv4_addr",
+ "inet_proto",
+ "inet_service"
+ ],
+ "handle": 0,
+ "elem": [
+ {
+ "concat": [
+ "192.168.0.113",
+ "tcp",
+ 22
+ ]
+ },
+ {
+ "concat": [
+ "192.168.0.12",
+ "tcp",
+ 53
+ ]
+ },
+ {
+ "concat": [
+ "192.168.0.12",
+ "udp",
+ 53
+ ]
+ },
+ {
+ "concat": [
+ "192.168.0.12",
+ "tcp",
+ 80
+ ]
+ },
+ {
+ "concat": [
+ "192.168.0.13",
+ "tcp",
+ 80
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "forward",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": [
+ "established",
+ "related"
+ ]
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "forward",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "new"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "protocol"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "th",
+ "field": "dport"
+ }
+ }
+ ]
+ },
+ "right": "@myset"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0037_set_with_inet_service_0.nft b/tests/shell/testcases/sets/dumps/0037_set_with_inet_service_0.nft
index 0e85f7c2..68b1f7be 100644
--- a/tests/shell/testcases/sets/dumps/0037_set_with_inet_service_0.nft
+++ b/tests/shell/testcases/sets/dumps/0037_set_with_inet_service_0.nft
@@ -1,11 +1,11 @@
table inet filter {
set myset {
type ipv4_addr . inet_proto . inet_service
- elements = { 192.168.0.12 . tcp . 53,
- 192.168.0.12 . tcp . 80,
+ elements = { 192.168.0.113 . tcp . 22,
+ 192.168.0.12 . tcp . 53,
192.168.0.12 . udp . 53,
- 192.168.0.13 . tcp . 80,
- 192.168.0.113 . tcp . 22 }
+ 192.168.0.12 . tcp . 80,
+ 192.168.0.13 . tcp . 80 }
}
chain forward {
diff --git a/tests/shell/testcases/sets/dumps/0038meter_list_0.json-nft b/tests/shell/testcases/sets/dumps/0038meter_list_0.json-nft
new file mode 100644
index 00000000..5b13f59a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0038meter_list_0.json-nft
@@ -0,0 +1,96 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 256,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "m",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 128,
+ "flags": [
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 80
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "set": "@m",
+ "stmt": [
+ {
+ "limit": {
+ "rate": 10,
+ "burst": 5,
+ "per": "second"
+ }
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0038meter_list_0.nft b/tests/shell/testcases/sets/dumps/0038meter_list_0.nft
new file mode 100644
index 00000000..8037dfa5
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0038meter_list_0.nft
@@ -0,0 +1,17 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ size 256
+ flags dynamic,timeout
+ }
+
+ set m {
+ type ipv4_addr
+ size 128
+ flags dynamic
+ }
+
+ chain c {
+ tcp dport 80 add @m { ip saddr limit rate 10/second burst 5 packets }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0039delete_interval_0.json-nft b/tests/shell/testcases/sets/dumps/0039delete_interval_0.json-nft
new file mode 100644
index 00000000..d6e46aad
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0039delete_interval_0.json-nft
@@ -0,0 +1,39 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "range": [
+ "192.168.1.0",
+ "192.168.1.254"
+ ]
+ },
+ "192.168.1.255"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0039delete_interval_0.nft b/tests/shell/testcases/sets/dumps/0039delete_interval_0.nft
new file mode 100644
index 00000000..1fc76572
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0039delete_interval_0.nft
@@ -0,0 +1,7 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ flags interval
+ elements = { 192.168.1.0-192.168.1.254, 192.168.1.255 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.json-nft b/tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.json-nft
new file mode 100644
index 00000000..4b6cf03c
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.json-nft
@@ -0,0 +1,39 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "mark",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "range": [
+ 35,
+ 66
+ ]
+ },
+ 4919
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.nft b/tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.nft
new file mode 100644
index 00000000..f580c381
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0040get_host_endian_elements_0.nft
@@ -0,0 +1,7 @@
+table ip t {
+ set s {
+ type mark
+ flags interval
+ elements = { 0x00000023-0x00000042, 0x00001337 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0041interval_0.json-nft b/tests/shell/testcases/sets/dumps/0041interval_0.json-nft
new file mode 100644
index 00000000..14a39330
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0041interval_0.json-nft
@@ -0,0 +1,33 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ "192.168.2.196"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0041interval_0.nft b/tests/shell/testcases/sets/dumps/0041interval_0.nft
new file mode 100644
index 00000000..222d4d74
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0041interval_0.nft
@@ -0,0 +1,7 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ flags interval
+ elements = { 192.168.2.196 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0042update_set_0.json-nft b/tests/shell/testcases/sets/dumps/0042update_set_0.json-nft
new file mode 100644
index 00000000..bc1d4cc2
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0042update_set_0.json-nft
@@ -0,0 +1,87 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "set1",
+ "table": "t",
+ "type": "ether_addr",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "set2",
+ "table": "t",
+ "type": "ether_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ether",
+ "field": "daddr"
+ }
+ },
+ "right": "@set1"
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "payload": {
+ "protocol": "ether",
+ "field": "daddr"
+ }
+ },
+ "set": "@set2",
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0042update_set_0.nft b/tests/shell/testcases/sets/dumps/0042update_set_0.nft
new file mode 100644
index 00000000..56cc875e
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0042update_set_0.nft
@@ -0,0 +1,15 @@
+table ip t {
+ set set1 {
+ type ether_addr
+ }
+
+ set set2 {
+ type ether_addr
+ size 65535
+ flags dynamic
+ }
+
+ chain c {
+ ether daddr @set1 add @set2 { ether daddr counter }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0043concatenated_ranges_0.json-nft b/tests/shell/testcases/sets/dumps/0043concatenated_ranges_0.json-nft
new file mode 100644
index 00000000..ffb76e2f
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0043concatenated_ranges_0.json-nft
@@ -0,0 +1,98 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "output",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "test",
+ "table": "filter",
+ "type": [
+ "mark",
+ "inet_service",
+ "inet_proto"
+ ],
+ "handle": 0,
+ "map": "mark",
+ "flags": [
+ "interval",
+ "timeout"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "output",
+ "handle": 0,
+ "expr": [
+ {
+ "mangle": {
+ "key": {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ "value": {
+ "map": {
+ "key": {
+ "concat": [
+ {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ {
+ "meta": {
+ "key": "l4proto"
+ }
+ }
+ ]
+ },
+ "data": "@test"
+ }
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0043concatenated_ranges_0.nft b/tests/shell/testcases/sets/dumps/0043concatenated_ranges_0.nft
new file mode 100644
index 00000000..f2077b91
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0043concatenated_ranges_0.nft
@@ -0,0 +1,11 @@
+table inet filter {
+ map test {
+ type mark . inet_service . inet_proto : mark
+ flags interval,timeout
+ }
+
+ chain output {
+ type filter hook output priority filter; policy accept;
+ meta mark set meta mark . tcp dport . meta l4proto map @test counter packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.json-nft b/tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.json-nft
new file mode 100644
index 00000000..92b59c86
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.json-nft
@@ -0,0 +1,1723 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip6",
+ "name": "s",
+ "table": "t",
+ "type": [
+ "ipv6_addr",
+ "ipv6_addr"
+ ],
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 32
+ }
+ },
+ {
+ "range": [
+ "2001:db8:20::",
+ "2001:db8:20::20:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 33
+ }
+ },
+ {
+ "range": [
+ "2001:db8:21::",
+ "2001:db8:21::21:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 34
+ }
+ },
+ {
+ "range": [
+ "2001:db8:22::",
+ "2001:db8:22::22:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 35
+ }
+ },
+ {
+ "range": [
+ "2001:db8:23::",
+ "2001:db8:23::23:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 36
+ }
+ },
+ {
+ "range": [
+ "2001:db8:24::",
+ "2001:db8:24::24:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 37
+ }
+ },
+ {
+ "range": [
+ "2001:db8:25::",
+ "2001:db8:25::25:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 38
+ }
+ },
+ {
+ "range": [
+ "2001:db8:26::",
+ "2001:db8:26::26:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 39
+ }
+ },
+ {
+ "range": [
+ "2001:db8:27::",
+ "2001:db8:27::27:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 40
+ }
+ },
+ {
+ "range": [
+ "2001:db8:28::",
+ "2001:db8:28::28:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 41
+ }
+ },
+ {
+ "range": [
+ "2001:db8:29::",
+ "2001:db8:29::29:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 42
+ }
+ },
+ {
+ "range": [
+ "2001:db8:2a::",
+ "2001:db8:2a::2a:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 43
+ }
+ },
+ {
+ "range": [
+ "2001:db8:2b::",
+ "2001:db8:2b::2b:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 44
+ }
+ },
+ {
+ "range": [
+ "2001:db8:2c::",
+ "2001:db8:2c::2c:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 45
+ }
+ },
+ {
+ "range": [
+ "2001:db8:2d::",
+ "2001:db8:2d::2d:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 46
+ }
+ },
+ {
+ "range": [
+ "2001:db8:2e::",
+ "2001:db8:2e::2e:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 47
+ }
+ },
+ {
+ "range": [
+ "2001:db8:2f::",
+ "2001:db8:2f::2f:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 48
+ }
+ },
+ {
+ "range": [
+ "2001:db8:30::",
+ "2001:db8:30::30:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 49
+ }
+ },
+ {
+ "range": [
+ "2001:db8:31::",
+ "2001:db8:31::31:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 50
+ }
+ },
+ {
+ "range": [
+ "2001:db8:32::",
+ "2001:db8:32::32:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 51
+ }
+ },
+ {
+ "range": [
+ "2001:db8:33::",
+ "2001:db8:33::33:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 52
+ }
+ },
+ {
+ "range": [
+ "2001:db8:34::",
+ "2001:db8:34::34:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 53
+ }
+ },
+ {
+ "range": [
+ "2001:db8:35::",
+ "2001:db8:35::35:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 54
+ }
+ },
+ {
+ "range": [
+ "2001:db8:36::",
+ "2001:db8:36::36:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 55
+ }
+ },
+ {
+ "range": [
+ "2001:db8:37::",
+ "2001:db8:37::37:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 56
+ }
+ },
+ {
+ "range": [
+ "2001:db8:38::",
+ "2001:db8:38::38:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 57
+ }
+ },
+ {
+ "range": [
+ "2001:db8:39::",
+ "2001:db8:39::39:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 58
+ }
+ },
+ {
+ "range": [
+ "2001:db8:3a::",
+ "2001:db8:3a::3a:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 59
+ }
+ },
+ {
+ "range": [
+ "2001:db8:3b::",
+ "2001:db8:3b::3b:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 60
+ }
+ },
+ {
+ "range": [
+ "2001:db8:3c::",
+ "2001:db8:3c::3c:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 61
+ }
+ },
+ {
+ "range": [
+ "2001:db8:3d::",
+ "2001:db8:3d::3d:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 62
+ }
+ },
+ {
+ "range": [
+ "2001:db8:3e::",
+ "2001:db8:3e::3e:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 63
+ }
+ },
+ {
+ "range": [
+ "2001:db8:3f::",
+ "2001:db8:3f::3f:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 64
+ }
+ },
+ {
+ "range": [
+ "2001:db8:40::",
+ "2001:db8:40::40:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 65
+ }
+ },
+ {
+ "range": [
+ "2001:db8:41::",
+ "2001:db8:41::41:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 66
+ }
+ },
+ {
+ "range": [
+ "2001:db8:42::",
+ "2001:db8:42::42:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 67
+ }
+ },
+ {
+ "range": [
+ "2001:db8:43::",
+ "2001:db8:43::43:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 68
+ }
+ },
+ {
+ "range": [
+ "2001:db8:44::",
+ "2001:db8:44::44:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 69
+ }
+ },
+ {
+ "range": [
+ "2001:db8:45::",
+ "2001:db8:45::45:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 70
+ }
+ },
+ {
+ "range": [
+ "2001:db8:46::",
+ "2001:db8:46::46:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 71
+ }
+ },
+ {
+ "range": [
+ "2001:db8:47::",
+ "2001:db8:47::47:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 72
+ }
+ },
+ {
+ "range": [
+ "2001:db8:48::",
+ "2001:db8:48::48:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 73
+ }
+ },
+ {
+ "range": [
+ "2001:db8:49::",
+ "2001:db8:49::49:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 74
+ }
+ },
+ {
+ "range": [
+ "2001:db8:4a::",
+ "2001:db8:4a::4a:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 75
+ }
+ },
+ {
+ "range": [
+ "2001:db8:4b::",
+ "2001:db8:4b::4b:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 76
+ }
+ },
+ {
+ "range": [
+ "2001:db8:4c::",
+ "2001:db8:4c::4c:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 77
+ }
+ },
+ {
+ "range": [
+ "2001:db8:4d::",
+ "2001:db8:4d::4d:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 78
+ }
+ },
+ {
+ "range": [
+ "2001:db8:4e::",
+ "2001:db8:4e::4e:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 79
+ }
+ },
+ {
+ "range": [
+ "2001:db8:4f::",
+ "2001:db8:4f::4f:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 80
+ }
+ },
+ {
+ "range": [
+ "2001:db8:50::",
+ "2001:db8:50::50:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 81
+ }
+ },
+ {
+ "range": [
+ "2001:db8:51::",
+ "2001:db8:51::51:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 82
+ }
+ },
+ {
+ "range": [
+ "2001:db8:52::",
+ "2001:db8:52::52:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 83
+ }
+ },
+ {
+ "range": [
+ "2001:db8:53::",
+ "2001:db8:53::53:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 84
+ }
+ },
+ {
+ "range": [
+ "2001:db8:54::",
+ "2001:db8:54::54:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 85
+ }
+ },
+ {
+ "range": [
+ "2001:db8:55::",
+ "2001:db8:55::55:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 86
+ }
+ },
+ {
+ "range": [
+ "2001:db8:56::",
+ "2001:db8:56::56:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 87
+ }
+ },
+ {
+ "range": [
+ "2001:db8:57::",
+ "2001:db8:57::57:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 88
+ }
+ },
+ {
+ "range": [
+ "2001:db8:58::",
+ "2001:db8:58::58:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 89
+ }
+ },
+ {
+ "range": [
+ "2001:db8:59::",
+ "2001:db8:59::59:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 90
+ }
+ },
+ {
+ "range": [
+ "2001:db8:5a::",
+ "2001:db8:5a::5a:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 91
+ }
+ },
+ {
+ "range": [
+ "2001:db8:5b::",
+ "2001:db8:5b::5b:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 92
+ }
+ },
+ {
+ "range": [
+ "2001:db8:5c::",
+ "2001:db8:5c::5c:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 93
+ }
+ },
+ {
+ "range": [
+ "2001:db8:5d::",
+ "2001:db8:5d::5d:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 94
+ }
+ },
+ {
+ "range": [
+ "2001:db8:5e::",
+ "2001:db8:5e::5e:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 95
+ }
+ },
+ {
+ "range": [
+ "2001:db8:5f::",
+ "2001:db8:5f::5f:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 96
+ }
+ },
+ {
+ "range": [
+ "2001:db8:60::",
+ "2001:db8:60::60:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 97
+ }
+ },
+ {
+ "range": [
+ "2001:db8:61::",
+ "2001:db8:61::61:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 98
+ }
+ },
+ {
+ "range": [
+ "2001:db8:62::",
+ "2001:db8:62::62:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 99
+ }
+ },
+ {
+ "range": [
+ "2001:db8:63::",
+ "2001:db8:63::63:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 100
+ }
+ },
+ {
+ "range": [
+ "2001:db8:64::",
+ "2001:db8:64::64:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 101
+ }
+ },
+ {
+ "range": [
+ "2001:db8:65::",
+ "2001:db8:65::65:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 102
+ }
+ },
+ {
+ "range": [
+ "2001:db8:66::",
+ "2001:db8:66::66:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 103
+ }
+ },
+ {
+ "range": [
+ "2001:db8:67::",
+ "2001:db8:67::67:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 104
+ }
+ },
+ {
+ "range": [
+ "2001:db8:68::",
+ "2001:db8:68::68:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 105
+ }
+ },
+ {
+ "range": [
+ "2001:db8:69::",
+ "2001:db8:69::69:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 106
+ }
+ },
+ {
+ "range": [
+ "2001:db8:6a::",
+ "2001:db8:6a::6a:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 107
+ }
+ },
+ {
+ "range": [
+ "2001:db8:6b::",
+ "2001:db8:6b::6b:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 108
+ }
+ },
+ {
+ "range": [
+ "2001:db8:6c::",
+ "2001:db8:6c::6c:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 109
+ }
+ },
+ {
+ "range": [
+ "2001:db8:6d::",
+ "2001:db8:6d::6d:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 110
+ }
+ },
+ {
+ "range": [
+ "2001:db8:6e::",
+ "2001:db8:6e::6e:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 111
+ }
+ },
+ {
+ "range": [
+ "2001:db8:6f::",
+ "2001:db8:6f::6f:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 112
+ }
+ },
+ {
+ "range": [
+ "2001:db8:70::",
+ "2001:db8:70::70:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 113
+ }
+ },
+ {
+ "range": [
+ "2001:db8:71::",
+ "2001:db8:71::71:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 114
+ }
+ },
+ {
+ "range": [
+ "2001:db8:72::",
+ "2001:db8:72::72:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 115
+ }
+ },
+ {
+ "range": [
+ "2001:db8:73::",
+ "2001:db8:73::73:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 116
+ }
+ },
+ {
+ "range": [
+ "2001:db8:74::",
+ "2001:db8:74::74:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 117
+ }
+ },
+ {
+ "range": [
+ "2001:db8:75::",
+ "2001:db8:75::75:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 118
+ }
+ },
+ {
+ "range": [
+ "2001:db8:76::",
+ "2001:db8:76::76:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 119
+ }
+ },
+ {
+ "range": [
+ "2001:db8:77::",
+ "2001:db8:77::77:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 120
+ }
+ },
+ {
+ "range": [
+ "2001:db8:78::",
+ "2001:db8:78::78:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 121
+ }
+ },
+ {
+ "range": [
+ "2001:db8:79::",
+ "2001:db8:79::79:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 122
+ }
+ },
+ {
+ "range": [
+ "2001:db8:7a::",
+ "2001:db8:7a::7a:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 123
+ }
+ },
+ {
+ "range": [
+ "2001:db8:7b::",
+ "2001:db8:7b::7b:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 124
+ }
+ },
+ {
+ "range": [
+ "2001:db8:7c::",
+ "2001:db8:7c::7c:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 125
+ }
+ },
+ {
+ "range": [
+ "2001:db8:7d::",
+ "2001:db8:7d::7d:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 126
+ }
+ },
+ {
+ "range": [
+ "2001:db8:7e::",
+ "2001:db8:7e::7e:1"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "2001:db8::",
+ "len": 127
+ }
+ },
+ {
+ "range": [
+ "2001:db8:7f::",
+ "2001:db8:7f::7f:1"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": [
+ "ipv4_addr",
+ "ipv4_addr"
+ ],
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "192.0.2.0",
+ "len": 24
+ }
+ },
+ {
+ "range": [
+ "192.0.2.72",
+ "192.0.2.74"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "192.0.2.0",
+ "len": 25
+ }
+ },
+ {
+ "range": [
+ "192.0.2.75",
+ "192.0.2.77"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "192.0.2.0",
+ "len": 26
+ }
+ },
+ {
+ "range": [
+ "192.0.2.78",
+ "192.0.2.80"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "192.0.2.0",
+ "len": 27
+ }
+ },
+ {
+ "range": [
+ "192.0.2.81",
+ "192.0.2.83"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "192.0.2.0",
+ "len": 28
+ }
+ },
+ {
+ "range": [
+ "192.0.2.84",
+ "192.0.2.86"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "192.0.2.0",
+ "len": 29
+ }
+ },
+ {
+ "range": [
+ "192.0.2.87",
+ "192.0.2.89"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "192.0.2.0",
+ "len": 30
+ }
+ },
+ {
+ "range": [
+ "192.0.2.90",
+ "192.0.2.92"
+ ]
+ }
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "192.0.2.0",
+ "len": 31
+ }
+ },
+ {
+ "range": [
+ "192.0.2.93",
+ "192.0.2.95"
+ ]
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.nft b/tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.nft
new file mode 100644
index 00000000..19d08d3d
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0043concatenated_ranges_1.nft
@@ -0,0 +1,116 @@
+table ip6 t {
+ set s {
+ type ipv6_addr . ipv6_addr
+ flags interval
+ elements = { 2001:db8::/32 . 2001:db8:20::-2001:db8:20::20:1,
+ 2001:db8::/33 . 2001:db8:21::-2001:db8:21::21:1,
+ 2001:db8::/34 . 2001:db8:22::-2001:db8:22::22:1,
+ 2001:db8::/35 . 2001:db8:23::-2001:db8:23::23:1,
+ 2001:db8::/36 . 2001:db8:24::-2001:db8:24::24:1,
+ 2001:db8::/37 . 2001:db8:25::-2001:db8:25::25:1,
+ 2001:db8::/38 . 2001:db8:26::-2001:db8:26::26:1,
+ 2001:db8::/39 . 2001:db8:27::-2001:db8:27::27:1,
+ 2001:db8::/40 . 2001:db8:28::-2001:db8:28::28:1,
+ 2001:db8::/41 . 2001:db8:29::-2001:db8:29::29:1,
+ 2001:db8::/42 . 2001:db8:2a::-2001:db8:2a::2a:1,
+ 2001:db8::/43 . 2001:db8:2b::-2001:db8:2b::2b:1,
+ 2001:db8::/44 . 2001:db8:2c::-2001:db8:2c::2c:1,
+ 2001:db8::/45 . 2001:db8:2d::-2001:db8:2d::2d:1,
+ 2001:db8::/46 . 2001:db8:2e::-2001:db8:2e::2e:1,
+ 2001:db8::/47 . 2001:db8:2f::-2001:db8:2f::2f:1,
+ 2001:db8::/48 . 2001:db8:30::-2001:db8:30::30:1,
+ 2001:db8::/49 . 2001:db8:31::-2001:db8:31::31:1,
+ 2001:db8::/50 . 2001:db8:32::-2001:db8:32::32:1,
+ 2001:db8::/51 . 2001:db8:33::-2001:db8:33::33:1,
+ 2001:db8::/52 . 2001:db8:34::-2001:db8:34::34:1,
+ 2001:db8::/53 . 2001:db8:35::-2001:db8:35::35:1,
+ 2001:db8::/54 . 2001:db8:36::-2001:db8:36::36:1,
+ 2001:db8::/55 . 2001:db8:37::-2001:db8:37::37:1,
+ 2001:db8::/56 . 2001:db8:38::-2001:db8:38::38:1,
+ 2001:db8::/57 . 2001:db8:39::-2001:db8:39::39:1,
+ 2001:db8::/58 . 2001:db8:3a::-2001:db8:3a::3a:1,
+ 2001:db8::/59 . 2001:db8:3b::-2001:db8:3b::3b:1,
+ 2001:db8::/60 . 2001:db8:3c::-2001:db8:3c::3c:1,
+ 2001:db8::/61 . 2001:db8:3d::-2001:db8:3d::3d:1,
+ 2001:db8::/62 . 2001:db8:3e::-2001:db8:3e::3e:1,
+ 2001:db8::/63 . 2001:db8:3f::-2001:db8:3f::3f:1,
+ 2001:db8::/64 . 2001:db8:40::-2001:db8:40::40:1,
+ 2001:db8::/65 . 2001:db8:41::-2001:db8:41::41:1,
+ 2001:db8::/66 . 2001:db8:42::-2001:db8:42::42:1,
+ 2001:db8::/67 . 2001:db8:43::-2001:db8:43::43:1,
+ 2001:db8::/68 . 2001:db8:44::-2001:db8:44::44:1,
+ 2001:db8::/69 . 2001:db8:45::-2001:db8:45::45:1,
+ 2001:db8::/70 . 2001:db8:46::-2001:db8:46::46:1,
+ 2001:db8::/71 . 2001:db8:47::-2001:db8:47::47:1,
+ 2001:db8::/72 . 2001:db8:48::-2001:db8:48::48:1,
+ 2001:db8::/73 . 2001:db8:49::-2001:db8:49::49:1,
+ 2001:db8::/74 . 2001:db8:4a::-2001:db8:4a::4a:1,
+ 2001:db8::/75 . 2001:db8:4b::-2001:db8:4b::4b:1,
+ 2001:db8::/76 . 2001:db8:4c::-2001:db8:4c::4c:1,
+ 2001:db8::/77 . 2001:db8:4d::-2001:db8:4d::4d:1,
+ 2001:db8::/78 . 2001:db8:4e::-2001:db8:4e::4e:1,
+ 2001:db8::/79 . 2001:db8:4f::-2001:db8:4f::4f:1,
+ 2001:db8::/80 . 2001:db8:50::-2001:db8:50::50:1,
+ 2001:db8::/81 . 2001:db8:51::-2001:db8:51::51:1,
+ 2001:db8::/82 . 2001:db8:52::-2001:db8:52::52:1,
+ 2001:db8::/83 . 2001:db8:53::-2001:db8:53::53:1,
+ 2001:db8::/84 . 2001:db8:54::-2001:db8:54::54:1,
+ 2001:db8::/85 . 2001:db8:55::-2001:db8:55::55:1,
+ 2001:db8::/86 . 2001:db8:56::-2001:db8:56::56:1,
+ 2001:db8::/87 . 2001:db8:57::-2001:db8:57::57:1,
+ 2001:db8::/88 . 2001:db8:58::-2001:db8:58::58:1,
+ 2001:db8::/89 . 2001:db8:59::-2001:db8:59::59:1,
+ 2001:db8::/90 . 2001:db8:5a::-2001:db8:5a::5a:1,
+ 2001:db8::/91 . 2001:db8:5b::-2001:db8:5b::5b:1,
+ 2001:db8::/92 . 2001:db8:5c::-2001:db8:5c::5c:1,
+ 2001:db8::/93 . 2001:db8:5d::-2001:db8:5d::5d:1,
+ 2001:db8::/94 . 2001:db8:5e::-2001:db8:5e::5e:1,
+ 2001:db8::/95 . 2001:db8:5f::-2001:db8:5f::5f:1,
+ 2001:db8::/96 . 2001:db8:60::-2001:db8:60::60:1,
+ 2001:db8::/97 . 2001:db8:61::-2001:db8:61::61:1,
+ 2001:db8::/98 . 2001:db8:62::-2001:db8:62::62:1,
+ 2001:db8::/99 . 2001:db8:63::-2001:db8:63::63:1,
+ 2001:db8::/100 . 2001:db8:64::-2001:db8:64::64:1,
+ 2001:db8::/101 . 2001:db8:65::-2001:db8:65::65:1,
+ 2001:db8::/102 . 2001:db8:66::-2001:db8:66::66:1,
+ 2001:db8::/103 . 2001:db8:67::-2001:db8:67::67:1,
+ 2001:db8::/104 . 2001:db8:68::-2001:db8:68::68:1,
+ 2001:db8::/105 . 2001:db8:69::-2001:db8:69::69:1,
+ 2001:db8::/106 . 2001:db8:6a::-2001:db8:6a::6a:1,
+ 2001:db8::/107 . 2001:db8:6b::-2001:db8:6b::6b:1,
+ 2001:db8::/108 . 2001:db8:6c::-2001:db8:6c::6c:1,
+ 2001:db8::/109 . 2001:db8:6d::-2001:db8:6d::6d:1,
+ 2001:db8::/110 . 2001:db8:6e::-2001:db8:6e::6e:1,
+ 2001:db8::/111 . 2001:db8:6f::-2001:db8:6f::6f:1,
+ 2001:db8::/112 . 2001:db8:70::-2001:db8:70::70:1,
+ 2001:db8::/113 . 2001:db8:71::-2001:db8:71::71:1,
+ 2001:db8::/114 . 2001:db8:72::-2001:db8:72::72:1,
+ 2001:db8::/115 . 2001:db8:73::-2001:db8:73::73:1,
+ 2001:db8::/116 . 2001:db8:74::-2001:db8:74::74:1,
+ 2001:db8::/117 . 2001:db8:75::-2001:db8:75::75:1,
+ 2001:db8::/118 . 2001:db8:76::-2001:db8:76::76:1,
+ 2001:db8::/119 . 2001:db8:77::-2001:db8:77::77:1,
+ 2001:db8::/120 . 2001:db8:78::-2001:db8:78::78:1,
+ 2001:db8::/121 . 2001:db8:79::-2001:db8:79::79:1,
+ 2001:db8::/122 . 2001:db8:7a::-2001:db8:7a::7a:1,
+ 2001:db8::/123 . 2001:db8:7b::-2001:db8:7b::7b:1,
+ 2001:db8::/124 . 2001:db8:7c::-2001:db8:7c::7c:1,
+ 2001:db8::/125 . 2001:db8:7d::-2001:db8:7d::7d:1,
+ 2001:db8::/126 . 2001:db8:7e::-2001:db8:7e::7e:1,
+ 2001:db8::/127 . 2001:db8:7f::-2001:db8:7f::7f:1 }
+ }
+}
+table ip t {
+ set s {
+ type ipv4_addr . ipv4_addr
+ flags interval
+ elements = { 192.0.2.0/24 . 192.0.2.72-192.0.2.74,
+ 192.0.2.0/25 . 192.0.2.75-192.0.2.77,
+ 192.0.2.0/26 . 192.0.2.78-192.0.2.80,
+ 192.0.2.0/27 . 192.0.2.81-192.0.2.83,
+ 192.0.2.0/28 . 192.0.2.84-192.0.2.86,
+ 192.0.2.0/29 . 192.0.2.87-192.0.2.89,
+ 192.0.2.0/30 . 192.0.2.90-192.0.2.92,
+ 192.0.2.0/31 . 192.0.2.93-192.0.2.95 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0044interval_overlap_0.nodump b/tests/shell/testcases/sets/dumps/0044interval_overlap_0.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0044interval_overlap_0.nodump
diff --git a/tests/shell/testcases/sets/dumps/0044interval_overlap_1.json-nft b/tests/shell/testcases/sets/dumps/0044interval_overlap_1.json-nft
new file mode 100644
index 00000000..f4aae383
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0044interval_overlap_1.json-nft
@@ -0,0 +1,529 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "inet_service",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ 25,
+ 30,
+ 82,
+ 119,
+ 349,
+ 745,
+ 748,
+ 1165,
+ 1233,
+ 1476,
+ 1550,
+ 1562,
+ 1743,
+ 1745,
+ 1882,
+ 2070,
+ 2194,
+ 2238,
+ 2450,
+ 2455,
+ 2642,
+ 2671,
+ 2906,
+ 3093,
+ 3203,
+ 3287,
+ 3348,
+ 3411,
+ 3540,
+ 3892,
+ 3943,
+ 4133,
+ 4205,
+ 4317,
+ 4733,
+ 5095,
+ 5156,
+ 5223,
+ 5230,
+ 5432,
+ 5826,
+ 5828,
+ 6044,
+ 6377,
+ 6388,
+ 6491,
+ 6952,
+ 6986,
+ 7012,
+ 7187,
+ 7300,
+ 7305,
+ 7549,
+ 7664,
+ 8111,
+ 8206,
+ 8396,
+ 8782,
+ 8920,
+ 8981,
+ 9067,
+ 9216,
+ 9245,
+ 9315,
+ 9432,
+ 9587,
+ 9689,
+ 9844,
+ 9991,
+ 10045,
+ 10252,
+ 10328,
+ 10670,
+ 10907,
+ 11021,
+ 11337,
+ 11427,
+ 11497,
+ 11502,
+ 11523,
+ 11552,
+ 11577,
+ 11721,
+ 11943,
+ 12474,
+ 12718,
+ 12764,
+ 12794,
+ 12922,
+ 13186,
+ 13232,
+ 13383,
+ 13431,
+ 13551,
+ 13676,
+ 13685,
+ 13747,
+ 13925,
+ 13935,
+ 14015,
+ 14090,
+ 14320,
+ 14392,
+ 14515,
+ 14647,
+ 14911,
+ 15096,
+ 15105,
+ 15154,
+ 15440,
+ 15583,
+ 15623,
+ 15677,
+ 15710,
+ 15926,
+ 15934,
+ 15960,
+ 16068,
+ 16166,
+ 16486,
+ 16489,
+ 16528,
+ 16646,
+ 16650,
+ 16770,
+ 16882,
+ 17052,
+ 17237,
+ 17387,
+ 17431,
+ 17886,
+ 17939,
+ 17999,
+ 18092,
+ 18123,
+ 18238,
+ 18562,
+ 18698,
+ 19004,
+ 19229,
+ 19237,
+ 19585,
+ 19879,
+ 19938,
+ 19950,
+ 19958,
+ 20031,
+ 20138,
+ 20157,
+ 20205,
+ 20368,
+ 20682,
+ 20687,
+ 20873,
+ 20910,
+ 20919,
+ 21019,
+ 21068,
+ 21115,
+ 21188,
+ 21236,
+ 21319,
+ 21563,
+ 21734,
+ 21806,
+ 21810,
+ 21959,
+ 21982,
+ 22078,
+ 22181,
+ 22308,
+ 22480,
+ 22643,
+ 22854,
+ 22879,
+ 22961,
+ 23397,
+ 23534,
+ 23845,
+ 23893,
+ 24130,
+ 24406,
+ 24794,
+ 24997,
+ 25019,
+ 25143,
+ 25179,
+ 25439,
+ 25603,
+ 25718,
+ 25859,
+ 25949,
+ 26006,
+ 26022,
+ 26047,
+ 26170,
+ 26193,
+ 26725,
+ 26747,
+ 26924,
+ 27023,
+ 27040,
+ 27233,
+ 27344,
+ 27478,
+ 27593,
+ 27600,
+ 27664,
+ 27678,
+ 27818,
+ 27822,
+ 28003,
+ 28038,
+ 28709,
+ 28808,
+ 29010,
+ 29057,
+ 29228,
+ 29485,
+ 30132,
+ 30160,
+ 30415,
+ 30469,
+ 30673,
+ 30736,
+ 30776,
+ 30780,
+ 31450,
+ 31537,
+ 31669,
+ 31839,
+ 31873,
+ 32019,
+ 32229,
+ 32685,
+ 32879,
+ 33318,
+ 33337,
+ 33404,
+ 33517,
+ 33906,
+ 34214,
+ 34346,
+ 34416,
+ 34727,
+ 34848,
+ 35325,
+ 35400,
+ 35451,
+ 35501,
+ 35637,
+ 35653,
+ 35710,
+ 35761,
+ 35767,
+ 36238,
+ 36258,
+ 36279,
+ 36464,
+ 36586,
+ 36603,
+ 36770,
+ 36774,
+ 36805,
+ 36851,
+ 37079,
+ 37189,
+ 37209,
+ 37565,
+ 37570,
+ 37585,
+ 37832,
+ 37931,
+ 37954,
+ 38006,
+ 38015,
+ 38045,
+ 38109,
+ 38114,
+ 38200,
+ 38209,
+ 38214,
+ 38277,
+ 38306,
+ 38402,
+ 38606,
+ 38697,
+ 38960,
+ 39004,
+ 39006,
+ 39197,
+ 39217,
+ 39265,
+ 39319,
+ 39460,
+ 39550,
+ 39615,
+ 39871,
+ 39886,
+ 40088,
+ 40135,
+ 40244,
+ 40323,
+ 40339,
+ 40355,
+ 40385,
+ 40428,
+ 40538,
+ 40791,
+ 40848,
+ 40959,
+ 41003,
+ 41131,
+ 41349,
+ 41643,
+ 41710,
+ 41826,
+ 41904,
+ 42027,
+ 42148,
+ 42235,
+ 42255,
+ 42498,
+ 42680,
+ 42973,
+ 43118,
+ 43135,
+ 43233,
+ 43349,
+ 43411,
+ 43487,
+ 43840,
+ 43843,
+ 43870,
+ 44040,
+ 44204,
+ 44817,
+ 44883,
+ 44894,
+ 44958,
+ 45201,
+ 45259,
+ 45283,
+ 45357,
+ 45423,
+ 45473,
+ 45498,
+ 45519,
+ 45561,
+ 45611,
+ 45627,
+ 45831,
+ 46043,
+ 46105,
+ 46116,
+ 46147,
+ 46169,
+ 46349,
+ 47147,
+ 47252,
+ 47314,
+ 47335,
+ 47360,
+ 47546,
+ 47617,
+ 47648,
+ 47772,
+ 47793,
+ 47846,
+ 47913,
+ 47952,
+ 48095,
+ 48325,
+ 48334,
+ 48412,
+ 48419,
+ 48540,
+ 48569,
+ 48628,
+ 48751,
+ 48944,
+ 48971,
+ 49008,
+ 49025,
+ 49503,
+ 49505,
+ 49613,
+ 49767,
+ 49839,
+ 49925,
+ 50022,
+ 50028,
+ 50238,
+ 51057,
+ 51477,
+ 51617,
+ 51910,
+ 52044,
+ 52482,
+ 52550,
+ 52643,
+ 52832,
+ 53382,
+ 53690,
+ 53809,
+ 53858,
+ 54001,
+ 54198,
+ 54280,
+ 54327,
+ 54376,
+ 54609,
+ 54776,
+ 54983,
+ 54984,
+ 55019,
+ 55038,
+ 55094,
+ 55368,
+ 55737,
+ 55793,
+ 55904,
+ 55941,
+ 55960,
+ 55978,
+ 56063,
+ 56121,
+ 56314,
+ 56505,
+ 56548,
+ 56568,
+ 56696,
+ 56798,
+ 56855,
+ 57102,
+ 57236,
+ 57333,
+ 57334,
+ 57441,
+ 57574,
+ 57659,
+ 57987,
+ 58325,
+ 58404,
+ 58509,
+ 58782,
+ 58876,
+ 59116,
+ 59544,
+ 59685,
+ 59700,
+ 59750,
+ 59799,
+ 59866,
+ 59870,
+ 59894,
+ 59984,
+ 60343,
+ 60481,
+ 60564,
+ 60731,
+ 61075,
+ 61087,
+ 61148,
+ 61174,
+ 61655,
+ 61679,
+ 61691,
+ 61723,
+ 61730,
+ 61758,
+ 61824,
+ 62035,
+ 62056,
+ 62661,
+ 62768,
+ 62946,
+ 63059,
+ 63116,
+ 63338,
+ 63387,
+ 63672,
+ 63719,
+ 63881,
+ 63995,
+ 64197,
+ 64374,
+ 64377,
+ 64472,
+ 64606,
+ 64662,
+ 64777,
+ 64795,
+ 64906,
+ 65049,
+ 65122,
+ 65318
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0044interval_overlap_1.nft b/tests/shell/testcases/sets/dumps/0044interval_overlap_1.nft
new file mode 100644
index 00000000..5b249a3e
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0044interval_overlap_1.nft
@@ -0,0 +1,106 @@
+table ip t {
+ set s {
+ type inet_service
+ flags interval
+ elements = { 25, 30, 82, 119, 349,
+ 745, 748, 1165, 1233, 1476,
+ 1550, 1562, 1743, 1745, 1882,
+ 2070, 2194, 2238, 2450, 2455,
+ 2642, 2671, 2906, 3093, 3203,
+ 3287, 3348, 3411, 3540, 3892,
+ 3943, 4133, 4205, 4317, 4733,
+ 5095, 5156, 5223, 5230, 5432,
+ 5826, 5828, 6044, 6377, 6388,
+ 6491, 6952, 6986, 7012, 7187,
+ 7300, 7305, 7549, 7664, 8111,
+ 8206, 8396, 8782, 8920, 8981,
+ 9067, 9216, 9245, 9315, 9432,
+ 9587, 9689, 9844, 9991, 10045,
+ 10252, 10328, 10670, 10907, 11021,
+ 11337, 11427, 11497, 11502, 11523,
+ 11552, 11577, 11721, 11943, 12474,
+ 12718, 12764, 12794, 12922, 13186,
+ 13232, 13383, 13431, 13551, 13676,
+ 13685, 13747, 13925, 13935, 14015,
+ 14090, 14320, 14392, 14515, 14647,
+ 14911, 15096, 15105, 15154, 15440,
+ 15583, 15623, 15677, 15710, 15926,
+ 15934, 15960, 16068, 16166, 16486,
+ 16489, 16528, 16646, 16650, 16770,
+ 16882, 17052, 17237, 17387, 17431,
+ 17886, 17939, 17999, 18092, 18123,
+ 18238, 18562, 18698, 19004, 19229,
+ 19237, 19585, 19879, 19938, 19950,
+ 19958, 20031, 20138, 20157, 20205,
+ 20368, 20682, 20687, 20873, 20910,
+ 20919, 21019, 21068, 21115, 21188,
+ 21236, 21319, 21563, 21734, 21806,
+ 21810, 21959, 21982, 22078, 22181,
+ 22308, 22480, 22643, 22854, 22879,
+ 22961, 23397, 23534, 23845, 23893,
+ 24130, 24406, 24794, 24997, 25019,
+ 25143, 25179, 25439, 25603, 25718,
+ 25859, 25949, 26006, 26022, 26047,
+ 26170, 26193, 26725, 26747, 26924,
+ 27023, 27040, 27233, 27344, 27478,
+ 27593, 27600, 27664, 27678, 27818,
+ 27822, 28003, 28038, 28709, 28808,
+ 29010, 29057, 29228, 29485, 30132,
+ 30160, 30415, 30469, 30673, 30736,
+ 30776, 30780, 31450, 31537, 31669,
+ 31839, 31873, 32019, 32229, 32685,
+ 32879, 33318, 33337, 33404, 33517,
+ 33906, 34214, 34346, 34416, 34727,
+ 34848, 35325, 35400, 35451, 35501,
+ 35637, 35653, 35710, 35761, 35767,
+ 36238, 36258, 36279, 36464, 36586,
+ 36603, 36770, 36774, 36805, 36851,
+ 37079, 37189, 37209, 37565, 37570,
+ 37585, 37832, 37931, 37954, 38006,
+ 38015, 38045, 38109, 38114, 38200,
+ 38209, 38214, 38277, 38306, 38402,
+ 38606, 38697, 38960, 39004, 39006,
+ 39197, 39217, 39265, 39319, 39460,
+ 39550, 39615, 39871, 39886, 40088,
+ 40135, 40244, 40323, 40339, 40355,
+ 40385, 40428, 40538, 40791, 40848,
+ 40959, 41003, 41131, 41349, 41643,
+ 41710, 41826, 41904, 42027, 42148,
+ 42235, 42255, 42498, 42680, 42973,
+ 43118, 43135, 43233, 43349, 43411,
+ 43487, 43840, 43843, 43870, 44040,
+ 44204, 44817, 44883, 44894, 44958,
+ 45201, 45259, 45283, 45357, 45423,
+ 45473, 45498, 45519, 45561, 45611,
+ 45627, 45831, 46043, 46105, 46116,
+ 46147, 46169, 46349, 47147, 47252,
+ 47314, 47335, 47360, 47546, 47617,
+ 47648, 47772, 47793, 47846, 47913,
+ 47952, 48095, 48325, 48334, 48412,
+ 48419, 48540, 48569, 48628, 48751,
+ 48944, 48971, 49008, 49025, 49503,
+ 49505, 49613, 49767, 49839, 49925,
+ 50022, 50028, 50238, 51057, 51477,
+ 51617, 51910, 52044, 52482, 52550,
+ 52643, 52832, 53382, 53690, 53809,
+ 53858, 54001, 54198, 54280, 54327,
+ 54376, 54609, 54776, 54983, 54984,
+ 55019, 55038, 55094, 55368, 55737,
+ 55793, 55904, 55941, 55960, 55978,
+ 56063, 56121, 56314, 56505, 56548,
+ 56568, 56696, 56798, 56855, 57102,
+ 57236, 57333, 57334, 57441, 57574,
+ 57659, 57987, 58325, 58404, 58509,
+ 58782, 58876, 59116, 59544, 59685,
+ 59700, 59750, 59799, 59866, 59870,
+ 59894, 59984, 60343, 60481, 60564,
+ 60731, 61075, 61087, 61148, 61174,
+ 61655, 61679, 61691, 61723, 61730,
+ 61758, 61824, 62035, 62056, 62661,
+ 62768, 62946, 63059, 63116, 63338,
+ 63387, 63672, 63719, 63881, 63995,
+ 64197, 64374, 64377, 64472, 64606,
+ 64662, 64777, 64795, 64906, 65049,
+ 65122, 65318 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0045concat_ipv4_service.json-nft b/tests/shell/testcases/sets/dumps/0045concat_ipv4_service.json-nft
new file mode 100644
index 00000000..8473c333
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0045concat_ipv4_service.json-nft
@@ -0,0 +1,95 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s",
+ "table": "t",
+ "type": [
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "size": 65536,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ],
+ "elem": [
+ {
+ "concat": [
+ "192.168.7.1",
+ 22
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 21
+ }
+ },
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "elem": {
+ "val": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ 22
+ ]
+ },
+ "timeout": 60
+ }
+ },
+ "set": "@s"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0045concat_ipv4_service.nft b/tests/shell/testcases/sets/dumps/0045concat_ipv4_service.nft
new file mode 100644
index 00000000..e548a17a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0045concat_ipv4_service.nft
@@ -0,0 +1,12 @@
+table inet t {
+ set s {
+ type ipv4_addr . inet_service
+ size 65536
+ flags dynamic,timeout
+ elements = { 192.168.7.1 . 22 }
+ }
+
+ chain c {
+ tcp dport 21 add @s { ip saddr . 22 timeout 1m }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0046netmap_0.json-nft b/tests/shell/testcases/sets/dumps/0046netmap_0.json-nft
new file mode 100644
index 00000000..55f1a2ad
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0046netmap_0.json-nft
@@ -0,0 +1,167 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "nat",
+ "hook": "postrouting",
+ "prio": 100,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "snat": {
+ "family": "ip",
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "prefix": {
+ "addr": "10.141.11.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "192.168.2.0",
+ "len": 24
+ }
+ }
+ ],
+ [
+ {
+ "prefix": {
+ "addr": "10.141.12.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "192.168.3.0",
+ "len": 24
+ }
+ }
+ ],
+ [
+ {
+ "prefix": {
+ "addr": "10.141.13.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "192.168.4.0",
+ "len": 24
+ }
+ }
+ ]
+ ]
+ }
+ }
+ },
+ "flags": "netmap",
+ "type_flags": "prefix"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "nat",
+ "hook": "postrouting",
+ "prio": 100,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "snat": {
+ "family": "ip6",
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "prefix": {
+ "addr": "2001:db8:1111::",
+ "len": 64
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2001:db8:2222::",
+ "len": 64
+ }
+ }
+ ]
+ ]
+ }
+ }
+ },
+ "flags": "netmap",
+ "type_flags": "prefix"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0046netmap_0.nft b/tests/shell/testcases/sets/dumps/0046netmap_0.nft
new file mode 100644
index 00000000..5ac6b346
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0046netmap_0.nft
@@ -0,0 +1,12 @@
+table ip x {
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24, 10.141.12.0/24 : 192.168.3.0/24, 10.141.13.0/24 : 192.168.4.0/24 }
+ }
+}
+table ip6 x {
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip6 prefix to ip6 saddr map { 2001:db8:1111::/64 : 2001:db8:2222::/64 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0047nat_0.nft b/tests/shell/testcases/sets/dumps/0047nat_0.nft
new file mode 100644
index 00000000..9fa9fc74
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0047nat_0.nft
@@ -0,0 +1,30 @@
+table ip x {
+ map y {
+ type ipv4_addr : interval ipv4_addr
+ flags interval
+ elements = { 10.141.10.0/24 : 192.168.2.2-192.168.2.4, 10.141.11.0/24 : 192.168.4.2/31,
+ 10.141.12.0/24 : 192.168.5.10-192.168.5.20 }
+ }
+
+ chain x {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69 . 22, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 }
+ dnat ip to iifname . ip saddr map { "enp2s0" . 10.1.1.136 : 1.1.2.69/32, "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 }
+ }
+
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip to ip saddr map @y
+ }
+}
+table inet x {
+ chain x {
+ type nat hook prerouting priority dstnat; policy accept;
+ dnat ip to ip daddr . tcp dport map { 10.141.10.1 . 22 : 192.168.2.2, 10.141.11.2 . 2222 : 192.168.4.2 }
+ }
+
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip to ip saddr map { 10.141.10.0/24 : 192.168.2.2-192.168.2.4, 10.141.11.0/24 : 192.168.4.2/31 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0048set_counters_0.json-nft b/tests/shell/testcases/sets/dumps/0048set_counters_0.json-nft
new file mode 100644
index 00000000..62a6a177
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0048set_counters_0.json-nft
@@ -0,0 +1,95 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "z",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ {
+ "elem": {
+ "val": "192.168.10.35",
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ },
+ {
+ "elem": {
+ "val": "192.168.10.101",
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ },
+ {
+ "elem": {
+ "val": "192.168.10.135",
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ }
+ ],
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": "@y"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0048set_counters_0.nft b/tests/shell/testcases/sets/dumps/0048set_counters_0.nft
new file mode 100644
index 00000000..2145f6b1
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0048set_counters_0.nft
@@ -0,0 +1,13 @@
+table ip x {
+ set y {
+ typeof ip saddr
+ counter
+ elements = { 192.168.10.35 counter packets 0 bytes 0, 192.168.10.101 counter packets 0 bytes 0,
+ 192.168.10.135 counter packets 0 bytes 0 }
+ }
+
+ chain z {
+ type filter hook output priority filter; policy accept;
+ ip daddr @y
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0049set_define_0.json-nft b/tests/shell/testcases/sets/dumps/0049set_define_0.json-nft
new file mode 100644
index 00000000..f8495bab
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0049set_define_0.json-nft
@@ -0,0 +1,94 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "drop"
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "ip-block-4-test",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "auto-merge": true,
+ "elem": [
+ "1.1.1.1"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": {
+ "set": [
+ 22,
+ 80,
+ 443
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "new"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0049set_define_0.nft b/tests/shell/testcases/sets/dumps/0049set_define_0.nft
new file mode 100644
index 00000000..d654420c
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0049set_define_0.nft
@@ -0,0 +1,13 @@
+table inet filter {
+ set ip-block-4-test {
+ type ipv4_addr
+ flags interval
+ auto-merge
+ elements = { 1.1.1.1 }
+ }
+
+ chain input {
+ type filter hook input priority filter; policy drop;
+ tcp dport { 22, 80, 443 } ct state new counter packets 0 bytes 0 accept
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0050set_define_1.json-nft b/tests/shell/testcases/sets/dumps/0050set_define_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0050set_define_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0050set_define_1.nft b/tests/shell/testcases/sets/dumps/0050set_define_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0050set_define_1.nft
diff --git a/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.json-nft b/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.json-nft
new file mode 100644
index 00000000..b468b5f9
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.json-nft
@@ -0,0 +1,85 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "elem": {
+ "val": {
+ "prefix": {
+ "addr": "192.168.2.0",
+ "len": 24
+ }
+ },
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ }
+ ],
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": "@s"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.nft b/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.nft
new file mode 100644
index 00000000..fd488a76
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0051set_interval_counter_0.nft
@@ -0,0 +1,13 @@
+table ip x {
+ set s {
+ type ipv4_addr
+ flags interval
+ counter
+ elements = { 192.168.2.0/24 counter packets 0 bytes 0 }
+ }
+
+ chain y {
+ type filter hook output priority filter; policy accept;
+ ip daddr @s
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0052overlap_0.json-nft b/tests/shell/testcases/sets/dumps/0052overlap_0.json-nft
new file mode 100644
index 00000000..96d5fbcc
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0052overlap_0.json-nft
@@ -0,0 +1,35 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "w_all",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "auto-merge": true,
+ "elem": [
+ "10.10.10.10",
+ "10.10.10.253"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0052overlap_0.nft b/tests/shell/testcases/sets/dumps/0052overlap_0.nft
new file mode 100644
index 00000000..1cc02ada
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0052overlap_0.nft
@@ -0,0 +1,8 @@
+table ip filter {
+ set w_all {
+ type ipv4_addr
+ flags interval
+ auto-merge
+ elements = { 10.10.10.10, 10.10.10.253 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0053echo_0.json-nft b/tests/shell/testcases/sets/dumps/0053echo_0.json-nft
new file mode 100644
index 00000000..12a5c4b4
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0053echo_0.json-nft
@@ -0,0 +1,101 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "drop"
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": {
+ "prefix": {
+ "addr": "10.0.0.0",
+ "len": 8
+ }
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": "192.168.100.62"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 2001
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0053echo_0.nft b/tests/shell/testcases/sets/dumps/0053echo_0.nft
new file mode 100644
index 00000000..bb7c5513
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0053echo_0.nft
@@ -0,0 +1,6 @@
+table inet filter {
+ chain input {
+ type filter hook input priority filter; policy drop;
+ iifname "lo" ip saddr 10.0.0.0/8 ip daddr 192.168.100.62 tcp dport 2001 counter packets 0 bytes 0 accept
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0054comments_set_0.json-nft b/tests/shell/testcases/sets/dumps/0054comments_set_0.json-nft
new file mode 100644
index 00000000..3fd6d37e
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0054comments_set_0.json-nft
@@ -0,0 +1,45 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "comment": "test",
+ "flags": [
+ "interval"
+ ]
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "m",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "comment": "another test",
+ "map": "ipv4_addr",
+ "flags": [
+ "interval"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0054comments_set_0.nft b/tests/shell/testcases/sets/dumps/0054comments_set_0.nft
new file mode 100644
index 00000000..79299241
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0054comments_set_0.nft
@@ -0,0 +1,13 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ flags interval
+ comment "test"
+ }
+
+ map m {
+ type ipv4_addr : ipv4_addr
+ flags interval
+ comment "another test"
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0055tcpflags_0.json-nft b/tests/shell/testcases/sets/dumps/0055tcpflags_0.json-nft
new file mode 100644
index 00000000..e37139f3
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0055tcpflags_0.json-nft
@@ -0,0 +1,138 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "tcp_good_flags",
+ "table": "test",
+ "type": "tcp_flag",
+ "handle": 0,
+ "flags": [
+ "constant"
+ ],
+ "elem": [
+ {
+ "|": [
+ "fin",
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ "fin",
+ "ack",
+ "urg"
+ ]
+ },
+ {
+ "|": [
+ "fin",
+ "psh",
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ "fin",
+ "psh",
+ "ack",
+ "urg"
+ ]
+ },
+ "syn",
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ "syn",
+ "ack",
+ "urg"
+ ]
+ },
+ {
+ "|": [
+ "syn",
+ "psh",
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ "syn",
+ "psh",
+ "ack",
+ "urg"
+ ]
+ },
+ "rst",
+ {
+ "|": [
+ "rst",
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ "rst",
+ "ack",
+ "urg"
+ ]
+ },
+ {
+ "|": [
+ "rst",
+ "psh",
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ "rst",
+ "psh",
+ "ack",
+ "urg"
+ ]
+ },
+ {
+ "|": [
+ "psh",
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ "psh",
+ "ack",
+ "urg"
+ ]
+ },
+ "ack",
+ {
+ "|": [
+ "ack",
+ "urg"
+ ]
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0055tcpflags_0.nft b/tests/shell/testcases/sets/dumps/0055tcpflags_0.nft
new file mode 100644
index 00000000..22bf5c46
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0055tcpflags_0.nft
@@ -0,0 +1,10 @@
+table ip test {
+ set tcp_good_flags {
+ type tcp_flag
+ flags constant
+ elements = { fin | ack, fin | ack | urg, fin | psh | ack, fin | psh | ack | urg, syn,
+ syn | ack, syn | ack | urg, syn | psh | ack, syn | psh | ack | urg, rst,
+ rst | ack, rst | ack | urg, rst | psh | ack, rst | psh | ack | urg, psh | ack,
+ psh | ack | urg, ack, ack | urg }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0056dynamic_limit_0.json-nft b/tests/shell/testcases/sets/dumps/0056dynamic_limit_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0056dynamic_limit_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0056dynamic_limit_0.nft b/tests/shell/testcases/sets/dumps/0056dynamic_limit_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0056dynamic_limit_0.nft
diff --git a/tests/shell/testcases/sets/dumps/0057set_create_fails_0.json-nft b/tests/shell/testcases/sets/dumps/0057set_create_fails_0.json-nft
new file mode 100644
index 00000000..79d7257e
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0057set_create_fails_0.json-nft
@@ -0,0 +1,31 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "test",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "elem": [
+ "1.1.1.1"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0057set_create_fails_0.nft b/tests/shell/testcases/sets/dumps/0057set_create_fails_0.nft
new file mode 100644
index 00000000..de43d565
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0057set_create_fails_0.nft
@@ -0,0 +1,7 @@
+table inet filter {
+ set test {
+ type ipv4_addr
+ size 65535
+ elements = { 1.1.1.1 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0058_setupdate_timeout_0.json-nft b/tests/shell/testcases/sets/dumps/0058_setupdate_timeout_0.json-nft
new file mode 100644
index 00000000..ac8d8bef
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0058_setupdate_timeout_0.json-nft
@@ -0,0 +1,68 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "filter",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "ssh_meter",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ],
+ "timeout": 2592000
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "filter",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "set": {
+ "op": "add",
+ "elem": {
+ "elem": {
+ "val": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "timeout": 2592000
+ }
+ },
+ "set": "@ssh_meter"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0058_setupdate_timeout_0.nft b/tests/shell/testcases/sets/dumps/0058_setupdate_timeout_0.nft
new file mode 100644
index 00000000..873adc63
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0058_setupdate_timeout_0.nft
@@ -0,0 +1,12 @@
+table inet filter {
+ set ssh_meter {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ timeout 30d
+ }
+
+ chain test {
+ add @ssh_meter { ip saddr timeout 30d }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.json-nft b/tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.json-nft
new file mode 100644
index 00000000..16ecdb2a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.json-nft
@@ -0,0 +1,79 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "z",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ],
+ "timeout": 3600
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "z",
+ "handle": 0,
+ "expr": [
+ {
+ "set": {
+ "op": "update",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "set": "@y",
+ "stmt": [
+ {
+ "limit": {
+ "rate": 1,
+ "burst": 5,
+ "per": "second"
+ }
+ },
+ {
+ "counter": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.nft b/tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.nft
new file mode 100644
index 00000000..c1cc3b51
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.nft
@@ -0,0 +1,13 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ size 65535
+ flags dynamic,timeout
+ timeout 1h
+ }
+
+ chain z {
+ type filter hook output priority filter; policy accept;
+ update @y { ip daddr limit rate 1/second burst 5 packets counter }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0060set_multistmt_0.json-nft b/tests/shell/testcases/sets/dumps/0060set_multistmt_0.json-nft
new file mode 100644
index 00000000..1aede147
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0060set_multistmt_0.json-nft
@@ -0,0 +1,105 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ {
+ "elem": {
+ "val": "1.1.1.1",
+ "limit": {
+ "rate": 1,
+ "burst": 5,
+ "per": "second"
+ }
+ }
+ },
+ {
+ "elem": {
+ "val": "4.4.4.4",
+ "limit": {
+ "rate": 1,
+ "burst": 5,
+ "per": "second"
+ }
+ }
+ },
+ {
+ "elem": {
+ "val": "5.5.5.5",
+ "limit": {
+ "rate": 1,
+ "burst": 5,
+ "per": "second"
+ }
+ }
+ }
+ ],
+ "stmt": [
+ {
+ "limit": {
+ "rate": 1,
+ "burst": 5,
+ "per": "second"
+ }
+ },
+ {
+ "counter": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": "@y"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0060set_multistmt_0.nft b/tests/shell/testcases/sets/dumps/0060set_multistmt_0.nft
new file mode 100644
index 00000000..df68fcdf
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0060set_multistmt_0.nft
@@ -0,0 +1,13 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ limit rate 1/second burst 5 packets counter
+ elements = { 1.1.1.1 limit rate 1/second burst 5 packets counter packets 0 bytes 0, 4.4.4.4 limit rate 1/second burst 5 packets counter packets 0 bytes 0,
+ 5.5.5.5 limit rate 1/second burst 5 packets counter packets 0 bytes 0 }
+ }
+
+ chain y {
+ type filter hook output priority filter; policy accept;
+ ip daddr @y
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0060set_multistmt_1.json-nft b/tests/shell/testcases/sets/dumps/0060set_multistmt_1.json-nft
new file mode 100644
index 00000000..6098dc56
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0060set_multistmt_1.json-nft
@@ -0,0 +1,105 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "dynamic"
+ ],
+ "elem": [
+ {
+ "elem": {
+ "val": "1.1.1.1",
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ },
+ {
+ "elem": {
+ "val": "1.2.3.4",
+ "counter": {
+ "packets": 9,
+ "bytes": 756
+ }
+ }
+ },
+ {
+ "elem": {
+ "val": "2.2.2.2",
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ }
+ ],
+ "stmt": [
+ {
+ "counter": null
+ },
+ {
+ "quota": {
+ "val": 500,
+ "val_unit": "bytes"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "set": {
+ "op": "update",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "set": "@y"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0060set_multistmt_1.nft b/tests/shell/testcases/sets/dumps/0060set_multistmt_1.nft
new file mode 100644
index 00000000..ac1bd26b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0060set_multistmt_1.nft
@@ -0,0 +1,15 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ counter quota 500 bytes
+ elements = { 1.1.1.1 counter packets 0 bytes 0 quota 500 bytes, 1.2.3.4 counter packets 9 bytes 756 quota 500 bytes used 500 bytes,
+ 2.2.2.2 counter packets 0 bytes 0 quota 1000 bytes }
+ }
+
+ chain y {
+ type filter hook output priority filter; policy accept;
+ update @y { ip daddr }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0061anonymous_automerge_0.json-nft b/tests/shell/testcases/sets/dumps/0061anonymous_automerge_0.json-nft
new file mode 100644
index 00000000..c5591505
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0061anonymous_automerge_0.json-nft
@@ -0,0 +1,57 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": {
+ "set": [
+ {
+ "range": [
+ "1.1.1.1",
+ "1.1.1.2"
+ ]
+ }
+ ]
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0061anonymous_automerge_0.nft b/tests/shell/testcases/sets/dumps/0061anonymous_automerge_0.nft
new file mode 100644
index 00000000..04361f4c
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0061anonymous_automerge_0.nft
@@ -0,0 +1,5 @@
+table ip x {
+ chain y {
+ ip saddr { 1.1.1.1-1.1.1.2 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0062set_connlimit_0.json-nft b/tests/shell/testcases/sets/dumps/0062set_connlimit_0.json-nft
new file mode 100644
index 00000000..c5e60e36
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0062set_connlimit_0.json-nft
@@ -0,0 +1,52 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "est-connlimit",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "new-connlimit",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "dynamic"
+ ],
+ "stmt": [
+ {
+ "ct count": {
+ "val": 20,
+ "inv": true
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0062set_connlimit_0.nft b/tests/shell/testcases/sets/dumps/0062set_connlimit_0.nft
new file mode 100644
index 00000000..13bbb953
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0062set_connlimit_0.nft
@@ -0,0 +1,14 @@
+table ip x {
+ set est-connlimit {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ }
+
+ set new-connlimit {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ ct count over 20
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0063set_catchall_0.json-nft b/tests/shell/testcases/sets/dumps/0063set_catchall_0.json-nft
new file mode 100644
index 00000000..3006f75a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0063set_catchall_0.json-nft
@@ -0,0 +1,94 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ {
+ "elem": {
+ "val": "1.1.1.1",
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ },
+ {
+ "elem": {
+ "val": "*",
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ }
+ ],
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "z",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "elem": {
+ "val": {
+ "prefix": {
+ "addr": "1.1.1.0",
+ "len": 24
+ }
+ },
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ },
+ {
+ "elem": {
+ "val": "*",
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ }
+ ],
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0063set_catchall_0.nft b/tests/shell/testcases/sets/dumps/0063set_catchall_0.nft
new file mode 100644
index 00000000..f0d42cc2
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0063set_catchall_0.nft
@@ -0,0 +1,14 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ counter
+ elements = { 1.1.1.1 counter packets 0 bytes 0, * counter packets 0 bytes 0 }
+ }
+
+ set z {
+ type ipv4_addr
+ flags interval
+ counter
+ elements = { 1.1.1.0/24 counter packets 0 bytes 0, * counter packets 0 bytes 0 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0064map_catchall_0.json-nft b/tests/shell/testcases/sets/dumps/0064map_catchall_0.json-nft
new file mode 100644
index 00000000..64dd2667
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0064map_catchall_0.json-nft
@@ -0,0 +1,220 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "ipv4_addr",
+ "elem": [
+ [
+ "10.141.0.1",
+ "192.168.0.2"
+ ],
+ [
+ "*",
+ "192.168.0.4"
+ ]
+ ]
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "z",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "ipv4_addr",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "prefix": {
+ "addr": "10.141.0.0",
+ "len": 24
+ }
+ },
+ "192.168.0.2"
+ ],
+ [
+ "*",
+ "192.168.0.3"
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": "@z"
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "prefix": {
+ "addr": "10.141.0.0",
+ "len": 24
+ }
+ },
+ "192.168.0.2"
+ ],
+ [
+ "*",
+ "192.168.0.3"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "snat": {
+ "addr": {
+ "map": {
+ "key": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ }
+ ]
+ },
+ "data": {
+ "set": [
+ [
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "10.141.0.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "10.0.0.0",
+ "len": 8
+ }
+ }
+ ]
+ },
+ "192.168.0.2"
+ ],
+ [
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "192.168.9.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "192.168.10.0",
+ "len": 24
+ }
+ }
+ ]
+ },
+ "192.168.0.4"
+ ],
+ [
+ "*",
+ "192.168.0.3"
+ ]
+ ]
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0064map_catchall_0.nft b/tests/shell/testcases/sets/dumps/0064map_catchall_0.nft
new file mode 100644
index 00000000..890ed2aa
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0064map_catchall_0.nft
@@ -0,0 +1,18 @@
+table ip x {
+ map y {
+ type ipv4_addr : ipv4_addr
+ elements = { 10.141.0.1 : 192.168.0.2, * : 192.168.0.4 }
+ }
+
+ map z {
+ type ipv4_addr : ipv4_addr
+ flags interval
+ elements = { 10.141.0.0/24 : 192.168.0.2, * : 192.168.0.3 }
+ }
+
+ chain y {
+ snat to ip saddr map @z
+ snat to ip saddr map { 10.141.0.0/24 : 192.168.0.2, * : 192.168.0.3 }
+ snat to ip saddr . ip daddr map { 10.141.0.0/24 . 10.0.0.0/8 : 192.168.0.2, 192.168.9.0/24 . 192.168.10.0/24 : 192.168.0.4, * : 192.168.0.3 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0065_icmp_postprocessing.json-nft b/tests/shell/testcases/sets/dumps/0065_icmp_postprocessing.json-nft
new file mode 100644
index 00000000..f470adf3
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0065_icmp_postprocessing.json-nft
@@ -0,0 +1,78 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "foo",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "foo",
+ "handle": 0,
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "foo",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "type"
+ }
+ },
+ "right": {
+ "set": [
+ "echo-reply",
+ "echo-request"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmp",
+ "field": "id"
+ }
+ },
+ "right": 42
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0065_icmp_postprocessing.nft b/tests/shell/testcases/sets/dumps/0065_icmp_postprocessing.nft
new file mode 100644
index 00000000..461c7a73
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0065_icmp_postprocessing.nft
@@ -0,0 +1,6 @@
+table ip x {
+ chain foo {
+ accept
+ icmp type { echo-reply, echo-request } icmp id 42
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0067nat_concat_interval_0.nft b/tests/shell/testcases/sets/dumps/0067nat_concat_interval_0.nft
new file mode 100644
index 00000000..9ac3774a
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0067nat_concat_interval_0.nft
@@ -0,0 +1,35 @@
+table ip nat {
+ map ipportmap2 {
+ type ipv4_addr . ipv4_addr : interval ipv4_addr . inet_service
+ flags interval
+ elements = { 192.168.1.2 . 192.168.2.2 : 127.0.0.0/8 . 42-43 }
+ }
+
+ map fwdtoip_th {
+ type ipv4_addr . inet_service : interval ipv4_addr . inet_service
+ flags interval
+ elements = { 1.2.3.4 . 10000-20000 : 192.168.3.4 . 30000-40000 }
+ }
+
+ map ipportmap4 {
+ typeof iifname . ip saddr : interval ip daddr
+ flags interval
+ elements = { "enp2s0" . 10.1.1.136 : 1.1.2.69/32,
+ "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 }
+ }
+
+ map ipportmap5 {
+ typeof iifname . ip saddr : interval ip daddr . tcp dport
+ flags interval
+ elements = { "enp2s0" . 10.1.1.136 : 1.1.2.69 . 22,
+ "enp2s0" . 10.1.1.1-10.1.1.135 : 1.1.2.66-1.84.236.78 . 22 }
+ }
+
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ ip protocol tcp dnat ip to ip saddr . ip daddr map @ipportmap2
+ meta l4proto { tcp, udp } dnat ip to ip daddr . th dport map @fwdtoip_th
+ dnat ip to iifname . ip saddr map @ipportmap4
+ meta l4proto tcp dnat ip to iifname . ip saddr map @ipportmap5
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0067nat_interval_0.nft b/tests/shell/testcases/sets/dumps/0067nat_interval_0.nft
new file mode 100644
index 00000000..b6d07fcd
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0067nat_interval_0.nft
@@ -0,0 +1,12 @@
+table ip nat {
+ map ipportmap {
+ type ipv4_addr : interval ipv4_addr . inet_service
+ flags interval
+ elements = { 192.168.1.2 : 10.141.10.1-10.141.10.3 . 8888-8999, 192.168.2.0/24 : 10.141.11.5-10.141.11.20 . 8888-8999 }
+ }
+
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ ip protocol tcp dnat ip to ip saddr map @ipportmap
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0068interval_stack_overflow_0.nodump b/tests/shell/testcases/sets/dumps/0068interval_stack_overflow_0.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0068interval_stack_overflow_0.nodump
diff --git a/tests/shell/testcases/sets/dumps/0069interval_merge_0.json-nft b/tests/shell/testcases/sets/dumps/0069interval_merge_0.json-nft
new file mode 100644
index 00000000..d7b32f8c
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0069interval_merge_0.json-nft
@@ -0,0 +1,51 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "auto-merge": true,
+ "elem": [
+ {
+ "range": [
+ "1.2.3.0",
+ "1.2.4.255"
+ ]
+ },
+ {
+ "range": [
+ "3.3.3.3",
+ "3.3.3.6"
+ ]
+ },
+ {
+ "range": [
+ "4.4.4.0",
+ "4.4.5.0"
+ ]
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0069interval_merge_0.nft b/tests/shell/testcases/sets/dumps/0069interval_merge_0.nft
new file mode 100644
index 00000000..2d4e1706
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0069interval_merge_0.nft
@@ -0,0 +1,9 @@
+table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ auto-merge
+ elements = { 1.2.3.0-1.2.4.255, 3.3.3.3-3.3.3.6,
+ 4.4.4.0-4.4.5.0 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft b/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
new file mode 100644
index 00000000..0057e9c6
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0070stacked_l2_headers.nft
@@ -0,0 +1,28 @@
+table netdev nt {
+ set vlanidset {
+ typeof vlan id
+ size 1024
+ flags dynamic,timeout
+ }
+
+ set macset {
+ typeof ether saddr . vlan id
+ size 1024
+ flags dynamic,timeout
+ }
+
+ set ipset {
+ typeof vlan id . ip saddr
+ size 1024
+ flags dynamic,timeout
+ }
+
+ chain nc {
+ update @macset { ether saddr . vlan id timeout 5s } counter packets 0 bytes 0
+ ether saddr . vlan id @macset
+ vlan pcp 1
+ ether saddr 0a:0b:0c:0d:0e:0f vlan id 42
+ update @vlanidset { vlan id timeout 5s } counter packets 0 bytes 0
+ update @ipset { vlan id . ip saddr timeout 5s } counter packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.json-nft b/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.json-nft
new file mode 100644
index 00000000..6b579a2e
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.json-nft
@@ -0,0 +1,128 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "t",
+ "name": "c",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s1",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "10.0.0.0",
+ "len": 8
+ }
+ },
+ {
+ "prefix": {
+ "addr": "192.0.0.0",
+ "len": 2
+ }
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "s2",
+ "table": "t",
+ "type": "ipv6_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "fe80::",
+ "len": 10
+ }
+ },
+ {
+ "prefix": {
+ "addr": "ff00::",
+ "len": 8
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "@s1"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "right": "@s2"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.nft b/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.nft
new file mode 100644
index 00000000..4eed94c2
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0071unclosed_prefix_interval_0.nft
@@ -0,0 +1,19 @@
+table inet t {
+ set s1 {
+ type ipv4_addr
+ flags interval
+ elements = { 10.0.0.0/8, 192.0.0.0/2 }
+ }
+
+ set s2 {
+ type ipv6_addr
+ flags interval
+ elements = { fe80::/10,
+ ff00::/8 }
+ }
+
+ chain c {
+ ip saddr @s1 accept
+ ip6 daddr @s2 accept
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0072destroy_0.json-nft b/tests/shell/testcases/sets/dumps/0072destroy_0.json-nft
new file mode 100644
index 00000000..15ec0aac
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0072destroy_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0072destroy_0.nft b/tests/shell/testcases/sets/dumps/0072destroy_0.nft
new file mode 100644
index 00000000..5d4d2caf
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0072destroy_0.nft
@@ -0,0 +1,2 @@
+table ip x {
+}
diff --git a/tests/shell/testcases/sets/dumps/0073flat_interval_set.json-nft b/tests/shell/testcases/sets/dumps/0073flat_interval_set.json-nft
new file mode 100644
index 00000000..e2fb6214
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0073flat_interval_set.json-nft
@@ -0,0 +1,52 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "counter": {
+ "family": "inet",
+ "name": "TEST",
+ "table": "filter",
+ "handle": 0,
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "testmap",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "counter",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "prefix": {
+ "addr": "192.168.0.0",
+ "len": 24
+ }
+ },
+ "TEST"
+ ]
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0073flat_interval_set.nft b/tests/shell/testcases/sets/dumps/0073flat_interval_set.nft
new file mode 100644
index 00000000..20f53741
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0073flat_interval_set.nft
@@ -0,0 +1,11 @@
+table inet filter {
+ counter TEST {
+ packets 0 bytes 0
+ }
+
+ map testmap {
+ type ipv4_addr : counter
+ flags interval
+ elements = { 192.168.0.0/24 : "TEST" }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0074nested_interval_set.json-nft b/tests/shell/testcases/sets/dumps/0074nested_interval_set.json-nft
new file mode 100644
index 00000000..e2fb6214
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0074nested_interval_set.json-nft
@@ -0,0 +1,52 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "counter": {
+ "family": "inet",
+ "name": "TEST",
+ "table": "filter",
+ "handle": 0,
+ "packets": 0,
+ "bytes": 0
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "testmap",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "counter",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ {
+ "prefix": {
+ "addr": "192.168.0.0",
+ "len": 24
+ }
+ },
+ "TEST"
+ ]
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/0074nested_interval_set.nft b/tests/shell/testcases/sets/dumps/0074nested_interval_set.nft
new file mode 100644
index 00000000..20f53741
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0074nested_interval_set.nft
@@ -0,0 +1,11 @@
+table inet filter {
+ counter TEST {
+ packets 0 bytes 0
+ }
+
+ map testmap {
+ type ipv4_addr : counter
+ flags interval
+ elements = { 192.168.0.0/24 : "TEST" }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/automerge_0.nodump b/tests/shell/testcases/sets/dumps/automerge_0.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/automerge_0.nodump
diff --git a/tests/shell/testcases/sets/dumps/collapse_elem_0.json-nft b/tests/shell/testcases/sets/dumps/collapse_elem_0.json-nft
new file mode 100644
index 00000000..c713828d
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/collapse_elem_0.json-nft
@@ -0,0 +1,50 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "a",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "x",
+ "table": "a",
+ "type": "inet_service",
+ "handle": 0,
+ "elem": [
+ 1,
+ 2
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "a",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip6",
+ "name": "x",
+ "table": "a",
+ "type": "inet_service",
+ "handle": 0,
+ "elem": [
+ 2
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/collapse_elem_0.nft b/tests/shell/testcases/sets/dumps/collapse_elem_0.nft
new file mode 100644
index 00000000..a3244fc6
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/collapse_elem_0.nft
@@ -0,0 +1,12 @@
+table ip a {
+ set x {
+ type inet_service
+ elements = { 1, 2 }
+ }
+}
+table ip6 a {
+ set x {
+ type inet_service
+ elements = { 2 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/concat_interval_0.json-nft b/tests/shell/testcases/sets/dumps/concat_interval_0.json-nft
new file mode 100644
index 00000000..d65065e4
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/concat_interval_0.json-nft
@@ -0,0 +1,68 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": [
+ "ipv4_addr",
+ "inet_proto",
+ "inet_service"
+ ],
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s2",
+ "table": "t",
+ "type": [
+ "ipv4_addr",
+ "mark"
+ ],
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "concat": [
+ "10.10.10.10",
+ 256
+ ]
+ },
+ {
+ "concat": [
+ "20.20.20.20",
+ 512
+ ]
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/concat_interval_0.nft b/tests/shell/testcases/sets/dumps/concat_interval_0.nft
new file mode 100644
index 00000000..61547c5e
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/concat_interval_0.nft
@@ -0,0 +1,14 @@
+table ip t {
+ set s {
+ type ipv4_addr . inet_proto . inet_service
+ flags interval
+ counter
+ }
+
+ set s2 {
+ type ipv4_addr . mark
+ flags interval
+ elements = { 10.10.10.10 . 0x00000100,
+ 20.20.20.20 . 0x00000200 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/dynset_missing.json-nft b/tests/shell/testcases/sets/dumps/dynset_missing.json-nft
new file mode 100644
index 00000000..ad8a7cc0
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/dynset_missing.json-nft
@@ -0,0 +1,83 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test",
+ "name": "output",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "dlist",
+ "table": "test",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "output",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 1234
+ }
+ },
+ {
+ "set": {
+ "op": "update",
+ "elem": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "set": "@dlist"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/dynset_missing.nft b/tests/shell/testcases/sets/dumps/dynset_missing.nft
new file mode 100644
index 00000000..6c8ed323
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/dynset_missing.nft
@@ -0,0 +1,12 @@
+table ip test {
+ set dlist {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ }
+
+ chain output {
+ type filter hook output priority filter; policy accept;
+ udp dport 1234 update @dlist { ip daddr } counter packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/elem_opts_compat_0.nodump b/tests/shell/testcases/sets/dumps/elem_opts_compat_0.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/elem_opts_compat_0.nodump
diff --git a/tests/shell/testcases/sets/dumps/errors_0.json-nft b/tests/shell/testcases/sets/dumps/errors_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/errors_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/errors_0.nft b/tests/shell/testcases/sets/dumps/errors_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/errors_0.nft
diff --git a/tests/shell/testcases/sets/dumps/exact_overlap_0.json-nft b/tests/shell/testcases/sets/dumps/exact_overlap_0.json-nft
new file mode 100644
index 00000000..958d1e5c
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/exact_overlap_0.json-nft
@@ -0,0 +1,110 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "1.0.1.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.0.2.0",
+ "len": 23
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.0.8.0",
+ "len": 21
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.0.32.0",
+ "len": 19
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.1.0.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.1.2.0",
+ "len": 23
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.1.4.0",
+ "len": 22
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.1.8.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.1.9.0",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.1.10.0",
+ "len": 23
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.1.12.0",
+ "len": 22
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.1.16.0",
+ "len": 20
+ }
+ },
+ {
+ "prefix": {
+ "addr": "1.1.32.0",
+ "len": 19
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/exact_overlap_0.nft b/tests/shell/testcases/sets/dumps/exact_overlap_0.nft
new file mode 100644
index 00000000..c903e3fc
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/exact_overlap_0.nft
@@ -0,0 +1,13 @@
+table ip t {
+ set s {
+ type ipv4_addr
+ flags interval
+ elements = { 1.0.1.0/24, 1.0.2.0/23,
+ 1.0.8.0/21, 1.0.32.0/19,
+ 1.1.0.0/24, 1.1.2.0/23,
+ 1.1.4.0/22, 1.1.8.0/24,
+ 1.1.9.0/24, 1.1.10.0/23,
+ 1.1.12.0/22, 1.1.16.0/20,
+ 1.1.32.0/19 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/inner_0.json-nft b/tests/shell/testcases/sets/dumps/inner_0.json-nft
new file mode 100644
index 00000000..8d84e1cc
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/inner_0.json-nft
@@ -0,0 +1,207 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "netdev",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "netdev",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "netdev",
+ "name": "x",
+ "table": "x",
+ "type": [
+ "ipv4_addr",
+ "ipv4_addr"
+ ],
+ "handle": 0,
+ "elem": [
+ {
+ "concat": [
+ "3.3.3.3",
+ "4.4.4.4"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "netdev",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "netdev",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "tunnel": "vxlan",
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "tunnel": "vxlan",
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "1.1.1.1",
+ "2.2.2.2"
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "netdev",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 4789
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "tunnel": "vxlan",
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "payload": {
+ "tunnel": "vxlan",
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ }
+ ]
+ },
+ "right": "@x"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "netdev",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 4789
+ }
+ },
+ {
+ "set": {
+ "op": "update",
+ "elem": {
+ "payload": {
+ "tunnel": "vxlan",
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "set": "@y"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/inner_0.nft b/tests/shell/testcases/sets/dumps/inner_0.nft
new file mode 100644
index 00000000..925ca777
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/inner_0.nft
@@ -0,0 +1,18 @@
+table netdev x {
+ set x {
+ typeof vxlan ip saddr . vxlan ip daddr
+ elements = { 3.3.3.3 . 4.4.4.4 }
+ }
+
+ set y {
+ typeof vxlan ip saddr
+ size 65535
+ flags dynamic
+ }
+
+ chain y {
+ udp dport 4789 vxlan ip saddr . vxlan ip daddr { 1.1.1.1 . 2.2.2.2 } counter packets 0 bytes 0
+ udp dport 4789 vxlan ip saddr . vxlan ip daddr @x counter packets 0 bytes 0
+ udp dport 4789 update @y { vxlan ip saddr }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/meter_0.json-nft b/tests/shell/testcases/sets/dumps/meter_0.json-nft
new file mode 100644
index 00000000..c318e4f2
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/meter_0.json-nft
@@ -0,0 +1,203 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "test",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip6",
+ "name": "acct_out",
+ "table": "test",
+ "type": [
+ "iface_index",
+ "ipv6_addr"
+ ],
+ "handle": 0,
+ "size": 4096,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "ip6",
+ "name": "acct_out2",
+ "table": "test",
+ "type": [
+ "ipv6_addr",
+ "iface_index"
+ ],
+ "handle": 0,
+ "size": 12345,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "set": {
+ "op": "update",
+ "elem": {
+ "elem": {
+ "val": {
+ "concat": [
+ {
+ "meta": {
+ "key": "iif"
+ }
+ },
+ {
+ "payload": {
+ "protocol": "ip6",
+ "field": "saddr"
+ }
+ }
+ ]
+ },
+ "timeout": 600
+ }
+ },
+ "set": "@acct_out",
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "set": {
+ "op": "update",
+ "elem": {
+ "elem": {
+ "val": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip6",
+ "field": "saddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "iif"
+ }
+ }
+ ]
+ },
+ "timeout": 600
+ }
+ },
+ "set": "@acct_out2",
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "test",
+ "name": "test",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "xyz",
+ "table": "test",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "size": 8192,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "test",
+ "chain": "test",
+ "handle": 0,
+ "expr": [
+ {
+ "set": {
+ "op": "update",
+ "elem": {
+ "elem": {
+ "val": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "timeout": 30
+ }
+ },
+ "set": "@xyz",
+ "stmt": [
+ {
+ "counter": null
+ }
+ ]
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/meter_0.nft b/tests/shell/testcases/sets/dumps/meter_0.nft
new file mode 100644
index 00000000..3843f9a9
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/meter_0.nft
@@ -0,0 +1,29 @@
+table ip6 test {
+ set acct_out {
+ type iface_index . ipv6_addr
+ size 4096
+ flags dynamic,timeout
+ }
+
+ set acct_out2 {
+ type ipv6_addr . iface_index
+ size 12345
+ flags dynamic,timeout
+ }
+
+ chain test {
+ update @acct_out { iif . ip6 saddr timeout 10m counter }
+ update @acct_out2 { ip6 saddr . iif timeout 10m counter }
+ }
+}
+table ip test {
+ set xyz {
+ type ipv4_addr
+ size 8192
+ flags dynamic,timeout
+ }
+
+ chain test {
+ update @xyz { ip saddr timeout 30s counter }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/reset_command_0.nodump b/tests/shell/testcases/sets/dumps/reset_command_0.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/reset_command_0.nodump
diff --git a/tests/shell/testcases/sets/dumps/set_eval_0.json-nft b/tests/shell/testcases/sets/dumps/set_eval_0.json-nft
new file mode 100644
index 00000000..6f692381
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/set_eval_0.json-nft
@@ -0,0 +1,85 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "nat",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "nat",
+ "name": "prerouting",
+ "handle": 0,
+ "type": "nat",
+ "hook": "prerouting",
+ "prio": -100,
+ "policy": "accept"
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "set_with_interval",
+ "table": "nat",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "nat",
+ "chain": "prerouting",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": {
+ "set": [
+ "tcp",
+ "udp"
+ ]
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "th",
+ "field": "dport"
+ }
+ },
+ "right": 443
+ }
+ },
+ {
+ "dnat": {
+ "addr": "10.0.0.1"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/set_eval_0.nft b/tests/shell/testcases/sets/dumps/set_eval_0.nft
new file mode 100644
index 00000000..a45462b8
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/set_eval_0.nft
@@ -0,0 +1,11 @@
+table ip nat {
+ set set_with_interval {
+ type ipv4_addr
+ flags interval
+ }
+
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto { tcp, udp } th dport 443 dnat to 10.0.0.1
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/sets_with_ifnames.json-nft b/tests/shell/testcases/sets/dumps/sets_with_ifnames.json-nft
new file mode 100644
index 00000000..ac428429
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/sets_with_ifnames.json-nft
@@ -0,0 +1,551 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "testifsets",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "testifsets",
+ "name": "v4icmp",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "testifsets",
+ "name": "v4icmpc",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "testifsets",
+ "name": "input",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "testifsets",
+ "name": "do_nothing",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "simple",
+ "table": "testifsets",
+ "type": "ifname",
+ "handle": 0,
+ "elem": [
+ "abcdef0",
+ "abcdef1",
+ "othername"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "simple_wild",
+ "table": "testifsets",
+ "type": "ifname",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ "abcdef*",
+ "othername",
+ "ppp0"
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "concat",
+ "table": "testifsets",
+ "type": [
+ "ipv4_addr",
+ "ifname"
+ ],
+ "handle": 0,
+ "elem": [
+ {
+ "concat": [
+ "10.1.2.2",
+ "abcdef0"
+ ]
+ },
+ {
+ "concat": [
+ "10.1.2.2",
+ "abcdef1"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "set": {
+ "family": "inet",
+ "name": "concat_wild",
+ "table": "testifsets",
+ "type": [
+ "ipv4_addr",
+ "ifname"
+ ],
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "concat": [
+ "10.1.2.2",
+ "abcdef*"
+ ]
+ },
+ {
+ "concat": [
+ "10.1.2.1",
+ "bar"
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "1.1.2.0",
+ "len": 24
+ }
+ },
+ "abcdef0"
+ ]
+ },
+ {
+ "concat": [
+ {
+ "prefix": {
+ "addr": "12.2.2.0",
+ "len": 24
+ }
+ },
+ "abcdef*"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "map": {
+ "family": "inet",
+ "name": "map_wild",
+ "table": "testifsets",
+ "type": "ifname",
+ "handle": 0,
+ "map": "verdict",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ "abcdef*",
+ {
+ "jump": {
+ "target": "do_nothing"
+ }
+ }
+ ],
+ [
+ "eth0",
+ {
+ "jump": {
+ "target": "do_nothing"
+ }
+ }
+ ]
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "testifsets",
+ "chain": "v4icmp",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "@simple"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "testifsets",
+ "chain": "v4icmp",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "@simple_wild"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "testifsets",
+ "chain": "v4icmp",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": {
+ "set": [
+ "eth0",
+ "abcdef0"
+ ]
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "testifsets",
+ "chain": "v4icmp",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": {
+ "set": [
+ "abcdef*",
+ "eth0"
+ ]
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "testifsets",
+ "chain": "v4icmp",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "data": "@map_wild"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "testifsets",
+ "chain": "v4icmpc",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ }
+ ]
+ },
+ "right": "@concat"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "testifsets",
+ "chain": "v4icmpc",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ }
+ ]
+ },
+ "right": "@concat_wild"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "testifsets",
+ "chain": "v4icmpc",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "10.1.2.2",
+ "abcdef0"
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "testifsets",
+ "chain": "v4icmpc",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ {
+ "meta": {
+ "key": "iifname"
+ }
+ }
+ ]
+ },
+ "right": {
+ "set": [
+ {
+ "concat": [
+ "10.1.2.2",
+ "abcdef*"
+ ]
+ }
+ ]
+ }
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "testifsets",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "protocol"
+ }
+ },
+ "right": "icmp"
+ }
+ },
+ {
+ "jump": {
+ "target": "v4icmp"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "testifsets",
+ "chain": "input",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "protocol"
+ }
+ },
+ "right": "icmp"
+ }
+ },
+ {
+ "goto": {
+ "target": "v4icmpc"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/sets_with_ifnames.nft b/tests/shell/testcases/sets/dumps/sets_with_ifnames.nft
new file mode 100644
index 00000000..77a8baf5
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/sets_with_ifnames.nft
@@ -0,0 +1,62 @@
+table inet testifsets {
+ set simple {
+ type ifname
+ elements = { "abcdef0",
+ "abcdef1",
+ "othername" }
+ }
+
+ set simple_wild {
+ type ifname
+ flags interval
+ elements = { "abcdef*",
+ "othername",
+ "ppp0" }
+ }
+
+ set concat {
+ type ipv4_addr . ifname
+ elements = { 10.1.2.2 . "abcdef0",
+ 10.1.2.2 . "abcdef1" }
+ }
+
+ set concat_wild {
+ type ipv4_addr . ifname
+ flags interval
+ elements = { 10.1.2.2 . "abcdef*",
+ 10.1.2.1 . "bar",
+ 1.1.2.0/24 . "abcdef0",
+ 12.2.2.0/24 . "abcdef*" }
+ }
+
+ map map_wild {
+ type ifname : verdict
+ flags interval
+ elements = { "abcdef*" : jump do_nothing,
+ "eth0" : jump do_nothing }
+ }
+
+ chain v4icmp {
+ iifname @simple counter packets 0 bytes 0
+ iifname @simple_wild counter packets 0 bytes 0
+ iifname { "eth0", "abcdef0" } counter packets 0 bytes 0
+ iifname { "abcdef*", "eth0" } counter packets 0 bytes 0
+ iifname vmap @map_wild
+ }
+
+ chain v4icmpc {
+ ip saddr . iifname @concat counter packets 0 bytes 0
+ ip saddr . iifname @concat_wild counter packets 0 bytes 0
+ ip saddr . iifname { 10.1.2.2 . "abcdef0" } counter packets 0 bytes 0
+ ip saddr . iifname { 10.1.2.2 . "abcdef*" } counter packets 0 bytes 0
+ }
+
+ chain input {
+ type filter hook input priority filter; policy accept;
+ ip protocol icmp jump v4icmp
+ ip protocol icmp goto v4icmpc
+ }
+
+ chain do_nothing {
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/type_set_symbol.json-nft b/tests/shell/testcases/sets/dumps/type_set_symbol.json-nft
new file mode 100644
index 00000000..e22213ea
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/type_set_symbol.json-nft
@@ -0,0 +1,114 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c1",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c2",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s1",
+ "table": "t",
+ "type": [
+ "ipv4_addr",
+ "ipv4_addr",
+ "inet_service"
+ ],
+ "handle": 0,
+ "size": 65535,
+ "flags": [
+ "timeout",
+ "dynamic"
+ ],
+ "timeout": 10800
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c1",
+ "handle": 0,
+ "expr": [
+ {
+ "set": {
+ "op": "update",
+ "elem": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "10.180.0.4",
+ 80
+ ]
+ },
+ "set": "@s1"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c2",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "1.2.3.4",
+ 80
+ ]
+ },
+ "right": "@s1"
+ }
+ },
+ {
+ "goto": {
+ "target": "c1"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/sets/dumps/type_set_symbol.nft b/tests/shell/testcases/sets/dumps/type_set_symbol.nft
new file mode 100644
index 00000000..21209f6d
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/type_set_symbol.nft
@@ -0,0 +1,16 @@
+table ip t {
+ set s1 {
+ type ipv4_addr . ipv4_addr . inet_service
+ size 65535
+ flags dynamic,timeout
+ timeout 3h
+ }
+
+ chain c1 {
+ update @s1 { ip saddr . 10.180.0.4 . 80 }
+ }
+
+ chain c2 {
+ ip saddr . 1.2.3.4 . 80 @s1 goto c1
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/typeof_raw_0.nft b/tests/shell/testcases/sets/dumps/typeof_raw_0.nft
new file mode 100644
index 00000000..4d6abaaa
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/typeof_raw_0.nft
@@ -0,0 +1,12 @@
+table inet t {
+ set y {
+ typeof ip daddr . @ih,32,32
+ elements = { 1.1.1.1 . 0x14,
+ 2.2.2.2 . 0x20 }
+ }
+
+ chain y {
+ ip saddr . @nh,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }
+ ip daddr . @nh,32,32 @y
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/typeof_sets_0.nft b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
new file mode 100644
index 00000000..63fc5b14
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
@@ -0,0 +1,106 @@
+table inet t {
+ set s1 {
+ typeof osf name
+ elements = { "Linux" }
+ }
+
+ set s2 {
+ typeof vlan id
+ elements = { 2, 3, 103 }
+ }
+
+ set s3 {
+ typeof meta ibrpvid
+ elements = { 2, 3, 103 }
+ }
+
+ set s4 {
+ typeof frag frag-off
+ elements = { 1, 1024 }
+ }
+
+ set s5 {
+ typeof ip option ra value
+ elements = { 1, 1024 }
+ }
+
+ set s6 {
+ typeof tcp option maxseg size
+ elements = { 1, 1024 }
+ }
+
+ set s7 {
+ typeof sctp chunk init num-inbound-streams
+ elements = { 1, 4 }
+ }
+
+ set s8 {
+ typeof ip version
+ elements = { 4, 6 }
+ }
+
+ set s9 {
+ typeof ip hdrlength
+ elements = { 0, 1, 2, 3, 4,
+ 15 }
+ }
+
+ set s10 {
+ typeof iifname . ip saddr . ipsec in reqid
+ elements = { "eth0" . 10.1.1.2 . 42 }
+ }
+
+ set s11 {
+ typeof vlan id . ip saddr
+ elements = { 3567 . 1.2.3.4 }
+ }
+
+ set s12 {
+ typeof iifname . ip saddr . meta ipsec
+ elements = { "eth0" . 10.1.1.2 . exists }
+ }
+
+ chain c1 {
+ osf name @s1 accept
+ }
+
+ chain c2 {
+ vlan id @s2 accept
+ }
+
+ chain c4 {
+ frag frag-off @s4 accept
+ }
+
+ chain c5 {
+ ip option ra value @s5 accept
+ }
+
+ chain c6 {
+ tcp option maxseg size @s6 accept
+ }
+
+ chain c7 {
+ sctp chunk init num-inbound-streams @s7 accept
+ }
+
+ chain c8 {
+ ip version @s8 accept
+ }
+
+ chain c9 {
+ ip hdrlength @s9 accept
+ }
+
+ chain c10 {
+ iifname . ip saddr . ipsec in reqid @s10 accept
+ }
+
+ chain c11 {
+ vlan id . ip saddr @s11 accept
+ }
+
+ chain c12 {
+ iifname . ip saddr . meta ipsec @s12 accept
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/typeof_sets_1.nft b/tests/shell/testcases/sets/dumps/typeof_sets_1.nft
new file mode 100644
index 00000000..89cbc835
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/typeof_sets_1.nft
@@ -0,0 +1,15 @@
+table bridge t {
+ set nodhcpvlan {
+ typeof vlan id
+ elements = { 1 }
+ }
+
+ chain c1 {
+ vlan id != @nodhcpvlan vlan type arp counter packets 0 bytes 0 jump c2
+ vlan id != @nodhcpvlan vlan type ip counter packets 0 bytes 0 jump c2
+ vlan id != { 1, 2 } vlan type ip6 counter packets 0 bytes 0 jump c2
+ }
+
+ chain c2 {
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/typeof_sets_concat.nft b/tests/shell/testcases/sets/dumps/typeof_sets_concat.nft
new file mode 100644
index 00000000..348b5848
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/typeof_sets_concat.nft
@@ -0,0 +1,23 @@
+table netdev t {
+ set s {
+ typeof ether saddr . vlan id
+ size 2048
+ flags dynamic,timeout
+ }
+
+ chain c {
+ ether type != 8021q add @s { ether saddr . 0 timeout 5s } counter packets 0 bytes 0 return
+ ether type != 8021q update @s { ether daddr . 123 timeout 1m } counter packets 0 bytes 0 return
+ }
+}
+table ip t {
+ set s {
+ typeof ipsec in reqid . iif
+ size 16
+ flags interval
+ }
+
+ chain c2 {
+ ipsec in reqid . "lo" @s
+ }
+}
diff --git a/tests/shell/testcases/sets/dynset_missing b/tests/shell/testcases/sets/dynset_missing
new file mode 100755
index 00000000..fdf5f49e
--- /dev/null
+++ b/tests/shell/testcases/sets/dynset_missing
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+set -e
+
+$NFT -f /dev/stdin <<EOF
+table ip test {
+ chain output { type filter hook output priority 0;
+ }
+}
+EOF
+
+# misses 'flags dynamic'
+$NFT 'add set ip test dlist {type ipv4_addr; }'
+
+# picks rhash backend because 'size' was also missing.
+$NFT 'add rule ip test output udp dport 1234 update @dlist { ip daddr } counter'
+
+tmpfile=$(mktemp)
+
+trap "rm -rf $tmpfile" EXIT
+
+# kernel has forced an 64k upper size, i.e. this restore file
+# has 'size 65536' but no 'flags dynamic'.
+$NFT list ruleset > $tmpfile
+
+# this restore works, because set is still the rhash backend.
+$NFT -f $tmpfile # success
+$NFT flush ruleset
+
+# fails without commit 'attempt to set_eval flag if dynamic updates requested',
+# because set in $tmpfile has 'size x' but no 'flags dynamic'.
+$NFT -f $tmpfile
diff --git a/tests/shell/testcases/sets/elem_opts_compat_0 b/tests/shell/testcases/sets/elem_opts_compat_0
new file mode 100755
index 00000000..7563773e
--- /dev/null
+++ b/tests/shell/testcases/sets/elem_opts_compat_0
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
+# ordering of element options and expressions has changed, make sure parser
+# accepts both ways
+
+set -e
+
+$NFT -f - <<EOF
+table t {
+ set s {
+ type inet_service
+ counter;
+ timeout 30s;
+ }
+}
+EOF
+
+check() {
+ out=$($NFT list ruleset)
+ secs=$(sed -n 's/.*expires \([0-9]\+\)s.*/\1/p' <<< "$out")
+ [[ $secs -lt 11 ]]
+ grep -q 'counter packets 10 bytes 20' <<< "$out"
+}
+
+$NFT add element t s '{ 23 counter packets 10 bytes 20 expires 10s }'
+check
+$NFT flush set t s
+$NFT add element t s '{ 42 expires 10s counter packets 10 bytes 20 }'
+check
diff --git a/tests/shell/testcases/sets/errors_0 b/tests/shell/testcases/sets/errors_0
new file mode 100755
index 00000000..27f65df3
--- /dev/null
+++ b/tests/shell/testcases/sets/errors_0
@@ -0,0 +1,69 @@
+#!/bin/bash
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ }
+}
+
+delete element ip x y { 2.3.4.5 }"
+
+$NFT -f - <<< $RULESET
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+RULESET="table ip x {
+ set y {
+ type ipv4_addr
+ flags interval
+ }
+}
+
+add element x y { 1.1.1.1/24 }
+delete element x y { 1.1.1.1/24 }
+add element x y { 1.1.1.1/24 }
+delete element x y { 2.2.2.2/24 }"
+
+$NFT -f - <<< $RULESET
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+RULESET="flush ruleset
+create table inet filter
+set inet filter foo {}
+add element inet filter foo { foobar }"
+
+$NFT -f - <<< $RULESET
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+RULESET="table ip x {
+ map x {
+ type ifname . ipv4_addr : verdict
+ elements = { if2 . 10.0.0.2 : jump chain2,
+ if2 . 192.168.0.0/24 : jump chain2 }
+ }
+
+ chain chain2 {}
+}"
+
+$NFT -f - <<< $RULESET
+if [ $? -eq 0 ]
+then
+ exit 1
+fi
+
+RULESET="add set inet filter myset { type ipv4_addr; flags interval; auto-merge }
+add element inet filter myset { 192.168.0.0/24 }
+add element inet filter myset { 192.168.0.2 }
+add element inet filter myset { 192.168.1.0/24 }
+add element inet filter myset { 192.168.1.100 }"
+
+$NFT -f - <<< $RULESET || exit 0
diff --git a/tests/shell/testcases/sets/exact_overlap_0 b/tests/shell/testcases/sets/exact_overlap_0
new file mode 100755
index 00000000..1ce9304a
--- /dev/null
+++ b/tests/shell/testcases/sets/exact_overlap_0
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+RULESET="add table t
+add set t s { type ipv4_addr; flags interval; }
+add element t s { 1.0.1.0/24 }
+add element t s { 1.0.2.0/23 }
+add element t s { 1.0.8.0/21 }
+add element t s { 1.0.32.0/19 }
+add element t s { 1.1.0.0/24 }
+add element t s { 1.1.2.0/23 }
+add element t s { 1.1.4.0/22 }
+add element t s { 1.1.8.0/24 }
+add element t s { 1.1.9.0/24 }
+add element t s { 1.1.10.0/23 }
+add element t s { 1.1.12.0/22 }
+add element t s { 1.1.16.0/20 }
+add element t s { 1.1.32.0/19 }
+add element t s { 1.0.1.0/24 }"
+
+$NFT -f - <<< $RULESET || exit 1
+
+$NFT add element t s { 1.0.1.0/24 }
diff --git a/tests/shell/testcases/sets/inner_0 b/tests/shell/testcases/sets/inner_0
new file mode 100755
index 00000000..39d91bd9
--- /dev/null
+++ b/tests/shell/testcases/sets/inner_0
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_inner_matching)
+
+set -e
+
+RULESET="table netdev x {
+ set x {
+ typeof vxlan ip saddr . vxlan ip daddr
+ elements = {
+ 3.3.3.3 . 4.4.4.4,
+ }
+ }
+
+ set y {
+ typeof vxlan ip saddr
+ flags dynamic
+ }
+
+ chain y {
+ udp dport 4789 vxlan ip saddr . vxlan ip daddr { 1.1.1.1 . 2.2.2.2 } counter
+ udp dport 4789 vxlan ip saddr . vxlan ip daddr @x counter
+ udp dport 4789 update @y { vxlan ip saddr }
+ }
+}"
+
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/sets/meter_0 b/tests/shell/testcases/sets/meter_0
new file mode 100755
index 00000000..82e6f20a
--- /dev/null
+++ b/tests/shell/testcases/sets/meter_0
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip6 test {
+ chain test {
+ meter acct_out size 4096 { meta iif . ip6 saddr timeout 600s counter }
+ meter acct_out2 size 12345 { ip6 saddr . meta iif timeout 600s counter }
+ }
+}
+
+table ip test {
+ chain test {
+ meter xyz size 8192 { ip saddr timeout 30s counter}
+ }
+}"
+
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/sets/reset_command_0 b/tests/shell/testcases/sets/reset_command_0
new file mode 100755
index 00000000..d38ddb3f
--- /dev/null
+++ b/tests/shell/testcases/sets/reset_command_0
@@ -0,0 +1,87 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_reset_set)
+
+set -e
+
+trap '[[ $? -eq 0 ]] || echo FAIL' EXIT
+
+RULESET="table t {
+ set s {
+ type ipv4_addr . inet_proto . inet_service
+ flags interval, timeout
+ counter
+ timeout 30m
+ elements = {
+ 1.0.0.1 . udp . 53 counter packets 5 bytes 30 expires 20m,
+ 2.0.0.2 . tcp . 22 counter packets 10 bytes 100 timeout 15m expires 10m
+ }
+ }
+ map m {
+ type ipv4_addr : ipv4_addr
+ quota 50 bytes
+ elements = {
+ 1.2.3.4 quota 50 bytes used 10 bytes : 10.2.3.4,
+ 5.6.7.8 quota 100 bytes used 50 bytes : 50.6.7.8
+ }
+ }
+}"
+
+echo -n "applying test ruleset: "
+$NFT -f - <<< "$RULESET"
+echo OK
+
+drop_seconds() {
+ sed 's/[0-9]\+m\?s//g'
+}
+expires_minutes() {
+ sed -n 's/.*expires \([0-9]*\)m.*/\1/p'
+}
+
+echo -n "get set elem matches reset set elem: "
+elem='element t s { 1.0.0.1 . udp . 53 }'
+[[ $($NFT "get $elem ; reset $elem" | \
+ grep 'elements = ' | drop_seconds | uniq | wc -l) == 1 ]]
+echo OK
+
+echo -n "counters are reset, expiry left alone: "
+NEW=$($NFT "get $elem")
+grep -q 'counter packets 0 bytes 0' <<< "$NEW"
+[[ $(expires_minutes <<< "$NEW") -lt 20 ]]
+echo OK
+
+echo -n "get map elem matches reset map elem: "
+elem='element t m { 1.2.3.4 }'
+[[ $($NFT "get $elem ; reset $elem" | \
+ grep 'elements = ' | uniq | wc -l) == 1 ]]
+echo OK
+
+echo -n "quota value is reset: "
+$NFT get element t m '{ 1.2.3.4 }' | grep -q 'quota 50 bytes : 10.2.3.4'
+echo OK
+
+echo -n "other elements remain the same: "
+OUT=$($NFT get element t s '{ 2.0.0.2 . tcp . 22 }')
+grep -q 'counter packets 10 bytes 100 timeout 15m' <<< "$OUT"
+VAL=$(expires_minutes <<< "$OUT")
+[[ $val -lt 10 ]]
+$NFT get element t m '{ 5.6.7.8 }' | grep -q 'quota 100 bytes used 50 bytes'
+echo OK
+
+echo -n "list set matches reset set: "
+EXP=$($NFT list set t s | drop_seconds)
+OUT=$($NFT reset set t s | drop_seconds)
+$DIFF -u <(echo "$EXP") <(echo "$OUT")
+echo OK
+
+echo -n "list map matches reset map: "
+EXP=$($NFT list map t m)
+OUT=$($NFT reset map t m)
+$DIFF -u <(echo "$EXP") <(echo "$OUT")
+echo OK
+
+echo -n "remaining elements are reset: "
+OUT=$($NFT list ruleset)
+grep -q '2.0.0.2 . tcp . 22 counter packets 0 bytes 0' <<< "$OUT"
+grep -q '5.6.7.8 quota 100 bytes : 50.6.7.8' <<< "$OUT"
+echo OK
diff --git a/tests/shell/testcases/sets/set_eval_0 b/tests/shell/testcases/sets/set_eval_0
new file mode 100755
index 00000000..82b6d3bc
--- /dev/null
+++ b/tests/shell/testcases/sets/set_eval_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+RULESET="table ip nat {
+ set set_with_interval {
+ type ipv4_addr
+ flags interval
+ }
+
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto { tcp, udp } th dport 443 dnat to 10.0.0.1
+ }
+}"
+
+$NFT -f - <<< $RULESET
diff --git a/tests/shell/testcases/sets/sets_with_ifnames b/tests/shell/testcases/sets/sets_with_ifnames
new file mode 100755
index 00000000..a4bc5072
--- /dev/null
+++ b/tests/shell/testcases/sets/sets_with_ifnames
@@ -0,0 +1,152 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+[ -z "$NFT" ] && exit 111
+
+$NFT -f "$dumpfile" || exit 1
+
+rnd=$(mktemp -u XXXXXXXX)
+ns1="nft1ifname-$rnd"
+ns2="nft2ifname-$rnd"
+
+cleanup()
+{
+ ip netns del "$ns1"
+ ip netns del "$ns2"
+}
+
+trap cleanup EXIT
+
+# check a given element is (not) present in the set.
+lookup_elem()
+{
+ local setname=$1
+ local value=$2
+ local fail=$3
+ local expect_result=$4
+ local msg=$5
+
+ result=$(ip netns exec "$ns1" $NFT get element inet testifsets $setname { "$value" } 2>/dev/null | grep "$expect_result" )
+
+ if [ -z "$result" ] && [ $fail -ne 1 ] ; then
+ echo "empty result, expected $expect_result $msg"
+ ip netns exec "$ns1" $NFT get element inet testifsets $setname { "$value" }
+ exit 1
+ fi
+}
+
+check_elem_get()
+{
+ local setname=$1
+ local value=$2
+ local fail=$3
+ local expect_result=$4
+
+ # when query is 'abcde', and set has 'abc*', result is
+ # 'abc*', not 'abcde', so returned element can be different.
+ if [ -z "$expect_result" ]; then
+ expect_result=$ifname
+ fi
+
+ lookup_elem "$setname" "$value" "$fail" "$expect_result" ""
+}
+
+# same, but also delete and re-add the element.
+check_elem()
+{
+ local setname=$1
+ local value=$2
+
+ lookup_elem "$setname" "$value" "0" "$value" "initial check"
+
+ ip netns exec "$ns1" $NFT delete element inet testifsets $setname { "$value" }
+ if [ $? -ne 0 ]; then
+ ip netns exec "$ns1" $NFT list ruleset
+ echo "delete element $setname { $value } failed"
+ exit 1
+ fi
+
+ ip netns exec "$ns1" $NFT add element inet testifsets $setname { "$value" }
+
+ lookup_elem "$setname" "$value" "0" "$value" "check after add/del"
+}
+
+# send pings, check all rules with sets that contain abcdef1 match.
+# there are 4 rules in this chain, 4 should match.
+check_matching_icmp_ppp()
+{
+ pkt=$((RANDOM%10))
+ pkt=$((pkt+1))
+ ip netns exec "$ns1" ping -f -c $pkt 10.1.2.2
+
+ # replies should arrive via 'abcdeg', so, should NOT increment any counters.
+ ip netns exec "$ns1" ping -f -c 100 10.2.2.2
+
+ matches=$(ip netns exec "$ns1" $NFT list chain inet testifsets v4icmp | grep "counter packets $pkt " | wc -l)
+ want=3
+
+ if [ "$matches" -ne $want ] ;then
+ ip netns exec "$ns1" $NFT list ruleset
+ echo "Expected $want matching rules, got $matches, packets $pkt in v4icmp"
+ exit 1
+ fi
+
+ # same, for concat set type.
+
+ matches=$(ip netns exec "$ns1" $NFT list chain inet testifsets v4icmpc | grep "counter packets $pkt " | wc -l)
+
+ if [ "$matches" -ne $want ] ;then
+ ip netns exec "$ns1" $NFT list ruleset
+ echo "Expected $want matching rules, got $matches, packets $pkt in v4icmpc"
+ exit 1
+ fi
+}
+
+ip netns add "$ns1" || exit 111
+ip netns add "$ns2" || exit 111
+ip netns exec "$ns1" $NFT -f "$dumpfile" || exit 3
+
+for n in abcdef0 abcdef1 othername;do
+ check_elem simple $n
+done
+
+check_elem_get simple foo 1
+
+for n in ppp0 othername;do
+ check_elem simple_wild $n
+done
+
+check_elem_get simple_wild enoent 1
+check_elem simple_wild ppp0
+check_elem_get simple_wild abcdefghijk 0 'abcdef\*'
+
+check_elem_get concat '1.2.3.4 . "enoent"' 1
+check_elem_get concat '10.1.2.2 . "abcdef"' 1
+check_elem_get concat '10.1.2.1 . "abcdef1"' 1
+
+check_elem concat '10.1.2.2 . "abcdef0"'
+check_elem concat '10.1.2.2 . "abcdef1"'
+
+set -e
+ip -net "$ns1" link set lo up
+ip -net "$ns2" link set lo up
+ip netns exec "$ns1" ping -f -c 10 127.0.0.1
+
+ip link add abcdef1 netns $ns1 type veth peer name veth0 netns $ns2
+ip link add abcdeg netns $ns1 type veth peer name veth1 netns $ns2
+
+ip -net "$ns1" link set abcdef1 up
+ip -net "$ns2" link set veth0 up
+ip -net "$ns1" link set abcdeg up
+ip -net "$ns2" link set veth1 up
+
+ip -net "$ns1" addr add 10.1.2.1/24 dev abcdef1
+ip -net "$ns1" addr add 10.2.2.1/24 dev abcdeg
+
+ip -net "$ns2" addr add 10.1.2.2/24 dev veth0
+ip -net "$ns2" addr add 10.2.2.2/24 dev veth1
+
+check_matching_icmp_ppp
diff --git a/tests/shell/testcases/sets/type_set_symbol b/tests/shell/testcases/sets/type_set_symbol
new file mode 100755
index 00000000..07820b7c
--- /dev/null
+++ b/tests/shell/testcases/sets/type_set_symbol
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
diff --git a/tests/shell/testcases/sets/typeof_raw_0 b/tests/shell/testcases/sets/typeof_raw_0
new file mode 100755
index 00000000..66042eb4
--- /dev/null
+++ b/tests/shell/testcases/sets/typeof_raw_0
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+EXPECTED="table inet t {
+ set y {
+ typeof ip daddr . @ih,32,32
+ elements = { 1.1.1.1 . 0x14, 2.2.2.2 . 0x20}
+ }
+
+ chain y {
+ ip saddr . @nh,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }
+ ip daddr . @nh,32,32 @y
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
+
diff --git a/tests/shell/testcases/sets/typeof_sets_0 b/tests/shell/testcases/sets/typeof_sets_0
new file mode 100755
index 00000000..016227da
--- /dev/null
+++ b/tests/shell/testcases/sets/typeof_sets_0
@@ -0,0 +1,243 @@
+#!/bin/bash
+
+# support for strings/typeof in named sets.
+# s1 and s2 are identical, they just use different
+# ways for declaration.
+
+set -e
+
+die() {
+ printf '%s\n' "$*"
+ exit 1
+}
+
+INPUT_OSF_SET="
+ set s1 {
+ typeof osf name
+ elements = { \"Linux\" }
+ }
+"
+
+INPUT_FRAG_SET="
+ set s4 {
+ typeof frag frag-off
+ elements = { 1, 1024 }
+ }
+"
+
+INPUT_VERSION_SET="
+ set s8 {
+ typeof ip version
+ elements = { 4, 6 }
+ }
+"
+
+INPUT_OSF_CHAIN="
+ chain c1 {
+ osf name @s1 accept
+ }
+"
+
+INPUT_FRAG_CHAIN="
+ chain c4 {
+ frag frag-off @s4 accept
+ }
+"
+
+INPUT_SCTP_CHAIN="
+ chain c7 {
+ sctp chunk init num-inbound-streams @s7 accept
+ }
+"
+INPUT_VERSION_CHAIN="
+ chain c8 {
+ ip version @s8 accept
+ }
+"
+
+if [ "$NFT_TEST_HAVE_sctp_chunks" = n ] ; then
+ INPUT_SCTP_CHAIN=
+fi
+
+if [ "$NFT_TEST_HAVE_bitshift" = n ] ; then
+ INPUT_FRAG_CHAIN=
+ INPUT_VERSION_CHAIN=
+fi
+
+if [ "$NFT_TEST_HAVE_osf" = n ] ; then
+ if [ "$((RANDOM % 2))" -eq 1 ] ; then
+ # Regardless of $NFT_TEST_HAVE_osf, we can define the set.
+ # Randomly do so.
+ INPUT_OSF_SET=
+ fi
+ INPUT_OSF_CHAIN=
+fi
+
+INPUT="table inet t {$INPUT_OSF_SET
+ set s2 {
+ typeof vlan id
+ elements = { 2, 3, 103 }
+ }
+
+ set s3 {
+ typeof meta ibrpvid
+ elements = { 2, 3, 103 }
+ }$INPUT_FRAG_SET
+
+ set s5 {
+ typeof ip option ra value
+ elements = { 1, 1024 }
+ }
+
+ set s6 {
+ typeof tcp option maxseg size
+ elements = { 1, 1024 }
+ }
+
+ set s7 {
+ typeof sctp chunk init num-inbound-streams
+ elements = { 1, 4 }
+ }$INPUT_VERSION_SET
+
+ set s9 {
+ typeof ip hdrlength
+ elements = { 0, 1, 2, 3, 4, 15 }
+ }
+
+ set s10 {
+ typeof meta iifname . ip saddr . ipsec in reqid
+ elements = { \"eth0\" . 10.1.1.2 . 42 }
+ }
+
+ set s11 {
+ typeof vlan id . ip saddr
+ elements = { 3567 . 1.2.3.4 }
+ }
+ set s12 {
+ typeof meta iifname . ip saddr . meta ipsec
+ elements = { \"eth0\" . 10.1.1.2 . 1 }
+ }
+$INPUT_OSF_CHAIN
+ chain c2 {
+ ether type vlan vlan id @s2 accept
+ }
+$INPUT_FRAG_CHAIN
+ chain c5 {
+ ip option ra value @s5 accept
+ }
+
+ chain c6 {
+ tcp option maxseg size @s6 accept
+ }
+$INPUT_SCTP_CHAIN
+$INPUT_VERSION_CHAIN
+ chain c9 {
+ ip hdrlength @s9 accept
+ }
+
+ chain c10 {
+ meta iifname . ip saddr . ipsec in reqid @s10 accept
+ }
+
+ chain c11 {
+ ether type vlan vlan id . ip saddr @s11 accept
+ }
+
+ chain c12 {
+ meta iifname . ip saddr . meta ipsec @s12 accept
+ }
+}"
+
+EXPECTED="table inet t {$INPUT_OSF_SET
+ set s2 {
+ typeof vlan id
+ elements = { 2, 3, 103 }
+ }
+
+ set s3 {
+ typeof meta ibrpvid
+ elements = { 2, 3, 103 }
+ }
+$INPUT_FRAG_SET
+ set s5 {
+ typeof ip option ra value
+ elements = { 1, 1024 }
+ }
+
+ set s6 {
+ typeof tcp option maxseg size
+ elements = { 1, 1024 }
+ }
+
+ set s7 {
+ typeof sctp chunk init num-inbound-streams
+ elements = { 1, 4 }
+ }
+$INPUT_VERSION_SET
+ set s9 {
+ typeof ip hdrlength
+ elements = { 0, 1, 2, 3, 4,
+ 15 }
+ }
+
+ set s10 {
+ typeof iifname . ip saddr . ipsec in reqid
+ elements = { \"eth0\" . 10.1.1.2 . 42 }
+ }
+
+ set s11 {
+ typeof vlan id . ip saddr
+ elements = { 3567 . 1.2.3.4 }
+ }
+
+ set s12 {
+ typeof iifname . ip saddr . meta ipsec
+ elements = { \"eth0\" . 10.1.1.2 . exists }
+ }
+$INPUT_OSF_CHAIN
+ chain c2 {
+ vlan id @s2 accept
+ }
+$INPUT_FRAG_CHAIN
+ chain c5 {
+ ip option ra value @s5 accept
+ }
+
+ chain c6 {
+ tcp option maxseg size @s6 accept
+ }
+$INPUT_SCTP_CHAIN$INPUT_VERSION_CHAIN
+ chain c9 {
+ ip hdrlength @s9 accept
+ }
+
+ chain c10 {
+ iifname . ip saddr . ipsec in reqid @s10 accept
+ }
+
+ chain c11 {
+ vlan id . ip saddr @s11 accept
+ }
+
+ chain c12 {
+ iifname . ip saddr . meta ipsec @s12 accept
+ }
+}"
+
+
+$NFT -f - <<< "$INPUT" || die $'nft command failed to process input:\n'">$INPUT<"
+
+$DIFF -u <($NFT list ruleset) - <<<"$EXPECTED" || die $'diff failed between ruleset and expected data.\nExpected:\n'">$EXPECTED<"
+
+if [ "$NFT_TEST_HAVE_bitshift" = n ] ; then
+ echo "Partial test due to NFT_TEST_HAVE_bitshift=n. Skip"
+ exit 77
+fi
+if [ "$NFT_TEST_HAVE_osf" = n ] ; then
+ echo "Partial test due to NFT_TEST_HAVE_osf=n. Skip"
+ exit 77
+fi
+if [ "$NFT_TEST_HAVE_sctp_chunks" = n ] ; then
+ echo "Partial test due to NFT_TEST_HAVE_sctp_chunks=n. Skip"
+ exit 77
+fi
diff --git a/tests/shell/testcases/sets/typeof_sets_1 b/tests/shell/testcases/sets/typeof_sets_1
new file mode 100755
index 00000000..e520270c
--- /dev/null
+++ b/tests/shell/testcases/sets/typeof_sets_1
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# regression test for corner case in netlink_delinearize
+
+EXPECTED="table bridge t {
+ set nodhcpvlan {
+ typeof vlan id
+ elements = { 1 }
+ }
+
+ chain c1 {
+ vlan id != @nodhcpvlan vlan type arp counter packets 0 bytes 0 jump c2
+ vlan id != @nodhcpvlan vlan type ip counter packets 0 bytes 0 jump c2
+ vlan id != { 1, 2 } vlan type ip6 counter packets 0 bytes 0 jump c2
+ }
+
+ chain c2 {
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/sets/typeof_sets_concat b/tests/shell/testcases/sets/typeof_sets_concat
new file mode 100755
index 00000000..34465f1d
--- /dev/null
+++ b/tests/shell/testcases/sets/typeof_sets_concat
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+
+$NFT -f "$dumpfile"
diff --git a/tests/shell/testcases/transactions/0002table_0 b/tests/shell/testcases/transactions/0002table_0
index 246b1092..c5f31a6f 100755
--- a/tests/shell/testcases/transactions/0002table_0
+++ b/tests/shell/testcases/transactions/0002table_0
@@ -5,6 +5,7 @@ set -e
RULESET="add table x
delete table x
add table x
+add chain x y { type nat hook prerouting priority 0; policy accept; }
add table x { flags dormant; }"
$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/transactions/0003table_0 b/tests/shell/testcases/transactions/0003table_0
index 6861eaba..91186dec 100755
--- a/tests/shell/testcases/transactions/0003table_0
+++ b/tests/shell/testcases/transactions/0003table_0
@@ -14,7 +14,6 @@ fi
KERNEL_RULESET="$($NFT list ruleset)"
if [ "" != "$KERNEL_RULESET" ] ; then
- DIFF="$(which diff)"
echo "Got a ruleset, but expected empty: "
echo "$KERNEL_RULESET"
exit 1
@@ -42,7 +41,6 @@ $NFT -f - <<< "$RULESETFAIL" && exit 2
KERNEL_RULESET="$($NFT list ruleset)"
if [ "$RULESET" != "$KERNEL_RULESET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
+ $DIFF -u <(echo "$RULESET") <(echo "$KERNEL_RULESET")
exit 1
fi
diff --git a/tests/shell/testcases/transactions/0040set_0 b/tests/shell/testcases/transactions/0040set_0
index a404abc8..468816b0 100755
--- a/tests/shell/testcases/transactions/0040set_0
+++ b/tests/shell/testcases/transactions/0040set_0
@@ -29,8 +29,7 @@ fi
GET="$($NFT list ruleset)"
if [ "$RULESET" != "$GET" ] ; then
- DIFF="$(which diff)"
- [ -x $DIFF ] && $DIFF -u <(echo "$RULESET") <(echo "$GET")
+ $DIFF -u <(echo "$RULESET") <(echo "$GET")
exit 1
fi
diff --git a/tests/shell/testcases/transactions/0049huge_0 b/tests/shell/testcases/transactions/0049huge_0
index 684d27a1..f66953c2 100755
--- a/tests/shell/testcases/transactions/0049huge_0
+++ b/tests/shell/testcases/transactions/0049huge_0
@@ -7,6 +7,15 @@ $NFT add table inet test
$NFT add chain inet test c
RULE_COUNT=3000
+
+if [ "$NFT_TEST_HAS_SOCKET_LIMITS" = y ] ; then
+ # The socket limit /proc/sys/net/core/rmem_max may be unsuitable for
+ # the test.
+ #
+ # Run only a subset of the test and mark as skipped at the end.
+ RULE_COUNT=500
+fi
+
RULESET=$(
for ((i = 0; i < ${RULE_COUNT}; i++)); do
echo "add rule inet test c accept comment rule$i"
@@ -28,7 +37,10 @@ done
echo '{"add": {"rule": {"family": "inet", "table": "test", "chain": "c", "expr": [{"accept": null}], "comment": "rule'$((${RULE_COUNT} - 1))'"}}}'
echo ']}'
)
-test $($NFT -j -e -a -f - <<< "$RULESET" |sed 's/\({"add":\)/\n\1/g' |grep '"handle"' |wc -l) -eq ${RULE_COUNT} || exit 1
+
+if [ "$NFT_TEST_HAVE_json" != n ]; then
+ test $($NFT -j -e -a -f - <<< "$RULESET" |sed 's/\({"add":\)/\n\1/g' |grep '"handle"' |wc -l) -eq ${RULE_COUNT} || exit 1
+fi
# Now an example from firewalld's testsuite
#
@@ -38,4 +50,18 @@ RULESET='{"nftables": [{"metainfo": {"json_schema_version": 1}}, {"add": {"table
{"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PREROUTING", "type": "filter", "hook": "prerouting", "prio": -290}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PREROUTING_ZONES"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PREROUTING", "expr": [{"jump": {"target": "raw_PREROUTING_ZONES"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PREROUTING", "type": "filter", "hook": "prerouting", "prio": -140}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PREROUTING_ZONES"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PREROUTING", "expr": [{"jump": {"target": "mangle_PREROUTING_ZONES"}}]}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PREROUTING", "type": "nat", "hook": "prerouting", "prio": -90}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PREROUTING_ZONES"}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PREROUTING", "expr": [{"jump": {"target": "nat_PREROUTING_ZONES"}}]}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POSTROUTING", "type": "nat", "hook": "postrouting", "prio": 110}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POSTROUTING_ZONES"}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POSTROUTING", "expr": [{"jump": {"target": "nat_POSTROUTING_ZONES"}}]}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PREROUTING", "type": "nat", "hook": "prerouting", "prio": -90}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PREROUTING_ZONES"}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PREROUTING", "expr": [{"jump": {"target": "nat_PREROUTING_ZONES"}}]}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POSTROUTING", "type": "nat", "hook": "postrouting", "prio": 110}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POSTROUTING_ZONES"}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POSTROUTING", "expr": [{"jump": {"target": "nat_POSTROUTING_ZONES"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_INPUT", "type": "filter", "hook": "input", "prio": 10}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FORWARD", "type": "filter", "hook": "forward", "prio": 10}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_OUTPUT", "type": "filter", "hook": "output", "prio": 10}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_INPUT_ZONES"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_INPUT", "expr": [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["established", "related"]}}}, {"accept": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_INPUT", "expr": [{"match": {"left": {"ct": {"key": "status"}}, "op": "in", "right": "dnat"}}, {"accept": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_INPUT", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "lo"}}, {"accept": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_INPUT", "expr": [{"jump": {"target": "filter_INPUT_ZONES"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_INPUT", "expr": [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["invalid"]}}}, {"drop": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_INPUT", "expr": [{"reject": {"type": "icmpx", "expr": "admin-prohibited"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FORWARD_IN_ZONES"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FORWARD_OUT_ZONES"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD", "expr": [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["established", "related"]}}}, {"accept": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD", "expr": [{"match": {"left": {"ct": {"key": "status"}}, "op": "in", "right": "dnat"}}, {"accept": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "lo"}}, {"accept": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD", "expr": [{"jump": {"target": "filter_FORWARD_IN_ZONES"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD", "expr": [{"jump": {"target": "filter_FORWARD_OUT_ZONES"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD", "expr": [{"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["invalid"]}}}, {"drop": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD", "expr": [{"reject": {"type": "icmpx", "expr": "admin-prohibited"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_OUTPUT", "expr": [{"match": {"left": {"meta": {"key": "oifname"}}, "op": "==", "right": "lo"}}, {"accept": null}]}}}, {"insert": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PREROUTING", "expr": [{"match": {"left": {"meta": {"key": "nfproto"}}, "op": "==", "right": "ipv6"}}, {"match": {"left": {"fib": {"flags": ["saddr", "iif"], "result": "oif"}}, "op": "==", "right": false}}, {"drop": null}]}}}, {"insert": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PREROUTING", "expr": [{"match": {"left": {"payload": {"protocol": "icmpv6", "field": "type"}}, "op": "==", "right": {"set": ["nd-router-advert", "nd-neighbor-solicit"]}}}, {"accept": null}]}}},
{"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_OUTPUT", "index": 0, "expr": [{"match": {"left": {"payload": {"protocol": "ip6", "field": "daddr"}}, "op": "==", "right": {"set": [{"prefix": {"addr": "::0.0.0.0", "len": 96}}, {"prefix": {"addr": "::ffff:0.0.0.0", "len": 96}}, {"prefix": {"addr": "2002:0000::", "len": 24}}, {"prefix": {"addr": "2002:0a00::", "len": 24}}, {"prefix": {"addr": "2002:7f00::", "len": 24}}, {"prefix": {"addr": "2002:ac10::", "len": 28}}, {"prefix": {"addr": "2002:c0a8::", "len": 32}}, {"prefix": {"addr": "2002:a9fe::", "len": 32}}, {"prefix": {"addr": "2002:e000::", "len": 19}}]}}}, {"reject": {"type": "icmpv6", "expr": "addr-unreachable"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD", "index": 2, "expr": [{"match": {"left": {"payload": {"protocol": "ip6", "field": "daddr"}}, "op": "==", "right": {"set": [{"prefix": {"addr": "::0.0.0.0", "len": 96}}, {"prefix": {"addr": "::ffff:0.0.0.0", "len": 96}}, {"prefix": {"addr": "2002:0000::", "len": 24}}, {"prefix": {"addr": "2002:0a00::", "len": 24}}, {"prefix": {"addr": "2002:7f00::", "len": 24}}, {"prefix": {"addr": "2002:ac10::", "len": 28}}, {"prefix": {"addr": "2002:c0a8::", "len": 32}}, {"prefix": {"addr": "2002:a9fe::", "len": 32}}, {"prefix": {"addr": "2002:e000::", "len": 19}}]}}}, {"reject": {"type": "icmpv6", "expr": "addr-unreachable"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_public"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_public_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_public_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_public_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_public_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_public_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_public", "expr": [{"jump": {"target": "raw_PRE_public_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_public", "expr": [{"jump": {"target": "raw_PRE_public_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_public", "expr": [{"jump": {"target": "raw_PRE_public_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_public", "expr": [{"jump": {"target": "raw_PRE_public_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_public", "expr": [{"jump": {"target": "raw_PRE_public_post"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_public"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_public_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_public_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_public_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_public_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_public_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_public", "expr": [{"jump": {"target": "filter_IN_public_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_public", "expr": [{"jump": {"target": "filter_IN_public_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_public", "expr": [{"jump": {"target": "filter_IN_public_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_public", "expr": [{"jump": {"target": "filter_IN_public_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_public", "expr": [{"jump": {"target": "filter_IN_public_post"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_public_allow", "expr": [{"match": {"left": {"payload": {"protocol": "tcp", "field": "dport"}}, "op": "==", "right": 22}}, {"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["new", "untracked"]}}}, {"accept": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_public_allow", "expr": [{"match": {"left": {"payload": {"protocol": "ip6", "field": "daddr"}}, "op": "==", "right": {"prefix": {"addr": "fe80::", "len": 64}}}}, {"match": {"left": {"payload": {"protocol": "udp", "field": "dport"}}, "op": "==", "right": 546}}, {"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["new", "untracked"]}}}, {"accept": null}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_public"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_public_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_public_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_public_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_public_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_public_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_public", "expr": [{"jump": {"target": "filter_FWDI_public_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_public", "expr": [{"jump": {"target": "filter_FWDI_public_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_public", "expr": [{"jump": {"target": "filter_FWDI_public_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_public", "expr": [{"jump": {"target": "filter_FWDI_public_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_public", "expr": [{"jump": {"target": "filter_FWDI_public_post"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_public", "index": 4, "expr": [{"match": {"left": {"meta": {"key": "l4proto"}}, "op": "==", "right": {"set": ["icmp", "icmpv6"]}}}, {"accept": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_public", "index": 4, "expr": [{"match": {"left": {"meta": {"key": "l4proto"}}, "op": "==", "right": {"set": ["icmp", "icmpv6"]}}}, {"accept": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PREROUTING_ZONES", "expr": [{"goto": {"target": "raw_PRE_public"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_public"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_public_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_public_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_public_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_public_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_public_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_public", "expr": [{"jump": {"target": "mangle_PRE_public_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_public", "expr": [{"jump": {"target": "mangle_PRE_public_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_public", "expr": [{"jump": {"target": "mangle_PRE_public_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_public", "expr": [{"jump": {"target": "mangle_PRE_public_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_public", "expr": [{"jump": {"target": "mangle_PRE_public_post"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PREROUTING_ZONES", "expr": [{"goto": {"target": "mangle_PRE_public"}}]}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_public"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_public_pre"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_public_log"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_public_deny"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_public_allow"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_public_post"}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_public", "expr": [{"jump": {"target": "nat_PRE_public_pre"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_public", "expr": [{"jump": {"target": "nat_PRE_public_log"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_public", "expr": [{"jump": {"target": "nat_PRE_public_deny"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_public", "expr": [{"jump": {"target": "nat_PRE_public_allow"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_public", "expr": [{"jump": {"target": "nat_PRE_public_post"}}]}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_public"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_public_pre"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_public_log"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_public_deny"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_public_allow"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_public_post"}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_public", "expr": [{"jump": {"target": "nat_PRE_public_pre"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_public", "expr": [{"jump": {"target": "nat_PRE_public_log"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_public", "expr": [{"jump": {"target": "nat_PRE_public_deny"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_public", "expr": [{"jump": {"target": "nat_PRE_public_allow"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_public", "expr": [{"jump": {"target": "nat_PRE_public_post"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PREROUTING_ZONES", "expr": [{"goto": {"target": "nat_PRE_public"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PREROUTING_ZONES", "expr": [{"goto": {"target": "nat_PRE_public"}}]}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_public"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_public_pre"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_public_log"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_public_deny"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_public_allow"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_public_post"}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_public", "expr": [{"jump": {"target": "nat_POST_public_pre"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_public", "expr": [{"jump": {"target": "nat_POST_public_log"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_public", "expr": [{"jump": {"target": "nat_POST_public_deny"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_public", "expr": [{"jump": {"target": "nat_POST_public_allow"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_public", "expr": [{"jump": {"target": "nat_POST_public_post"}}]}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_public"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_public_pre"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_public_log"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_public_deny"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_public_allow"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_public_post"}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_public", "expr": [{"jump": {"target": "nat_POST_public_pre"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_public", "expr": [{"jump": {"target": "nat_POST_public_log"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_public", "expr": [{"jump": {"target": "nat_POST_public_deny"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_public", "expr": [{"jump": {"target": "nat_POST_public_allow"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_public", "expr": [{"jump": {"target": "nat_POST_public_post"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POSTROUTING_ZONES", "expr": [{"goto": {"target": "nat_POST_public"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POSTROUTING_ZONES", "expr": [{"goto": {"target": "nat_POST_public"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_INPUT_ZONES", "expr": [{"goto": {"target": "filter_IN_public"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD_IN_ZONES", "expr": [{"goto": {"target": "filter_FWDI_public"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_public"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_public_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_public_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_public_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_public_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_public_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_public", "expr": [{"jump": {"target": "filter_FWDO_public_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_public", "expr": [{"jump": {"target": "filter_FWDO_public_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_public", "expr": [{"jump": {"target": "filter_FWDO_public_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_public", "expr": [{"jump": {"target": "filter_FWDO_public_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_public", "expr": [{"jump": {"target": "filter_FWDO_public_post"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD_OUT_ZONES", "expr": [{"goto": {"target": "filter_FWDO_public"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_trusted"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_trusted_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_trusted_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_trusted_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_trusted_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_trusted_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_trusted", "expr": [{"jump": {"target": "raw_PRE_trusted_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_trusted", "expr": [{"jump": {"target": "raw_PRE_trusted_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_trusted", "expr": [{"jump": {"target": "raw_PRE_trusted_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_trusted", "expr": [{"jump": {"target": "raw_PRE_trusted_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_trusted", "expr": [{"jump": {"target": "raw_PRE_trusted_post"}}]}}}, {"insert": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PREROUTING_ZONES", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "perm_dummy2"}}, {"goto": {"target": "raw_PRE_trusted"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_trusted"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_trusted_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_trusted_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_trusted_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_trusted_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_trusted_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_trusted", "expr": [{"jump": {"target": "mangle_PRE_trusted_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_trusted", "expr": [{"jump": {"target": "mangle_PRE_trusted_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_trusted", "expr": [{"jump": {"target": "mangle_PRE_trusted_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_trusted", "expr": [{"jump": {"target": "mangle_PRE_trusted_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_trusted", "expr": [{"jump": {"target": "mangle_PRE_trusted_post"}}]}}}, {"insert": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PREROUTING_ZONES", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "perm_dummy2"}}, {"goto": {"target": "mangle_PRE_trusted"}}]}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_trusted"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_trusted_pre"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_trusted_log"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_trusted_deny"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_trusted_allow"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_trusted_post"}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_trusted", "expr": [{"jump": {"target": "nat_PRE_trusted_pre"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_trusted", "expr": [{"jump": {"target": "nat_PRE_trusted_log"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_trusted", "expr": [{"jump": {"target": "nat_PRE_trusted_deny"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_trusted", "expr": [{"jump": {"target": "nat_PRE_trusted_allow"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_trusted", "expr": [{"jump": {"target": "nat_PRE_trusted_post"}}]}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_trusted"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_trusted_pre"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_trusted_log"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_trusted_deny"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_trusted_allow"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_trusted_post"}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_trusted", "expr": [{"jump": {"target": "nat_PRE_trusted_pre"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_trusted", "expr": [{"jump": {"target": "nat_PRE_trusted_log"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_trusted", "expr": [{"jump": {"target": "nat_PRE_trusted_deny"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_trusted", "expr": [{"jump": {"target": "nat_PRE_trusted_allow"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_trusted", "expr": [{"jump": {"target": "nat_PRE_trusted_post"}}]}}}, {"insert": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PREROUTING_ZONES", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "perm_dummy2"}}, {"goto": {"target": "nat_PRE_trusted"}}]}}}, {"insert": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PREROUTING_ZONES", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "perm_dummy2"}}, {"goto": {"target": "nat_PRE_trusted"}}]}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_trusted"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_trusted_pre"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_trusted_log"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_trusted_deny"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_trusted_allow"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_trusted_post"}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_trusted", "expr": [{"jump": {"target": "nat_POST_trusted_pre"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_trusted", "expr": [{"jump": {"target": "nat_POST_trusted_log"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_trusted", "expr": [{"jump": {"target": "nat_POST_trusted_deny"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_trusted", "expr": [{"jump": {"target": "nat_POST_trusted_allow"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_trusted", "expr": [{"jump": {"target": "nat_POST_trusted_post"}}]}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_trusted"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_trusted_pre"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_trusted_log"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_trusted_deny"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_trusted_allow"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_trusted_post"}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_trusted", "expr": [{"jump": {"target": "nat_POST_trusted_pre"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_trusted", "expr": [{"jump": {"target": "nat_POST_trusted_log"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_trusted", "expr": [{"jump": {"target": "nat_POST_trusted_deny"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_trusted", "expr": [{"jump": {"target": "nat_POST_trusted_allow"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_trusted", "expr": [{"jump": {"target": "nat_POST_trusted_post"}}]}}}, {"insert": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POSTROUTING_ZONES", "expr": [{"match": {"left": {"meta": {"key": "oifname"}}, "op": "==", "right": "perm_dummy2"}}, {"goto": {"target": "nat_POST_trusted"}}]}}}, {"insert": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POSTROUTING_ZONES", "expr": [{"match": {"left": {"meta": {"key": "oifname"}}, "op": "==", "right": "perm_dummy2"}}, {"goto": {"target": "nat_POST_trusted"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_trusted"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_trusted_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_trusted_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_trusted_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_trusted_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_trusted_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_trusted", "expr": [{"jump": {"target": "filter_IN_trusted_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_trusted", "expr": [{"jump": {"target": "filter_IN_trusted_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_trusted", "expr": [{"jump": {"target": "filter_IN_trusted_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_trusted", "expr": [{"jump": {"target": "filter_IN_trusted_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_trusted", "expr": [{"jump": {"target": "filter_IN_trusted_post"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_trusted", "expr": [{"accept": null}]}}}, {"insert": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_INPUT_ZONES", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "perm_dummy2"}}, {"goto": {"target": "filter_IN_trusted"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_trusted"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_trusted_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_trusted_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_trusted_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_trusted_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_trusted_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_trusted", "expr": [{"jump": {"target": "filter_FWDI_trusted_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_trusted", "expr": [{"jump": {"target": "filter_FWDI_trusted_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_trusted", "expr": [{"jump": {"target": "filter_FWDI_trusted_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_trusted", "expr": [{"jump": {"target": "filter_FWDI_trusted_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_trusted", "expr": [{"jump": {"target": "filter_FWDI_trusted_post"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_trusted", "expr": [{"accept": null}]}}}, {"insert": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD_IN_ZONES", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "perm_dummy2"}}, {"goto": {"target": "filter_FWDI_trusted"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_trusted"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_trusted_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_trusted_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_trusted_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_trusted_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_trusted_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_trusted", "expr": [{"jump": {"target": "filter_FWDO_trusted_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_trusted", "expr": [{"jump": {"target": "filter_FWDO_trusted_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_trusted", "expr": [{"jump": {"target": "filter_FWDO_trusted_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_trusted", "expr": [{"jump": {"target": "filter_FWDO_trusted_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_trusted", "expr": [{"jump": {"target": "filter_FWDO_trusted_post"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_trusted", "expr": [{"accept": null}]}}}, {"insert": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD_OUT_ZONES", "expr": [{"match": {"left": {"meta": {"key": "oifname"}}, "op": "==", "right": "perm_dummy2"}}, {"goto": {"target": "filter_FWDO_trusted"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_work"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_work_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_work_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_work_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_work_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "raw_PRE_work_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_work", "expr": [{"jump": {"target": "raw_PRE_work_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_work", "expr": [{"jump": {"target": "raw_PRE_work_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_work", "expr": [{"jump": {"target": "raw_PRE_work_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_work", "expr": [{"jump": {"target": "raw_PRE_work_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PRE_work", "expr": [{"jump": {"target": "raw_PRE_work_post"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_work"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_work_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_work_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_work_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_work_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_IN_work_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_work", "expr": [{"jump": {"target": "filter_IN_work_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_work", "expr": [{"jump": {"target": "filter_IN_work_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_work", "expr": [{"jump": {"target": "filter_IN_work_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_work", "expr": [{"jump": {"target": "filter_IN_work_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_work", "expr": [{"jump": {"target": "filter_IN_work_post"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_work_allow", "expr": [{"match": {"left": {"payload": {"protocol": "tcp", "field": "dport"}}, "op": "==", "right": 22}}, {"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["new", "untracked"]}}}, {"accept": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_work_allow", "expr": [{"match": {"left": {"payload": {"protocol": "ip6", "field": "daddr"}}, "op": "==", "right": {"prefix": {"addr": "fe80::", "len": 64}}}}, {"match": {"left": {"payload": {"protocol": "udp", "field": "dport"}}, "op": "==", "right": 546}}, {"match": {"left": {"ct": {"key": "state"}}, "op": "in", "right": {"set": ["new", "untracked"]}}}, {"accept": null}]}}}, {"insert": {"rule": {"family": "inet", "table": "firewalld", "chain": "raw_PREROUTING_ZONES", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "perm_dummy"}}, {"goto": {"target": "raw_PRE_work"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_work"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_work_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_work_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_work_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_work_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "mangle_PRE_work_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_work", "expr": [{"jump": {"target": "mangle_PRE_work_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_work", "expr": [{"jump": {"target": "mangle_PRE_work_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_work", "expr": [{"jump": {"target": "mangle_PRE_work_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_work", "expr": [{"jump": {"target": "mangle_PRE_work_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PRE_work", "expr": [{"jump": {"target": "mangle_PRE_work_post"}}]}}}, {"insert": {"rule": {"family": "inet", "table": "firewalld", "chain": "mangle_PREROUTING_ZONES", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "perm_dummy"}}, {"goto": {"target": "mangle_PRE_work"}}]}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_work"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_work_pre"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_work_log"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_work_deny"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_work_allow"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_PRE_work_post"}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_work", "expr": [{"jump": {"target": "nat_PRE_work_pre"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_work", "expr": [{"jump": {"target": "nat_PRE_work_log"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_work", "expr": [{"jump": {"target": "nat_PRE_work_deny"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_work", "expr": [{"jump": {"target": "nat_PRE_work_allow"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PRE_work", "expr": [{"jump": {"target": "nat_PRE_work_post"}}]}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_work"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_work_pre"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_work_log"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_work_deny"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_work_allow"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_PRE_work_post"}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_work", "expr": [{"jump": {"target": "nat_PRE_work_pre"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_work", "expr": [{"jump": {"target": "nat_PRE_work_log"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_work", "expr": [{"jump": {"target": "nat_PRE_work_deny"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_work", "expr": [{"jump": {"target": "nat_PRE_work_allow"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PRE_work", "expr": [{"jump": {"target": "nat_PRE_work_post"}}]}}}, {"insert": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_PREROUTING_ZONES", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "perm_dummy"}}, {"goto": {"target": "nat_PRE_work"}}]}}}, {"insert": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_PREROUTING_ZONES", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "perm_dummy"}}, {"goto": {"target": "nat_PRE_work"}}]}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_work"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_work_pre"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_work_log"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_work_deny"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_work_allow"}}}, {"add": {"chain": {"family": "ip", "table": "firewalld", "name": "nat_POST_work_post"}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_work", "expr": [{"jump": {"target": "nat_POST_work_pre"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_work", "expr": [{"jump": {"target": "nat_POST_work_log"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_work", "expr": [{"jump": {"target": "nat_POST_work_deny"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_work", "expr": [{"jump": {"target": "nat_POST_work_allow"}}]}}}, {"add": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POST_work", "expr": [{"jump": {"target": "nat_POST_work_post"}}]}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_work"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_work_pre"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_work_log"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_work_deny"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_work_allow"}}}, {"add": {"chain": {"family": "ip6", "table": "firewalld", "name": "nat_POST_work_post"}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_work", "expr": [{"jump": {"target": "nat_POST_work_pre"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_work", "expr": [{"jump": {"target": "nat_POST_work_log"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_work", "expr": [{"jump": {"target": "nat_POST_work_deny"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_work", "expr": [{"jump": {"target": "nat_POST_work_allow"}}]}}}, {"add": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POST_work", "expr": [{"jump": {"target": "nat_POST_work_post"}}]}}}, {"insert": {"rule": {"family": "ip", "table": "firewalld", "chain": "nat_POSTROUTING_ZONES", "expr": [{"match": {"left": {"meta": {"key": "oifname"}}, "op": "==", "right": "perm_dummy"}}, {"goto": {"target": "nat_POST_work"}}]}}}, {"insert": {"rule": {"family": "ip6", "table": "firewalld", "chain": "nat_POSTROUTING_ZONES", "expr": [{"match": {"left": {"meta": {"key": "oifname"}}, "op": "==", "right": "perm_dummy"}}, {"goto": {"target": "nat_POST_work"}}]}}}, {"insert": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_INPUT_ZONES", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "perm_dummy"}}, {"goto": {"target": "filter_IN_work"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_work"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_work_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_work_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_work_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_work_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDI_work_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_work", "expr": [{"jump": {"target": "filter_FWDI_work_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_work", "expr": [{"jump": {"target": "filter_FWDI_work_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_work", "expr": [{"jump": {"target": "filter_FWDI_work_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_work", "expr": [{"jump": {"target": "filter_FWDI_work_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_work", "expr": [{"jump": {"target": "filter_FWDI_work_post"}}]}}}, {"insert": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD_IN_ZONES", "expr": [{"match": {"left": {"meta": {"key": "iifname"}}, "op": "==", "right": "perm_dummy"}}, {"goto": {"target": "filter_FWDI_work"}}]}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_work"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_work_pre"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_work_log"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_work_deny"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_work_allow"}}}, {"add": {"chain": {"family": "inet", "table": "firewalld", "name": "filter_FWDO_work_post"}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_work", "expr": [{"jump": {"target": "filter_FWDO_work_pre"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_work", "expr": [{"jump": {"target": "filter_FWDO_work_log"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_work", "expr": [{"jump": {"target": "filter_FWDO_work_deny"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_work", "expr": [{"jump": {"target": "filter_FWDO_work_allow"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDO_work", "expr": [{"jump": {"target": "filter_FWDO_work_post"}}]}}}, {"insert": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FORWARD_OUT_ZONES", "expr": [{"match": {"left": {"meta": {"key": "oifname"}}, "op": "==", "right": "perm_dummy"}}, {"goto": {"target": "filter_FWDO_work"}}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_IN_work", "index": 4, "expr": [{"match": {"left": {"meta": {"key": "l4proto"}}, "op": "==", "right": {"set": ["icmp", "icmpv6"]}}}, {"accept": null}]}}}, {"add": {"rule": {"family": "inet", "table": "firewalld", "chain": "filter_FWDI_work", "index": 4, "expr": [{"match": {"left": {"meta": {"key": "l4proto"}}, "op": "==", "right": {"set": ["icmp", "icmpv6"]}}}, {"accept": null}]}}}]}'
-test -z "$($NFT -j -e -a -f - <<< "$RULESET" |sed 's/\({"add":\|{"insert":\)/\n\1/g' |grep '\({"add":\|{"insert":\)' | grep -v '"handle"')"
+if [ "$NFT_TEST_HAVE_json" != n ]; then
+ test -z "$($NFT -j -e -a -f - <<< "$RULESET" |sed 's/\({"add":\|{"insert":\)/\n\1/g' |grep '\({"add":\|{"insert":\)' | grep -v '"handle"')"
+fi
+
+if [ "$NFT_TEST_HAVE_json" = n ]; then
+ echo "Test partially skipped due to missing JSON support."
+ exit 77
+fi
+
+if [ "$RULE_COUNT" != 3000 ] ; then
+ echo "NFT_TEST_HAS_SOCKET_LIMITS indicates that the socket limit for"
+ echo "/proc/sys/net/core/rmem_max is too small for this test. Mark as SKIPPED"
+ echo "You may bump the limit and rerun with \`NFT_TEST_HAS_SOCKET_LIMITS=n\`."
+ exit 77
+fi
diff --git a/tests/shell/testcases/transactions/0051map_0 b/tests/shell/testcases/transactions/0051map_0
new file mode 100755
index 00000000..9ea5cd4c
--- /dev/null
+++ b/tests/shell/testcases/transactions/0051map_0
@@ -0,0 +1,122 @@
+#!/bin/bash
+
+rnd=$(mktemp -u XXXXXXXX)
+ns1="nft1trans-$rnd"
+
+#
+# dependency tracking for implicit set
+#
+RULESET="table ip x {
+ chain w {}
+ chain m {}
+
+ chain y {
+ ip saddr vmap { 1.1.1.1 : jump w, 2.2.2.2 : accept, 3.3.3.3 : goto m }
+ }
+}"
+
+$NFT -c -f - <<< "$RULESET" >/dev/null || exit 0
+$NFT -f - <<< "$RULESET" >/dev/null || exit 0
+ip netns add $ns1
+ip netns exec $ns1 $NFT -f - <<< "$RULESET" >/dev/null || exit 0
+ip netns del $ns1
+
+RULESET="flush chain ip x y
+delete chain ip x w"
+
+$NFT -c -f - <<< "$RULESET" >/dev/null || exit 0
+$NFT -f - <<< "$RULESET" >/dev/null || exit 0
+
+#
+# dependency tracking for map in implicit chain
+#
+RULESET="table ip x {
+ chain w {}
+ chain m {}
+
+ chain y {
+ meta iifname \"eno1\" jump {
+ ip saddr vmap { 1.1.1.1 : jump w, 3.3.3.3 : goto m }
+ }
+ }
+}"
+
+$NFT -c -f - <<< "$RULESET" >/dev/null || exit 0
+$NFT -f - <<< "$RULESET" >/dev/null || exit 0
+ip netns add $ns1
+ip netns exec $ns1 $NFT -f - <<< "$RULESET" >/dev/null || exit 0
+ip netns del $ns1
+
+RULESET="flush chain ip x y
+delete chain ip x w"
+
+$NFT -c -f - <<< "$RULESET" >/dev/null || exit 0
+$NFT -f - <<< "$RULESET" >/dev/null || exit 0
+
+#
+# dependency tracking for explicit map
+#
+RULESET="table ip x {
+ chain w {}
+ chain m {}
+
+ map y {
+ type ipv4_addr : verdict
+ elements = { 1.1.1.1 : jump w, 2.2.2.2 : accept, 3.3.3.3 : goto m }
+ }
+}"
+
+$NFT -c -f - <<< "$RULESET" >/dev/null || exit 0
+$NFT -f - <<< "$RULESET" >/dev/null || exit 0
+ip netns add $ns1
+ip netns exec $ns1 $NFT -f - <<< "$RULESET" >/dev/null || exit 0
+ip netns del $ns1
+
+RULESET="delete set ip x y
+delete chain ip x w"
+
+$NFT -c -f - <<< "$RULESET" >/dev/null || exit 0
+$NFT -f - <<< "$RULESET" >/dev/null || exit 0
+
+#
+# error path for implicit set
+#
+RULESET="table inet filter {
+ chain w {
+ jump z
+ }
+ chain z {
+ jump w
+ }
+
+ chain test {
+ ip protocol { tcp, udp } ip saddr vmap { 1.1.1.1 : jump z } counter flow add @nonexisting
+ ip6 nexthdr { tcp, udp } ct mark and 2 == 2 counter
+ }
+}"
+
+$NFT -c -f - <<< "$RULESET" >/dev/null || exit 0
+$NFT -f - <<< "$RULESET" >/dev/null || exit 0
+
+#
+# error path for implicit set
+#
+RULESET="table inet filter {
+ chain w {
+ jump z
+ }
+ chain z {
+ jump w
+ }
+
+ chain test {
+ ip protocol { tcp, udp } jump {
+ ip saddr vmap { 1.1.1.1 : jump z }
+ }
+ ip6 nexthdr { tcp, udp } ct mark and 2 == 2 counter
+ }
+}"
+
+$NFT -c -f - <<< "$RULESET" >/dev/null || exit 0
+$NFT -f - <<< "$RULESET" >/dev/null || exit 0
+$NFT flush table inet filter || exit 0
diff --git a/tests/shell/testcases/transactions/30s-stress b/tests/shell/testcases/transactions/30s-stress
new file mode 100755
index 00000000..e92b9226
--- /dev/null
+++ b/tests/shell/testcases/transactions/30s-stress
@@ -0,0 +1,683 @@
+#!/bin/bash
+
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
+
+runtime=30
+
+# allow stand-alone execution as well, e.g. '$0 3600'
+if [ x"$1" != "x" ] ;then
+ if [ -z "${NFT_TEST_HAVE_chain_binding+x}" ]; then
+ NFT_TEST_HAVE_chain_binding=y
+ fi
+ if [ -z "${NFT_TEST_HAVE_pipapo+x}" ]; then
+ NFT_TEST_HAVE_pipapo=y
+ fi
+ echo "running standalone with:"
+ echo "NFT_TEST_HAVE_chain_binding="$NFT_TEST_HAVE_chain_binding
+ echo "NFT_TEST_HAVE_pipapo="$NFT_TEST_HAVE_pipapo
+ if [ $1 -ge 0 ]; then
+ runtime="$1"
+ else
+ echo "Invalid runtime $1"
+ exit 1
+ fi
+fi
+
+if [ x = x"$NFT" ] ; then
+ NFT=nft
+fi
+
+if [ "$NFT_TEST_HAS_SOCKET_LIMITS" = y ] ; then
+ # The socket limit /proc/sys/net/core/wmem_max may be unsuitable for
+ # the test.
+ #
+ # Skip it. You may ensure that the limits are suitable and rerun
+ # with NFT_TEST_HAS_SOCKET_LIMITS=n.
+ exit 77
+fi
+
+if [ -z "${NFT_TEST_HAVE_chain_binding+x}" ] ; then
+ NFT_TEST_HAVE_chain_binding=n
+ mydir="$(dirname "$0")"
+ $NFT --check -f "$mydir/../../features/chain_binding.nft"
+ if [ $? -eq 0 ];then
+ NFT_TEST_HAVE_chain_binding=y
+ else
+ echo "Assuming anonymous chains are not supported"
+ fi
+fi
+
+if [ "$NFT_TEST_HAVE_pipapo" != y ] ;then
+ echo "Skipping pipapo set backend, kernel does not support it"
+fi
+
+testns=testns-$(mktemp -u "XXXXXXXX")
+tmp=""
+
+faultname="/proc/self/make-it-fail"
+tables="foo bar"
+
+failslab_defaults() {
+ test -w $faultname || return
+
+ # Disable fault injection unless process has 'make-it-fail' set
+ echo Y > /sys/kernel/debug/failslab/task-filter
+
+ # allow all slabs to fail (if process is tagged).
+ find /sys/kernel/slab/ -wholename '*/kmalloc-[0-9]*/failslab' -type f -exec sh -c 'echo 1 > {}' \;
+
+ # no limit on the number of failures, or clause works around old kernels that reject negative integer.
+ echo -1 > /sys/kernel/debug/failslab/times 2>/dev/null || printf '%#x -1' > /sys/kernel/debug/failslab/times
+
+ # Set to 2 for full dmesg traces for each injected error
+ echo 0 > /sys/kernel/debug/failslab/verbose
+}
+
+failslab_random()
+{
+ r=$((RANDOM%2))
+
+ if [ $r -eq 0 ]; then
+ echo Y > /sys/kernel/debug/failslab/ignore-gfp-wait
+ else
+ echo N > /sys/kernel/debug/failslab/ignore-gfp-wait
+ fi
+
+ r=$((RANDOM%5))
+ echo $r > /sys/kernel/debug/failslab/probability
+ r=$((RANDOM%100))
+ echo $r > /sys/kernel/debug/failslab/interval
+
+ # allow a small initial 'success budget'.
+ # failures only appear after this many allocated bytes.
+ r=$((RANDOM%16384))
+ echo $r > /sys/kernel/debug/$FAILTYPE/space
+}
+
+netns_del() {
+ ip netns pids "$testns" | xargs kill 2>/dev/null
+ ip netns del "$testns"
+}
+
+netns_add()
+{
+ ip netns add "$testns"
+ ip -netns "$testns" link set lo up
+}
+
+cleanup() {
+ [ "$tmp" = "" ] || rm -f "$tmp"
+ netns_del
+}
+
+nft_with_fault_inject()
+{
+ file="$1"
+
+ if [ -w "$faultname" ]; then
+ failslab_random
+
+ ip netns exec "$testns" bash -c "echo 1 > $faultname ; exec $NFT -f $file"
+ fi
+
+ ip netns exec "$testns" $NFT -f "$file"
+}
+
+trap cleanup EXIT
+tmp=$(mktemp)
+
+jump_or_goto()
+{
+ if [ $((RANDOM & 1)) -eq 0 ] ;then
+ echo -n "jump"
+ else
+ echo -n "goto"
+ fi
+}
+
+random_verdict()
+{
+ max="$1"
+
+ if [ $max -eq 0 ]; then
+ max=1
+ fi
+
+ rnd=$((RANDOM%max))
+
+ if [ $rnd -gt 0 ];then
+ jump_or_goto
+ printf " chain%03u" "$((rnd+1))"
+ return
+ fi
+
+ if [ $((RANDOM & 1)) -eq 0 ] ;then
+ echo "accept"
+ else
+ echo "drop"
+ fi
+}
+
+randsleep()
+{
+ local s=$((RANDOM%1))
+ local ms=$((RANDOM%1000))
+ sleep $s.$ms
+}
+
+randlist()
+{
+ while [ -r $tmp ]; do
+ randsleep
+ ip netns exec $testns $NFT list ruleset > /dev/null
+ done
+}
+
+randflush()
+{
+ while [ -r $tmp ]; do
+ randsleep
+ ip netns exec $testns $NFT flush ruleset > /dev/null
+ done
+}
+
+randdeltable()
+{
+ while [ -r $tmp ]; do
+ randsleep
+ for t in $tables; do
+ r=$((RANDOM%10))
+
+ if [ $r -eq 1 ] ;then
+ ip netns exec $testns $NFT delete table inet $t
+ randsleep
+ fi
+ done
+ done
+}
+
+randdelset()
+{
+ while [ -r $tmp ]; do
+ randsleep
+ for t in $tables; do
+ r=$((RANDOM%10))
+ s=$((RANDOM%10))
+
+ case $r in
+ 0)
+ setname=set_$s
+ ;;
+ 1)
+ setname=sett${s}
+ ;;
+ 2)
+ setname=dmap_${s}
+ ;;
+ 3)
+ setname=dmapt${s}
+ ;;
+ 4)
+ setname=vmap_${s}
+ ;;
+ 5)
+ setname=vmapt${s}
+ ;;
+ *)
+ continue
+ ;;
+ esac
+
+ if [ $r -eq 1 ] ;then
+ ip netns exec $testns $NFT delete set inet $t $setname
+ fi
+ done
+ done
+}
+
+randdelchain()
+{
+ while [ -r $tmp ]; do
+ for t in $tables; do
+ local c=$((RANDOM%100))
+ randsleep
+ chain=$(printf "chain%03u" "$c")
+
+ local r=$((RANDOM%10))
+ if [ $r -eq 1 ];then
+ # chain can be invalid/unknown.
+ ip netns exec $testns $NFT delete chain inet $t $chain
+ fi
+ done
+ done
+}
+
+randdisable()
+{
+ while [ -r $tmp ]; do
+ for t in $tables; do
+ randsleep
+ local r=$((RANDOM%10))
+ if [ $r -eq 1 ];then
+ ip netns exec $testns $NFT add table inet $t '{flags dormant; }'
+ randsleep
+ ip netns exec $testns $NFT add table inet $t '{ }'
+ fi
+ done
+ done
+}
+
+randdelns()
+{
+ while [ -r $tmp ]; do
+ randsleep
+ netns_del
+ netns_add
+ randsleep
+ done
+}
+
+available_flags()
+{
+ local -n available_flags=$1
+ selected_key=$2
+ if [ "$selected_key" == "single" ] ;then
+ available_flags+=("interval")
+ elif [ "$selected_key" == "concat" ] ;then
+ if [ "$NFT_TEST_HAVE_pipapo" = y ] ;then
+ available_flags+=("interval")
+ fi
+ fi
+}
+
+random_element_string=""
+
+# create a random element. Could cause any of the following:
+# 1. Invalid set/map
+# 2. Element already exists in set/map w. create
+# 3. Element is new but wants to jump to unknown chain
+# 4. Element already exsists in set/map w. add, but verdict (map data) differs
+# 5. Element is created/added/deleted from 'flags constant' set.
+random_elem()
+{
+ tr=$((RANDOM%2))
+ t=0
+
+ for table in $tables; do
+ if [ $t -ne $tr ]; then
+ t=$((t+1))
+ continue
+ fi
+
+ kr=$((RANDOM%2))
+ k=0
+ cnt=0
+ for key in "single" "concat"; do
+ if [ $k -ne $kr ] ;then
+ cnt=$((cnt+2))
+ k=$((k+1))
+ continue
+ fi
+
+ fr=$((RANDOM%2))
+ f=0
+
+ FLAGS=("")
+ available_flags FLAGS $key
+ for flags in "${FLAGS[@]}" ; do
+ cnt=$((cnt+1))
+ if [ $f -ne fkr ] ;then
+ f=$((f+1))
+ continue
+ fi
+
+ want="${key}${flags}"
+
+ e=$((RANDOM%256))
+ case "$want" in
+ "single") element="10.1.1.$e"
+ ;;
+ "concat") element="10.1.2.$e . $((RANDOM%65536))"
+ ;;
+ "singleinterval") element="10.1.$e.0-10.1.$e.$e"
+ ;;
+ "concatinterval") element="10.1.$e.0-10.1.$e.$e . $((RANDOM%65536))"
+ ;;
+ *) echo "bogus key $want"
+ exit 111
+ ;;
+ esac
+
+ # This may result in invalid jump, but thats what we want.
+ count=$(($RANDOM%100))
+
+ r=$((RANDOM%7))
+ case "$r" in
+ 0)
+ random_element_string=" inet $table set_${cnt} { $element }"
+ ;;
+ 1) random_element_string="inet $table sett${cnt} { $element timeout $((RANDOM%60))s }"
+ ;;
+ 2) random_element_string="inet $table dmap_${cnt} { $element : $RANDOM }"
+ ;;
+ 3) random_element_string="inet $table dmapt${cnt} { $element timeout $((RANDOM%60))s : $RANDOM }"
+ ;;
+ 4) random_element_string="inet $table vmap_${cnt} { $element : `random_verdict $count` }"
+ ;;
+ 5) random_element_string="inet $table vmapt${cnt} { $element timeout $((RANDOM%60))s : `random_verdict $count` }"
+ ;;
+ 6) random_element_string="inet $table setc${cnt} { $element }"
+ ;;
+ esac
+
+ return
+ done
+ done
+ done
+}
+
+randload()
+{
+ while [ -r $tmp ]; do
+ random_element_string=""
+ r=$((RANDOM%10))
+
+ what=""
+ case $r in
+ 1)
+ (echo "flush ruleset"; cat "$tmp"
+ echo "insert rule inet foo INPUT meta nftrace set 1"
+ echo "insert rule inet foo OUTPUT meta nftrace set 1"
+ ) | nft_with_fault_inject "/dev/stdin"
+ ;;
+ 2) what="add"
+ ;;
+ 3) what="create"
+ ;;
+ 4) what="delete"
+ ;;
+ 5) what="destroy"
+ ;;
+ 6) what="get"
+ ;;
+ *)
+ randsleep
+ ;;
+ esac
+
+ if [ x"$what" = "x" ]; then
+ nft_with_fault_inject "$tmp"
+ else
+ # This can trigger abort path, for various reasons:
+ # invalid set name
+ # key mismatches set specification (concat vs. single value)
+ # attempt to delete non-existent key
+ # attempt to create dupliacte key
+ # attempt to add duplicate key with non-matching value (data)
+ # attempt to add new uniqeue key with a jump to an unknown chain
+ random_elem
+ ( cat "$tmp"; echo "$what element $random_element_string") | nft_with_fault_inject "/dev/stdin"
+ fi
+ done
+}
+
+randmonitor()
+{
+ while [ -r $tmp ]; do
+ randsleep
+ timeout=$((RANDOM%16))
+ timeout $((timeout+1)) $NFT monitor > /dev/null
+ done
+}
+
+floodping() {
+ cpunum=$(grep -c processor /proc/cpuinfo)
+ cpunum=$((cpunum+1))
+
+ while [ -r $tmp ]; do
+ spawn=$((RANDOM%$cpunum))
+
+ # spawn at most $cpunum processes. Or maybe none at all.
+ i=0
+ while [ $i -lt $spawn ]; do
+ mask=$(printf 0x%x $((1<<$i)))
+ timeout 3 ip netns exec "$testns" taskset $mask ping -4 -fq 127.0.0.1 > /dev/null &
+ timeout 3 ip netns exec "$testns" taskset $mask ping -6 -fq ::1 > /dev/null &
+ i=$((i+1))
+ done
+
+ wait
+ randsleep
+ done
+}
+
+stress_all()
+{
+ # if fault injection is enabled, first a quick test to trigger
+ # abort paths without any parallel deletes/flushes.
+ if [ -w $faultname ] ;then
+ for i in $(seq 1 10);do
+ nft_with_fault_inject "$tmp"
+ done
+ fi
+
+ randlist &
+ randflush &
+ randdeltable &
+ randdisable &
+ randdelchain &
+ randdelset &
+ randdelns &
+ randload &
+ randmonitor &
+}
+
+gen_anon_chain_jump()
+{
+ echo -n "insert rule inet $@ "
+ jump_or_goto
+
+ if [ "$NFT_TEST_HAVE_chain_binding" = n ] ; then
+ echo " defaultchain"
+ return
+ fi
+
+ echo -n " { "
+ jump_or_goto
+ echo " defaultchain; counter; }"
+}
+
+gen_ruleset() {
+echo > "$tmp"
+for table in $tables; do
+ count=$((RANDOM % 100))
+ if [ $count -lt 1 ];then
+ count=1
+ fi
+
+ echo add table inet "$table" >> "$tmp"
+ echo flush table inet "$table" >> "$tmp"
+
+ echo "add chain inet $table INPUT { type filter hook input priority 0; }" >> "$tmp"
+ echo "add chain inet $table OUTPUT { type filter hook output priority 0; }" >> "$tmp"
+ for c in $(seq 1 $count); do
+ chain=$(printf "chain%03u" "$c")
+ echo "add chain inet $table $chain" >> "$tmp"
+ done
+
+ echo "add chain inet $table defaultchain" >> "$tmp"
+
+ for c in $(seq 1 $count); do
+ chain=$(printf "chain%03u" "$c")
+ for BASE in INPUT OUTPUT; do
+ echo "add rule inet $table $BASE counter jump $chain" >> "$tmp"
+ done
+ if [ $((RANDOM%10)) -eq 1 ];then
+ echo "add rule inet $table $chain counter jump defaultchain" >> "$tmp"
+ else
+ echo "add rule inet $table $chain counter return" >> "$tmp"
+ fi
+ done
+
+ cnt=0
+
+ # add a few anonymous sets. rhashtable is convered by named sets below.
+ c=$((RANDOM%$count))
+ chain=$(printf "chain%03u" "$((c+1))")
+ echo "insert rule inet $table $chain tcp dport 22-26 ip saddr { 1.2.3.4, 5.6.7.8 } counter comment hash_fast" >> "$tmp"
+ echo "insert rule inet $table $chain ip6 saddr { ::1, dead::beef } counter" comment hash >> "$tmp"
+ echo "insert rule inet $table $chain ip saddr { 1.2.3.4 - 5.6.7.8, 127.0.0.1 } comment rbtree" >> "$tmp"
+ # bitmap 1byte, with anon chain jump
+ gen_anon_chain_jump "$table $chain ip protocol { 6, 17 }" >> "$tmp"
+
+ # bitmap 2byte
+ echo "insert rule inet $table $chain tcp dport != { 22, 23, 80 } goto defaultchain" >> "$tmp"
+ echo "insert rule inet $table $chain tcp dport { 1-1024, 8000-8080 } jump defaultchain comment rbtree" >> "$tmp"
+ if [ "$NFT_TEST_HAVE_pipapo" = y ] ;then
+ # pipapo (concat + set), with goto anonymous chain.
+ gen_anon_chain_jump "$table $chain ip saddr . tcp dport { 1.2.3.4 . 1-1024, 1.2.3.6 - 1.2.3.10 . 8000-8080, 1.2.3.4 . 8080, 1.2.3.6 - 1.2.3.10 . 22 }" >> "$tmp"
+ fi
+
+ # add a few anonymous sets. rhashtable is convered by named sets below.
+ c=$((RANDOM%$count))
+ chain=$(printf "chain%03u" "$((c+1))")
+ echo "insert rule inet $table $chain tcp dport 22-26 ip saddr { 1.2.3.4, 5.6.7.8 } counter comment hash_fast" >> "$tmp"
+ echo "insert rule inet $table $chain ip6 saddr { ::1, dead::beef } counter" comment hash >> "$tmp"
+ echo "insert rule inet $table $chain ip saddr { 1.2.3.4 - 5.6.7.8, 127.0.0.1 } comment rbtree" >> "$tmp"
+ # bitmap 1byte, with anon chain jump
+ gen_anon_chain_jump "$table $chain ip protocol { 6, 17 }" >> "$tmp"
+ # bitmap 2byte
+ echo "insert rule inet $table $chain tcp dport != { 22, 23, 80 } goto defaultchain" >> "$tmp"
+ echo "insert rule inet $table $chain tcp dport { 1-1024, 8000-8080 } jump defaultchain comment rbtree" >> "$tmp"
+ if [ "$NFT_TEST_HAVE_pipapo" = y ] ;then
+ # pipapo (concat + set), with goto anonymous chain.
+ gen_anon_chain_jump "$table $chain ip saddr . tcp dport { 1.2.3.4 . 1-1024, 1.2.3.6 - 1.2.3.10 . 8000-8080, 1.2.3.4 . 8080, 1.2.3.6 - 1.2.3.10 . 22 }" >> "$tmp"
+ fi
+
+ # add constant/immutable sets
+ size=$((RANDOM%5120000))
+ size=$((size+2))
+ echo "add set inet $table setc1 { typeof tcp dport; size $size; flags constant; elements = { 22, 44 } }" >> "$tmp"
+ echo "add set inet $table setc2 { typeof ip saddr; size $size; flags constant; elements = { 1.2.3.4, 5.6.7.8 } }" >> "$tmp"
+ echo "add set inet $table setc3 { typeof ip6 daddr; size $size; flags constant; elements = { ::1, dead::1 } }" >> "$tmp"
+ echo "add set inet $table setc4 { typeof tcp dport; size $size; flags interval,constant; elements = { 22-44, 55-66 } }" >> "$tmp"
+ echo "add set inet $table setc5 { typeof ip saddr; size $size; flags interval,constant; elements = { 1.2.3.4-5.6.7.8, 10.1.1.1 } }" >> "$tmp"
+ echo "add set inet $table setc6 { typeof ip6 daddr; size $size; flags interval,constant; elements = { ::1, dead::1-dead::3 } }" >> "$tmp"
+
+ # add named sets with various combinations (plain value, range, concatenated values, concatenated ranges, with timeouts, with data ...)
+ for key in "ip saddr" "ip saddr . tcp dport"; do
+ FLAGS=("")
+ if [ "$key" == "ip saddr" ] ;then
+ FLAGS+=("flags interval;")
+ elif [ "$key" == "ip saddr . tcp dport" ] ;then
+ if [ "$NFT_TEST_HAVE_pipapo" = y ] ;then
+ FLAGS+=("flags interval;")
+ fi
+ fi
+ for ((i = 0; i < ${#FLAGS[@]}; i++)) ; do
+ timeout=$((RANDOM%10))
+ timeout=$((timeout+1))
+ timeout="timeout ${timeout}s"
+
+ cnt=$((cnt+1))
+ flags=${FLAGS[$i]}
+ echo "add set inet $table set_${cnt} { typeof ${key} ; ${flags} }" >> "$tmp"
+ echo "add set inet $table sett${cnt} { typeof ${key} ; $timeout; ${flags} }" >> "$tmp"
+ echo "add map inet $table dmap_${cnt} { typeof ${key} : meta mark ; ${flags} }" >> "$tmp"
+ echo "add map inet $table dmapt${cnt} { typeof ${key} : meta mark ; $timeout ; ${flags} }" >> "$tmp"
+ echo "add map inet $table vmap_${cnt} { typeof ${key} : verdict ; ${flags} }" >> "$tmp"
+ echo "add map inet $table vmapt${cnt} { typeof ${key} : verdict; $timeout ; ${flags} }" >> "$tmp"
+ done
+ done
+
+ cnt=0
+ for key in "single" "concat"; do
+ FLAGS=("")
+ available_flags FLAGS $key
+
+ for ((i = 0; i < ${#FLAGS[@]}; i++)) ; do
+ flags=${FLAGS[$i]}
+ want="${key}${flags}"
+ cnt=$((cnt+1))
+ maxip=$((RANDOM%256))
+
+ if [ $maxip -eq 0 ];then
+ maxip=1
+ fi
+
+ for e in $(seq 1 $maxip);do
+ case "$want" in
+ "single") element="10.1.1.$e"
+ ;;
+ "concat")
+ element="10.1.2.$e . $((RANDOM%65536))"
+ ;;
+ "singleinterval")
+ element="10.1.$e.0-10.1.$e.$e"
+ ;;
+ "concatinterval")
+ element="10.1.$e.0-10.1.$e.$e . $((RANDOM%65536))"
+ ;;
+ *)
+ echo "bogus key $want"
+ exit 111
+ ;;
+ esac
+
+ echo "add element inet $table set_${cnt} { $element }" >> "$tmp"
+ echo "add element inet $table sett${cnt} { $element timeout $((RANDOM%60))s }" >> "$tmp"
+ echo "add element inet $table dmap_${cnt} { $element : $RANDOM }" >> "$tmp"
+ echo "add element inet $table dmapt${cnt} { $element timeout $((RANDOM%60))s : $RANDOM }" >> "$tmp"
+ echo "add element inet $table vmap_${cnt} { $element : `random_verdict $count` }" >> "$tmp"
+ echo "add element inet $table vmapt${cnt} { $element timeout $((RANDOM%60))s : `random_verdict $count` }" >> "$tmp"
+ done
+ done
+ done
+done
+}
+
+run_test()
+{
+ local time_now=$(date +%s)
+ local time_stop=$((time_now + $runtime))
+ local regen=30
+
+ while [ $time_now -lt $time_stop ]; do
+ if [ $regen -gt 0 ];then
+ sleep 1
+ time_now=$(date +%s)
+ regen=$((regen-1))
+ continue
+ fi
+
+ # This clobbers the previously generated ruleset, this is intentional.
+ gen_ruleset
+ regen=$((RANDOM%60))
+ regen=$((regen+2))
+ time_now=$(date +%s)
+ done
+}
+
+netns_add
+
+gen_ruleset
+ip netns exec "$testns" $NFT -f "$tmp" || exit 1
+
+failslab_defaults
+
+stress_all 2>/dev/null &
+
+randsleep
+
+floodping 2> /dev/null &
+
+run_test
+
+# this stops stress_all
+rm -f "$tmp"
+tmp=""
+sleep 4
+
+if [ "$NFT_TEST_HAVE_chain_binding" = n ] ; then
+ echo "Ran a modified version of the test due to NFT_TEST_HAVE_chain_binding=n"
+fi
diff --git a/tests/shell/testcases/transactions/anon_chain_loop b/tests/shell/testcases/transactions/anon_chain_loop
new file mode 100755
index 00000000..2fd61810
--- /dev/null
+++ b/tests/shell/testcases/transactions/anon_chain_loop
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# anon chains with c1 -> c2 recursive jump, expect failure
+$NFT -f - <<EOF
+table ip t {
+ chain c2 { }
+ chain c1 { }
+}
+
+add t c1 ip saddr 127.0.0.1 jump { jump c2; }
+add t c2 ip saddr 127.0.0.1 jump { jump c1; }
+EOF
+
+if [ $? -eq 0 ] ; then
+ echo "E: able to load bad ruleset" >&2
+ exit 1
+fi
+
+exit 0
diff --git a/tests/shell/testcases/transactions/bad_expression b/tests/shell/testcases/transactions/bad_expression
new file mode 100755
index 00000000..794b6258
--- /dev/null
+++ b/tests/shell/testcases/transactions/bad_expression
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# table with invalid expression (masquerade called from filter table).
+# nft must return an error. Also catch nfnetlink retry loops that
+# cause nft or kernel to spin.
+timeout 3 $NFT -f - <<EOF
+table ip t0 {
+ chain c { }
+ chain input {
+ type filter hook input priority 0;
+ jump c
+ }
+}
+
+table ip t1 {
+ chain a {
+ masquerade
+ }
+ chain input {
+ type filter hook input priority 1;
+ jump a
+ }
+}
+EOF
+
+rc=$?
+if [ $rc -eq 0 ]; then
+ echo "Ruleset should have failed" 1>&2
+ exit 111
+fi
+
+# 124 means 'command timed out', fail if this
+# happens. Else, pass, failure is wanted here.
+if [ $rc -ne 124 ]; then
+ exit 0
+fi
+
+exit $rc
diff --git a/tests/shell/testcases/transactions/concat_range_abort b/tests/shell/testcases/transactions/concat_range_abort
new file mode 100755
index 00000000..b2bbe37b
--- /dev/null
+++ b/tests/shell/testcases/transactions/concat_range_abort
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+set -e
+
+$NFT -f /dev/stdin <<EOF
+table ip x {
+ map m {
+ typeof ip saddr . meta mark : verdict
+ flags interval
+ counter
+ elements = {
+ 127.0.0.1-127.0.0.4 . 0x123434-0xb00122 : jump foo,
+ }
+ }
+
+ chain foo {
+ accept
+ }
+}
+EOF
+
+$NFT -f /dev/stdin <<EOF
+add chain ip x bar
+add element ip x m { 1.2.3.4 . 42 : jump bar }
+delete set ip x m
+EOF
diff --git a/tests/shell/testcases/transactions/doubled-set b/tests/shell/testcases/transactions/doubled-set
new file mode 100755
index 00000000..50b568eb
--- /dev/null
+++ b/tests/shell/testcases/transactions/doubled-set
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
+$NFT -f /dev/stdin <<EOF
+table t {
+ set s {
+ type ipv4_addr . ifname
+ flags interval
+ elements = { 1.2.3.4 . "foo" }
+ }
+
+ set s {
+ type ipv4_addr . ifname
+ flags interval
+ elements = { 1.2.3.4 . "foo" }
+
+ }
+}
+EOF
+
+# run-tests.sh will validate dumpfile.
diff --git a/tests/shell/testcases/transactions/dumps/0001table_0.json-nft b/tests/shell/testcases/transactions/dumps/0001table_0.json-nft
new file mode 100644
index 00000000..ea75b43f
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0001table_0.json-nft
@@ -0,0 +1,25 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "y",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0002table_0.json-nft b/tests/shell/testcases/transactions/dumps/0002table_0.json-nft
new file mode 100644
index 00000000..b1fefc31
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0002table_0.json-nft
@@ -0,0 +1,31 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0,
+ "flags": "dormant"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "nat",
+ "hook": "prerouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0002table_0.nft b/tests/shell/testcases/transactions/dumps/0002table_0.nft
index 6eb70726..429cbc34 100644
--- a/tests/shell/testcases/transactions/dumps/0002table_0.nft
+++ b/tests/shell/testcases/transactions/dumps/0002table_0.nft
@@ -1,3 +1,7 @@
table ip x {
flags dormant
+
+ chain y {
+ type nat hook prerouting priority filter; policy accept;
+ }
}
diff --git a/tests/shell/testcases/transactions/dumps/0003table_0.json-nft b/tests/shell/testcases/transactions/dumps/0003table_0.json-nft
new file mode 100644
index 00000000..ea75b43f
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0003table_0.json-nft
@@ -0,0 +1,25 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "y",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0003table_0.nft b/tests/shell/testcases/transactions/dumps/0003table_0.nft
new file mode 100644
index 00000000..e4e5f9b1
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0003table_0.nft
@@ -0,0 +1,4 @@
+table ip x {
+}
+table ip y {
+}
diff --git a/tests/shell/testcases/transactions/dumps/0010chain_0.json-nft b/tests/shell/testcases/transactions/dumps/0010chain_0.json-nft
new file mode 100644
index 00000000..85947674
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0010chain_0.json-nft
@@ -0,0 +1,26 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "w",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "w",
+ "name": "y",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0011chain_0.json-nft b/tests/shell/testcases/transactions/dumps/0011chain_0.json-nft
new file mode 100644
index 00000000..12cf0bbf
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0011chain_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "drop"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0012chain_0.json-nft b/tests/shell/testcases/transactions/dumps/0012chain_0.json-nft
new file mode 100644
index 00000000..dc5eaa61
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0012chain_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "w",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "w",
+ "name": "y",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0013chain_0.json-nft b/tests/shell/testcases/transactions/dumps/0013chain_0.json-nft
new file mode 100644
index 00000000..dc5eaa61
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0013chain_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "w",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "w",
+ "name": "y",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 0,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0014chain_1.json-nft b/tests/shell/testcases/transactions/dumps/0014chain_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0014chain_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0014chain_1.nft b/tests/shell/testcases/transactions/dumps/0014chain_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0014chain_1.nft
diff --git a/tests/shell/testcases/transactions/dumps/0015chain_0.json-nft b/tests/shell/testcases/transactions/dumps/0015chain_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0015chain_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0015chain_0.nft b/tests/shell/testcases/transactions/dumps/0015chain_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0015chain_0.nft
diff --git a/tests/shell/testcases/transactions/dumps/0020rule_0.json-nft b/tests/shell/testcases/transactions/dumps/0020rule_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0020rule_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0020rule_0.nft b/tests/shell/testcases/transactions/dumps/0020rule_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0020rule_0.nft
diff --git a/tests/shell/testcases/transactions/dumps/0021rule_0.json-nft b/tests/shell/testcases/transactions/dumps/0021rule_0.json-nft
new file mode 100644
index 00000000..4c5500cc
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0021rule_0.json-nft
@@ -0,0 +1,54 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "right": "2.2.2.2"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0022rule_1.json-nft b/tests/shell/testcases/transactions/dumps/0022rule_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0022rule_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0022rule_1.nft b/tests/shell/testcases/transactions/dumps/0022rule_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0022rule_1.nft
diff --git a/tests/shell/testcases/transactions/dumps/0023rule_1.json-nft b/tests/shell/testcases/transactions/dumps/0023rule_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0023rule_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0023rule_1.nft b/tests/shell/testcases/transactions/dumps/0023rule_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0023rule_1.nft
diff --git a/tests/shell/testcases/transactions/dumps/0024rule_0.json-nft b/tests/shell/testcases/transactions/dumps/0024rule_0.json-nft
new file mode 100644
index 00000000..1e37f7d9
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0024rule_0.json-nft
@@ -0,0 +1,82 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "comment": "rule1",
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "comment": "rule2",
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "comment": "rule3",
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "comment": "rule4",
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0025rule_0.json-nft b/tests/shell/testcases/transactions/dumps/0025rule_0.json-nft
new file mode 100644
index 00000000..623d9765
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0025rule_0.json-nft
@@ -0,0 +1,52 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "y",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "log": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "y",
+ "handle": 0,
+ "expr": [
+ {
+ "drop": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0030set_0.json-nft b/tests/shell/testcases/transactions/dumps/0030set_0.json-nft
new file mode 100644
index 00000000..15ec0aac
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0030set_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0031set_0.json-nft b/tests/shell/testcases/transactions/dumps/0031set_0.json-nft
new file mode 100644
index 00000000..c1b7639d
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0031set_0.json-nft
@@ -0,0 +1,27 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0032set_0.json-nft b/tests/shell/testcases/transactions/dumps/0032set_0.json-nft
new file mode 100644
index 00000000..66bbf0eb
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0032set_0.json-nft
@@ -0,0 +1,27 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "w",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "w",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0033set_0.json-nft b/tests/shell/testcases/transactions/dumps/0033set_0.json-nft
new file mode 100644
index 00000000..15ec0aac
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0033set_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0034set_0.json-nft b/tests/shell/testcases/transactions/dumps/0034set_0.json-nft
new file mode 100644
index 00000000..c1b7639d
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0034set_0.json-nft
@@ -0,0 +1,27 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0035set_0.json-nft b/tests/shell/testcases/transactions/dumps/0035set_0.json-nft
new file mode 100644
index 00000000..6b8f671c
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0035set_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "elem": [
+ "3.3.3.3"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0036set_1.json-nft b/tests/shell/testcases/transactions/dumps/0036set_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0036set_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0036set_1.nft b/tests/shell/testcases/transactions/dumps/0036set_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0036set_1.nft
diff --git a/tests/shell/testcases/transactions/dumps/0037set_0.json-nft b/tests/shell/testcases/transactions/dumps/0037set_0.json-nft
new file mode 100644
index 00000000..e4c77147
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0037set_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0038set_0.json-nft b/tests/shell/testcases/transactions/dumps/0038set_0.json-nft
new file mode 100644
index 00000000..0a36f4a8
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0038set_0.json-nft
@@ -0,0 +1,38 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "192.168.4.0",
+ "len": 24
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0039set_0.json-nft b/tests/shell/testcases/transactions/dumps/0039set_0.json-nft
new file mode 100644
index 00000000..0a36f4a8
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0039set_0.json-nft
@@ -0,0 +1,38 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "y",
+ "table": "x",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "prefix": {
+ "addr": "192.168.4.0",
+ "len": 24
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0040set_0.json-nft b/tests/shell/testcases/transactions/dumps/0040set_0.json-nft
new file mode 100644
index 00000000..1718a5b9
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0040set_0.json-nft
@@ -0,0 +1,84 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "FORWARD",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "filter",
+ "name": "client_to_any",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "client_to_any",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "verdict"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "client_to_any"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "filter",
+ "chain": "client_to_any",
+ "handle": 0,
+ "expr": [
+ {
+ "vmap": {
+ "key": {
+ "payload": {
+ "protocol": "ip",
+ "field": "saddr"
+ }
+ },
+ "data": "@client_to_any"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0041nat_restore_0.json-nft b/tests/shell/testcases/transactions/dumps/0041nat_restore_0.json-nft
new file mode 100644
index 00000000..32fce943
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0041nat_restore_0.json-nft
@@ -0,0 +1,30 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "nat",
+ "hook": "postrouting",
+ "prio": 0,
+ "policy": "accept"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0041nat_restore_0.nft b/tests/shell/testcases/transactions/dumps/0041nat_restore_0.nft
new file mode 100644
index 00000000..b7180012
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0041nat_restore_0.nft
@@ -0,0 +1,5 @@
+table ip t {
+ chain c {
+ type nat hook postrouting priority filter; policy accept;
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0042_stateful_expr_0.json-nft b/tests/shell/testcases/transactions/dumps/0042_stateful_expr_0.json-nft
new file mode 100644
index 00000000..ea3b5d3c
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0042_stateful_expr_0.json-nft
@@ -0,0 +1,28 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "m1",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "counter"
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0042_stateful_expr_0.nft b/tests/shell/testcases/transactions/dumps/0042_stateful_expr_0.nft
new file mode 100644
index 00000000..e5cc63f2
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0042_stateful_expr_0.nft
@@ -0,0 +1,5 @@
+table ip filter {
+ map m1 {
+ type ipv4_addr : counter
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0043set_1.json-nft b/tests/shell/testcases/transactions/dumps/0043set_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0043set_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0043set_1.nft b/tests/shell/testcases/transactions/dumps/0043set_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0043set_1.nft
diff --git a/tests/shell/testcases/transactions/dumps/0044rule_0.json-nft b/tests/shell/testcases/transactions/dumps/0044rule_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0044rule_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0044rule_0.nft b/tests/shell/testcases/transactions/dumps/0044rule_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0044rule_0.nft
diff --git a/tests/shell/testcases/transactions/dumps/0045anon-unbind_0.json-nft b/tests/shell/testcases/transactions/dumps/0045anon-unbind_0.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0045anon-unbind_0.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0045anon-unbind_0.nft b/tests/shell/testcases/transactions/dumps/0045anon-unbind_0.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0045anon-unbind_0.nft
diff --git a/tests/shell/testcases/transactions/dumps/0046set_0.json-nft b/tests/shell/testcases/transactions/dumps/0046set_0.json-nft
new file mode 100644
index 00000000..f9b488e7
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0046set_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0046set_0.nft b/tests/shell/testcases/transactions/dumps/0046set_0.nft
new file mode 100644
index 00000000..eb39c44f
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0046set_0.nft
@@ -0,0 +1,2 @@
+table ip filter {
+}
diff --git a/tests/shell/testcases/transactions/dumps/0047set_0.json-nft b/tests/shell/testcases/transactions/dumps/0047set_0.json-nft
new file mode 100644
index 00000000..a7e677b2
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0047set_0.json-nft
@@ -0,0 +1,73 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ },
+ {
+ "map": {
+ "family": "ip",
+ "name": "group_10060",
+ "table": "filter",
+ "type": "ipv4_addr",
+ "handle": 0,
+ "map": "classid",
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ [
+ "10.1.26.2",
+ "1:bbf8"
+ ],
+ [
+ "10.1.26.3",
+ "1:c1ad"
+ ],
+ [
+ "10.1.26.4",
+ "1:b2d7"
+ ],
+ [
+ "10.1.26.5",
+ "1:f705"
+ ],
+ [
+ "10.1.26.6",
+ "1:b895"
+ ],
+ [
+ "10.1.26.7",
+ "1:ec4c"
+ ],
+ [
+ "10.1.26.8",
+ "1:de78"
+ ],
+ [
+ "10.1.26.9",
+ "1:b4f3"
+ ],
+ [
+ "10.1.26.10",
+ "1:dec6"
+ ],
+ [
+ "10.1.26.11",
+ "1:b4c0"
+ ]
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0047set_0.nft b/tests/shell/testcases/transactions/dumps/0047set_0.nft
new file mode 100644
index 00000000..4da397b2
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0047set_0.nft
@@ -0,0 +1,11 @@
+table ip filter {
+ map group_10060 {
+ type ipv4_addr : classid
+ flags interval
+ elements = { 10.1.26.2 : 1:bbf8, 10.1.26.3 : 1:c1ad,
+ 10.1.26.4 : 1:b2d7, 10.1.26.5 : 1:f705,
+ 10.1.26.6 : 1:b895, 10.1.26.7 : 1:ec4c,
+ 10.1.26.8 : 1:de78, 10.1.26.9 : 1:b4f3,
+ 10.1.26.10 : 1:dec6, 10.1.26.11 : 1:b4c0 }
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0048helpers_0.json-nft b/tests/shell/testcases/transactions/dumps/0048helpers_0.json-nft
new file mode 100644
index 00000000..f9b488e7
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0048helpers_0.json-nft
@@ -0,0 +1,18 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "filter",
+ "handle": 0
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0048helpers_0.nft b/tests/shell/testcases/transactions/dumps/0048helpers_0.nft
new file mode 100644
index 00000000..eb39c44f
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0048helpers_0.nft
@@ -0,0 +1,2 @@
+table ip filter {
+}
diff --git a/tests/shell/testcases/transactions/dumps/0049huge_0.json-nft b/tests/shell/testcases/transactions/dumps/0049huge_0.json-nft
new file mode 100644
index 00000000..456ada94
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0049huge_0.json-nft
@@ -0,0 +1,5121 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "inet",
+ "name": "firewalld",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PREROUTING",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -290,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PREROUTING_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PREROUTING",
+ "handle": 0,
+ "type": "filter",
+ "hook": "prerouting",
+ "prio": -140,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PREROUTING_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_INPUT",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FORWARD",
+ "handle": 0,
+ "type": "filter",
+ "hook": "forward",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_OUTPUT",
+ "handle": 0,
+ "type": "filter",
+ "hook": "output",
+ "prio": 10,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_INPUT_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FORWARD_IN_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FORWARD_OUT_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_public_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_public_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_public_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_public_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_public_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_public_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_public_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_public_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_public_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_public_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_trusted",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_trusted_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_trusted_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_trusted_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_trusted_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_trusted_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_trusted",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_trusted_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_trusted_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_trusted_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_trusted_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_trusted_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_trusted",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_trusted_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_trusted_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_trusted_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_trusted_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_trusted_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_trusted",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_trusted_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_trusted_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_trusted_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_trusted_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_trusted_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_trusted",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_trusted_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_trusted_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_trusted_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_trusted_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_trusted_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_work_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "raw_PRE_work_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_work_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_IN_work_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_work_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "mangle_PRE_work_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_work_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDI_work_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_work_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "inet",
+ "table": "firewalld",
+ "name": "filter_FWDO_work_post",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "icmpv6",
+ "field": "type"
+ }
+ },
+ "right": {
+ "set": [
+ "nd-router-advert",
+ "nd-neighbor-solicit"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "nfproto"
+ }
+ },
+ "right": "ipv6"
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "fib": {
+ "result": "oif",
+ "flags": [
+ "saddr",
+ "iif"
+ ]
+ }
+ },
+ "right": false
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PREROUTING_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "perm_dummy"
+ }
+ },
+ {
+ "goto": {
+ "target": "raw_PRE_work"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "perm_dummy2"
+ }
+ },
+ {
+ "goto": {
+ "target": "raw_PRE_trusted"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "raw_PRE_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PREROUTING_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "perm_dummy"
+ }
+ },
+ {
+ "goto": {
+ "target": "mangle_PRE_work"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "perm_dummy2"
+ }
+ },
+ {
+ "goto": {
+ "target": "mangle_PRE_trusted"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "mangle_PRE_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": {
+ "set": [
+ "established",
+ "related"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "right": "dnat"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_INPUT_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "invalid"
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "reject": {
+ "type": "icmpx",
+ "expr": "admin-prohibited"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": {
+ "set": [
+ "established",
+ "related"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "status"
+ }
+ },
+ "right": "dnat"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "set": [
+ {
+ "prefix": {
+ "addr": "::",
+ "len": 96
+ }
+ },
+ {
+ "prefix": {
+ "addr": "::ffff:0.0.0.0",
+ "len": 96
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002::",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002:a00::",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002:7f00::",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002:a9fe::",
+ "len": 32
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002:ac10::",
+ "len": 28
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002:c0a8::",
+ "len": 32
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002:e000::",
+ "len": 19
+ }
+ }
+ ]
+ }
+ }
+ },
+ {
+ "reject": {
+ "type": "icmpv6",
+ "expr": "addr-unreachable"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FORWARD_IN_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FORWARD_OUT_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "in",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": "invalid"
+ }
+ },
+ {
+ "drop": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD",
+ "handle": 0,
+ "expr": [
+ {
+ "reject": {
+ "type": "icmpx",
+ "expr": "admin-prohibited"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_OUTPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "lo"
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_OUTPUT",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "set": [
+ {
+ "prefix": {
+ "addr": "::",
+ "len": 96
+ }
+ },
+ {
+ "prefix": {
+ "addr": "::ffff:0.0.0.0",
+ "len": 96
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002::",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002:a00::",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002:7f00::",
+ "len": 24
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002:a9fe::",
+ "len": 32
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002:ac10::",
+ "len": 28
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002:c0a8::",
+ "len": 32
+ }
+ },
+ {
+ "prefix": {
+ "addr": "2002:e000::",
+ "len": 19
+ }
+ }
+ ]
+ }
+ }
+ },
+ {
+ "reject": {
+ "type": "icmpv6",
+ "expr": "addr-unreachable"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "perm_dummy"
+ }
+ },
+ {
+ "goto": {
+ "target": "filter_IN_work"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "perm_dummy2"
+ }
+ },
+ {
+ "goto": {
+ "target": "filter_IN_trusted"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_INPUT_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "filter_IN_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD_IN_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "perm_dummy"
+ }
+ },
+ {
+ "goto": {
+ "target": "filter_FWDI_work"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD_IN_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "perm_dummy2"
+ }
+ },
+ {
+ "goto": {
+ "target": "filter_FWDI_trusted"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD_IN_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "filter_FWDI_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD_OUT_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "perm_dummy"
+ }
+ },
+ {
+ "goto": {
+ "target": "filter_FWDO_work"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD_OUT_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "perm_dummy2"
+ }
+ },
+ {
+ "goto": {
+ "target": "filter_FWDO_trusted"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FORWARD_OUT_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "filter_FWDO_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_public_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_public_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_public_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_public_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": {
+ "set": [
+ "icmp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": {
+ "set": [
+ "new",
+ "untracked"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_public_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "prefix": {
+ "addr": "fe80::",
+ "len": 64
+ }
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 546
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": {
+ "set": [
+ "new",
+ "untracked"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_public_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_public_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_public",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": {
+ "set": [
+ "icmp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_public_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_public_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_public_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_public_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_trusted_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_trusted_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_trusted_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_trusted_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_trusted_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_trusted_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_trusted_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_trusted_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_trusted_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_trusted_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_trusted_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_trusted_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_trusted_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_trusted_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_trusted_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_trusted_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_trusted_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_trusted_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_trusted_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_trusted_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_trusted_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_trusted_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_trusted_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_trusted_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_trusted_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_work_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "raw_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "raw_PRE_work_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_work_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_IN_work_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": {
+ "set": [
+ "icmp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "tcp",
+ "field": "dport"
+ }
+ },
+ "right": 22
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": {
+ "set": [
+ "new",
+ "untracked"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_IN_work_allow",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip6",
+ "field": "daddr"
+ }
+ },
+ "right": {
+ "prefix": {
+ "addr": "fe80::",
+ "len": 64
+ }
+ }
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "udp",
+ "field": "dport"
+ }
+ },
+ "right": 546
+ }
+ },
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "ct": {
+ "key": "state"
+ }
+ },
+ "right": {
+ "set": [
+ "new",
+ "untracked"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_work_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "mangle_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "mangle_PRE_work_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_work_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDI_work_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDI_work",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "l4proto"
+ }
+ },
+ "right": {
+ "set": [
+ "icmp",
+ "ipv6-icmp"
+ ]
+ }
+ }
+ },
+ {
+ "accept": null
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_work_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "inet",
+ "table": "firewalld",
+ "chain": "filter_FWDO_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "filter_FWDO_work_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "firewalld",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PREROUTING",
+ "handle": 0,
+ "type": "nat",
+ "hook": "prerouting",
+ "prio": -90,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PREROUTING_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POSTROUTING",
+ "handle": 0,
+ "type": "nat",
+ "hook": "postrouting",
+ "prio": 110,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POSTROUTING_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_public_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_public_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_public_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_public_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_trusted",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_trusted_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_trusted_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_trusted_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_trusted_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_trusted_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_trusted",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_trusted_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_trusted_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_trusted_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_trusted_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_trusted_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_work_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_PRE_work_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_work_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "firewalld",
+ "name": "nat_POST_work_post",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PREROUTING_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "perm_dummy"
+ }
+ },
+ {
+ "goto": {
+ "target": "nat_PRE_work"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "perm_dummy2"
+ }
+ },
+ {
+ "goto": {
+ "target": "nat_PRE_trusted"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "nat_PRE_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POSTROUTING_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "perm_dummy"
+ }
+ },
+ {
+ "goto": {
+ "target": "nat_POST_work"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "perm_dummy2"
+ }
+ },
+ {
+ "goto": {
+ "target": "nat_POST_trusted"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "nat_POST_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_trusted_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_trusted_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_trusted_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_trusted_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_trusted_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_trusted_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_trusted_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_trusted_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_trusted_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_trusted_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "table": {
+ "family": "ip6",
+ "name": "firewalld",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PREROUTING",
+ "handle": 0,
+ "type": "nat",
+ "hook": "prerouting",
+ "prio": -90,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PREROUTING_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POSTROUTING",
+ "handle": 0,
+ "type": "nat",
+ "hook": "postrouting",
+ "prio": 110,
+ "policy": "accept"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POSTROUTING_ZONES",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_public_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_public_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_public",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_public_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_public_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_public_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_public_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_public_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_trusted",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_trusted_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_trusted_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_trusted_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_trusted_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_trusted_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_trusted",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_trusted_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_trusted_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_trusted_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_trusted_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_trusted_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_work_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_PRE_work_post",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_work",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_work_pre",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_work_log",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_work_deny",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_work_allow",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip6",
+ "table": "firewalld",
+ "name": "nat_POST_work_post",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PREROUTING_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "perm_dummy"
+ }
+ },
+ {
+ "goto": {
+ "target": "nat_PRE_work"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "iifname"
+ }
+ },
+ "right": "perm_dummy2"
+ }
+ },
+ {
+ "goto": {
+ "target": "nat_PRE_trusted"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PREROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "nat_PRE_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POSTROUTING_ZONES"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "perm_dummy"
+ }
+ },
+ {
+ "goto": {
+ "target": "nat_POST_work"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "meta": {
+ "key": "oifname"
+ }
+ },
+ "right": "perm_dummy2"
+ }
+ },
+ {
+ "goto": {
+ "target": "nat_POST_trusted"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POSTROUTING_ZONES",
+ "handle": 0,
+ "expr": [
+ {
+ "goto": {
+ "target": "nat_POST_public"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_public_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_public",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_public_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_trusted_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_trusted_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_trusted_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_trusted_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_trusted_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_trusted_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_trusted_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_trusted_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_trusted_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_trusted",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_trusted_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_PRE_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_PRE_work_post"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_pre"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_log"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_deny"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_allow"
+ }
+ }
+ ]
+ }
+ },
+ {
+ "rule": {
+ "family": "ip6",
+ "table": "firewalld",
+ "chain": "nat_POST_work",
+ "handle": 0,
+ "expr": [
+ {
+ "jump": {
+ "target": "nat_POST_work_post"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0049huge_0.nft b/tests/shell/testcases/transactions/dumps/0049huge_0.nft
new file mode 100644
index 00000000..96f5a387
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0049huge_0.nft
@@ -0,0 +1,749 @@
+table inet firewalld {
+ chain raw_PREROUTING {
+ type filter hook prerouting priority raw + 10; policy accept;
+ icmpv6 type { nd-router-advert, nd-neighbor-solicit } accept
+ meta nfproto ipv6 fib saddr . iif oif missing drop
+ jump raw_PREROUTING_ZONES
+ }
+
+ chain raw_PREROUTING_ZONES {
+ iifname "perm_dummy" goto raw_PRE_work
+ iifname "perm_dummy2" goto raw_PRE_trusted
+ goto raw_PRE_public
+ }
+
+ chain mangle_PREROUTING {
+ type filter hook prerouting priority mangle + 10; policy accept;
+ jump mangle_PREROUTING_ZONES
+ }
+
+ chain mangle_PREROUTING_ZONES {
+ iifname "perm_dummy" goto mangle_PRE_work
+ iifname "perm_dummy2" goto mangle_PRE_trusted
+ goto mangle_PRE_public
+ }
+
+ chain filter_INPUT {
+ type filter hook input priority filter + 10; policy accept;
+ ct state { established, related } accept
+ ct status dnat accept
+ iifname "lo" accept
+ jump filter_INPUT_ZONES
+ ct state invalid drop
+ reject with icmpx admin-prohibited
+ }
+
+ chain filter_FORWARD {
+ type filter hook forward priority filter + 10; policy accept;
+ ct state { established, related } accept
+ ct status dnat accept
+ iifname "lo" accept
+ ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 addr-unreachable
+ jump filter_FORWARD_IN_ZONES
+ jump filter_FORWARD_OUT_ZONES
+ ct state invalid drop
+ reject with icmpx admin-prohibited
+ }
+
+ chain filter_OUTPUT {
+ type filter hook output priority filter + 10; policy accept;
+ oifname "lo" accept
+ ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 addr-unreachable
+ }
+
+ chain filter_INPUT_ZONES {
+ iifname "perm_dummy" goto filter_IN_work
+ iifname "perm_dummy2" goto filter_IN_trusted
+ goto filter_IN_public
+ }
+
+ chain filter_FORWARD_IN_ZONES {
+ iifname "perm_dummy" goto filter_FWDI_work
+ iifname "perm_dummy2" goto filter_FWDI_trusted
+ goto filter_FWDI_public
+ }
+
+ chain filter_FORWARD_OUT_ZONES {
+ oifname "perm_dummy" goto filter_FWDO_work
+ oifname "perm_dummy2" goto filter_FWDO_trusted
+ goto filter_FWDO_public
+ }
+
+ chain raw_PRE_public {
+ jump raw_PRE_public_pre
+ jump raw_PRE_public_log
+ jump raw_PRE_public_deny
+ jump raw_PRE_public_allow
+ jump raw_PRE_public_post
+ }
+
+ chain raw_PRE_public_pre {
+ }
+
+ chain raw_PRE_public_log {
+ }
+
+ chain raw_PRE_public_deny {
+ }
+
+ chain raw_PRE_public_allow {
+ }
+
+ chain raw_PRE_public_post {
+ }
+
+ chain filter_IN_public {
+ jump filter_IN_public_pre
+ jump filter_IN_public_log
+ jump filter_IN_public_deny
+ jump filter_IN_public_allow
+ jump filter_IN_public_post
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_IN_public_pre {
+ }
+
+ chain filter_IN_public_log {
+ }
+
+ chain filter_IN_public_deny {
+ }
+
+ chain filter_IN_public_allow {
+ tcp dport 22 ct state { new, untracked } accept
+ ip6 daddr fe80::/64 udp dport 546 ct state { new, untracked } accept
+ }
+
+ chain filter_IN_public_post {
+ }
+
+ chain filter_FWDI_public {
+ jump filter_FWDI_public_pre
+ jump filter_FWDI_public_log
+ jump filter_FWDI_public_deny
+ jump filter_FWDI_public_allow
+ jump filter_FWDI_public_post
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_FWDI_public_pre {
+ }
+
+ chain filter_FWDI_public_log {
+ }
+
+ chain filter_FWDI_public_deny {
+ }
+
+ chain filter_FWDI_public_allow {
+ }
+
+ chain filter_FWDI_public_post {
+ }
+
+ chain mangle_PRE_public {
+ jump mangle_PRE_public_pre
+ jump mangle_PRE_public_log
+ jump mangle_PRE_public_deny
+ jump mangle_PRE_public_allow
+ jump mangle_PRE_public_post
+ }
+
+ chain mangle_PRE_public_pre {
+ }
+
+ chain mangle_PRE_public_log {
+ }
+
+ chain mangle_PRE_public_deny {
+ }
+
+ chain mangle_PRE_public_allow {
+ }
+
+ chain mangle_PRE_public_post {
+ }
+
+ chain filter_FWDO_public {
+ jump filter_FWDO_public_pre
+ jump filter_FWDO_public_log
+ jump filter_FWDO_public_deny
+ jump filter_FWDO_public_allow
+ jump filter_FWDO_public_post
+ }
+
+ chain filter_FWDO_public_pre {
+ }
+
+ chain filter_FWDO_public_log {
+ }
+
+ chain filter_FWDO_public_deny {
+ }
+
+ chain filter_FWDO_public_allow {
+ }
+
+ chain filter_FWDO_public_post {
+ }
+
+ chain raw_PRE_trusted {
+ jump raw_PRE_trusted_pre
+ jump raw_PRE_trusted_log
+ jump raw_PRE_trusted_deny
+ jump raw_PRE_trusted_allow
+ jump raw_PRE_trusted_post
+ }
+
+ chain raw_PRE_trusted_pre {
+ }
+
+ chain raw_PRE_trusted_log {
+ }
+
+ chain raw_PRE_trusted_deny {
+ }
+
+ chain raw_PRE_trusted_allow {
+ }
+
+ chain raw_PRE_trusted_post {
+ }
+
+ chain mangle_PRE_trusted {
+ jump mangle_PRE_trusted_pre
+ jump mangle_PRE_trusted_log
+ jump mangle_PRE_trusted_deny
+ jump mangle_PRE_trusted_allow
+ jump mangle_PRE_trusted_post
+ }
+
+ chain mangle_PRE_trusted_pre {
+ }
+
+ chain mangle_PRE_trusted_log {
+ }
+
+ chain mangle_PRE_trusted_deny {
+ }
+
+ chain mangle_PRE_trusted_allow {
+ }
+
+ chain mangle_PRE_trusted_post {
+ }
+
+ chain filter_IN_trusted {
+ jump filter_IN_trusted_pre
+ jump filter_IN_trusted_log
+ jump filter_IN_trusted_deny
+ jump filter_IN_trusted_allow
+ jump filter_IN_trusted_post
+ accept
+ }
+
+ chain filter_IN_trusted_pre {
+ }
+
+ chain filter_IN_trusted_log {
+ }
+
+ chain filter_IN_trusted_deny {
+ }
+
+ chain filter_IN_trusted_allow {
+ }
+
+ chain filter_IN_trusted_post {
+ }
+
+ chain filter_FWDI_trusted {
+ jump filter_FWDI_trusted_pre
+ jump filter_FWDI_trusted_log
+ jump filter_FWDI_trusted_deny
+ jump filter_FWDI_trusted_allow
+ jump filter_FWDI_trusted_post
+ accept
+ }
+
+ chain filter_FWDI_trusted_pre {
+ }
+
+ chain filter_FWDI_trusted_log {
+ }
+
+ chain filter_FWDI_trusted_deny {
+ }
+
+ chain filter_FWDI_trusted_allow {
+ }
+
+ chain filter_FWDI_trusted_post {
+ }
+
+ chain filter_FWDO_trusted {
+ jump filter_FWDO_trusted_pre
+ jump filter_FWDO_trusted_log
+ jump filter_FWDO_trusted_deny
+ jump filter_FWDO_trusted_allow
+ jump filter_FWDO_trusted_post
+ accept
+ }
+
+ chain filter_FWDO_trusted_pre {
+ }
+
+ chain filter_FWDO_trusted_log {
+ }
+
+ chain filter_FWDO_trusted_deny {
+ }
+
+ chain filter_FWDO_trusted_allow {
+ }
+
+ chain filter_FWDO_trusted_post {
+ }
+
+ chain raw_PRE_work {
+ jump raw_PRE_work_pre
+ jump raw_PRE_work_log
+ jump raw_PRE_work_deny
+ jump raw_PRE_work_allow
+ jump raw_PRE_work_post
+ }
+
+ chain raw_PRE_work_pre {
+ }
+
+ chain raw_PRE_work_log {
+ }
+
+ chain raw_PRE_work_deny {
+ }
+
+ chain raw_PRE_work_allow {
+ }
+
+ chain raw_PRE_work_post {
+ }
+
+ chain filter_IN_work {
+ jump filter_IN_work_pre
+ jump filter_IN_work_log
+ jump filter_IN_work_deny
+ jump filter_IN_work_allow
+ jump filter_IN_work_post
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_IN_work_pre {
+ }
+
+ chain filter_IN_work_log {
+ }
+
+ chain filter_IN_work_deny {
+ }
+
+ chain filter_IN_work_allow {
+ tcp dport 22 ct state { new, untracked } accept
+ ip6 daddr fe80::/64 udp dport 546 ct state { new, untracked } accept
+ }
+
+ chain filter_IN_work_post {
+ }
+
+ chain mangle_PRE_work {
+ jump mangle_PRE_work_pre
+ jump mangle_PRE_work_log
+ jump mangle_PRE_work_deny
+ jump mangle_PRE_work_allow
+ jump mangle_PRE_work_post
+ }
+
+ chain mangle_PRE_work_pre {
+ }
+
+ chain mangle_PRE_work_log {
+ }
+
+ chain mangle_PRE_work_deny {
+ }
+
+ chain mangle_PRE_work_allow {
+ }
+
+ chain mangle_PRE_work_post {
+ }
+
+ chain filter_FWDI_work {
+ jump filter_FWDI_work_pre
+ jump filter_FWDI_work_log
+ jump filter_FWDI_work_deny
+ jump filter_FWDI_work_allow
+ jump filter_FWDI_work_post
+ meta l4proto { icmp, ipv6-icmp } accept
+ }
+
+ chain filter_FWDI_work_pre {
+ }
+
+ chain filter_FWDI_work_log {
+ }
+
+ chain filter_FWDI_work_deny {
+ }
+
+ chain filter_FWDI_work_allow {
+ }
+
+ chain filter_FWDI_work_post {
+ }
+
+ chain filter_FWDO_work {
+ jump filter_FWDO_work_pre
+ jump filter_FWDO_work_log
+ jump filter_FWDO_work_deny
+ jump filter_FWDO_work_allow
+ jump filter_FWDO_work_post
+ }
+
+ chain filter_FWDO_work_pre {
+ }
+
+ chain filter_FWDO_work_log {
+ }
+
+ chain filter_FWDO_work_deny {
+ }
+
+ chain filter_FWDO_work_allow {
+ }
+
+ chain filter_FWDO_work_post {
+ }
+}
+table ip firewalld {
+ chain nat_PREROUTING {
+ type nat hook prerouting priority dstnat + 10; policy accept;
+ jump nat_PREROUTING_ZONES
+ }
+
+ chain nat_PREROUTING_ZONES {
+ iifname "perm_dummy" goto nat_PRE_work
+ iifname "perm_dummy2" goto nat_PRE_trusted
+ goto nat_PRE_public
+ }
+
+ chain nat_POSTROUTING {
+ type nat hook postrouting priority srcnat + 10; policy accept;
+ jump nat_POSTROUTING_ZONES
+ }
+
+ chain nat_POSTROUTING_ZONES {
+ oifname "perm_dummy" goto nat_POST_work
+ oifname "perm_dummy2" goto nat_POST_trusted
+ goto nat_POST_public
+ }
+
+ chain nat_PRE_public {
+ jump nat_PRE_public_pre
+ jump nat_PRE_public_log
+ jump nat_PRE_public_deny
+ jump nat_PRE_public_allow
+ jump nat_PRE_public_post
+ }
+
+ chain nat_PRE_public_pre {
+ }
+
+ chain nat_PRE_public_log {
+ }
+
+ chain nat_PRE_public_deny {
+ }
+
+ chain nat_PRE_public_allow {
+ }
+
+ chain nat_PRE_public_post {
+ }
+
+ chain nat_POST_public {
+ jump nat_POST_public_pre
+ jump nat_POST_public_log
+ jump nat_POST_public_deny
+ jump nat_POST_public_allow
+ jump nat_POST_public_post
+ }
+
+ chain nat_POST_public_pre {
+ }
+
+ chain nat_POST_public_log {
+ }
+
+ chain nat_POST_public_deny {
+ }
+
+ chain nat_POST_public_allow {
+ }
+
+ chain nat_POST_public_post {
+ }
+
+ chain nat_PRE_trusted {
+ jump nat_PRE_trusted_pre
+ jump nat_PRE_trusted_log
+ jump nat_PRE_trusted_deny
+ jump nat_PRE_trusted_allow
+ jump nat_PRE_trusted_post
+ }
+
+ chain nat_PRE_trusted_pre {
+ }
+
+ chain nat_PRE_trusted_log {
+ }
+
+ chain nat_PRE_trusted_deny {
+ }
+
+ chain nat_PRE_trusted_allow {
+ }
+
+ chain nat_PRE_trusted_post {
+ }
+
+ chain nat_POST_trusted {
+ jump nat_POST_trusted_pre
+ jump nat_POST_trusted_log
+ jump nat_POST_trusted_deny
+ jump nat_POST_trusted_allow
+ jump nat_POST_trusted_post
+ }
+
+ chain nat_POST_trusted_pre {
+ }
+
+ chain nat_POST_trusted_log {
+ }
+
+ chain nat_POST_trusted_deny {
+ }
+
+ chain nat_POST_trusted_allow {
+ }
+
+ chain nat_POST_trusted_post {
+ }
+
+ chain nat_PRE_work {
+ jump nat_PRE_work_pre
+ jump nat_PRE_work_log
+ jump nat_PRE_work_deny
+ jump nat_PRE_work_allow
+ jump nat_PRE_work_post
+ }
+
+ chain nat_PRE_work_pre {
+ }
+
+ chain nat_PRE_work_log {
+ }
+
+ chain nat_PRE_work_deny {
+ }
+
+ chain nat_PRE_work_allow {
+ }
+
+ chain nat_PRE_work_post {
+ }
+
+ chain nat_POST_work {
+ jump nat_POST_work_pre
+ jump nat_POST_work_log
+ jump nat_POST_work_deny
+ jump nat_POST_work_allow
+ jump nat_POST_work_post
+ }
+
+ chain nat_POST_work_pre {
+ }
+
+ chain nat_POST_work_log {
+ }
+
+ chain nat_POST_work_deny {
+ }
+
+ chain nat_POST_work_allow {
+ }
+
+ chain nat_POST_work_post {
+ }
+}
+table ip6 firewalld {
+ chain nat_PREROUTING {
+ type nat hook prerouting priority dstnat + 10; policy accept;
+ jump nat_PREROUTING_ZONES
+ }
+
+ chain nat_PREROUTING_ZONES {
+ iifname "perm_dummy" goto nat_PRE_work
+ iifname "perm_dummy2" goto nat_PRE_trusted
+ goto nat_PRE_public
+ }
+
+ chain nat_POSTROUTING {
+ type nat hook postrouting priority srcnat + 10; policy accept;
+ jump nat_POSTROUTING_ZONES
+ }
+
+ chain nat_POSTROUTING_ZONES {
+ oifname "perm_dummy" goto nat_POST_work
+ oifname "perm_dummy2" goto nat_POST_trusted
+ goto nat_POST_public
+ }
+
+ chain nat_PRE_public {
+ jump nat_PRE_public_pre
+ jump nat_PRE_public_log
+ jump nat_PRE_public_deny
+ jump nat_PRE_public_allow
+ jump nat_PRE_public_post
+ }
+
+ chain nat_PRE_public_pre {
+ }
+
+ chain nat_PRE_public_log {
+ }
+
+ chain nat_PRE_public_deny {
+ }
+
+ chain nat_PRE_public_allow {
+ }
+
+ chain nat_PRE_public_post {
+ }
+
+ chain nat_POST_public {
+ jump nat_POST_public_pre
+ jump nat_POST_public_log
+ jump nat_POST_public_deny
+ jump nat_POST_public_allow
+ jump nat_POST_public_post
+ }
+
+ chain nat_POST_public_pre {
+ }
+
+ chain nat_POST_public_log {
+ }
+
+ chain nat_POST_public_deny {
+ }
+
+ chain nat_POST_public_allow {
+ }
+
+ chain nat_POST_public_post {
+ }
+
+ chain nat_PRE_trusted {
+ jump nat_PRE_trusted_pre
+ jump nat_PRE_trusted_log
+ jump nat_PRE_trusted_deny
+ jump nat_PRE_trusted_allow
+ jump nat_PRE_trusted_post
+ }
+
+ chain nat_PRE_trusted_pre {
+ }
+
+ chain nat_PRE_trusted_log {
+ }
+
+ chain nat_PRE_trusted_deny {
+ }
+
+ chain nat_PRE_trusted_allow {
+ }
+
+ chain nat_PRE_trusted_post {
+ }
+
+ chain nat_POST_trusted {
+ jump nat_POST_trusted_pre
+ jump nat_POST_trusted_log
+ jump nat_POST_trusted_deny
+ jump nat_POST_trusted_allow
+ jump nat_POST_trusted_post
+ }
+
+ chain nat_POST_trusted_pre {
+ }
+
+ chain nat_POST_trusted_log {
+ }
+
+ chain nat_POST_trusted_deny {
+ }
+
+ chain nat_POST_trusted_allow {
+ }
+
+ chain nat_POST_trusted_post {
+ }
+
+ chain nat_PRE_work {
+ jump nat_PRE_work_pre
+ jump nat_PRE_work_log
+ jump nat_PRE_work_deny
+ jump nat_PRE_work_allow
+ jump nat_PRE_work_post
+ }
+
+ chain nat_PRE_work_pre {
+ }
+
+ chain nat_PRE_work_log {
+ }
+
+ chain nat_PRE_work_deny {
+ }
+
+ chain nat_PRE_work_allow {
+ }
+
+ chain nat_PRE_work_post {
+ }
+
+ chain nat_POST_work {
+ jump nat_POST_work_pre
+ jump nat_POST_work_log
+ jump nat_POST_work_deny
+ jump nat_POST_work_allow
+ jump nat_POST_work_post
+ }
+
+ chain nat_POST_work_pre {
+ }
+
+ chain nat_POST_work_log {
+ }
+
+ chain nat_POST_work_deny {
+ }
+
+ chain nat_POST_work_allow {
+ }
+
+ chain nat_POST_work_post {
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/0050rule_1.json-nft b/tests/shell/testcases/transactions/dumps/0050rule_1.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0050rule_1.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/0050rule_1.nft b/tests/shell/testcases/transactions/dumps/0050rule_1.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0050rule_1.nft
diff --git a/tests/shell/testcases/transactions/dumps/0051map_0.nodump b/tests/shell/testcases/transactions/dumps/0051map_0.nodump
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/0051map_0.nodump
diff --git a/tests/shell/testcases/transactions/dumps/30s-stress.json-nft b/tests/shell/testcases/transactions/dumps/30s-stress.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/30s-stress.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/30s-stress.nft b/tests/shell/testcases/transactions/dumps/30s-stress.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/30s-stress.nft
diff --git a/tests/shell/testcases/transactions/dumps/anon_chain_loop.json-nft b/tests/shell/testcases/transactions/dumps/anon_chain_loop.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/anon_chain_loop.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/anon_chain_loop.nft b/tests/shell/testcases/transactions/dumps/anon_chain_loop.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/anon_chain_loop.nft
diff --git a/tests/shell/testcases/transactions/dumps/bad_expression.json-nft b/tests/shell/testcases/transactions/dumps/bad_expression.json-nft
new file mode 100644
index 00000000..546cc597
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/bad_expression.json-nft
@@ -0,0 +1,11 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/bad_expression.nft b/tests/shell/testcases/transactions/dumps/bad_expression.nft
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/bad_expression.nft
diff --git a/tests/shell/testcases/transactions/dumps/concat_range_abort.json-nft b/tests/shell/testcases/transactions/dumps/concat_range_abort.json-nft
new file mode 100644
index 00000000..8db71894
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/concat_range_abort.json-nft
@@ -0,0 +1,47 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "x",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "foo",
+ "handle": 0
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "x",
+ "name": "bar",
+ "handle": 0
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "x",
+ "chain": "foo",
+ "handle": 0,
+ "expr": [
+ {
+ "accept": null
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/concat_range_abort.nft b/tests/shell/testcases/transactions/dumps/concat_range_abort.nft
new file mode 100644
index 00000000..06adca7a
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/concat_range_abort.nft
@@ -0,0 +1,8 @@
+table ip x {
+ chain foo {
+ accept
+ }
+
+ chain bar {
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/doubled-set.json-nft b/tests/shell/testcases/transactions/dumps/doubled-set.json-nft
new file mode 100644
index 00000000..2dced124
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/doubled-set.json-nft
@@ -0,0 +1,41 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0
+ }
+ },
+ {
+ "set": {
+ "family": "ip",
+ "name": "s",
+ "table": "t",
+ "type": [
+ "ipv4_addr",
+ "ifname"
+ ],
+ "handle": 0,
+ "flags": [
+ "interval"
+ ],
+ "elem": [
+ {
+ "concat": [
+ "1.2.3.4",
+ "foo"
+ ]
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/doubled-set.nft b/tests/shell/testcases/transactions/dumps/doubled-set.nft
new file mode 100644
index 00000000..48a322eb
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/doubled-set.nft
@@ -0,0 +1,7 @@
+table ip t {
+ set s {
+ type ipv4_addr . ifname
+ flags interval
+ elements = { 1.2.3.4 . "foo" }
+ }
+}
diff --git a/tests/shell/testcases/transactions/dumps/table_onoff.json-nft b/tests/shell/testcases/transactions/dumps/table_onoff.json-nft
new file mode 100644
index 00000000..a7583e8c
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/table_onoff.json-nft
@@ -0,0 +1,59 @@
+{
+ "nftables": [
+ {
+ "metainfo": {
+ "version": "VERSION",
+ "release_name": "RELEASE_NAME",
+ "json_schema_version": 1
+ }
+ },
+ {
+ "table": {
+ "family": "ip",
+ "name": "t",
+ "handle": 0,
+ "flags": "dormant"
+ }
+ },
+ {
+ "chain": {
+ "family": "ip",
+ "table": "t",
+ "name": "c",
+ "handle": 0,
+ "type": "filter",
+ "hook": "input",
+ "prio": 0,
+ "policy": "accept"
+ }
+ },
+ {
+ "rule": {
+ "family": "ip",
+ "table": "t",
+ "chain": "c",
+ "handle": 0,
+ "expr": [
+ {
+ "match": {
+ "op": "==",
+ "left": {
+ "payload": {
+ "protocol": "ip",
+ "field": "daddr"
+ }
+ },
+ "right": "127.0.0.42"
+ }
+ },
+ {
+ "counter": {
+ "packets": 0,
+ "bytes": 0
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
diff --git a/tests/shell/testcases/transactions/dumps/table_onoff.nft b/tests/shell/testcases/transactions/dumps/table_onoff.nft
new file mode 100644
index 00000000..038be1c0
--- /dev/null
+++ b/tests/shell/testcases/transactions/dumps/table_onoff.nft
@@ -0,0 +1,8 @@
+table ip t {
+ flags dormant
+
+ chain c {
+ type filter hook input priority filter; policy accept;
+ ip daddr 127.0.0.42 counter packets 0 bytes 0
+ }
+}
diff --git a/tests/shell/testcases/transactions/table_onoff b/tests/shell/testcases/transactions/table_onoff
new file mode 100755
index 00000000..831d4614
--- /dev/null
+++ b/tests/shell/testcases/transactions/table_onoff
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# attempt to re-awaken a table that is flagged dormant within
+# same transaction
+$NFT -f - <<EOF
+add table ip t
+add table ip t { flags dormant; }
+add chain ip t c { type filter hook input priority 0; }
+add table ip t
+delete table ip t
+EOF
+
+if [ $? -eq 0 ]; then
+ exit 1
+fi
+
+set -e
+
+ip link set lo up
+
+# add a dormant table, then wake it up in same
+# transaction.
+$NFT -f - <<EOF
+add table ip t { flags dormant; }
+add chain ip t c { type filter hook input priority 0; }
+add rule ip t c ip daddr 127.0.0.42 counter
+add table ip t
+EOF
+
+# check table is indeed active.
+ping -c 1 127.0.0.42
+$NFT list chain ip t c | grep "counter packets 1"
+$NFT delete table ip t
+
+# allow to flag table dormant.
+$NFT -f - <<EOF
+add table ip t
+add chain ip t c { type filter hook input priority 0; }
+add rule ip t c ip daddr 127.0.0.42 counter
+add table ip t { flags dormant; }
+EOF
+
+ping -c 1 127.0.0.42
+# expect run-tests.sh to complain if counter isn't 0.
diff --git a/tools/check-tree.sh b/tools/check-tree.sh
new file mode 100755
index 00000000..e358c957
--- /dev/null
+++ b/tools/check-tree.sh
@@ -0,0 +1,134 @@
+#!/bin/bash -e
+
+# Preform various consistency checks of the source tree.
+
+unset LANGUAGE
+export LANG=C
+export LC_ALL=C
+
+die() {
+ printf '%s\n' "$*"
+ exit 1
+}
+
+array_contains() {
+ local needle="$1"
+ local a
+ shift
+ for a; do
+ [ "$a" = "$needle" ] && return 0
+ done
+ return 1
+}
+
+cd "$(dirname "$0")/.."
+
+EXIT_CODE=0
+
+msg_err() {
+ printf "ERR: %s\n" "$*"
+ EXIT_CODE=1
+}
+
+msg_warn() {
+ printf "WARN: %s\n" "$*"
+}
+
+##############################################################################
+
+check_shell_dumps() {
+ local TEST="$1"
+ local base="$(basename "$TEST")"
+ local dir="$(dirname "$TEST")"
+ local has_nft=0
+ local has_jnft=0
+ local has_nodump=0
+ local nft_name
+ local nodump_name
+
+ if [ ! -d "$dir/dumps/" ] ; then
+ msg_err "\"$TEST\" has no \"$dir/dumps/\" directory"
+ return 0
+ fi
+
+ nft_name="$dir/dumps/$base.nft"
+ jnft_name="$dir/dumps/$base.json-nft"
+ nodump_name="$dir/dumps/$base.nodump"
+
+ [ -f "$nft_name" ] && has_nft=1
+ [ -f "$jnft_name" ] && has_jnft=1
+ [ -f "$nodump_name" ] && has_nodump=1
+
+ if [ "$has_nft" != 1 -a "$has_nodump" != 1 ] ; then
+ msg_err "\"$TEST\" has no \"$dir/dumps/$base.{nft,nodump}\" file"
+ elif [ "$has_nft" == 1 -a "$has_nodump" == 1 ] ; then
+ msg_err "\"$TEST\" has both \"$dir/dumps/$base.{nft,nodump}\" files"
+ elif [ "$has_nodump" == 1 -a -s "$nodump_name" ] ; then
+ msg_err "\"$TEST\" has a non-empty \"$dir/dumps/$base.nodump\" file"
+ fi
+ if [ "$has_jnft" = 1 -a "$has_nft" != 1 ] ; then
+ msg_err "\"$TEST\" has a JSON dump file \"$jnft_name\" but lacks a dump \"$nft_name\""
+ fi
+ if [ "$has_nft" = 1 -a "$has_jnft" != 1 ] ; then
+ # it's currently known that `nft -j --check` cannot parse all dumped rulesets.
+ # Accept having no JSON dump file.
+ #
+ # This should be fixed. Currently this is only a warning.
+ msg_warn "\"$TEST\" has a dump file \"$nft_name\" but lacks a JSON dump \"$jnft_name\""
+ fi
+
+ if [ "$has_jnft" = 1 ] && command -v jq &>/dev/null ; then
+ if ! jq empty < "$jnft_name" &>/dev/null ; then
+ msg_err "\"$TEST\" has a JSON dump file \"$jnft_name\" that does not validate with \`jq empty < \"$jnft_name\"\`"
+ fi
+ fi
+}
+
+SHELL_TESTS=( $(find "tests/shell/testcases/" -type f -executable | sort) )
+
+if [ "${#SHELL_TESTS[@]}" -eq 0 ] ; then
+ msg_err "No executable tests under \"tests/shell/testcases/\" found"
+fi
+for t in "${SHELL_TESTS[@]}" ; do
+ check_shell_dumps "$t"
+ if ! ( head -n 1 "$t" | grep -q '^#!/bin/bash\( -e\)\?$' ) ; then
+ # Currently all tests only use bash as shebang. That also
+ # works with `./tests/shell/run-tests.sh -x`.
+ #
+ # We could allow other shebangs, but for now there is no need.
+ # Unless you have a good reason, create a bash script.
+ msg_err "$t should use either \"#!/bin/bash\" or \"#!/bin/bash -e\" as shebang"
+ fi
+done
+
+##############################################################################
+
+SHELL_TESTS2=( $(./tests/shell/run-tests.sh --list-tests) )
+if [ "${SHELL_TESTS[*]}" != "${SHELL_TESTS2[*]}" ] ; then
+ msg_err "\`./tests/shell/run-tests.sh --list-tests\` does not list the expected tests"
+fi
+
+##############################################################################
+#
+F=( $(find tests/shell/testcases/ -type f | grep '^tests/shell/testcases/[^/]\+/dumps/[^/]\+\.\(json-nft\|nft\|nodump\)$' -v | sort) )
+IGNORED_FILES=( tests/shell/testcases/bogons/nft-f/* )
+for f in "${F[@]}" ; do
+ if ! array_contains "$f" "${SHELL_TESTS[@]}" "${IGNORED_FILES[@]}" ; then
+ msg_err "Unexpected file \"$f\""
+ fi
+done
+
+##############################################################################
+
+FILES=( $(find "tests/shell/testcases/" -type f | sed -n 's#\(tests/shell/testcases\(/.*\)\?/\)dumps/\(.*\)\.\(nft\|nodump\)$#\0#p' | sort) )
+
+for f in "${FILES[@]}" ; do
+ f2="$(echo "$f" | sed -n 's#\(tests/shell/testcases\(/.*\)\?/\)dumps/\(.*\)\.\(nft\|nodump\)$#\1\3#p')"
+ if ! array_contains "$f2" "${SHELL_TESTS[@]}" ; then
+ msg_err "\"$f\" has no test \"$f2\""
+ fi
+done
+
+##############################################################################
+
+exit "$EXIT_CODE"