summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--COPYING8
-rw-r--r--INSTALL55
-rw-r--r--Make_global.am21
-rw-r--r--Makefile.am415
-rw-r--r--configure.ac56
-rw-r--r--doc/Makefile.am30
-rw-r--r--doc/data-types.txt4
-rw-r--r--doc/libnftables-json.adoc46
-rw-r--r--doc/libnftables.adoc49
-rw-r--r--doc/nft.txt87
-rw-r--r--doc/payload-expression.txt194
-rw-r--r--doc/primary-expression.txt20
-rw-r--r--doc/stateful-objects.txt2
-rw-r--r--doc/statements.txt115
-rw-r--r--examples/Makefile.am6
-rw-r--r--files/Makefile.am3
-rw-r--r--files/examples/Makefile.am5
-rw-r--r--files/nftables/Makefile.am14
-rw-r--r--files/osf/Makefile.am2
-rw-r--r--include/Makefile.am41
-rw-r--r--include/cache.h23
-rw-r--r--include/cli.h3
-rw-r--r--include/cmd.h6
-rw-r--r--include/ct.h2
-rw-r--r--include/datatype.h15
-rw-r--r--include/dccpopt.h41
-rw-r--r--include/expression.h23
-rw-r--r--include/exthdr.h1
-rw-r--r--include/gmputil.h4
-rw-r--r--include/headers.h2
-rw-r--r--include/intervals.h1
-rw-r--r--include/json.h6
-rw-r--r--include/linux/Makefile.am12
-rw-r--r--include/linux/netfilter/Makefile.am10
-rw-r--r--include/linux/netfilter/nf_tables.h77
-rw-r--r--include/linux/netfilter/nfnetlink_hook.h24
-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/meta.h2
-rw-r--r--include/mnl.h19
-rw-r--r--include/netlink.h31
-rw-r--r--include/nft.h18
-rw-r--r--include/nftables.h20
-rw-r--r--include/nftables/Makefile.am1
-rw-r--r--include/nftables/libnftables.h9
-rw-r--r--include/parser.h9
-rw-r--r--include/payload.h4
-rw-r--r--include/proto.h65
-rw-r--r--include/rule.h48
-rw-r--r--include/statement.h22
-rw-r--r--include/utils.h42
-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)204
-rw-r--r--py/src/schema.json (renamed from py/schema.json)0
-rw-r--r--src/Makefile.am119
-rw-r--r--src/cache.c222
-rw-r--r--src/cli.c68
-rw-r--r--src/cmd.c261
-rw-r--r--src/ct.c21
-rw-r--r--src/datatype.c382
-rw-r--r--src/dccpopt.c277
-rw-r--r--src/erec.c14
-rw-r--r--src/evaluate.c1512
-rw-r--r--src/expression.c73
-rw-r--r--src/exthdr.c20
-rw-r--r--src/fib.c7
-rw-r--r--src/gmputil.c27
-rw-r--r--src/hash.c6
-rw-r--r--src/iface.c8
-rw-r--r--src/intervals.c94
-rw-r--r--src/ipopt.c3
-rw-r--r--src/json.c268
-rw-r--r--src/libnftables.c166
-rw-r--r--src/libnftables.map5
-rw-r--r--src/main.c82
-rw-r--r--src/mergesort.c40
-rw-r--r--src/meta.c180
-rw-r--r--src/mini-gmp.c4
-rw-r--r--src/misspell.c14
-rw-r--r--src/mnl.c469
-rw-r--r--src/monitor.c37
-rw-r--r--src/netlink.c323
-rw-r--r--src/netlink_delinearize.c655
-rw-r--r--src/netlink_linearize.c132
-rw-r--r--src/nfnl_osf.c4
-rw-r--r--src/nftutils.c100
-rw-r--r--src/nftutils.h20
-rw-r--r--src/numgen.c6
-rw-r--r--src/optimize.c607
-rw-r--r--src/osf.c11
-rw-r--r--src/owner.c13
-rw-r--r--src/parser_bison.y946
-rw-r--r--src/parser_json.c568
-rw-r--r--src/payload.c337
-rw-r--r--src/print.c7
-rw-r--r--src/proto.c170
-rw-r--r--src/rt.c15
-rw-r--r--src/rule.c397
-rw-r--r--src/scanner.l164
-rw-r--r--src/sctp_chunk.c3
-rw-r--r--src/segtree.c106
-rw-r--r--src/socket.c6
-rw-r--r--src/statement.c50
-rw-r--r--src/tcpopt.c51
-rw-r--r--src/utils.c14
-rw-r--r--src/xfrm.c9
-rw-r--r--src/xt.c246
-rwxr-xr-xtests/build/run-tests.sh34
-rwxr-xr-xtests/monitor/run-tests.sh9
-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.t2
-rw-r--r--tests/monitor/testcases/simple.t4
-rw-r--r--tests/py/README31
-rw-r--r--tests/py/any/last.t13
-rw-r--r--tests/py/any/last.t.json16
-rw-r--r--tests/py/any/last.t.json.output14
-rw-r--r--tests/py/any/last.t.payload8
-rw-r--r--tests/py/any/limit.t24
-rw-r--r--tests/py/any/limit.t.json57
-rw-r--r--tests/py/any/limit.t.json.output48
-rw-r--r--tests/py/any/limit.t.payload43
-rw-r--r--tests/py/any/meta.t6
-rw-r--r--tests/py/any/meta.t.json78
-rw-r--r--tests/py/any/meta.t.payload25
-rw-r--r--tests/py/any/meta.t.payload.bridge20
-rw-r--r--tests/py/any/queue.t1
-rw-r--r--tests/py/any/rawpayload.t2
-rw-r--r--tests/py/any/rawpayload.t.json31
-rw-r--r--tests/py/any/rawpayload.t.payload8
-rw-r--r--tests/py/bridge/meta.t2
-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/vlan.t7
-rw-r--r--tests/py/bridge/vlan.t.json131
-rw-r--r--tests/py/bridge/vlan.t.json.output31
-rw-r--r--tests/py/bridge/vlan.t.payload36
-rw-r--r--tests/py/bridge/vlan.t.payload.netdev44
-rw-r--r--tests/py/inet/dccp.t5
-rw-r--r--tests/py/inet/dccp.t.json44
-rw-r--r--tests/py/inet/dccp.t.payload14
-rw-r--r--tests/py/inet/ether.t6
-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.bridge16
-rw-r--r--tests/py/inet/ether.t.payload.ip20
-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/ipsec.t2
-rw-r--r--tests/py/inet/ipsec.t.json21
-rw-r--r--tests/py/inet/ipsec.t.payload6
-rw-r--r--tests/py/inet/meta.t10
-rw-r--r--tests/py/inet/meta.t.json278
-rw-r--r--tests/py/inet/meta.t.json.output41
-rw-r--r--tests/py/inet/meta.t.payload90
-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/tcp.t16
-rw-r--r--tests/py/inet/tcp.t.json42
-rw-r--r--tests/py/inet/tcp.t.json.output279
-rw-r--r--tests/py/inet/tcp.t.payload6
-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.payload12
-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.t6
-rw-r--r--tests/py/ip/ct.t.json154
-rw-r--r--tests/py/ip/ct.t.payload50
-rw-r--r--tests/py/ip/dnat.t2
-rw-r--r--tests/py/ip/dnat.t.json146
-rw-r--r--tests/py/ip/dnat.t.payload.ip22
-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/ip.t20
-rw-r--r--tests/py/ip/ip.t.json157
-rw-r--r--tests/py/ip/ip.t.json.output31
-rw-r--r--tests/py/ip/ip.t.payload53
-rw-r--r--tests/py/ip/ip.t.payload.bridge64
-rw-r--r--tests/py/ip/ip.t.payload.inet64
-rw-r--r--tests/py/ip/ip.t.payload.netdev64
-rw-r--r--tests/py/ip/meta.t5
-rw-r--r--tests/py/ip/meta.t.json78
-rw-r--r--tests/py/ip/meta.t.payload25
-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.json.output30
-rw-r--r--tests/py/ip/numgen.t.payload11
-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.payload4
-rw-r--r--tests/py/ip/sets.t3
-rw-r--r--tests/py/ip/sets.t.json31
-rw-r--r--tests/py/ip/sets.t.payload.inet9
-rw-r--r--tests/py/ip/sets.t.payload.ip8
-rw-r--r--tests/py/ip/sets.t.payload.netdev10
-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/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.t.payload.netdev2026
-rw-r--r--tests/py/ip6/icmpv6.t12
-rw-r--r--tests/py/ip6/icmpv6.t.json260
-rw-r--r--tests/py/ip6/icmpv6.t.payload.ip680
-rw-r--r--tests/py/ip6/ip6.t9
-rw-r--r--tests/py/ip6/ip6.t.json100
-rw-r--r--tests/py/ip6/ip6.t.payload.inet44
-rw-r--r--tests/py/ip6/ip6.t.payload.ip636
-rw-r--r--tests/py/ip6/meta.t3
-rw-r--r--tests/py/ip6/meta.t.json117
-rw-r--r--tests/py/ip6/meta.t.payload20
-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.ip64
-rw-r--r--tests/py/ip6/sets.t4
-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/srh.t.payload6
-rwxr-xr-xtests/py/nft-test.py81
-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/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.sh1009
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_0 (renamed from tests/shell/testcases/chains/0040mark_shift_0)4
-rwxr-xr-xtests/shell/testcases/bitwise/0040mark_binop_1 (renamed from tests/shell/testcases/chains/0040mark_shift_1)4
-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.nft (renamed from tests/shell/testcases/chains/dumps/0040mark_shift_0.nft)2
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_1.json-nft86
-rw-r--r--tests/shell/testcases/bitwise/dumps/0040mark_binop_1.nft (renamed from tests/shell/testcases/chains/dumps/0040mark_shift_1.nft)2
-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/0008_delete_by_handle_02
-rwxr-xr-xtests/shell/testcases/cache/0010_implicit_chain_02
-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/0014rename_02
-rwxr-xr-xtests/shell/testcases/chains/0021prio_07
-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/0041chain_binding_05
-rwxr-xr-xtests/shell/testcases/chains/0042chain_variable_042
-rwxr-xr-xtests/shell/testcases/chains/0043chain_ingress_09
-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/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/0032priority_variable_0.json-nft54
-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/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/0042chain_variable_0.json-nft90
-rw-r--r--tests/shell/testcases/chains/dumps/0042chain_variable_0.nft8
-rw-r--r--tests/shell/testcases/chains/dumps/0043chain_ingress_0.json-nft55
-rw-r--r--tests/shell/testcases/chains/dumps/0043chain_ingress_0.nft (renamed from tests/shell/testcases/chains/dumps/0043chain_ingress.nft)4
-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_gone32
-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_gone35
-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/0012flowtable_variable_08
-rwxr-xr-xtests/shell/testcases/flowtable/0013addafterdelete_02
-rwxr-xr-xtests/shell/testcases/flowtable/0014addafterdelete_02
-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.nft4
-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/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/0013objects_050
-rwxr-xr-xtests/shell/testcases/listing/0020flowtable_014
-rwxr-xr-xtests/shell/testcases/listing/0021ruleset_json_terse_013
-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.nft32
-rwxr-xr-xtests/shell/testcases/listing/meta_time59
-rwxr-xr-xtests/shell/testcases/maps/0004interval_map_create_once_08
-rwxr-xr-xtests/shell/testcases/maps/0009vmap_04
-rwxr-xr-xtests/shell/testcases/maps/0010concat_map_02
-rwxr-xr-xtests/shell/testcases/maps/0011vmap_010
-rwxr-xr-xtests/shell/testcases/maps/0012map_concat_024
-rwxr-xr-xtests/shell/testcases/maps/0013map_02
-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)15
-rwxr-xr-xtests/shell/testcases/maps/anon_objmap_concat2
-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.nft2
-rw-r--r--tests/shell/testcases/maps/dumps/0010concat_map_0.json-nft106
-rw-r--r--tests/shell/testcases/maps/dumps/0011vmap_0.json-nft145
-rw-r--r--tests/shell/testcases/maps/dumps/0012map_0.json-nft97
-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/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)18
-rw-r--r--tests/shell/testcases/maps/dumps/anon_objmap_concat.json-nft116
-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/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.nft4
-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_raw_0.nft4
-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_limits59
-rwxr-xr-xtests/shell/testcases/maps/pipapo_double_flush25
-rwxr-xr-xtests/shell/testcases/maps/typeof_integer_06
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_066
-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_raw_04
-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_unary17
-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/0017ct_timeout_obj_02
-rwxr-xr-xtests/shell/testcases/nft-f/0018ct_expectation_obj_02
-rwxr-xr-xtests/shell/testcases/nft-f/0025empty_dynset_08
-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-nft782
-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/0022variables_0.json-nft115
-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/0025empty_dynset_0.json-nft111
-rw-r--r--tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.nft2
-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/0028variable_cmdline_0.json-nft34
-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/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
-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
-rw-r--r--tests/shell/testcases/optimizations/dumps/dependency_kill.json-nft776
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_nat.json-nft379
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_nat.nft11
-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_concat.json-nft374
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft15
-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.nft4
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.json-nft182
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.nft4
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_vmap_raw.json-nft438
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_vmaps.json-nft205
-rw-r--r--tests/shell/testcases/optimizations/dumps/merge_vmaps.nft7
-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.nft.input35
-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_nat17
-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_stmts6
-rwxr-xr-xtests/shell/testcases/optimizations/merge_stmts_concat24
-rwxr-xr-xtests/shell/testcases/optimizations/merge_stmts_concat_vmap4
-rwxr-xr-xtests/shell/testcases/optimizations/merge_stmts_vmap6
-rwxr-xr-xtests/shell/testcases/optimizations/merge_vmap_raw2
-rwxr-xr-xtests/shell/testcases/optimizations/merge_vmaps5
-rwxr-xr-xtests/shell/testcases/optimizations/not_mergeable22
-rwxr-xr-xtests/shell/testcases/optimizations/ruleset170
-rwxr-xr-xtests/shell/testcases/optimizations/single_anon_set44
-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_chain_02
-rwxr-xr-xtests/shell/testcases/optionals/comments_objects_024
-rwxr-xr-xtests/shell/testcases/optionals/comments_table_02
-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_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.nft7
-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/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/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/update_object_handles_02
-rwxr-xr-xtests/shell/testcases/owner/0001-flowtable-uaf4
-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/payload180
-rwxr-xr-xtests/shell/testcases/packetpath/set_lookups64
-rwxr-xr-xtests/shell/testcases/packetpath/tcp_options55
-rwxr-xr-xtests/shell/testcases/packetpath/vlan_8021ad_tag50
-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/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/0030add_many_elements_interval_014
-rwxr-xr-xtests/shell/testcases/sets/0034get_element_02
-rwxr-xr-xtests/shell/testcases/sets/0036add_set_element_expiration_018
-rwxr-xr-xtests/shell/testcases/sets/0038meter_list_07
-rwxr-xr-xtests/shell/testcases/sets/0043concatenated_ranges_018
-rwxr-xr-xtests/shell/testcases/sets/0043concatenated_ranges_14
-rwxr-xr-xtests/shell/testcases/sets/0044interval_overlap_016
-rwxr-xr-xtests/shell/testcases/sets/0044interval_overlap_14
-rwxr-xr-xtests/shell/testcases/sets/0046netmap_08
-rwxr-xr-xtests/shell/testcases/sets/0047nat_022
-rwxr-xr-xtests/shell/testcases/sets/0048set_counters_02
-rwxr-xr-xtests/shell/testcases/sets/0049set_define_012
-rwxr-xr-xtests/shell/testcases/sets/0051set_interval_counter_02
-rwxr-xr-xtests/shell/testcases/sets/0059set_update_multistmt_02
-rwxr-xr-xtests/shell/testcases/sets/0060set_multistmt_02
-rwxr-xr-xtests/shell/testcases/sets/0060set_multistmt_140
-rwxr-xr-xtests/shell/testcases/sets/0062set_connlimit_05
-rwxr-xr-xtests/shell/testcases/sets/0063set_catchall_02
-rwxr-xr-xtests/shell/testcases/sets/0064map_catchall_02
-rwxr-xr-xtests/shell/testcases/sets/0067nat_concat_interval_044
-rwxr-xr-xtests/shell/testcases/sets/0067nat_interval_018
-rwxr-xr-xtests/shell/testcases/sets/0068interval_stack_overflow_018
-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/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/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/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/0046netmap_0.json-nft167
-rw-r--r--tests/shell/testcases/sets/dumps/0046netmap_0.nft6
-rw-r--r--tests/shell/testcases/sets/dumps/0047nat_0.nft17
-rw-r--r--tests/shell/testcases/sets/dumps/0048set_counters_0.json-nft95
-rw-r--r--tests/shell/testcases/sets/dumps/0049set_define_0.json-nft94
-rw-r--r--tests/shell/testcases/sets/dumps/0049set_define_0.nft7
-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/0052overlap_0.json-nft35
-rw-r--r--tests/shell/testcases/sets/dumps/0053echo_0.json-nft101
-rw-r--r--tests/shell/testcases/sets/dumps/0054comments_set_0.json-nft45
-rw-r--r--tests/shell/testcases/sets/dumps/0055tcpflags_0.json-nft190
-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/0059set_update_multistmt_0.json-nft79
-rw-r--r--tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.nft2
-rw-r--r--tests/shell/testcases/sets/dumps/0060set_multistmt_0.json-nft105
-rw-r--r--tests/shell/testcases/sets/dumps/0060set_multistmt_0.nft6
-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/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/0064map_catchall_0.json-nft220
-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.nft23
-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/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/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.nft11
-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.nft4
-rw-r--r--tests/shell/testcases/sets/dumps/typeof_sets_0.nft18
-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/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_ifnames3
-rwxr-xr-xtests/shell/testcases/sets/type_set_symbol6
-rwxr-xr-xtests/shell/testcases/sets/typeof_raw_04
-rwxr-xr-xtests/shell/testcases/sets/typeof_sets_0202
-rwxr-xr-xtests/shell/testcases/sets/typeof_sets_122
-rwxr-xr-xtests/shell/testcases/sets/typeof_sets_concat6
-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/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/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/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
1153 files changed, 72958 insertions, 5668 deletions
diff --git a/.gitignore b/.gitignore
index 6b37b123..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,12 @@ build-aux/
libnftables.pc
libtool
+# cscope files
+/cscope.*
+
# Generated by tests
*.payload.got
+tests/build/tests.log
# Debian package build temporary files
build-stamp
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 5bb541f6..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=2:0:1
diff --git a/Makefile.am b/Makefile.am
index 72fb4e88..fef1d8d1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,16 +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 \
- examples
-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 e3c980a7..724a4ae7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,10 +1,10 @@
-AC_INIT([nftables], [1.0.2], [netfilter-devel@vger.kernel.org])
-AC_DEFINE([RELEASE_NAME], ["Lester Gooch"], [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])])
@@ -23,6 +23,9 @@ 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
@@ -44,7 +47,6 @@ fi
AM_PROG_AR
LT_INIT([disable-static])
-AM_PROG_CC_C_O
AC_EXEEXT
CHECK_GCC_FVISIBILITY
@@ -55,7 +57,7 @@ AS_IF([test "x$enable_man_doc" = "xyes"], [
])
PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.4])
-PKG_CHECK_MODULES([LIBNFTNL], [libnftnl >= 1.2.1])
+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)])],
@@ -108,44 +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 python3)]
- )
-
-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/examples/Makefile \
- files/nftables/Makefile \
- files/osf/Makefile \
- doc/Makefile \
- py/Makefile \
- examples/Makefile \
])
AC_OUTPUT
@@ -157,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 21482320..00000000
--- a/doc/Makefile.am
+++ /dev/null
@@ -1,30 +0,0 @@
-if BUILD_MAN
-man_MANS = nft.8 libnftables-json.5 libnftables.3
-
-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}
-
-EXTRA_DIST = ${ASCIIDOCS} ${man_MANS} libnftables-json.adoc libnftables.adoc
-
-CLEANFILES = \
- *~
-
-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} $<
-
-CLEANFILES += ${man_MANS}
-endif
diff --git a/doc/data-types.txt b/doc/data-types.txt
index 961fc624..e5ee91a9 100644
--- a/doc/data-types.txt
+++ b/doc/data-types.txt
@@ -270,7 +270,7 @@ ICMPV6 TYPE TYPE
|==================
|Name | Keyword | Size | Base type
|ICMPv6 Type |
-icmpx_code |
+icmpv6_type |
8 bit |
integer
|===================
@@ -364,7 +364,7 @@ ICMPVX CODE TYPE
|==================
|Name | Keyword | Size | Base type
|ICMPvX Code |
-icmpv6_type |
+icmpx_code |
8 bit |
integer
|===================
diff --git a/doc/libnftables-json.adoc b/doc/libnftables-json.adoc
index 9cc17ff2..3948a0ba 100644
--- a/doc/libnftables-json.adoc
+++ b/doc/libnftables-json.adoc
@@ -175,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.
@@ -312,7 +312,8 @@ ____
"elem":* 'SET_ELEMENTS'*,
"timeout":* 'NUMBER'*,
"gc-interval":* 'NUMBER'*,
- "size":* 'NUMBER'
+ "size":* 'NUMBER'*,
+ "auto-merge":* 'BOOLEAN'
*}}*
*{ "map": {
@@ -327,7 +328,8 @@ ____
"elem":* 'SET_ELEMENTS'*,
"timeout":* 'NUMBER'*,
"gc-interval":* 'NUMBER'*,
- "size":* 'NUMBER'
+ "size":* 'NUMBER'*,
+ "auto-merge":* 'BOOLEAN'
*}}*
'SET_TYPE' := 'STRING' | *[* 'SET_TYPE_LIST' *]*
@@ -366,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
@@ -682,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
@@ -1059,10 +1058,22 @@ Assign connection tracking expectation.
=== XT
[verse]
-*{ "xt": null }*
+____
+*{ "xt": {
+ "type":* 'TYPENAME'*,
+ "name":* 'STRING'
+*}}*
+
+'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.
-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.
+*BEWARE:* nftables won't restore these statements.
== EXPRESSIONS
Expressions are the building blocks of (most) statements. In their most basic
@@ -1172,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
@@ -1214,6 +1225,17 @@ 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]
____
diff --git a/doc/libnftables.adoc b/doc/libnftables.adoc
index 3abb9595..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,13 +74,37 @@ 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.
@@ -115,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::
@@ -196,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'.
@@ -206,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 f7a53ac9..b08e32fa 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*
@@ -322,9 +322,10 @@ TABLES
------
[verse]
{*add* | *create*} *table* ['family'] 'table' [ {*comment* 'comment' *;*'} *{ flags* 'flags' *; }*]
-{*delete* | *list* | *flush*} *table* ['family'] 'table'
+{*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*,
@@ -368,6 +369,7 @@ 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.
@@ -375,9 +377,10 @@ CHAINS
------
[verse]
{*add* | *create*} *chain* ['family'] 'table' 'chain' [*{ type* 'type' *hook* 'hook' [*device* 'device'] *priority* 'priority' *;* [*policy* 'policy' *;*] [*comment* 'comment' *;*'] *}*]
-{*delete* | *list* | *flush*} *chain* ['family'] 'table' 'chain'
+{*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
@@ -390,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.
@@ -411,7 +415,7 @@ 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
@@ -430,11 +434,19 @@ further quirks worth noticing:
*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 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.
@@ -472,7 +484,7 @@ with these standard names to ease relative prioritizing, e.g. *mangle - 5* stand
for *-155*. Values will also be printed like this until the value is not
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*.
@@ -481,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
@@ -509,6 +523,8 @@ 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 output chain*
-------------
@@ -559,10 +575,10 @@ section describes nft set syntax in more detail.
[verse]
*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* | *list* | *flush*} *set* ['family'] 'table' 'set'
+{*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
@@ -571,8 +587,10 @@ 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 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.
+*reset*:: Reset state in all contained elements, e.g. counter and quota statement values.
.Set specifications
[options="header"]
@@ -585,8 +603,7 @@ string: ipv4_addr, ipv6_addr, ether_addr, inet_proto, inet_service, mark
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)|
string, decimal followed by unit. Units are: d, h, m, s
@@ -612,7 +629,7 @@ MAPS
-----
[verse]
*add map* ['family'] 'table' 'map' *{ type* 'type' | *typeof* 'expression' [*flags* 'flags' *;*] [*elements = {* 'element'[*,* ...] *} ;*] [*size* 'size' *;*] [*comment* 'comment' *;*'] [*policy* 'policy' *;*] *}*
-{*delete* | *list* | *flush*} *map* ['family'] 'table' 'map'
+{*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.
@@ -620,10 +637,10 @@ Maps store data based on some specific key used as input. They are uniquely iden
[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"]
@@ -637,7 +654,7 @@ 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
@@ -649,18 +666,34 @@ 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* | *get* } *element* ['family'] 'table' 'set' *{* 'ELEMENT'[*,* ...] *}*
+{*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 to change contents of named sets and maps.
+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
@@ -674,6 +707,9 @@ listed elements may already exist.
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"]
|=================
@@ -692,7 +728,7 @@ FLOWTABLES
[verse]
{*add* | *create*} *flowtable* ['family'] 'table' 'flowtable' *{ hook* 'hook' *priority* 'priority' *; devices = {* 'device'[*,* ...] *} ; }*
*list flowtables* ['family']
-{*delete* | *list*} *flowtable* ['family'] 'table' 'flowtable'
+{*delete* | *destroy* | *list*} *flowtable* ['family'] 'table' 'flowtable'
*delete* *flowtable* ['family'] 'table' *handle* 'handle'
Flowtables allow you to accelerate packet forwarding in software. Flowtables
@@ -716,6 +752,7 @@ 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
@@ -732,11 +769,22 @@ kernel modules, such as nf_conntrack.
STATEFUL OBJECTS
----------------
[verse]
-{*add* | *delete* | *list* | *reset*} 'type' ['family'] 'table' 'object'
-*delete* 'type' ['family'] 'table' *handle* 'handle'
+{*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
@@ -745,6 +793,7 @@ 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.
diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt
index 106ff74c..c7c267da 100644
--- a/doc/payload-expression.txt
+++ b/doc/payload-expression.txt
@@ -23,6 +23,14 @@ VLAN HEADER EXPRESSION
[verse]
*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"]
|==================
@@ -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]
@@ -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
@@ -524,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]
@@ -548,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
@@ -589,6 +775,7 @@ The following syntaxes are valid only in a relational expression with boolean ty
*exthdr* {*hbh* | *frag* | *rt* | *dst* | *mh*}
*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"]
@@ -691,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. +
diff --git a/doc/primary-expression.txt b/doc/primary-expression.txt
index f97778b9..782494bd 100644
--- a/doc/primary-expression.txt
+++ b/doc/primary-expression.txt
@@ -168,15 +168,18 @@ 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
@@ -190,6 +193,9 @@ filter output oif eth0
# 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
@@ -428,6 +434,10 @@ 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
~~~~~~~~~~~~~~~~~
@@ -438,7 +448,7 @@ 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 to increment the returned value
+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:
@@ -468,7 +478,7 @@ 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 to increment the returned value by a fixed offset.
+allows one to increment the returned value by a fixed offset.
A typical use-case for *jhash* and *symhash* is load-balancing:
diff --git a/doc/stateful-objects.txt b/doc/stateful-objects.txt
index e3c79220..00d3c5f1 100644
--- a/doc/stateful-objects.txt
+++ b/doc/stateful-objects.txt
@@ -94,7 +94,7 @@ table ip filter {
ct timeout customtimeout {
protocol tcp;
l3proto ip
- policy = { established: 120, close: 20 }
+ policy = { established: 2m, close: 20s }
}
chain output {
diff --git a/doc/statements.txt b/doc/statements.txt
index 6aaf806b..ae6442b0 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.
@@ -180,7 +180,7 @@ ____
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 base chains
-using the *input*,
+using the *prerouting*, *input*,
*forward* or *output* hooks, and user-defined chains which are only called from
those chains.
@@ -278,7 +278,7 @@ ct event set new,related,destroy
NOTRACK STATEMENT
~~~~~~~~~~~~~~~~~
-The notrack statement allows to disable connection tracking for certain
+The notrack statement allows one to disable connection tracking for certain
packets.
[verse]
@@ -296,7 +296,7 @@ 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. +
@@ -316,6 +316,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
@@ -332,8 +335,13 @@ ____
A limit statement matches at a limited rate using a token bucket filter. A rule
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. Default *burst* is 5.
-if you specify *burst*, it must be non-zero value.
+*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"]
@@ -351,8 +359,8 @@ NAT STATEMENTS
~~~~~~~~~~~~~~
[verse]
____
-*snat* [[*ip* | *ip6*] *to*] 'ADDR_SPEC' [*:*'PORT_SPEC'] ['FLAGS']
-*dnat* [[*ip* | *ip6*] *to*] 'ADDR_SPEC' [*:*'PORT_SPEC'] ['FLAGS']
+*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']
@@ -390,6 +398,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"]
|==================
@@ -400,7 +411,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)
|===============================
@@ -449,6 +460,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
@@ -608,7 +665,7 @@ ____
QUEUE_EXPRESSION can be used to compute a queue number
at run-time with the hash or numgen expressions. It also
-allows to use the map statement to assign fixed queue numbers
+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
@@ -678,7 +735,24 @@ The fwd statement is used to redirect a raw packet to another interface. It is
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
~~~~~~~~~~~~~
@@ -694,6 +768,10 @@ 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'] *}*
@@ -778,3 +856,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/Makefile.am b/examples/Makefile.am
deleted file mode 100644
index 3b8b0b67..00000000
--- a/examples/Makefile.am
+++ /dev/null
@@ -1,6 +0,0 @@
-check_PROGRAMS = nft-buffer \
- nft-json-file
-
-AM_CPPFLAGS = -I$(top_srcdir)/include
-
-LDADD = $(top_builddir)/src/libnftables.la
diff --git a/files/Makefile.am b/files/Makefile.am
deleted file mode 100644
index 7deec151..00000000
--- a/files/Makefile.am
+++ /dev/null
@@ -1,3 +0,0 @@
-SUBDIRS = nftables \
- examples \
- osf
diff --git a/files/examples/Makefile.am b/files/examples/Makefile.am
deleted file mode 100644
index b29e9f61..00000000
--- a/files/examples/Makefile.am
+++ /dev/null
@@ -1,5 +0,0 @@
-pkgdocdir = ${docdir}/examples
-dist_pkgdoc_SCRIPTS = ct_helpers.nft \
- load_balancing.nft \
- secmark.nft \
- sets_and_maps.nft
diff --git a/files/nftables/Makefile.am b/files/nftables/Makefile.am
deleted file mode 100644
index ee88dd89..00000000
--- a/files/nftables/Makefile.am
+++ /dev/null
@@ -1,14 +0,0 @@
-dist_pkgdata_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
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 ff56dfe4..00000000
--- a/include/Makefile.am
+++ /dev/null
@@ -1,41 +0,0 @@
-SUBDIRS = linux \
- nftables
-
-noinst_HEADERS = cli.h \
- cache.h \
- cmd.h \
- datatype.h \
- expression.h \
- fib.h \
- hash.h \
- intervals.h \
- ipopt.h \
- json.h \
- mini-gmp.h \
- gmputil.h \
- iface.h \
- mnl.h \
- nftables.h \
- payload.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 \
- owner.h \
- parser.h \
- proto.h \
- sctp_chunk.h \
- socket.h \
- rule.h \
- rt.h \
- utils.h \
- xfrm.h \
- xt.h
diff --git a/include/cache.h b/include/cache.h
index b6c7d48b..8ca4a9a7 100644
--- a/include/cache.h
+++ b/include/cache.h
@@ -1,7 +1,9 @@
#ifndef _NFT_CACHE_H_
#define _NFT_CACHE_H_
-#include <string.h>
+#include <list.h>
+
+struct handle;
enum cache_level_bits {
NFT_CACHE_TABLE_BIT = (1 << 0),
@@ -55,6 +57,7 @@ struct nft_cache_filter {
const char *chain;
const char *set;
const char *ft;
+ uint64_t rule_handle;
} list;
struct {
@@ -63,11 +66,13 @@ struct nft_cache_filter {
};
struct nft_cache;
+struct nft_ctx;
enum cmd_ops;
-unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
- struct nft_cache_filter *filter);
-int nft_cache_update(struct nft_ctx *ctx, enum cmd_ops cmd,
+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);
@@ -93,6 +98,8 @@ 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);
@@ -117,6 +124,8 @@ 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,
@@ -134,7 +143,13 @@ struct nft_cache {
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 609ed2ed..f0a0d47a 100644
--- a/include/cli.h
+++ b/include/cli.h
@@ -2,7 +2,6 @@
#define _NFT_CLI_H_
#include <nftables/libnftables.h>
-#include <config.h>
#if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDIT) || defined(HAVE_LIBLINENOISE)
extern 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
index 27fa6087..92a4152b 100644
--- a/include/cmd.h
+++ b/include/cmd.h
@@ -1,7 +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 73f38f66..c4d6282d 100644
--- a/include/datatype.h
+++ b/include/datatype.h
@@ -1,7 +1,6 @@
#ifndef NFTABLES_DATATYPE_H
#define NFTABLES_DATATYPE_H
-#include <stdbool.h>
#include <json.h>
/**
@@ -23,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)
@@ -167,6 +166,7 @@ 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;
@@ -174,13 +174,15 @@ struct datatype {
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 *dtype_clone(const struct datatype *orig_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,
@@ -250,6 +252,9 @@ 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;
@@ -299,7 +304,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);
+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,
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/expression.h b/include/expression.h
index 2c3818e8..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>
@@ -12,6 +11,10 @@
#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
*
@@ -41,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,
@@ -73,8 +80,9 @@ enum expr_types {
EXPR_XFRM,
EXPR_SET_ELEM_CATCHALL,
EXPR_FLAGCMP,
+
+ EXPR_MAX = EXPR_FLAGCMP
};
-#define EXPR_MAX EXPR_XFRM
enum ops {
OP_INVALID,
@@ -116,7 +124,11 @@ 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;
@@ -181,7 +193,7 @@ struct expr_ops {
};
const struct expr_ops *expr_ops(const struct expr *e);
-const struct expr_ops *expr_ops_by_type(enum expr_types etype);
+const struct expr_ops *expr_ops_by_type_u32(uint32_t value);
/**
* enum expr_flags
@@ -243,6 +255,7 @@ struct expr {
enum expr_types etype:8;
enum ops op:8;
unsigned int len;
+ struct cmd *cmd;
union {
struct {
@@ -310,6 +323,7 @@ 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;
@@ -328,6 +342,7 @@ struct expr {
/* EXPR_META */
enum nft_meta_keys key;
enum proto_bases base;
+ const struct proto_desc *inner_desc;
} meta;
struct {
/* SOCKET */
@@ -480,6 +495,7 @@ extern struct expr *compound_expr_alloc(const struct location *loc,
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);
@@ -514,5 +530,6 @@ struct expr *flagcmp_expr_alloc(const struct location *loc, enum ops op,
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 1bc756f9..084daba5 100644
--- a/include/exthdr.h
+++ b/include/exthdr.h
@@ -4,6 +4,7 @@
#include <proto.h>
#include <tcpopt.h>
#include <ipopt.h>
+#include <dccpopt.h>
enum exthdr_desc_id {
EXTHDR_DESC_UNKNOWN = 0,
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
index 964804b1..ef0fb53e 100644
--- a/include/intervals.h
+++ b/include/intervals.h
@@ -1,7 +1,6 @@
#ifndef NFTABLES_INTERVALS_H
#define NFTABLES_INTERVALS_H
-void set_to_range(struct expr *init);
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,
diff --git a/include/json.h b/include/json.h
index b0d78eb8..39be8928 100644
--- a/include/json.h
+++ b/include/json.h
@@ -74,6 +74,7 @@ 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);
@@ -83,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);
@@ -92,6 +94,7 @@ 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);
@@ -176,6 +179,7 @@ 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)
@@ -185,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)
@@ -194,6 +199,7 @@ 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
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/Makefile.am b/include/linux/netfilter/Makefile.am
deleted file mode 100644
index 22f66a7e..00000000
--- a/include/linux/netfilter/Makefile.am
+++ /dev/null
@@ -1,10 +0,0 @@
-noinst_HEADERS = nf_conntrack_common.h \
- nf_conntrack_tuple_common.h \
- nf_log.h \
- nf_nat.h \
- nf_tables.h \
- nf_tables_compat.h \
- nf_synproxy.h \
- nfnetlink_osf.h \
- nfnetlink_hook.h \
- nfnetlink.h
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 75df968d..c62e6ac5 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -97,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,
@@ -124,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,
};
@@ -164,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
@@ -173,6 +194,7 @@ enum nft_table_flags {
* @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,
@@ -182,6 +204,7 @@ enum nft_table_attributes {
NFTA_TABLE_HANDLE,
NFTA_TABLE_PAD,
NFTA_TABLE_USERDATA,
+ NFTA_TABLE_OWNER,
__NFTA_TABLE_MAX
};
#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
@@ -748,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,
};
/**
@@ -772,6 +798,32 @@ 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
*
@@ -809,12 +861,14 @@ enum nft_exthdr_flags {
* @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)
@@ -881,6 +935,7 @@ enum nft_exthdr_attributes {
* @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,
@@ -891,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,
@@ -918,6 +974,8 @@ enum nft_meta_keys {
NFT_META_TIME_HOUR,
NFT_META_SDIF,
NFT_META_SDIFNAME,
+ NFT_META_BRI_BROUTE,
+ __NFT_META_IIFTYPE,
};
/**
@@ -1013,6 +1071,7 @@ 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,
@@ -1029,6 +1088,7 @@ 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,
@@ -1189,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)
diff --git a/include/linux/netfilter/nfnetlink_hook.h b/include/linux/netfilter/nfnetlink_hook.h
index bbcd285b..84a561a7 100644
--- a/include/linux/netfilter/nfnetlink_hook.h
+++ b/include/linux/netfilter/nfnetlink_hook.h
@@ -32,8 +32,12 @@ enum nfnl_hook_attributes {
/**
* enum nfnl_hook_chain_info_attributes - chain description
*
- * NFNLA_HOOK_INFO_DESC: nft chain and table name (enum nft_table_attributes) (NLA_NESTED)
- * NFNLA_HOOK_INFO_TYPE: chain type (enum nfnl_hook_chaintype) (NLA_U32)
+ * @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,
@@ -55,10 +59,24 @@ enum nfnl_hook_chain_desc_attributes {
/**
* enum nfnl_hook_chaintype - chain type
*
- * @NFNL_HOOK_TYPE_NFTABLES nf_tables base chain
+ * @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/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 4c701d4e..cd5a2053 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -34,7 +34,9 @@ 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,
- const char *table, const char *chain);
+ const char *table, const char *chain,
+ uint64_t rule_handle,
+ bool dump, bool reset);
int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
@@ -60,14 +62,17 @@ 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 *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 handle *h,
- const struct expr *init);
+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,
diff --git a/include/netlink.h b/include/netlink.h
index e8e0f68a..27a62462 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -40,12 +40,28 @@ struct netlink_parse_ctx {
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;
@@ -69,6 +85,7 @@ 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);
@@ -84,7 +101,7 @@ 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;
@@ -149,10 +166,11 @@ 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 set *cache_set,
- struct set *set, struct expr *init);
+ struct set *set, struct expr *init, bool reset);
extern int netlink_delinearize_setelem(struct nftnl_set_elem *nlse,
struct set *set,
struct nft_cache *cache);
@@ -168,6 +186,9 @@ extern int netlink_list_flowtables(struct netlink_ctx *ctx,
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);
extern void netlink_dump_rule(const struct nftnl_rule *nlr,
@@ -238,4 +259,6 @@ struct nft_expr_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 d49eb579..4b7c3359 100644
--- a/include/nftables.h
+++ b/include/nftables.h
@@ -1,7 +1,6 @@
#ifndef NFTABLES_NFTABLES_H
#define NFTABLES_NFTABLES_H
-#include <stdbool.h>
#include <stdarg.h>
#include <limits.h>
#include <utils.h>
@@ -23,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 {
@@ -119,6 +132,7 @@ struct nft_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;
@@ -210,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);
@@ -222,8 +235,7 @@ 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);
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 85e08c9b..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>
@@ -49,6 +48,14 @@ 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),
NFT_CTX_OUTPUT_STATELESS = (1 << 2),
diff --git a/include/parser.h b/include/parser.h
index f32154cc..f79a22f3 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -22,10 +22,12 @@ struct parser_state {
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 {
@@ -35,11 +37,12 @@ enum startcond_type {
PARSER_SC_CT,
PARSER_SC_COUNTER,
PARSER_SC_ETH,
- PARSER_SC_FLAGS,
+ 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,
@@ -49,6 +52,8 @@ enum startcond_type {
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,
@@ -82,6 +87,8 @@ enum startcond_type {
PARSER_SC_STMT_REJECT,
PARSER_SC_STMT_SYNPROXY,
PARSER_SC_STMT_TPROXY,
+
+ __SC_MAX
};
struct mnl_socket;
diff --git a/include/payload.h b/include/payload.h
index 37869928..08e45f7f 100644
--- a/include/payload.h
+++ b/include/payload.h
@@ -15,6 +15,8 @@ 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);
@@ -67,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 a04240a5..9c98a0b7 100644
--- a/include/proto.h
+++ b/include/proto.h
@@ -35,6 +35,8 @@ enum icmp_hdr_field_type {
PROTO_ICMP6_PPTR,
PROTO_ICMP6_ECHO,
PROTO_ICMP6_MGMQ,
+ PROTO_ICMP6_ADDRESS, /* neighbor solicit/advert, redirect and MLD */
+ PROTO_ICMP6_REDIRECT,
};
/**
@@ -96,6 +98,10 @@ enum proto_desc_id {
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)
@@ -131,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), }
@@ -185,6 +195,7 @@ extern const struct proto_desc *proto_dev_desc(uint16_t type);
struct proto_ctx {
unsigned int debug_mask;
uint8_t family;
+ bool inner;
union {
struct {
uint8_t type;
@@ -193,17 +204,18 @@ struct proto_ctx {
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);
@@ -215,6 +227,8 @@ 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);
@@ -262,6 +276,7 @@ enum ip_hdr_fields {
IPHDR_SADDR,
IPHDR_DADDR,
};
+#define IPHDR_MAX IPHDR_DADDR
enum icmp_hdr_fields {
ICMPHDR_INVALID,
@@ -292,6 +307,8 @@ enum icmp6_hdr_fields {
ICMP6HDR_ID,
ICMP6HDR_SEQ,
ICMP6HDR_MAXDELAY,
+ ICMP6HDR_TADDR,
+ ICMP6HDR_DADDR,
};
enum ip6_hdr_fields {
@@ -375,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;
@@ -412,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/rule.h b/include/rule.h
index e232b97a..3a833cf3 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -1,13 +1,11 @@
#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 <string.h>
#include <cache.h>
/**
@@ -169,6 +167,7 @@ struct table {
unsigned int refcnt;
uint32_t owner;
const char *comment;
+ bool has_xt_stmts;
};
extern struct table *table_alloc(void);
@@ -260,7 +259,7 @@ 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 struct chain *chain_lookup_fuzzy(const struct handle *h,
@@ -330,6 +329,7 @@ void rule_stmt_insert_at(struct rule *rule, struct stmt *nstmt,
* @policy: set mechanism policy
* @automerge: merge adjacents and overlapping elements, if possible
* @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
@@ -354,6 +354,7 @@ struct set {
bool root;
bool automerge;
bool key_typeof_valid;
+ bool errors;
const char *comment;
struct {
uint32_t size;
@@ -410,6 +411,11 @@ 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;
@@ -518,7 +524,7 @@ struct obj *obj_lookup_fuzzy(const char *obj_name,
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;
@@ -562,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,
@@ -579,6 +586,7 @@ enum cmd_ops {
CMD_EXPORT,
CMD_MONITOR,
CMD_DESCRIBE,
+ CMD_DESTROY,
};
/**
@@ -619,6 +627,7 @@ enum cmd_obj {
CMD_OBJ_SETELEMS,
CMD_OBJ_SETS,
CMD_OBJ_RULE,
+ CMD_OBJ_RULES,
CMD_OBJ_CHAIN,
CMD_OBJ_CHAINS,
CMD_OBJ_TABLE,
@@ -641,9 +650,11 @@ 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,
@@ -681,6 +692,11 @@ 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
*
@@ -700,6 +716,7 @@ struct cmd {
enum cmd_obj obj;
struct handle handle;
uint32_t seqnum;
+ struct list_head collapse_list;
union {
void *data;
struct expr *expr;
@@ -716,25 +733,20 @@ struct cmd {
struct markup *markup;
struct obj *object;
};
- struct {
- uint16_t offset;
- const struct location *location;
- } attr[NFT_NLATTR_LOC_MAX];
- int num_attrs;
+ 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);
extern void cmd_free(struct cmd *cmd);
-void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc);
-
#include <payload.h>
#include <expression.h>
@@ -748,10 +760,13 @@ void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc);
* @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;
@@ -761,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);
@@ -778,7 +796,7 @@ struct timeout_protocol {
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/statement.h b/include/statement.h
index 2a2d3001..662f99dd 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -47,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;
@@ -255,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;
@@ -264,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);
@@ -304,6 +310,7 @@ extern struct stmt *xt_stmt_alloc(const struct location *loc);
* @STMT_SYNPROXY: synproxy statement
* @STMT_CHAIN: chain statement
* @STMT_OPTSTRIP: optstrip statement
+ * @STMT_LAST: last statement
*/
enum stmt_types {
STMT_INVALID,
@@ -334,6 +341,7 @@ enum stmt_types {
STMT_SYNPROXY,
STMT_CHAIN,
STMT_OPTSTRIP,
+ STMT_LAST,
};
/**
@@ -383,6 +391,7 @@ 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;
@@ -407,6 +416,7 @@ struct stmt {
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/utils.h b/include/utils.h
index ffbe2cbb..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
@@ -128,7 +142,6 @@ 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);
@@ -136,5 +149,6 @@ 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 2a0a1e89..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,
@@ -74,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
@@ -82,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]
@@ -116,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]
@@ -125,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]
@@ -139,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.
@@ -346,16 +447,7 @@ class Nftables:
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.
@@ -377,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):
@@ -446,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 264d981e..00000000
--- a/src/Makefile.am
+++ /dev/null
@@ -1,119 +0,0 @@
-include $(top_srcdir)/Make_global.am
-
-sbin_PROGRAMS = nft
-
-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
-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 \
- -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 \
- cmd.c \
- datatype.c \
- expression.c \
- evaluate.c \
- proto.c \
- payload.c \
- exthdr.c \
- fib.c \
- hash.c \
- intervals.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 \
- owner.c \
- segtree.c \
- gmputil.c \
- utils.c \
- erec.c \
- mnl.c \
- iface.c \
- mergesort.c \
- optimize.c \
- osf.c \
- nfnl_osf.c \
- tcpopt.c \
- socket.c \
- print.c \
- sctp_chunk.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} \
- -Wl,--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 fd8df884..c000e32c 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -6,6 +6,8 @@
* later) as published by the Free Software Foundation.
*/
+#include <nft.h>
+
#include <expression.h>
#include <statement.h>
#include <rule.h>
@@ -16,6 +18,7 @@
#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)
{
@@ -123,9 +126,9 @@ void nft_cache_filter_fini(struct nft_cache_filter *filter)
struct nft_filter_obj *obj, *next;
list_for_each_entry_safe(obj, next, &filter->obj[i].head, list)
- xfree(obj);
+ free(obj);
}
- xfree(filter);
+ free(filter);
}
static void cache_filter_add(struct nft_cache_filter *filter,
@@ -200,8 +203,12 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd,
{
switch (cmd->obj) {
case CMD_OBJ_TABLE:
- if (filter && cmd->handle.table.name) {
+ 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;
@@ -211,6 +218,10 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd,
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;
@@ -223,8 +234,6 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd,
}
if (filter->list.table && filter->list.set)
flags |= NFT_CACHE_TABLE | NFT_CACHE_SET | NFT_CACHE_SETELEM;
- else if (nft_output_terse(&nft->output))
- flags |= NFT_CACHE_FULL | NFT_CACHE_TERSE;
else
flags |= NFT_CACHE_FULL;
break;
@@ -234,6 +243,8 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd,
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 &&
@@ -248,27 +259,164 @@ static unsigned int evaluate_cache_list(struct nft_ctx *nft, struct cmd *cmd,
flags |= NFT_CACHE_TABLE | NFT_CACHE_FLOWTABLE;
break;
case CMD_OBJ_RULESET:
- if (nft_output_terse(&nft->output))
- flags |= NFT_CACHE_FULL | NFT_CACHE_TERSE;
- else
- flags |= NFT_CACHE_FULL;
- break;
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;
}
-unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
- struct nft_cache_filter *filter)
+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));
@@ -284,6 +432,7 @@ unsigned int nft_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 |
@@ -296,7 +445,7 @@ unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
flags = evaluate_cache_get(cmd, flags);
break;
case CMD_RESET:
- flags |= NFT_CACHE_TABLE;
+ flags |= evaluate_cache_reset(cmd, flags, filter);
break;
case CMD_LIST:
flags |= evaluate_cache_list(nft, cmd, flags, filter);
@@ -318,8 +467,9 @@ unsigned int nft_cache_evaluate(struct nft_ctx *nft, struct list_head *cmds,
break;
}
}
+ *pflags = flags;
- return flags;
+ return 0;
}
void table_cache_add(struct table *table, struct nft_cache *cache)
@@ -483,31 +633,36 @@ static int list_rule_cb(struct nftnl_rule *nlr, void *data)
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 ||
+ 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;
}
-static int rule_cache_dump(struct netlink_ctx *ctx, const struct handle *h,
- const struct nft_cache_filter *filter)
+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_cache = mnl_nft_rule_dump(ctx, h->family,
+ table, chain, rule_handle, dump, reset);
if (rule_cache == NULL) {
if (errno == EINTR)
return -1;
@@ -839,7 +994,7 @@ static int rule_init_cache(struct netlink_ctx *ctx, struct table *table,
struct chain *chain;
int ret;
- ret = rule_cache_dump(ctx, &table->handle, filter);
+ 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);
@@ -847,12 +1002,21 @@ static int rule_init_cache(struct netlink_ctx *ctx, struct table *table,
chain = chain_binding_lookup(table,
rule->handle.chain.name);
if (!chain)
- return -1;
+ 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,
@@ -863,8 +1027,10 @@ static int implicit_chain_cache(struct netlink_ctx *ctx, struct table *table,
int ret = 0;
list_for_each_entry(chain, &table->chain_bindings, cache.list) {
- filter.list.table = table->handle.table.name;
- filter.list.chain = chain->handle.chain.name;
+ filter.list = (typeof(filter.list)) {
+ .table = table->handle.table.name,
+ .chain = chain->handle.chain.name,
+ };
ret = rule_init_cache(ctx, table, &filter);
}
@@ -917,7 +1083,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
continue;
ret = netlink_list_setelems(ctx, &set->handle,
- set);
+ set, false);
if (ret < 0)
goto cache_fails;
}
@@ -930,7 +1096,7 @@ static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags,
continue;
ret = netlink_list_setelems(ctx, &set->handle,
- set);
+ set, false);
if (ret < 0)
goto cache_fails;
}
@@ -1064,7 +1230,11 @@ replay:
goto replay;
}
+ erec_queue(error(&netlink_location, "cache initialization failed: %s",
+ strerror(errno)),
+ msgs);
nft_cache_release(cache);
+
return -1;
}
@@ -1109,7 +1279,7 @@ void cache_init(struct cache *cache)
void cache_free(struct cache *cache)
{
- xfree(cache->ht);
+ free(cache->ht);
}
void cache_add(struct cache_item *item, struct cache *cache, uint32_t hash)
diff --git a/src/cli.c b/src/cli.c
index 11fc85ab..448c25c2 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -12,13 +12,12 @@
* 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
@@ -37,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
@@ -100,8 +108,8 @@ static char *cli_append_multiline(char *line)
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);
@@ -125,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);
@@ -139,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);
@@ -176,16 +181,19 @@ 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)
@@ -205,51 +213,63 @@ int cli_init(struct nft_ctx *nft)
history_set_pos(history_length);
rl_set_prompt(CMDLINE_PROMPT);
- while ((line = readline(rl_prompt)) != NULL) {
+ while (!cli_quit) {
+ line = readline(rl_prompt);
+ if (!line) {
+ cli_exit(0);
+ break;
+ }
line = cli_append_multiline(line);
if (!line)
continue;
cli_complete(line);
}
- cli_exit();
- return 0;
+ return cli_rc;
}
-void cli_exit(void)
+void cli_exit(int rc)
{
rl_deprep_terminal();
write_history(histfile);
+
+ __cli_exit(rc);
}
#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_LINENOISE */
diff --git a/src/cmd.c b/src/cmd.c
index f6a8aa11..14cb1b51 100644
--- a/src/cmd.c
+++ b/src/cmd.c
@@ -1,3 +1,13 @@
+/*
+ * 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>
@@ -5,9 +15,19 @@
#include <utils.h>
#include <iface.h>
#include <errno.h>
-#include <stdlib.h>
#include <cache.h>
-#include <string.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)
@@ -21,7 +41,7 @@ static int nft_cmd_enoent_table(struct netlink_ctx *ctx, const struct cmd *cmd,
if (!table)
return 0;
- netlink_io_error(ctx, loc, "%s; did you mean table ‘%s’ in family %s?",
+ 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;
@@ -37,7 +57,7 @@ static int table_fuzzy_check(struct netlink_ctx *ctx, const struct cmd *cmd,
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?",
+ "%s; did you mean table '%s' in family %s?",
strerror(ENOENT), table->handle.table.name,
family2str(table->handle.family));
return 1;
@@ -66,7 +86,7 @@ static int nft_cmd_enoent_chain(struct netlink_ctx *ctx, const struct cmd *cmd,
if (!chain)
return 0;
- netlink_io_error(ctx, loc, "%s; did you mean chain ‘%s’ in table %s ‘%s’?",
+ 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);
@@ -96,7 +116,7 @@ static int nft_cmd_enoent_rule(struct netlink_ctx *ctx, const struct cmd *cmd,
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’?",
+ 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),
@@ -127,7 +147,7 @@ static int nft_cmd_enoent_set(struct netlink_ctx *ctx, const struct cmd *cmd,
if (!set)
return 0;
- netlink_io_error(ctx, loc, "%s; did you mean %s ‘%s’ in table %s ‘%s’?",
+ 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,
@@ -156,7 +176,7 @@ static int nft_cmd_enoent_obj(struct netlink_ctx *ctx, const struct cmd *cmd,
if (!obj)
return 0;
- netlink_io_error(ctx, loc, "%s; did you mean obj ‘%s’ in table %s ‘%s’?",
+ 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);
@@ -185,7 +205,7 @@ static int nft_cmd_enoent_flowtable(struct netlink_ctx *ctx,
if (!ft)
return 0;
- netlink_io_error(ctx, loc, "%s; did you mean flowtable ‘%s’ in table %s ‘%s’?",
+ 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);
@@ -233,11 +253,38 @@ static void nft_cmd_enoent(struct netlink_ctx *ctx, const struct cmd *cmd,
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;
- int i;
+ uint32_t i;
for (i = 0; i < cmd->num_attrs; i++) {
if (!cmd->attr[i].offset)
@@ -255,6 +302,200 @@ void nft_cmd_error(struct netlink_ctx *ctx, struct cmd *cmd,
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 e246d303..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",
@@ -216,10 +216,17 @@ static struct error_record *ct_label_type_parse(struct parse_ctx *ctx,
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,
@@ -271,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,
@@ -570,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 = {
diff --git a/src/datatype.c b/src/datatype.c
index 2e31c858..b368ea91 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>
@@ -28,6 +28,8 @@
#include <erec.h>
#include <netlink.h>
#include <json.h>
+#include <misspell.h>
+#include "nftutils.h"
#include <netinet/ip_icmp.h>
@@ -62,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,
@@ -71,6 +74,7 @@ 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,
@@ -123,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);
@@ -136,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,
@@ -163,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;
@@ -321,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 = {
@@ -337,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 = {
@@ -528,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;
+
+ 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;
- err = getaddrinfo(sym->identifier, NULL, &hints, &ai);
- if (err != 0)
- return error(&sym->location, "Could not resolve hostname: %s",
- gai_strerror(err));
+ 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) {
+ 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;
}
@@ -587,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;
+
+ 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) {
+ 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;
}
@@ -626,12 +715,12 @@ 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;
}
}
@@ -640,15 +729,15 @@ static void inet_protocol_type_print(const struct expr *expr,
static void inet_protocol_type_describe(struct output_ctx *octx)
{
- struct protoent *p;
uint8_t protonum;
for (protonum = 0; protonum < UINT8_MAX; protonum++) {
- p = getprotobynumber(protonum);
- if (!p)
+ char name[NFT_PROTONAME_MAXSIZE];
+
+ if (!nft_getprotobynumber(protonum, name, sizeof(name)))
continue;
- nft_print(octx, "\t%-30s\t%u\n", p->p_name, protonum);
+ nft_print(octx, "\t%-30s\t%u\n", name, protonum);
}
}
@@ -656,7 +745,6 @@ 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;
@@ -669,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,
@@ -697,17 +787,18 @@ const struct datatype inet_protocol_type = {
static void inet_service_print(const struct expr *expr, struct output_ctx *octx)
{
uint16_t port = mpz_get_be16(expr->value);
- const struct servent *s = getservbyport(port, NULL);
+ char name[NFT_SERVNAME_MAXSIZE];
- if (s == NULL)
+ if (!nft_getservbyport(port, NULL, name, sizeof(name)))
nft_print(octx, "%hu", ntohs(port));
else
- nft_print(octx, "\"%s\"", s->s_name);
+ 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;
}
@@ -737,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);
}
@@ -761,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;
@@ -783,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;
}
@@ -805,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;
}
@@ -814,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)
@@ -840,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,
@@ -851,7 +1015,6 @@ const struct datatype mark_type = {
.print = mark_type_print,
.json = mark_type_json,
.parse = mark_type_parse,
- .flags = DTYPE_F_PREFIX,
};
static const struct symbol_table icmp_code_tbl = {
@@ -926,6 +1089,7 @@ const struct datatype icmpx_code_type = {
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);
@@ -944,16 +1108,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 {
@@ -1105,17 +1282,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;
@@ -1128,24 +1306,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)
{
- if (dtype == expr->dtype)
- return;
- datatype_free(expr->dtype);
- expr->dtype = datatype_get(dtype);
+ if (dtype != expr->dtype)
+ __datatype_set(expr, datatype_get(dtype));
}
-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;
}
@@ -1158,12 +1343,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)
@@ -1192,7 +1380,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;
@@ -1204,15 +1392,15 @@ 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;
@@ -1360,10 +1548,10 @@ const struct datatype policy_type = {
#define SYSFS_CGROUPSV2_PATH "/sys/fs/cgroup"
-static const char *cgroupv2_get_path(const char *path, uint64_t id)
+static char *cgroupv2_get_path(const char *path, uint64_t id)
{
- const char *cgroup_path = NULL;
char dent_name[PATH_MAX + 1];
+ char *cgroup_path = NULL;
struct dirent *dent;
struct stat st;
DIR *d;
@@ -1401,7 +1589,7 @@ static void cgroupv2_type_print(const struct expr *expr,
struct output_ctx *octx)
{
uint64_t id = mpz_get_uint64(expr->value);
- const char *cgroup_path;
+ char *cgroup_path;
cgroup_path = cgroupv2_get_path(SYSFS_CGROUPSV2_PATH, id);
if (cgroup_path)
@@ -1410,7 +1598,7 @@ static void cgroupv2_type_print(const struct expr *expr,
else
nft_print(octx, "%" PRIu64, id);
- xfree(cgroup_path);
+ free(cgroup_path);
}
static struct error_record *cgroupv2_type_parse(struct parse_ctx *ctx,
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 a4b93fb0..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>
@@ -45,8 +43,8 @@ void erec_add_location(struct error_record *erec, const struct location *loc)
void erec_destroy(struct error_record *erec)
{
- xfree(erec->msg);
- xfree(erec);
+ free(erec->msg);
+ free(erec);
}
__attribute__((format(printf, 3, 0)))
@@ -170,6 +168,8 @@ 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;
@@ -203,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 1447a4c2..1682ba58 100644
--- a/src/evaluate.c
+++ b/src/evaluate.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 <arpa/inet.h>
#include <linux/netfilter.h>
#include <linux/netfilter_arp.h>
@@ -39,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[] = {
@@ -68,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;
@@ -75,7 +108,7 @@ 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);
@@ -83,7 +116,8 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
const char *name,
struct expr *key,
struct expr *data,
- struct expr *expr)
+ struct expr *expr,
+ uint32_t flags)
{
struct cmd *cmd;
struct set *set;
@@ -93,17 +127,25 @@ 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;
@@ -112,8 +154,6 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
list_add_tail(&cmd->list, &ctx->cmd->list);
}
- set_evaluate(ctx, set);
-
return set_ref_expr_alloc(&expr->location, set);
}
@@ -148,8 +188,38 @@ static int byteorder_conversion(struct eval_ctx *ctx, struct expr **expr,
return 0;
/* Conversion for EXPR_CONCAT is handled for single composing ranges */
- if ((*expr)->etype == EXPR_CONCAT)
+ 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) {
@@ -165,7 +235,7 @@ static int byteorder_conversion(struct eval_ctx *ctx, struct expr **expr,
byteorder_names[(*expr)->byteorder]);
}
- if (expr_is_constant(*expr) || (*expr)->len / BITS_PER_BYTE < 2)
+ if (expr_is_constant(*expr) || div_round_up((*expr)->len, BITS_PER_BYTE) < 2)
(*expr)->byteorder = byteorder;
else {
op = byteorder_conversion_op(*expr, byteorder);
@@ -186,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));
}
@@ -202,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);
@@ -219,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,
@@ -238,7 +308,7 @@ static int flowtable_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 flowtable ‘%s’ in table %s ‘%s’?",
+ "%s; did you mean flowtable '%s' in table %s '%s'?",
strerror(ENOENT), ft->handle.flowtable.name,
family2str(ft->handle.family),
table->handle.table.name);
@@ -249,7 +319,10 @@ static int flowtable_not_found(struct eval_ctx *ctx, const struct location *loc,
*/
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;
@@ -361,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 &&
@@ -369,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;
}
@@ -418,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);
@@ -441,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;
}
@@ -465,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, *rshift, *off;
unsigned masklen, len = expr->len, extra_len = 0;
+ enum byteorder byteorder;
uint8_t shift;
mpz_t bitmask;
@@ -486,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);
@@ -503,6 +603,16 @@ 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_HOST_ENDIAN,
@@ -510,7 +620,7 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
rshift = binop_expr_alloc(&expr->location, OP_RSHIFT, and, off);
rshift->dtype = expr->dtype;
- rshift->byteorder = expr->byteorder;
+ rshift->byteorder = byteorder;
rshift->len = masklen;
*exprp = rshift;
@@ -519,10 +629,13 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
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)
@@ -531,9 +644,15 @@ static int __expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp)
if (expr_evaluate_primary(ctx, exprp) < 0)
return -1;
+ ctx->ectx.key = key;
+
if (expr->exthdr.offset % BITS_PER_BYTE != 0 ||
- expr->len % BITS_PER_BYTE != 0)
- expr_evaluate_bits(ctx, exprp);
+ 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: {
@@ -577,11 +696,13 @@ 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:
case NFT_EXTHDR_OP_SCTP:
+ case NFT_EXTHDR_OP_DCCP:
return __expr_evaluate_exthdr(ctx, exprp);
case NFT_EXTHDR_OP_IPV4:
dependency = &proto_ip;
@@ -594,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);
@@ -638,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;
@@ -651,34 +775,53 @@ 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);
- rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
+ 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;
+
+ 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;
+ 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;
@@ -694,25 +837,48 @@ 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;
rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
- desc = ctx->pctx.protocol[base].desc;
+
+ 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(&ctx->pctx, base)) {
- desc = proto_ctx_find_conflict(&ctx->pctx, base, payload->payload.desc);
+ proto_ctx_is_ambiguous(pctx, base)) {
+ desc = proto_ctx_find_conflict(pctx, base, payload->payload.desc);
assert(desc);
return expr_error(ctx->msgs, payload,
@@ -727,7 +893,12 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr)
if (desc == payload->payload.desc) {
const struct proto_hdr_template *tmpl;
- payload->payload.offset += ctx->pctx.protocol[base].offset;
+ 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;
@@ -748,18 +919,19 @@ check_icmp:
/* 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 (base == PROTO_BASE_LL_HDR) {
+ err = resolve_ll_protocol_conflict(ctx, desc, payload);
if (err <= 0)
return err;
- desc = ctx->pctx.protocol[base].desc;
+ desc = pctx->protocol[base].desc;
if (desc == payload->payload.desc)
return 0;
}
return expr_error(ctx->msgs, payload,
- "conflicting protocols specified: %s vs. %s",
- ctx->pctx.protocol[base].desc->name,
+ "conflicting %s protocols specified: %s vs. %s",
+ proto_base_names[base],
+ pctx->protocol[base].desc->name,
payload->payload.desc->name);
}
@@ -771,6 +943,7 @@ 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)
@@ -782,14 +955,81 @@ static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **exprp)
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.
*/
@@ -797,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:
@@ -825,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:
@@ -836,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)
@@ -858,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;
@@ -872,7 +1116,7 @@ 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);
@@ -888,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:
@@ -914,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);
}
@@ -967,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;
}
@@ -978,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;
@@ -1030,8 +1275,8 @@ static int expr_evaluate_range(struct eval_ctx *ctx, struct expr **expr)
right = range->right;
if (mpz_cmp(left->value, right->value) > 0)
- return expr_error(ctx->msgs, range,
- "Range has zero or negative size");
+ return expr_error(ctx->msgs, range, "Range negative size");
+
datatype_set(range, left->dtype);
range->flags |= EXPR_F_CONSTANT;
return 0;
@@ -1043,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);
@@ -1067,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;
@@ -1134,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;
- if (mpz_get_uint32(right->value) >= left->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,
- "%s shift of %u bits is undefined "
- "for type of %u bits width",
+ "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 (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",
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)
@@ -1150,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);
@@ -1162,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 (ctx->stmt_len > left->len) {
+ max_len = ctx->stmt_len;
+ byteorder = BYTEORDER_HOST_ENDIAN;
+ dtype = &integer_type;
- if (byteorder_conversion(ctx, &op->right, left->byteorder) < 0)
+ /* 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);
@@ -1185,14 +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)
+ 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, ctx->ectx.len, 0);
+ left->byteorder, max_shift_len, 0);
+ }
+
if (expr_evaluate(ctx, &op->right) < 0)
return -1;
right = op->right;
@@ -1225,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)
@@ -1259,20 +1575,28 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
uint32_t type = dtype ? dtype->type : 0, ntype = 0;
int off = dtype ? dtype->subtypes : 0;
unsigned int flags = EXPR_F_CONSTANT | EXPR_F_SINGLETON;
+ 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))
@@ -1290,7 +1614,7 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
dsize = key->len;
bo = key->byteorder;
off--;
- } else if (dtype == NULL) {
+ } else if (dtype == NULL || off == 0) {
tmp = datatype_lookup(TYPE_INVALID);
} else {
tmp = concat_subtype_lookup(type, --off);
@@ -1299,19 +1623,30 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
}
__expr_set_context(&ctx->ectx, tmp, bo, dsize, 0);
+ ctx->ectx.key = i;
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 = dtype_clone(i->dtype);
+ clone = datatype_clone(i->dtype);
clone->size = i->len;
clone->byteorder = i->byteorder;
- clone->refcnt = 1;
- i->dtype = clone;
+ __datatype_set(i, clone);
}
if (dtype == NULL && i->dtype->size == 0)
@@ -1328,12 +1663,22 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
dsize_bytes = div_round_up(dsize, BITS_PER_BYTE);
(*expr)->field_len[(*expr)->field_count++] = dsize_bytes;
size += netlink_padded_len(dsize);
- if (key)
- key = list_next_entry(key, list);
+ 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));
+ __datatype_set(*expr, concat_type_alloc(ntype));
(*expr)->len = size;
if (off > 0)
@@ -1358,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);
}
@@ -1401,7 +1752,8 @@ static int __expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr *elem)
"but element has %d", num_set_exprs,
num_elem_exprs);
} else if (num_set_exprs == 0) {
- if (!(set->flags & NFT_SET_EVAL)) {
+ 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",
@@ -1431,10 +1783,9 @@ static int __expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr *elem)
static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *elem = *expr;
+ const struct expr *key;
if (ctx->set) {
- const struct expr *key;
-
if (__expr_evaluate_set_elem(ctx, elem) < 0)
return -1;
@@ -1451,9 +1802,19 @@ static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr)
switch (elem->key->etype) {
case EXPR_PREFIX:
case EXPR_RANGE:
- return expr_error(ctx->msgs, elem,
- "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(elem->key));
+ 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;
}
@@ -1462,7 +1823,13 @@ 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)
@@ -1485,6 +1852,8 @@ static int interval_set_eval(struct eval_ctx *ctx, struct set *set,
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);
@@ -1493,6 +1862,7 @@ static int interval_set_eval(struct eval_ctx *ctx, struct set *set,
}
break;
case CMD_DELETE:
+ case CMD_DESTROY:
ret = set_delete(ctx->msgs, ctx->cmd, set, init,
ctx->nft->debug_mask);
break;
@@ -1506,6 +1876,14 @@ static int interval_set_eval(struct eval_ctx *ctx, struct set *set,
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;
@@ -1571,21 +1949,6 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
if (ctx->set) {
if (ctx->set->flags & NFT_SET_CONCAT)
set->set_flags |= NFT_SET_CONCAT;
- } else if (set->size == 1) {
- i = list_first_entry(&set->expressions, struct expr, list);
- if (i->etype == EXPR_SET_ELEM) {
- switch (i->key->etype) {
- case EXPR_PREFIX:
- case EXPR_RANGE:
- case EXPR_VALUE:
- *expr = i->key;
- i->key = NULL;
- expr_free(set);
- return 0;
- default:
- break;
- }
- }
}
set->set_flags |= NFT_SET_CONSTANT;
@@ -1612,11 +1975,61 @@ static void map_set_concat_info(struct expr *map)
}
}
+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;
- const struct datatype *dtype;
+ struct expr_ctx ectx = ctx->ectx;
struct expr *key, *data;
if (map->map->etype == EXPR_CT &&
@@ -1643,6 +2056,7 @@ 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;
@@ -1657,16 +2071,29 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
ctx->ectx.len, NULL);
}
- dtype = set_datatype_alloc(ectx.dtype, ectx.byteorder);
- if (dtype->type == TYPE_VERDICT)
+ 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
+ } 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, data,
- mappings);
+ 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);
@@ -1686,9 +2113,13 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
if (binop_transfer(ctx, expr) < 0)
return -1;
- if (ctx->set->data->flags & EXPR_F_INTERVAL)
+ 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;
@@ -1705,13 +2136,16 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
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",
@@ -1769,17 +2203,14 @@ 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;
- if (set->data) {
- 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);
- } else {
- assert((set->flags & NFT_SET_MAP) == 0);
- }
+ 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;
@@ -1791,11 +2222,20 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
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;
}
@@ -2030,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;
@@ -2039,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;
@@ -2056,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)
@@ -2083,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;
}
}
@@ -2126,6 +2604,19 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
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:
@@ -2133,7 +2624,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
* Update protocol context for payload and meta iiftype
* equality expressions.
*/
- relational_expr_pctx_update(&ctx->pctx, rel);
+ relational_expr_pctx_update(pctx, rel);
/* fall through */
case OP_NEQ:
@@ -2146,7 +2637,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
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");
+ "negation can only be used with singleton bitmask values. Did you mean \"!=\"?");
}
switch (right->etype) {
@@ -2173,7 +2664,11 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr)
right = rel->right =
implicit_set_declaration(ctx, "__set%d",
expr_get(left), NULL,
- right);
+ right,
+ NFT_SET_ANONYMOUS);
+ if (!right)
+ return -1;
+
/* fall through */
case EXPR_SET_REF:
if (rel->left->etype == EXPR_CT &&
@@ -2245,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");
@@ -2316,9 +2812,10 @@ static int expr_evaluate_variable(struct eval_ctx *ctx, struct expr **exprp)
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:
@@ -2350,6 +2847,35 @@ static int expr_evaluate_flagcmp(struct eval_ctx *ctx, struct expr **exprp)
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) {
@@ -2368,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:
@@ -2384,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:
@@ -2491,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))
+
+ 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:
@@ -2512,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;
}
@@ -2530,6 +3066,25 @@ static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
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)
@@ -2540,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:
@@ -2571,14 +3130,22 @@ 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)
@@ -2591,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;
@@ -2604,6 +3176,9 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
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)) {
@@ -2623,6 +3198,11 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
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++;
@@ -2698,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)
@@ -2717,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), NULL, set);
+ expr_get(key), NULL, set, 0);
+ if (!setref)
+ return -1;
setref->set->desc.size = stmt->meter.size;
stmt->meter.set = setref;
@@ -2733,26 +3333,45 @@ 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)
{
- if (stmt_evaluate_arg(ctx, stmt,
- stmt->ct.tmpl->dtype,
- stmt->ct.tmpl->len,
- stmt->ct.tmpl->byteorder,
- &stmt->ct.expr) < 0)
+ 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;
}
@@ -2760,9 +3379,10 @@ 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,
@@ -2774,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;
@@ -2835,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;
}
@@ -2843,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;
@@ -2852,7 +3474,7 @@ 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:
@@ -2860,14 +3482,14 @@ static int stmt_evaluate_reject_inet_family(struct eval_ctx *ctx,
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:
return stmt_error(ctx, stmt,
@@ -2882,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;
@@ -2899,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):
@@ -2913,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;
@@ -2947,14 +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;
+ 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;
@@ -2968,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:
@@ -2982,7 +3609,7 @@ 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");
@@ -3006,28 +3633,29 @@ 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:
@@ -3044,14 +3672,14 @@ static int stmt_evaluate_reject_default(struct eval_ctx *ctx,
break;
case NFPROTO_BRIDGE:
case NFPROTO_NETDEV:
- 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 __constant_htons(ETH_P_IP):
@@ -3070,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;
@@ -3079,6 +3710,13 @@ 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);
@@ -3087,9 +3725,9 @@ static int stmt_evaluate_reject_icmp(struct eval_ctx *ctx, struct stmt *stmt)
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)
@@ -3106,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;
@@ -3134,13 +3772,14 @@ 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) {
@@ -3150,7 +3789,7 @@ static int nat_evaluate_family(struct eval_ctx *ctx, struct stmt *stmt)
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;
@@ -3179,7 +3818,7 @@ static const struct datatype *get_addr_dtype(uint8_t family)
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;
dtype = get_addr_dtype(pctx->family);
@@ -3232,7 +3871,14 @@ static bool nat_evaluate_addr_has_th_expr(const struct expr *map)
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;
+
+ 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))
@@ -3240,41 +3886,75 @@ static int nat_evaluate_transport(struct eval_ctx *ctx, struct stmt *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],
+ &pctx->protocol[PROTO_BASE_NETWORK_HDR],
"conflicting protocols specified: %s vs. %s. You must specify ip or ip6 family in %s statement",
- ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc->name,
+ pctx->protocol[PROTO_BASE_NETWORK_HDR].desc->name,
family2str(family),
stmt->ops->name);
return 0;
}
+static void expr_family_infer(struct proto_ctx *pctx, const struct expr *expr,
+ uint8_t *family)
+{
+ struct expr *i;
+
+ 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 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)
+ uint8_t *family, struct expr **addr)
{
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
const struct datatype *dtype;
int err;
- if (ctx->pctx.family == NFPROTO_INET) {
- dtype = get_addr_dtype(family);
- if (dtype->size == 0)
+ 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, dtype->size,
BYTEORDER_BIG_ENDIAN, addr);
@@ -3287,10 +3967,15 @@ static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt)
{
- struct proto_ctx *pctx = &ctx->pctx;
+ struct proto_ctx *pctx = eval_proto_ctx(ctx);
struct expr *one, *two, *data, *tmp;
- const struct datatype *dtype;
- int addr_type, err;
+ 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:
@@ -3300,23 +3985,30 @@ static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt)
addr_type = TYPE_IP6ADDR;
break;
default:
- return -1;
+ 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))
- return -1;
+ 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)) {
- return stmt_binary_error(ctx, stmt->nat.addr, stmt,
+ 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)
- return 0;
+ if (stmt->nat.addr->etype != EXPR_MAP) {
+ err = 0;
+ goto out;
+ }
data = stmt->nat.addr->mappings->set->data;
if (data->flags & EXPR_F_INTERVAL)
@@ -3324,36 +4016,42 @@ static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt)
datatype_set(data, dtype);
- if (expr_ops(data)->type != EXPR_CONCAT)
- return __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ 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))
- return __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ 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;
+ }
- dtype = get_addr_dtype(stmt->nat.family);
+ dtype2 = get_addr_dtype(stmt->nat.family);
tmp = one;
- err = __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ err = __stmt_evaluate_arg(ctx, stmt, dtype2, dtype2->size,
BYTEORDER_BIG_ENDIAN,
&tmp);
if (err < 0)
- return err;
+ 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)
- return err;
+ goto out;
if (tmp != two)
BUG("Internal error: Unexpected alteration of l4 expression");
+out:
+ datatype_free(dtype);
return err;
}
@@ -3379,6 +4077,12 @@ static bool nat_concat_map(struct eval_ctx *ctx, struct stmt *stmt)
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;
@@ -3416,7 +4120,7 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt)
return 0;
}
- err = stmt_evaluate_addr(ctx, stmt, stmt->nat.family,
+ err = stmt_evaluate_addr(ctx, stmt, &stmt->nat.family,
&stmt->nat.addr);
if (err < 0)
return err;
@@ -3436,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;
@@ -3451,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");
@@ -3463,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;
@@ -3515,7 +4220,7 @@ static int stmt_evaluate_chain(struct eval_ctx *ctx, struct stmt *stmt)
memset(&h, 0, sizeof(h));
handle_merge(&h, &chain->handle);
h.family = ctx->rule->handle.family;
- xfree(h.table.name);
+ 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;
@@ -3535,9 +4240,9 @@ static int stmt_evaluate_chain(struct eval_ctx *ctx, struct stmt *stmt)
struct handle h2 = {};
handle_merge(&rule->handle, &ctx->rule->handle);
- xfree(rule->handle.table.name);
+ free_const(rule->handle.table.name);
rule->handle.table.name = xstrdup(ctx->rule->handle.table.name);
- xfree(rule->handle.chain.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)
@@ -3561,9 +4266,10 @@ static int stmt_evaluate_optstrip(struct eval_ctx *ctx, struct stmt *stmt)
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)
@@ -3580,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:
@@ -3598,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,
@@ -3618,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:
@@ -3636,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:
@@ -3669,15 +4389,25 @@ static int stmt_evaluate_queue(struct eval_ctx *ctx, struct stmt *stmt)
static int stmt_evaluate_log_prefix(struct eval_ctx *ctx, struct stmt *stmt)
{
- char prefix[NF_LOG_PREFIXLEN] = {}, tmp[NF_LOG_PREFIXLEN] = {};
- int len = sizeof(prefix), offset = 0, ret;
+ char tmp[NF_LOG_PREFIXLEN] = {};
+ char prefix[NF_LOG_PREFIXLEN];
+ size_t len = sizeof(prefix);
+ size_t offset = 0;
struct expr *expr;
- size_t size = 0;
- if (stmt->log.prefix->etype != EXPR_LIST)
+ 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);
@@ -3688,13 +4418,13 @@ static int stmt_evaluate_log_prefix(struct eval_ctx *ctx, struct stmt *stmt)
expr->sym->expr->identifier);
break;
default:
- BUG("unknown expresion type %s\n", expr_name(expr));
+ BUG("unknown expression type %s\n", expr_name(expr));
break;
}
- SNPRINTF_BUFFER_SIZE(ret, size, len, offset);
+ SNPRINTF_BUFFER_SIZE(ret, &len, &offset);
}
- if (len == NF_LOG_PREFIXLEN)
+ if (len == 0)
return stmt_error(ctx, stmt, "log prefix is too long");
expr = constant_expr_alloc(&stmt->log.prefix->location, &string_type,
@@ -3742,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,
@@ -3785,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,
@@ -3810,6 +4544,9 @@ 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");
list_for_each_entry(this, &stmt->map.stmt_list, list) {
if (stmt_evaluate(ctx, this) < 0)
@@ -3846,7 +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, NULL, mappings);
+ key, NULL, mappings,
+ NFT_SET_ANONYMOUS);
+ if (!mappings)
+ return -1;
mappings->set->objtype = stmt->objref.type;
map->mappings = mappings;
@@ -3879,7 +4619,7 @@ 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",
@@ -3927,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:
@@ -3996,6 +4739,9 @@ static int setelem_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
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);
@@ -4003,10 +4749,14 @@ static int setelem_evaluate(struct eval_ctx *ctx, struct cmd *cmd)
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;
- if (set_is_interval(ctx->set->flags) &&
- !(set->flags & NFT_SET_CONCAT))
- return interval_set_eval(ctx, ctx->set, cmd->expr);
+ assert(cmd->expr->etype == EXPR_SET);
+ cmd->expr->set_flags |= NFT_SET_INTERVAL;
+ }
ctx->set = NULL;
@@ -4046,11 +4796,10 @@ static int set_expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
i->dtype->type == TYPE_INTEGER) {
struct datatype *dtype;
- dtype = dtype_clone(i->dtype);
+ dtype = datatype_clone(i->dtype);
dtype->size = i->len;
dtype->byteorder = i->byteorder;
- dtype->refcnt = 1;
- i->dtype = dtype;
+ __datatype_set(i, dtype);
}
if (i->dtype->size == 0 && i->len == 0)
@@ -4060,20 +4809,25 @@ static int set_expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr)
"expressions",
i->dtype->name);
- if (i->dtype->size)
- assert(i->len == i->dtype->size);
-
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));
+ __datatype_set(*expr, concat_type_alloc(ntype));
(*expr)->len = size;
expr_set_context(&ctx->ectx, (*expr)->dtype, (*expr)->len);
@@ -4082,6 +4836,34 @@ static int set_expr_evaluate_concat(struct eval_ctx *ctx, struct expr **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;
@@ -4090,6 +4872,12 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
struct stmt *stmt;
const char *type;
+ 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,
@@ -4100,13 +4888,19 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
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);
@@ -4128,6 +4922,21 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
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_is_datamap(set->flags)) {
if (set->data == NULL)
return set_error(ctx, set, "map definition does not "
@@ -4172,22 +4981,6 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
}
set->existing_set = existing_set;
- ctx->set = set;
- if (set->init != NULL) {
- __expr_set_context(&ctx->ectx, set->key->dtype,
- set->key->byteorder, set->key->len, 0);
- if (expr_evaluate(ctx, &set->init) < 0)
- 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))
- return interval_set_eval(ctx, ctx->set, set->init);
-
- ctx->set = NULL;
return 0;
}
@@ -4218,7 +5011,7 @@ static bool evaluate_priority(struct eval_ctx *ctx, struct prio_spec *prio,
NFT_NAME_MAXLEN);
loc = prio->expr->location;
- 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;
@@ -4293,7 +5086,7 @@ static bool evaluate_device_expr(struct eval_ctx *ctx, struct expr **dev_expr)
case EXPR_VALUE:
break;
default:
- BUG("invalid expresion type %s\n", expr_name(expr));
+ BUG("invalid expression type %s\n", expr_name(expr));
break;
}
@@ -4316,8 +5109,12 @@ static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft)
if (table == NULL)
return table_not_found(ctx);
- if (!ft_cache_find(table, ft->handle.flowtable.name))
+ 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");
+
ft_cache_add(flowtable_get(ft), table);
+ }
if (ft->hook.name) {
ft->hook.num = str2hooknum(NFPROTO_NETDEV, ft->hook.name);
@@ -4427,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;
@@ -4442,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);
@@ -4505,7 +5306,6 @@ static uint32_t str2hooknum(uint32_t family, const char *hook)
static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
{
struct table *table;
- struct rule *rule;
table = table_cache_find(&ctx->nft->cache.table_cache,
ctx->cmd->handle.table.name,
@@ -4515,7 +5315,7 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
if (chain == NULL) {
if (!chain_cache_find(table, ctx->cmd->handle.chain.name)) {
- chain = chain_alloc(NULL);
+ chain = chain_alloc();
handle_merge(&chain->handle, &ctx->cmd->handle);
chain_cache_add(chain, table);
}
@@ -4545,15 +5345,17 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
return chain_error(ctx, chain, "invalid policy expression %s",
expr_name(chain->policy));
}
+ }
+
+ 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)
- return __stmt_binary_error(ctx, &chain->loc, NULL,
- "Missing `device' in this chain definition");
-
- if (!evaluate_device_expr(ctx, &chain->dev_expr))
+ 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,
@@ -4561,11 +5363,6 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
}
}
- list_for_each_entry(rule, &chain->rules, list) {
- handle_merge(&rule->handle, &chain->handle);
- if (rule_evaluate(ctx, rule, CMD_INVALID) < 0)
- return -1;
- }
return 0;
}
@@ -4599,8 +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->timeout_str);
- xfree(ts);
+ free_const(ts->timeout_str);
+ free(ts);
}
return 0;
@@ -4633,11 +5430,6 @@ 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_cache_find(&ctx->nft->cache.table_cache,
ctx->cmd->handle.table.name,
ctx->cmd->handle.family)) {
@@ -4650,34 +5442,6 @@ static int table_evaluate(struct eval_ctx *ctx, struct table *table)
}
}
- 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;
}
@@ -4689,6 +5453,8 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *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);
@@ -4888,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);
@@ -4934,38 +5700,8 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
return 0;
case CMD_OBJ_SET:
- 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_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));
-
- return 0;
- case CMD_OBJ_METER:
- 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_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_meter(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_cache_find(&ctx->nft->cache.table_cache,
cmd->handle.table.name,
cmd->handle.family);
@@ -4976,10 +5712,13 @@ static int cmd_evaluate_list(struct eval_ctx *ctx, struct cmd *cmd)
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))
+ 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_CHAIN:
table = table_cache_find(&ctx->nft->cache.table_cache,
@@ -5029,6 +5768,8 @@ 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_cache_find(&ctx->nft->cache.table_cache,
@@ -5064,6 +5805,8 @@ 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_cache_find(&ctx->nft->cache.table_cache,
@@ -5072,6 +5815,11 @@ static int cmd_evaluate_reset(struct eval_ctx *ctx, struct cmd *cmd)
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);
}
@@ -5145,7 +5893,7 @@ static int cmd_evaluate_flush(struct eval_ctx *ctx, struct cmd *cmd)
if (set == NULL)
return set_not_found(ctx, &ctx->cmd->handle.set.location,
ctx->cmd->handle.set.name);
- else if (!set_is_meter(set->flags))
+ else if (!set_is_meter_compat(set->flags))
return cmd_error(ctx, &ctx->cmd->handle.set.location,
"%s", strerror(ENOENT));
@@ -5308,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];
@@ -5340,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 deb649e1..cb2573fe 100644
--- a/src/expression.c
+++ b/src/expression.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 <limits.h>
#include <expression.h>
@@ -29,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;
@@ -94,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)
@@ -140,8 +140,10 @@ void expr_describe(const struct expr *expr, struct output_ctx *octx)
nft_print(octx, "%s expression, datatype %s (%s)",
expr_name(expr), dtype->name, dtype->desc);
- if (dtype == &invalid_type)
+ if (dtype == &invalid_type) {
+ nft_print(octx, "\n");
return;
+ }
}
if (dtype->basetype != NULL) {
@@ -314,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 = {
@@ -879,17 +881,30 @@ static void concat_expr_print(const struct expr *expr, struct output_ctx *octx)
#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;
- struct expr *expr;
- list_for_each_entry(expr, &concat_expr->expressions, list) {
+ 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;
@@ -981,7 +996,7 @@ static struct expr *concat_expr_parse_udata(const struct nftnl_udata *attr)
goto err_free;
etype = nftnl_udata_get_u32(nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE]);
- ops = expr_ops_by_type(etype);
+ ops = expr_ops_by_type_u32(etype);
if (!ops || !ops->parse_udata)
goto err_free;
@@ -999,7 +1014,7 @@ static struct expr *concat_expr_parse_udata(const struct nftnl_udata *attr)
if (!dtype)
goto err_free;
- concat_expr->dtype = datatype_get(dtype);
+ __datatype_set(concat_expr, dtype);
concat_expr->len = len;
return concat_expr;
@@ -1322,15 +1337,14 @@ static void set_elem_expr_destroy(struct expr *expr)
{
struct stmt *stmt, *next;
- xfree(expr->comment);
+ free_const(expr->comment);
expr_free(expr->key);
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)
@@ -1338,6 +1352,12 @@ static void set_elem_expr_clone(struct expr *new, const struct expr *expr)
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 = {
.type = EXPR_SET_ELEM,
.name = "set element",
@@ -1365,11 +1385,17 @@ static void set_elem_catchall_expr_print(const struct expr *expr,
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)
@@ -1484,9 +1510,7 @@ void range_expr_value_high(mpz_t rop, const struct expr *expr)
static const struct expr_ops *__expr_ops_by_type(enum expr_types etype)
{
switch (etype) {
- case EXPR_INVALID:
- BUG("Invalid expression ops requested");
- break;
+ 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;
@@ -1518,20 +1542,23 @@ static const struct expr_ops *__expr_ops_by_type(enum expr_types etype)
case EXPR_FLAGCMP: return &flagcmp_expr_ops;
}
- BUG("Unknown expression type %d\n", etype);
+ return NULL;
}
const struct expr_ops *expr_ops(const struct expr *e)
{
- return __expr_ops_by_type(e->etype);
+ 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(uint32_t value)
+const struct expr_ops *expr_ops_by_type_u32(uint32_t value)
{
- /* value might come from unreliable source, such as "udata"
- * annotation of set keys. Avoid BUG() assertion.
- */
- if (value == EXPR_INVALID || value > EXPR_MAX)
+ if (value > EXPR_MAX)
return NULL;
return __expr_ops_by_type(value);
diff --git a/src/exthdr.c b/src/exthdr.c
index 3e5f5cd8..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>
@@ -84,6 +83,9 @@ static void exthdr_expr_print(const struct expr *expr, struct output_ctx *octx)
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", name);
@@ -177,6 +179,8 @@ static struct expr *exthdr_expr_parse_udata(const struct nftnl_udata *attr)
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;
}
@@ -206,6 +210,7 @@ static int exthdr_expr_build_udata(struct nftnl_udata_buf *udbuf,
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;
@@ -283,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,
@@ -332,14 +337,15 @@ void exthdr_init_raw(struct expr *expr, uint8_t type,
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;
@@ -398,7 +404,7 @@ bool exthdr_find_template(struct expr *expr, const struct expr *mask, unsigned i
found = tcpopt_find_template(expr, off, mask_len - mask_offset);
break;
case NFT_EXTHDR_OP_IPV6:
- exthdr_init_raw(expr, expr->exthdr.desc->type,
+ exthdr_init_raw(expr, expr->exthdr.raw_type,
off, mask_len - mask_offset, expr->exthdr.op, 0);
/* still failed to find a template... Bug. */
diff --git a/src/fib.c b/src/fib.c
index c6ad0f9c..e95271c9 100644
--- a/src/fib.c
+++ b/src/fib.c
@@ -4,17 +4,18 @@
* 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>
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 42c50407..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>
diff --git a/src/iface.c b/src/iface.c
index c0642e0c..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>
diff --git a/src/intervals.c b/src/intervals.c
index e61adc76..68728349 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -6,11 +6,15 @@
* 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];
@@ -24,6 +28,9 @@ static void setelem_expr_to_range(struct expr *expr)
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)
@@ -118,6 +125,26 @@ static bool merge_ranges(struct set_automerge_ctx *ctx,
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;
@@ -193,7 +220,7 @@ static struct expr *interval_expr_key(struct expr *i)
return elem;
}
-void set_to_range(struct expr *init)
+static void set_to_range(struct expr *init)
{
struct expr *i, *elem;
@@ -216,21 +243,13 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
struct cmd *purge_cmd;
struct handle h = {};
- if (existing_set) {
- if (existing_set->init) {
- list_splice_init(&existing_set->init->expressions,
- &init->expressions);
- } else {
- existing_set->init = set_expr_alloc(&internal_location,
- set);
- }
+ if (set->flags & NFT_SET_MAP) {
+ set_to_range(init);
+ list_expr_sort(&init->expressions);
+ return 0;
}
- set_to_range(init);
- list_expr_sort(&init->expressions);
-
- if (set->flags & NFT_SET_MAP)
- return 0;
+ set_sort_splice(init, set);
ctx.purge = set_expr_alloc(&internal_location, set);
@@ -404,8 +423,13 @@ static int setelem_delete(struct list_head *msgs, struct set *set,
list_del(&i->list);
expr_free(i);
}
- } else if (set->automerge &&
- setelem_adjust(set, purge, &prev_range, &range, prev, i) < 0) {
+ } 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;
@@ -463,7 +487,11 @@ int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set,
if (set->automerge)
automerge_delete(msgs, set, init, debug_mask);
- set_to_range(existing_set->init);
+ 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);
@@ -486,14 +514,14 @@ int set_delete(struct list_head *msgs, struct cmd *cmd, struct set *set,
if (debug_mask & NFT_DEBUG_SEGTREE) {
list_for_each_entry(i, &init->expressions, list)
- gmp_printf("remove: [%Zx-%Zx]\n",
- i->key->left->value, i->key->right->value);
+ pr_gmp_debug("remove: [%Zx-%Zx]\n",
+ i->key->left->value, i->key->right->value);
list_for_each_entry(i, &add->expressions, list)
- gmp_printf("add: [%Zx-%Zx]\n",
- i->key->left->value, i->key->right->value);
+ 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)
- gmp_printf("existing: [%Zx-%Zx]\n",
- i->key->left->value, i->key->right->value);
+ pr_gmp_debug("existing: [%Zx-%Zx]\n",
+ i->key->left->value, i->key->right->value);
}
if (list_empty(&add->expressions)) {
@@ -540,8 +568,7 @@ static int setelem_overlap(struct list_head *msgs, struct set *set,
}
if (mpz_cmp(prev_range.low, range.low) == 0 &&
- mpz_cmp(prev_range.high, range.high) == 0 &&
- (elem->flags & EXPR_F_KERNEL || prev->flags & EXPR_F_KERNEL))
+ mpz_cmp(prev_range.high, range.high) == 0)
goto next;
if (mpz_cmp(prev_range.low, range.low) <= 0 &&
@@ -589,18 +616,7 @@ int set_overlap(struct list_head *msgs, struct set *set, struct expr *init)
struct expr *i, *n, *clone;
int err;
- if (existing_set) {
- if (existing_set->init) {
- list_splice_init(&existing_set->init->expressions,
- &init->expressions);
- } else {
- existing_set->init = set_expr_alloc(&internal_location,
- set);
- }
- }
-
- set_to_range(init);
- list_expr_sort(&init->expressions);
+ set_sort_splice(init, set);
err = setelem_overlap(msgs, set, init);
@@ -700,9 +716,9 @@ int set_to_intervals(const struct set *set, struct expr *init, bool add)
if (set->key->byteorder == BYTEORDER_HOST_ENDIAN)
mpz_switch_byteorder(expr->value, set->key->len / BITS_PER_BYTE);
- newelem = set_elem_expr_alloc(&internal_location, expr);
+ newelem = set_elem_expr_alloc(&expr->location, expr);
if (i->etype == EXPR_MAPPING) {
- newelem = mapping_expr_alloc(&internal_location,
+ newelem = mapping_expr_alloc(&expr->location,
newelem,
expr_get(i->right));
}
diff --git a/src/ipopt.c b/src/ipopt.c
index 67e904ff..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>
diff --git a/src/json.c b/src/json.c
index 0b7224c2..29fbd0cf 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1,12 +1,21 @@
-#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 <stdio.h>
-#include <string.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>
@@ -61,8 +70,9 @@ 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(tok);
if (!root)
@@ -71,23 +81,64 @@ static json_t *set_dtype_json(const struct expr *key)
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->data->dtype->name;
+ datatype_ext = set_dtype_json(set->data);
} else if (set_is_objmap(set->flags)) {
type = "map";
- datatype_ext = obj_type_name(set->objtype);
+ datatype_ext = json_string(obj_type_name(set->objtype));
} else if (set_is_meter(set->flags)) {
type = "meter";
} else {
@@ -104,7 +155,7 @@ static json_t *set_print_json(struct output_ctx *octx, const struct set *set)
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) {
@@ -124,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);
@@ -141,6 +194,8 @@ 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 (!nft_output_terse(octx) && set->init && set->init->size > 0) {
json_t *array = json_array();
@@ -152,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);
}
@@ -168,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);
-
- 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 *rule_print_json(struct output_ctx *octx,
const struct rule *rule)
{
@@ -227,9 +259,8 @@ static json_t *rule_print_json(struct output_ctx *octx,
static json_t *chain_print_json(const struct chain *chain)
{
- int priority, policy, n = 0;
- struct expr *dev, *expr;
- json_t *root, *tmp;
+ 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),
@@ -237,6 +268,9 @@ 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));
@@ -248,17 +282,19 @@ static json_t *chain_print_json(const struct chain *chain)
chain->hook.num),
"prio", priority,
"policy", chain_policy2str(policy));
- if (chain->dev_expr) {
- list_for_each_entry(expr, &chain->dev_expr->expressions, list) {
- dev = expr;
- n++;
- }
- }
- if (n == 1) {
- json_object_set_new(tmp, "dev",
- json_string(dev->identifier));
+ 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);
}
@@ -268,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);
}
@@ -305,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}",
@@ -457,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;
@@ -478,6 +520,9 @@ 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);
}
@@ -535,15 +580,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);
}
@@ -713,6 +766,11 @@ json_t *exthdr_expr_json(const struct expr *expr, struct output_ctx *octx)
return json_pack("{s:o}", "tcp 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);
if (!is_exists)
json_object_set_new(root, "field", json_string(field));
@@ -1042,12 +1100,11 @@ 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);
}
@@ -1055,13 +1112,13 @@ json_t *inet_protocol_type_json(const struct expr *expr,
json_t *inet_service_type_json(const struct expr *expr, struct output_ctx *octx)
{
uint16_t port = mpz_get_be16(expr->value);
- const struct servent *s = NULL;
+ char name[NFT_SERVNAME_MAXSIZE];
if (!nft_output_service(octx) ||
- (s = getservbyport(port, NULL)) == NULL)
+ !nft_getservbyport(port, NULL, name, sizeof(name)))
return json_integer(ntohs(port));
- return json_string(s->s_name);
+ return json_string(name);
}
json_t *mark_type_json(const struct expr *expr, struct output_ctx *octx)
@@ -1439,12 +1496,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)
@@ -1584,10 +1678,23 @@ json_t *optstrip_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
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;
@@ -1597,6 +1704,11 @@ static json_t *table_print_json_full(struct netlink_ctx *ctx,
tmp = table_print_json(table);
json_array_append_new(root, tmp);
+ /* 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);
@@ -1612,15 +1724,15 @@ static json_t *table_print_json_full(struct netlink_ctx *ctx,
json_array_append_new(root, tmp);
}
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(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;
}
@@ -1714,10 +1826,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_cache_find(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));
}
@@ -1853,6 +1968,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;
diff --git a/src/libnftables.c b/src/libnftables.c
index 6a22ea09..0dee1bac 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -2,10 +2,12 @@
* 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>
@@ -14,12 +16,10 @@
#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, last_seqnum = UINT32_MAX, num_cmds = 0;
struct netlink_ctx ctx = {
@@ -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;
@@ -147,11 +154,11 @@ void nft_ctx_clear_vars(struct nft_ctx *ctx)
unsigned int i;
for (i = 0; i < ctx->num_vars; i++) {
- xfree(ctx->vars[i].key);
- xfree(ctx->vars[i].value);
+ free_const(ctx->vars[i].key);
+ free_const(ctx->vars[i].value);
}
ctx->num_vars = 0;
- xfree(ctx->vars);
+ free(ctx->vars);
}
EXPORT_SYMBOL(nft_ctx_add_include_path);
@@ -175,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);
@@ -213,8 +210,7 @@ struct nft_ctx *nft_ctx_new(uint32_t flags)
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;
}
@@ -338,8 +334,7 @@ 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);
@@ -348,9 +343,9 @@ void nft_ctx_free(struct nft_ctx *ctx)
nft_ctx_clear_vars(ctx);
nft_ctx_clear_include_paths(ctx);
scope_free(ctx->top_scope);
- xfree(ctx->state);
+ free(ctx->state);
nft_exit(ctx);
- xfree(ctx);
+ free(ctx);
}
EXPORT_SYMBOL(nft_ctx_set_output);
@@ -403,6 +398,22 @@ 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)
{
@@ -501,10 +512,15 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
{
struct nft_cache_filter *filter;
struct cmd *cmd, *next;
+ bool collapsed = false;
unsigned int flags;
+ int err = 0;
filter = nft_cache_filter_init();
- flags = nft_cache_evaluate(nft, cmds, filter);
+ 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;
@@ -512,25 +528,35 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
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) {
- if (cmd->op != CMD_ADD)
- continue;
-
- nft_cmd_expand(cmd);
- }
+ if (err < 0 || nft->state->nerrs)
+ return -1;
return 0;
}
@@ -547,7 +573,7 @@ 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,
@@ -569,7 +595,7 @@ int nft_run_cmd_from_buffer(struct nft_ctx *nft, const char *buf)
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);
@@ -588,8 +614,10 @@ err:
nft_output_json(&nft->output) &&
nft_output_echo(&nft->output))
json_print_echo(nft);
- if (rc)
+
+ if (rc || nft->check)
nft_cache_release(&nft->cache);
+
return rc;
}
@@ -634,19 +662,52 @@ retry:
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);
+ 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);
@@ -665,7 +726,7 @@ static 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);
@@ -683,20 +744,23 @@ err:
list_for_each_entry_safe(indesc, next, &nft->vars_ctx.indesc_list, list) {
if (indesc->name)
- xfree(indesc->name);
+ free_const(indesc->name);
- xfree(indesc);
+ free(indesc);
}
}
- xfree(nft->vars_ctx.buf);
+ free_const(nft->vars_ctx.buf);
if (!rc &&
nft_output_json(&nft->output) &&
nft_output_echo(&nft->output))
json_print_echo(nft);
- if (rc)
+
+ if (rc || nft->check)
nft_cache_release(&nft->cache);
+ scope_release(nft->state->scopes[0]);
+
return rc;
}
@@ -736,12 +800,12 @@ int nft_run_cmd_from_filename(struct nft_ctx *nft, const char *filename)
if (nft->optimize_flags) {
ret = nft_run_optimized_file(nft, filename);
- xfree(nft->stdin_buf);
+ free_const(nft->stdin_buf);
return ret;
}
ret = __nft_run_cmd_from_filename(nft, filename);
- xfree(nft->stdin_buf);
+ free_const(nft->stdin_buf);
return ret;
}
diff --git a/src/libnftables.map b/src/libnftables.map
index a46a3ad5..9369f44f 100644
--- a/src/libnftables.map
+++ b/src/libnftables.map
@@ -33,3 +33,8 @@ 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 9bd25db8..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>
@@ -325,6 +325,7 @@ 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;
@@ -333,23 +334,22 @@ static bool nft_options_check(int argc, char * const argv[])
} else if (skip) {
skip = false;
continue;
- } else if (argv[i][0] == '-') {
- if (nonoption) {
- nft_options_error(argc, argv, pos);
- return false;
- } else if (argv[i][1] == 'd' ||
- argv[i][1] == 'I' ||
- argv[i][1] == 'f' ||
- argv[i][1] == 'D' ||
- !strcmp(argv[i], "--debug") ||
- !strcmp(argv[i], "--includepath") ||
- !strcmp(argv[i], "--define") ||
- !strcmp(argv[i], "--file")) {
- skip = true;
- 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;
+ }
}
}
@@ -361,11 +361,11 @@ int main(int argc, char * const *argv)
const struct option *options = get_options();
bool interactive = false, define = false;
const char *optstring = get_optstring();
- char *buf = NULL, *filename = NULL;
unsigned int output_flags = 0;
+ 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())
@@ -384,20 +384,20 @@ int main(int argc, char * const *argv)
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();
- exit(EXIT_SUCCESS);
+ goto out;
case OPT_DEFINE:
if (nft_ctx_add_var(nft, optarg)) {
fprintf(stderr,
"Failed to define variable '%s'\n",
optarg);
- exit(EXIT_FAILURE);
+ goto out_fail;
}
define = true;
break;
@@ -405,9 +405,19 @@ int main(int argc, char * const *argv)
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:
@@ -415,7 +425,7 @@ 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:
@@ -450,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)
@@ -470,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:
@@ -492,18 +502,20 @@ int main(int argc, char * const *argv)
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");
- exit(EXIT_FAILURE);
+ 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(" ");
@@ -511,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]);
@@ -519,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 8e6aac5f..4d0e280f 100644
--- a/src/mergesort.c
+++ b/src/mergesort.c
@@ -2,17 +2,16 @@
* 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 void expr_msort_value(const struct expr *expr, mpz_t value);
-
static void concat_expr_msort_value(const struct expr *expr, mpz_t value)
{
unsigned int len = 0, ilen;
@@ -28,20 +27,17 @@ static void concat_expr_msort_value(const struct expr *expr, mpz_t value)
mpz_import_data(value, data, BYTEORDER_HOST_ENDIAN, len);
}
-static void expr_msort_value(const struct expr *expr, mpz_t value)
+static mpz_srcptr expr_msort_value(const struct expr *expr, mpz_t value)
{
switch (expr->etype) {
case EXPR_SET_ELEM:
- expr_msort_value(expr->key, value);
- break;
+ return expr_msort_value(expr->key, value);
case EXPR_BINOP:
case EXPR_MAPPING:
case EXPR_RANGE:
- expr_msort_value(expr->left, value);
- break;
+ return expr_msort_value(expr->left, value);
case EXPR_VALUE:
- mpz_set(value, expr->value);
- break;
+ return expr->value;
case EXPR_CONCAT:
concat_expr_msort_value(expr, value);
break;
@@ -52,25 +48,29 @@ static void expr_msort_value(const struct expr *expr, mpz_t value)
default:
BUG("Unknown expression %s\n", expr_name(expr));
}
+ return value;
}
static int expr_msort_cmp(const struct expr *e1, const struct expr *e2)
{
- mpz_t value1, value2;
+ mpz_srcptr value1;
+ mpz_srcptr value2;
+ mpz_t value1_tmp;
+ mpz_t value2_tmp;
int ret;
- mpz_init(value1);
- mpz_init(value2);
- expr_msort_value(e1, value1);
- expr_msort_value(e2, value2);
+ 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);
- mpz_clear(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;
diff --git a/src/meta.c b/src/meta.c
index 80ace25b..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, ':')) {
+ char *colon, *end;
uint32_t tmp;
- char *colon;
-
- str = xstrdup(sym->identifier);
-
- colon = strchr(str, ':');
- if (!colon)
- goto err;
-
- *colon = '\0';
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);
}
@@ -340,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)
@@ -361,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 = {
@@ -385,21 +376,22 @@ 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;
+ tstamp64 /= 1000000000L;
/* Obtain current tm, to add tm_gmtoff to the timestamp */
- cur_tm = localtime((time_t *) &tstamp);
+ tstamp = tstamp64;
+ if (localtime_r(&tstamp, &tm))
+ tstamp64 += tm.tm_gmtoff;
- if (cur_tm)
- tstamp += cur_tm->tm_gmtoff;
-
- if ((tm = gmtime((time_t *) &tstamp)) != NULL &&
- strftime(timestr, sizeof(timestr) - 1, "%F %T", tm))
+ 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");
@@ -407,16 +399,17 @@ static void date_type_print(const struct expr *expr, struct output_ctx *octx)
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 false;
@@ -429,14 +422,15 @@ 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 */
- *tstamp = ts - cur_tm->tm_gmtoff;
+ *tstamp = ts - cur_tm.tm_gmtoff;
return true;
}
@@ -491,16 +485,21 @@ static void day_type_print(const struct expr *expr, struct output_ctx *octx)
static void hour_type_print(const struct expr *expr, struct output_ctx *octx)
{
uint32_t seconds = mpz_get_uint32(expr->value), minutes, hours;
- struct tm *cur_tm;
+ struct tm cur_tm;
time_t ts;
/* Obtain current tm, so that we can add tm_gmtoff */
ts = time(NULL);
- cur_tm = localtime(&ts);
+ if (ts != ((time_t) -1) && localtime_r(&ts, &cur_tm)) {
+ int32_t adj = seconds + cur_tm.tm_gmtoff;
- if (cur_tm)
- seconds = (seconds + cur_tm->tm_gmtoff) % SECONDS_PER_DAY;
+ if (adj < 0)
+ adj += SECONDS_PER_DAY;
+ else if (adj >= SECONDS_PER_DAY)
+ adj -= SECONDS_PER_DAY;
+ seconds = adj;
+ }
minutes = seconds / 60;
seconds %= 60;
hours = minutes / 60;
@@ -517,10 +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;
+ 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));
@@ -534,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')
@@ -698,6 +702,8 @@ const struct meta_template meta_templates[] = {
[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)
@@ -717,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)
@@ -734,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;
}
/**
@@ -768,6 +779,11 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
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;
@@ -807,13 +823,19 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx,
}
#define NFTNL_UDATA_META_KEY 0
-#define NFTNL_UDATA_META_MAX 1
+#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;
}
@@ -825,6 +847,7 @@ static int meta_parse_udata(const struct nftnl_udata *attr, void *data)
switch (type) {
case NFTNL_UDATA_META_KEY:
+ case NFTNL_UDATA_META_INNER_DESC:
if (len != sizeof(uint32_t))
return -1;
break;
@@ -839,6 +862,8 @@ static int meta_parse_udata(const struct nftnl_udata *attr, void *data)
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;
@@ -852,7 +877,14 @@ static struct expr *meta_expr_parse_udata(const struct nftnl_udata *attr)
key = nftnl_udata_get_u32(ud[NFTNL_UDATA_META_KEY]);
- return meta_expr_alloc(&internal_location, 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 = {
@@ -901,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);
}
@@ -931,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;
}
@@ -960,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))
@@ -987,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;
@@ -997,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 7dd77be1..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>
@@ -26,13 +28,12 @@
#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 <stdlib.h>
#include <utils.h>
#include <nftables.h>
#include <linux/netfilter.h>
@@ -241,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;
@@ -259,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;
@@ -408,7 +416,7 @@ int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
.nl_ctx = ctx,
};
- mnl_set_sndbuffer(ctx->nft->nf_sock, ctx->batch);
+ mnl_set_sndbuffer(ctx);
mnl_nft_batch_to_msg(ctx, &msg, &snl, iov, iov_len);
@@ -592,6 +600,7 @@ int mnl_nft_rule_replace(struct netlink_ctx *ctx, struct cmd *cmd)
int mnl_nft_rule_del(struct netlink_ctx *ctx, struct cmd *cmd)
{
+ enum nf_tables_msg_types msg_type = NFT_MSG_DELRULE;
struct handle *h = &cmd->handle;
struct nftnl_rule *nlr;
struct nlmsghdr *nlh;
@@ -602,8 +611,11 @@ int mnl_nft_rule_del(struct netlink_ctx *ctx, struct cmd *cmd)
nftnl_rule_set_u32(nlr, NFTNL_RULE_FAMILY, h->family);
+ 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);
@@ -654,13 +666,21 @@ err_free:
}
struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
- const char *table, const char *chain)
+ 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();
@@ -670,14 +690,16 @@ struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx, int family,
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);
@@ -696,18 +718,98 @@ err:
/*
* Chain
*/
+
+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;
- int priority, policy, i = 0;
struct nftnl_chain *nlc;
- unsigned int ifname_len;
- const char **dev_array;
- char ifname[IFNAMSIZ];
struct nlmsghdr *nlh;
- struct expr *expr;
- int dev_array_len;
+ int priority, policy;
nlc = nftnl_chain_alloc();
if (nlc == NULL)
@@ -720,46 +822,6 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FLAGS,
CHAIN_F_HW_OFFLOAD);
}
- if (cmd->chain->flags & CHAIN_F_BASECHAIN) {
- nftnl_chain_set_u32(nlc, NFTNL_CHAIN_HOOKNUM,
- cmd->chain->hook.num);
- 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.str);
- }
- if (cmd->chain->dev_expr) {
- dev_array = xmalloc(sizeof(char *) * 8);
- dev_array_len = 8;
- list_for_each_entry(expr, &cmd->chain->dev_expr->expressions, list) {
- 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++] = xstrdup(ifname);
- if (i == dev_array_len) {
- dev_array_len *= 2;
- dev_array = xrealloc(dev_array,
- dev_array_len * sizeof(char *));
- }
- }
-
- dev_array[i] = NULL;
- if (i == 1)
- nftnl_chain_set_str(nlc, NFTNL_CHAIN_DEV, dev_array[0]);
- else if (i > 1)
- nftnl_chain_set_data(nlc, NFTNL_CHAIN_DEVICES, dev_array,
- sizeof(char *) * dev_array_len);
-
- i = 0;
- while (dev_array[i] != NULL)
- xfree(dev_array[i++]);
-
- xfree(dev_array);
- }
if (cmd->chain->comment) {
udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
if (!udbuf)
@@ -794,12 +856,6 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FLAGS, cmd->chain->flags);
}
- if (cmd->chain && cmd->chain->flags & CHAIN_F_BASECHAIN) {
- nftnl_chain_unset(nlc, NFTNL_CHAIN_TYPE);
- cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->chain->type.loc);
- mnl_attr_put_strz(nlh, NFTA_CHAIN_TYPE, cmd->chain->type.str);
- }
-
if (cmd->chain && cmd->chain->policy) {
mpz_export_data(&policy, cmd->chain->policy->value,
BYTEORDER_HOST_ENDIAN, sizeof(int));
@@ -807,7 +863,33 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
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);
@@ -847,6 +929,7 @@ int mnl_nft_chain_rename(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;
@@ -856,8 +939,11 @@ int mnl_nft_chain_del(struct netlink_ctx *ctx, struct cmd *cmd)
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FAMILY, cmd->handle.family);
+ 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);
@@ -872,6 +958,15 @@ int mnl_nft_chain_del(struct netlink_ctx *ctx, struct cmd *cmd)
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);
@@ -992,6 +1087,7 @@ int mnl_nft_table_add(struct netlink_ctx *ctx, 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;
@@ -1001,10 +1097,11 @@ int mnl_nft_table_del(struct netlink_ctx *ctx, struct cmd *cmd)
nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, cmd->handle.family);
- 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);
@@ -1238,6 +1335,7 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, 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;
@@ -1248,8 +1346,11 @@ int mnl_nft_set_del(struct netlink_ctx *ctx, struct cmd *cmd)
nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
+ 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);
@@ -1453,6 +1554,7 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, struct cmd *cmd,
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;
@@ -1463,8 +1565,11 @@ int mnl_nft_obj_del(struct netlink_ctx *ctx, struct cmd *cmd, int type)
nftnl_obj_set_u32(nlo, NFTNL_OBJ_FAMILY, cmd->handle.family);
nftnl_obj_set_u32(nlo, NFTNL_OBJ_TYPE, type);
+ 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);
@@ -1609,9 +1714,9 @@ static void netlink_dump_setelem_done(struct netlink_ctx *ctx)
fprintf(fp, "\n");
}
-static int mnl_nft_setelem_batch(const struct nftnl_set *nls,
+static int mnl_nft_setelem_batch(const struct nftnl_set *nls, struct cmd *cmd,
struct nftnl_batch *batch,
- enum nf_tables_msg_types cmd,
+ enum nf_tables_msg_types msg_type,
unsigned int flags, uint32_t seqnum,
const struct expr *set,
struct netlink_ctx *ctx)
@@ -1622,14 +1727,14 @@ static int mnl_nft_setelem_batch(const struct nftnl_set *nls,
struct expr *expr = NULL;
int i = 0;
- if (cmd == NFT_MSG_NEWSETELEM)
+ if (msg_type == NFT_MSG_NEWSETELEM)
flags |= NLM_F_CREATE;
if (set)
expr = list_first_entry(&set->expressions, struct expr, list);
next:
- nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch), cmd,
+ nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch), msg_type,
nftnl_set_get_u32(nls, NFTNL_SET_FAMILY),
flags, seqnum);
@@ -1653,7 +1758,12 @@ next:
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);
- nest2 = nftnl_set_elem_nlmsg_build(nlh, nlse, ++i);
+
+ 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)) {
@@ -1669,8 +1779,9 @@ next:
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;
@@ -1691,7 +1802,7 @@ int mnl_nft_setelem_add(struct netlink_ctx *ctx, const struct set *set,
netlink_dump_set(nls, ctx);
- err = mnl_nft_setelem_batch(nls, ctx->batch, NFT_MSG_NEWSETELEM,
+ err = mnl_nft_setelem_batch(nls, cmd, ctx->batch, NFT_MSG_NEWSETELEM,
flags, ctx->seqnum, expr, ctx);
nftnl_set_free(nls);
@@ -1728,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 handle *h,
- const struct expr *init)
+int mnl_nft_setelem_del(struct netlink_ctx *ctx, struct cmd *cmd,
+ const struct handle *h, const struct expr *init)
{
+ enum nf_tables_msg_types msg_type = NFT_MSG_DELSETELEM;
struct nftnl_set *nls;
int err;
@@ -1747,7 +1859,10 @@ int mnl_nft_setelem_del(struct netlink_ctx *ctx, const struct handle *h,
netlink_dump_set(nls, ctx);
- err = mnl_nft_setelem_batch(nls, ctx->batch, NFT_MSG_DELSETELEM, 0,
+ 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);
@@ -1755,14 +1870,21 @@ int mnl_nft_setelem_del(struct netlink_ctx *ctx, const struct handle *h,
}
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);
@@ -1785,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;
+
+ if (reset)
+ msg_type = NFT_MSG_GETSETELEM_RESET;
+ else
+ msg_type = NFT_MSG_GETSETELEM;
- nlh = nftnl_nlmsg_build_hdr(buf, 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);
@@ -1861,48 +1990,30 @@ err:
return NULL;
}
-static const char **nft_flowtable_dev_array(struct cmd *cmd)
+static void mnl_nft_ft_devs_build(struct nlmsghdr *nlh, struct cmd *cmd)
{
- unsigned int ifname_len;
- const char **dev_array;
- char ifname[IFNAMSIZ];
- int i = 0, len = 1;
- struct expr *expr;
+ const struct expr *dev_expr = cmd->flowtable->dev_expr;
+ const struct nft_dev *dev_array;
+ struct nlattr *nest_dev;
+ int i, num_devs= 0;
- list_for_each_entry(expr, &cmd->flowtable->dev_expr->expressions, list)
- len++;
-
- dev_array = xmalloc(sizeof(char *) * len);
-
- list_for_each_entry(expr, &cmd->flowtable->dev_expr->expressions, list) {
- 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++] = xstrdup(ifname);
+ 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);
}
- dev_array[i] = NULL;
-
- return dev_array;
-}
-
-static void nft_flowtable_dev_array_free(const char **dev_array)
-{
- int i = 0;
-
- while (dev_array[i] != NULL)
- xfree(dev_array[i++]);
-
- free(dev_array);
+ 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;
struct nlmsghdr *nlh;
+ struct nlattr *nest;
int priority;
flo = nftnl_flowtable_alloc();
@@ -1912,24 +2023,6 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
cmd->handle.family);
- if (cmd->flowtable->hook.name) {
- nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM,
- cmd->flowtable->hook.num);
- mpz_export_data(&priority, cmd->flowtable->priority.expr->value,
- BYTEORDER_HOST_ENDIAN, sizeof(int));
- nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, priority);
- } else {
- nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM, 0);
- nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, 0);
- }
-
- if (cmd->flowtable->dev_expr) {
- dev_array = nft_flowtable_dev_array(cmd);
- nftnl_flowtable_set_data(flo, NFTNL_FLOWTABLE_DEVICES,
- dev_array, 0);
- nft_flowtable_dev_array_free(dev_array);
- }
-
nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FLAGS,
cmd->flowtable->flags);
@@ -1945,6 +2038,21 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
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);
@@ -1954,9 +2062,10 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, 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;
- const char **dev_array;
struct nlmsghdr *nlh;
+ struct nlattr *nest;
flo = nftnl_flowtable_alloc();
if (!flo)
@@ -1965,18 +2074,11 @@ int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd)
nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
cmd->handle.family);
- if (cmd->flowtable && cmd->flowtable->dev_expr) {
- nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM, 0);
- nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, 0);
-
- dev_array = nft_flowtable_dev_array(cmd);
- nftnl_flowtable_set_data(flo, NFTNL_FLOWTABLE_DEVICES,
- dev_array, 0);
- nft_flowtable_dev_array_free(dev_array);
- }
+ 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);
@@ -1994,6 +2096,14 @@ int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd)
}
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);
@@ -2065,11 +2175,11 @@ static struct basehook *basehook_alloc(void)
static void basehook_free(struct basehook *b)
{
list_del(&b->list);
- xfree(b->module_name);
- xfree(b->hookfn);
- xfree(b->chain);
- xfree(b->table);
- xfree(b);
+ 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)
@@ -2177,6 +2287,27 @@ static int dump_nf_attr_chain_cb(const struct nlattr *attr, void *data)
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;
@@ -2211,16 +2342,23 @@ static int dump_nf_hooks(const struct nlmsghdr *nlh, void *_data)
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)
+ 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)
+ 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]);
@@ -2229,6 +2367,23 @@ static int dump_nf_hooks(const struct nlmsghdr *nlh, void *_data)
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])
@@ -2350,6 +2505,8 @@ static void print_hooks(struct netlink_ctx *ctx, int family, struct list_head *h
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);
}
diff --git a/src/monitor.c b/src/monitor.c
index 7fa92ebf..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>
@@ -272,10 +272,13 @@ 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");
@@ -387,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;
}
@@ -428,11 +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);
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)
@@ -551,6 +562,10 @@ 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, nlh->nlmsg_flags);
@@ -587,6 +602,7 @@ static int netlink_events_rule_cb(const struct nlmsghdr *nlh, int type,
break;
}
rule_free(r);
+out_free_nlr:
nftnl_rule_free(nlr);
return MNL_CB_OK;
}
@@ -638,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);
diff --git a/src/netlink.c b/src/netlink.c
index 89d864ed..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>
@@ -96,9 +96,10 @@ struct nftnl_expr *alloc_nft_expr(const char *name)
return nle;
}
-
-void __netlink_gen_data(const struct expr *expr,
- struct nft_data_linearize *data, bool expand);
+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);
struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
const struct expr *expr)
@@ -133,16 +134,23 @@ struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
case EXPR_SET_ELEM_CATCHALL:
break;
default:
- __netlink_gen_data(key, &nld, false);
- nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_KEY, &nld.value, nld.len);
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_data(key, &nld, false);
+ 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;
}
@@ -246,22 +254,38 @@ static int netlink_export_pad(unsigned char *data, const mpz_t v,
return netlink_padded_len(i->len) / BITS_PER_BYTE;
}
-static int netlink_gen_concat_data_expr(int end, const struct expr *i,
- unsigned char *data)
+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:
- i = end ? i->right : i->left;
+ 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 (end) {
+ 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)
- mpz_switch_byteorder(v, i->len / BITS_PER_BYTE);
+ byteorder_switch_expr_value(v, i);
mpz_add(v, i->prefix->value, v);
count = netlink_export_pad(data, v, i);
@@ -270,6 +294,16 @@ static int netlink_gen_concat_data_expr(int end, const struct expr *i,
}
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);
@@ -278,21 +312,57 @@ static int netlink_gen_concat_data_expr(int end, const struct expr *i,
return netlink_export_pad(data, i->value, i);
}
-static void __netlink_gen_concat(const struct expr *expr,
- struct nft_data_linearize *nld)
+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;
- int end = expr->flags & EXPR_F_INTERVAL_END;
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(end, i, data + offset);
+ offset += __netlink_gen_concat_key(expr->flags, i, data + offset);
- memcpy(nld->value, data, len);
- nld->len = len;
+ 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,
@@ -305,18 +375,31 @@ static void __netlink_gen_concat_expand(const struct expr *expr,
memset(data, 0, len);
list_for_each_entry(i, &expr->expressions, list)
- offset += netlink_gen_concat_data_expr(false, i, data + offset);
+ offset += __netlink_gen_concat_data(false, i, data + offset);
list_for_each_entry(i, &expr->expressions, list)
- offset += netlink_gen_concat_data_expr(true, i, data + offset);
+ offset += __netlink_gen_concat_data(true, i, data + offset);
- memcpy(nld->value, data, len);
- nld->len = len;
+ 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)
+ struct nft_data_linearize *nld, bool expand)
{
if (expand)
__netlink_gen_concat_expand(expr, nld);
@@ -381,30 +464,48 @@ static void netlink_gen_range(const struct expr *expr,
memset(data, 0, len);
offset = netlink_export_pad(data, expr->left->value, expr->left);
netlink_export_pad(data + offset, expr->right->value, expr->right);
- memcpy(nld->value, data, len);
- nld->len = len;
+ nft_data_memcpy(nld, data, len);
}
static void netlink_gen_prefix(const struct expr *expr,
struct nft_data_linearize *nld)
{
- unsigned int len = div_round_up(expr->len, BITS_PER_BYTE) * 2;
- unsigned char data[len];
+ 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(data))
+ BUG("Value export of %u bytes would overflow", len);
+
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);
- memcpy(nld->value, data, len);
- nld->len = len;
+ 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, bool expand)
+static void __netlink_gen_data(const struct expr *expr,
+ struct nft_data_linearize *data, bool expand)
{
switch (expr->etype) {
case EXPR_VALUE:
@@ -529,18 +630,20 @@ static int qsort_device_cmp(const void *a, const void *b)
struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
const struct nftnl_chain *nlc)
{
- const struct nftnl_udata *ud[NFTNL_UDATA_OBJ_MAX + 1] = {};
+ const struct nftnl_udata *ud[NFTNL_UDATA_CHAIN_MAX + 1] = {};
int priority, policy, len = 0, i;
const char * const *dev_array;
struct chain *chain;
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))
@@ -707,13 +810,17 @@ enum nft_data_types dtype_map_to_kernel(const struct datatype *dtype)
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);
}
}
@@ -783,8 +890,8 @@ 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;
- enum expr_types etype;
struct expr *expr;
+ uint32_t etype;
int err;
if (!attr)
@@ -800,7 +907,9 @@ static struct expr *set_make_key(const struct nftnl_udata *attr)
return NULL;
etype = nftnl_udata_get_u32(ud[NFTNL_UDATA_SET_TYPEOF_EXPR]);
- ops = expr_ops_by_type(etype);
+ ops = expr_ops_by_type_u32(etype);
+ if (!ops)
+ return NULL;
expr = ops->parse_udata(ud[NFTNL_UDATA_SET_TYPEOF_DATA]);
if (!expr)
@@ -842,21 +951,21 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
const struct nftnl_udata *ud[NFTNL_UDATA_SET_MAX + 1] = {};
enum byteorder keybyteorder = BYTEORDER_INVALID;
enum byteorder databyteorder = BYTEORDER_INVALID;
- const struct datatype *keytype, *datatype = NULL;
- struct expr *typeof_expr_key, *typeof_expr_data;
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;
- const struct datatype *dtype;
uint32_t data_interval = 0;
bool automerge = false;
struct set *set;
uint32_t ulen;
uint32_t klen;
- typeof_expr_key = NULL;
- typeof_expr_data = NULL;
-
if (nftnl_set_is_set(nls, NFTNL_SET_USERDATA)) {
udata = nftnl_set_get_data(nls, NFTNL_SET_USERDATA, &ulen);
if (nftnl_udata_parse(udata, ulen, set_parse_udata_cb, ud) < 0) {
@@ -899,8 +1008,8 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
netlink_io_error(ctx, NULL,
"Unknown data type in set key %u",
data);
- datatype_free(keytype);
- return NULL;
+ set = NULL;
+ goto out;
}
}
@@ -935,17 +1044,28 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
}
list_splice_tail(&set_parse_ctx.stmt_list, &set->stmt_list);
+ set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
+
if (datatype) {
- dtype = set_datatype_alloc(datatype, databyteorder);
+ uint32_t dlen;
+
+ dtype2 = set_datatype_alloc(datatype, databyteorder);
klen = nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN) * BITS_PER_BYTE;
- if (set_udata_key_valid(typeof_expr_data, klen)) {
- datatype_free(datatype_get(dtype));
+ 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 {
- expr_free(typeof_expr_data);
set->data = constant_expr_alloc(&netlink_location,
- dtype,
+ dtype2,
databyteorder, klen,
NULL);
@@ -956,29 +1076,21 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
if (data_interval)
set->data->flags |= EXPR_F_INTERVAL;
-
- if (dtype != datatype)
- datatype_free(datatype);
}
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)) {
- datatype_free(datatype_get(dtype));
set->key = typeof_expr_key;
+ typeof_expr_key = NULL;
set->key_typeof_valid = true;
} else {
- expr_free(typeof_expr_key);
set->key = constant_expr_alloc(&netlink_location, dtype,
keybyteorder, klen,
NULL);
}
- if (dtype != keytype)
- datatype_free(keytype);
-
- set->flags = nftnl_set_get_u32(nls, NFTNL_SET_FLAGS);
set->handle.handle.id = nftnl_set_get_u64(nls, NFTNL_SET_HANDLE);
set->objtype = objtype;
@@ -1005,6 +1117,13 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
}
}
+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;
}
@@ -1109,34 +1228,40 @@ static struct expr *netlink_parse_interval_elem(const struct set *set,
return range_expr_to_prefix(range);
}
-static struct expr *concat_elem_expr(struct expr *key,
+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;
+ unsigned int sub_length;
struct expr *expr;
if (key) {
(*off)--;
- expr = constant_expr_splice(data, key->len);
+ 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));
- expr = constant_expr_splice(data, subtype->size);
+ 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->byteorder == BYTEORDER_HOST_ENDIAN)
+ 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(expr->len);
+ data->len -= netlink_padding_len(sub_length);
return expr;
}
@@ -1153,7 +1278,7 @@ static struct expr *netlink_parse_concat_elem_key(const struct set *set,
concat = concat_expr_alloc(&data->location);
while (off > 0) {
- expr = concat_elem_expr(n, dtype, data, &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);
@@ -1176,7 +1301,7 @@ static struct expr *netlink_parse_concat_elem(const struct set *set,
concat = concat_expr_alloc(&data->location);
while (off > 0) {
- expr = concat_elem_expr(NULL, dtype, data, &off);
+ expr = concat_elem_expr(set, NULL, dtype, data, &off);
list_add_tail(&expr->list, &expressions);
}
@@ -1188,7 +1313,7 @@ static struct expr *netlink_parse_concat_elem(const struct set *set,
while (off > 0) {
left = list_first_entry(&expressions, struct expr, list);
- expr = concat_elem_expr(NULL, dtype, data, &off);
+ expr = concat_elem_expr(set, NULL, dtype, data, &off);
list_del(&left->list);
range = range_expr_alloc(&data->location, left, expr);
@@ -1416,7 +1541,7 @@ static int list_setelements(struct nftnl_set *s, struct netlink_ctx *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;
@@ -1431,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)
@@ -1459,7 +1584,7 @@ int netlink_list_setelems(struct netlink_ctx *ctx, const struct handle *h,
int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h,
const struct location *loc, struct set *cache_set,
- struct set *set, struct expr *init)
+ struct set *set, struct expr *init, bool reset)
{
struct nftnl_set *nls, *nls_out = NULL;
int err = 0;
@@ -1478,7 +1603,7 @@ 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);
+ nls_out = mnl_nft_setelem_get_one(ctx, nls, reset);
if (!nls_out) {
nftnl_set_free(nls);
return -1;
@@ -1673,6 +1798,55 @@ int netlink_reset_objs(struct netlink_ctx *ctx, const struct cmd *cmd,
return err;
}
+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)
@@ -1696,7 +1870,8 @@ netlink_delinearize_flowtable(struct netlink_ctx *ctx,
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]);
@@ -1991,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)) {
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 068c3bba..5a4cf1b8 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -9,9 +9,8 @@
* 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>
@@ -30,6 +29,16 @@
#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);
@@ -72,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;
}
@@ -200,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;
@@ -478,7 +487,7 @@ static struct expr *netlink_parse_bitwise_bool(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 {
@@ -526,7 +535,7 @@ static struct expr *netlink_parse_bitwise_shift(struct netlink_parse_ctx *ctx,
right->byteorder = BYTEORDER_HOST_ENDIAN;
expr = binop_expr_alloc(loc, op, left, right);
- expr->len = left->len;
+ expr->len = nftnl_expr_get_u32(nle, NFTNL_EXPR_BITWISE_LEN) * BITS_PER_BYTE;
return expr;
}
@@ -612,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;
@@ -619,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)
@@ -778,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);
}
@@ -831,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;
}
@@ -978,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)
@@ -1630,6 +1732,8 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
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);
@@ -1659,6 +1763,14 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
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) {
@@ -1771,6 +1883,7 @@ static const struct expr_handler netlink_parsers[] = {
{ .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 },
@@ -1779,6 +1892,7 @@ static const struct expr_handler netlink_parsers[] = {
{ .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 },
@@ -1867,6 +1981,37 @@ struct stmt *netlink_parse_set_expr(const struct set *set,
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,
@@ -1875,11 +2020,12 @@ 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;
+ 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);
@@ -1894,7 +2040,7 @@ static void payload_match_expand(struct rule_pp_ctx *ctx,
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);
@@ -1903,17 +2049,31 @@ static void payload_match_expand(struct rule_pp_ctx *ctx,
assert(left->payload.base);
assert(base == left->payload.base);
- if (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.
*/
- payload_dependency_kill(&ctx->pdctx, nexpr->left,
- ctx->pctx.family);
+ payload_dependency_kill(&dl->pdctx, nexpr->left,
+ dl->pctx.family);
if (expr->op == OP_EQ && left->flags & EXPR_F_PROTOCOL)
- payload_dependency_store(&ctx->pdctx, nstmt, base);
+ payload_dependency_store(&dl->pdctx, nstmt, base);
}
list_del(&ctx->stmt->list);
stmt_free(ctx->stmt);
@@ -1922,6 +2082,7 @@ static void payload_match_expand(struct rule_pp_ctx *ctx,
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;
@@ -1936,10 +2097,10 @@ static void payload_icmp_check(struct rule_pp_ctx *rctx, struct expr *expr, cons
/* 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 || rctx->pctx.th_dep.icmp.type)
+ if (expr->len != 8 || value->len != 8 || dl->pctx.th_dep.icmp.type)
return;
- desc = rctx->pctx.protocol[expr->payload.base].desc;
+ desc = dl->pctx.protocol[expr->payload.base].desc;
if (desc == NULL)
return;
@@ -1967,7 +2128,7 @@ static void payload_icmp_check(struct rule_pp_ctx *rctx, struct expr *expr, cons
expr->payload.desc = desc;
expr->payload.tmpl = tmpl;
- rctx->pctx.th_dep.icmp.type = icmp_type;
+ dl->pctx.th_dep.icmp.type = icmp_type;
return;
}
}
@@ -1976,10 +2137,7 @@ 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:
@@ -2004,10 +2162,10 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx,
}
/* 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;
}
}
@@ -2115,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;
@@ -2128,16 +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(&ctx->pdctx, base) &&
- meta_may_dependency_kill(&ctx->pdctx,
- ctx->pctx.family, expr))
- payload_dependency_release(&ctx->pdctx, base);
+ if (payload_dependency_exists(&dl->pdctx, base) &&
+ meta_may_dependency_kill(&dl->pdctx,
+ dl->pctx.family, expr))
+ payload_dependency_release(&dl->pdctx, base);
if (left->flags & EXPR_F_PROTOCOL)
- payload_dependency_store(&ctx->pdctx, ctx->stmt, base);
+ payload_dependency_store(&dl->pdctx, ctx->stmt, base);
}
break;
default:
@@ -2232,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:
@@ -2259,18 +2421,20 @@ static void binop_adjust(const struct expr *binop, struct expr *right,
}
}
-static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr,
- struct expr **expr_binop)
+static void __binop_postprocess(struct rule_pp_ctx *ctx,
+ struct expr *expr,
+ struct expr *left,
+ struct expr *mask,
+ struct expr **expr_binop)
{
+ struct dl_proto_ctx *dl = dl_proto_ctx(ctx);
struct expr *binop = *expr_binop;
- struct expr *left = binop->left;
- struct expr *mask = binop->right;
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;
@@ -2300,15 +2464,26 @@ static void binop_postprocess(struct rule_pp_ctx *ctx, struct expr *expr,
assert(binop->left == left);
*expr_binop = expr_get(left);
- expr_free(binop);
if (left->etype == EXPR_PAYLOAD)
payload_match_postprocess(ctx, expr, left);
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->map;
@@ -2342,56 +2517,29 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx,
if (binop->op == OP_AND && (expr->op == OP_NEQ || expr->op == OP_EQ) &&
right->dtype->basetype &&
- right->dtype->basetype->type == TYPE_BITMASK) {
- switch (right->etype) {
- case EXPR_VALUE:
- if (!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(right);
-
- expr->left = expr_get(binop->left);
- expr->right = binop_tree_to_list(NULL, binop->right);
- 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->right->etype == EXPR_VALUE &&
- right->etype == EXPR_VALUE &&
- !mpz_cmp(right->value, binop->right->value)) {
- /* Skip flag / flag representation for:
- * data & flag == flag
- * data & flag != flag
- */
- ;
- } else {
- *exprp = flagcmp_expr_alloc(&expr->location, expr->op,
- expr_get(binop->left),
- binop_tree_to_list(NULL, binop->right),
- expr_get(right));
- expr_free(expr);
- }
+ 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(right);
+
+ expr->left = expr_get(binop->left);
+ expr->right = binop_tree_to_list(NULL, binop->right);
+ switch (expr->op) {
+ case OP_NEQ:
+ expr->op = OP_IMPLICIT;
break;
- case EXPR_BINOP:
- *exprp = flagcmp_expr_alloc(&expr->location, expr->op,
- expr_get(binop->left),
- binop_tree_to_list(NULL, binop->right),
- binop_tree_to_list(NULL, right));
- expr_free(expr);
+ case OP_EQ:
+ expr->op = OP_NEG;
break;
default:
- break;
+ BUG("unknown operation type %d\n", expr->op);
}
+ expr_free(binop);
} else if (binop->left->dtype->flags & DTYPE_F_PREFIX &&
binop->op == OP_AND && expr->right->etype == EXPR_VALUE &&
expr_mask_is_prefix(binop->right)) {
@@ -2444,6 +2592,42 @@ static void relational_binop_postprocess(struct rule_pp_ctx *ctx,
}
}
+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)
@@ -2509,8 +2693,54 @@ static struct expr *expr_postprocess_string(struct expr *expr)
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;
switch (expr->etype) {
@@ -2534,28 +2764,17 @@ 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);
switch (expr->op) {
case OP_LSHIFT:
@@ -2563,20 +2782,93 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
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:
- expr_set_type(expr->right, expr->left->dtype,
- expr->left->byteorder);
+ 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) {
+ if (expr->op == OP_NEQ) {
+ range_expr_swap_values(range);
+ expr->op = OP_IMPLICIT;
+ } else if (expr->op == OP_IMPLICIT) {
+ range_expr_swap_values(range);
+ expr->op = OP_NEG;
+ }
+ }
+ }
+ /* fallthrough */
default:
expr_postprocess(ctx, &expr->left);
break;
@@ -2600,22 +2892,18 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
}
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);
@@ -2625,10 +2913,12 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
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:
@@ -2645,7 +2935,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));
@@ -2654,27 +2944,28 @@ 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;
+ stmt->reject.family = dl->pctx.family;
datatype_set(stmt->reject.expr, &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;
+ stmt->reject.family = dl->pctx.family;
datatype_set(stmt->reject.expr, &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:
@@ -2690,8 +2981,8 @@ 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 NFPROTO_IPV4: /* INET */
@@ -2708,8 +2999,8 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx)
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:
@@ -2753,23 +3044,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);
@@ -2778,26 +3070,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)) {
+ if (payload_expr_trim(payload, mask, &dl->pctx, &shift)) {
binop_adjust(binop, mask, shift);
- payload_expr_complete(payload, &ctx->pctx);
+ payload_expr_complete(payload, &dl->pctx);
expr_set_type(mask, payload->dtype,
payload->byteorder);
}
@@ -2952,17 +3246,19 @@ 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);
}
@@ -2999,19 +3295,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 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:
@@ -3042,16 +3394,14 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
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;
@@ -3089,9 +3439,9 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r
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);
}
}
@@ -3157,7 +3507,10 @@ struct rule *netlink_delinearize_rule(struct netlink_ctx *ctx,
pctx->rule = rule_alloc(&netlink_location, &h);
pctx->table = table_cache_find(&ctx->nft->cache.table_cache,
h.table.name, h.family);
- assert(pctx->table != NULL);
+ 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 c8bbcb74..6204d8fd 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -9,10 +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>
@@ -178,9 +179,8 @@ static void netlink_gen_hash(struct netlink_linearize_ctx *ctx,
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;
@@ -193,6 +193,72 @@ 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));
+ 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);
}
@@ -221,9 +287,12 @@ 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);
+ 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);
}
@@ -391,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;
@@ -625,10 +695,10 @@ 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;
@@ -640,16 +710,18 @@ static void netlink_gen_bitwise(struct netlink_linearize_ctx *ctx,
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))
+ (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) {
@@ -725,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)
@@ -738,7 +812,7 @@ 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,
@@ -933,6 +1007,17 @@ static struct nftnl_expr *netlink_gen_quota_stmt(const struct stmt *stmt)
return nle;
}
+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) {
@@ -944,6 +1029,8 @@ struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt)
return netlink_gen_limit_stmt(stmt);
case STMT_QUOTA:
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);
}
@@ -1502,13 +1589,13 @@ static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
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");
@@ -1520,6 +1607,10 @@ static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
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);
+
list_for_each_entry(this, &stmt->map.stmt_list, list)
num_stmts++;
@@ -1615,6 +1706,7 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
case STMT_COUNTER:
case STMT_LIMIT:
case STMT_QUOTA:
+ case STMT_LAST:
nle = netlink_gen_stmt_stateful(stmt);
nft_rule_add_expr(ctx, nle, &stmt->location);
break;
@@ -1656,9 +1748,9 @@ void netlink_linearize_fini(struct netlink_linearize_ctx *lctx)
for (i = 0; i < NFT_EXPR_LOC_HSIZE; i++) {
list_for_each_entry_safe(eloc, next, &lctx->expr_loc_htable[i], hlist)
- xfree(eloc);
+ free(eloc);
}
- xfree(lctx->expr_loc_htable);
+ free(lctx->expr_loc_htable);
}
void netlink_linearize_rule(struct netlink_ctx *ctx,
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 ea2b2626..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>
diff --git a/src/optimize.c b/src/optimize.c
index d6dfffec..b90dd995 100644
--- a/src/optimize.c
+++ b/src/optimize.c
@@ -11,8 +11,8 @@
* programme.
*/
-#define _GNU_SOURCE
-#include <string.h>
+#include <nft.h>
+
#include <errno.h>
#include <inttypes.h>
#include <nftables.h>
@@ -21,6 +21,7 @@
#include <statement.h>
#include <utils.h>
#include <erec.h>
+#include <linux/netfilter.h>
#define MAX_STMTS 32
@@ -46,6 +47,8 @@ static bool __expr_cmp(const struct expr *expr_a, const struct expr *expr_b)
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;
@@ -81,6 +84,46 @@ static bool __expr_cmp(const struct expr *expr_a, const struct expr *expr_b)
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;
}
@@ -105,7 +148,14 @@ static bool stmt_expr_supported(const struct expr *expr)
return false;
}
-static bool __stmt_type_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
+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;
@@ -117,15 +167,29 @@ static bool __stmt_type_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
expr_a = stmt_a->expr;
expr_b = stmt_b->expr;
- if (!stmt_expr_supported(expr_a) ||
- !stmt_expr_supported(expr_b))
+ 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;
@@ -136,14 +200,6 @@ static bool __stmt_type_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
expr_b->etype == EXPR_MAP)
return __expr_cmp(expr_a->map, expr_b->map);
break;
- case STMT_LIMIT:
- if (stmt_a->limit.rate != stmt_b->limit.rate ||
- stmt_a->limit.unit != stmt_b->limit.unit ||
- stmt_a->limit.burst != stmt_b->limit.burst ||
- stmt_a->limit.type != stmt_b->limit.type ||
- stmt_a->limit.flags != stmt_b->limit.flags)
- return false;
- break;
case STMT_LOG:
if (stmt_a->log.snaplen != stmt_b->log.snaplen ||
stmt_a->log.group != stmt_b->log.group ||
@@ -165,33 +221,76 @@ static bool __stmt_type_eq(const struct stmt *stmt_a, const struct stmt *stmt_b)
return false;
break;
case STMT_REJECT:
- if (stmt_a->reject.expr || stmt_b->reject.expr)
- return false;
-
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 ||
- (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))
+ 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. */
@@ -237,30 +336,43 @@ static bool stmt_verdict_eq(const struct stmt *stmt_a, const struct stmt *stmt_b
return false;
}
-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);
-}
-
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 (__stmt_type_eq(stmt, ctx->stmt[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;
@@ -269,31 +381,41 @@ static int rule_collect_stmts(struct optimize_ctx *ctx, struct rule *rule)
if (stmt_type_find(ctx, stmt))
continue;
- if (stmt->ops->type == STMT_VERDICT &&
- stmt->expr->etype == EXPR_MAP)
- 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_LIMIT:
- memcpy(&clone->limit, &stmt->limit, sizeof(clone->limit));
- 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)
@@ -303,9 +425,16 @@ static int rule_collect_stmts(struct optimize_ctx *ctx, struct rule *rule)
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:
- stmt_free(clone);
- continue;
+ clone->ops = &unsupported_stmt_ops;
+ break;
}
ctx->stmt[ctx->num_stmts++] = clone;
@@ -316,18 +445,34 @@ static int rule_collect_stmts(struct optimize_ctx *ctx, struct rule *rule)
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]))
+ if (__stmt_type_eq(stmt, ctx->stmt[i], false))
return i;
}
- /* should not ever happen. */
- return 0;
+
+ 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)
{
@@ -336,6 +481,12 @@ static void rule_build_stmt_matrix_stmts(struct optimize_ctx *ctx,
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;
@@ -447,12 +598,68 @@ static void merge_stmts(const struct optimize_ctx *ctx,
}
}
+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 expr *concat, *elem, *set;
struct stmt *stmt, *stmt_a;
+ struct expr *concat, *set;
uint32_t i, k;
stmt = ctx->stmt_matrix[from][merge->stmt[0]];
@@ -470,15 +677,9 @@ static void merge_concat_stmts(const struct optimize_ctx *ctx,
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 (k = 0; k < merge->num_stmts; k++) {
- stmt_a = ctx->stmt_matrix[i][merge->stmt[k]];
- compound_expr_add(concat, expr_get(stmt_a->expr->right));
- }
- elem = set_elem_expr_alloc(&internal_location, concat);
- compound_expr_add(set, elem);
- }
+ for (i = from; i <= to; i++)
+ __merge_concat_stmts(ctx, i, merge, set);
+
expr_free(stmt->expr->right);
stmt->expr->right = set;
@@ -489,7 +690,8 @@ static void merge_concat_stmts(const struct optimize_ctx *ctx,
}
}
-static void build_verdict_map(struct expr *expr, struct stmt *verdict, struct expr *set)
+static void build_verdict_map(struct expr *expr, struct stmt *verdict,
+ struct expr *set, struct stmt *counter)
{
struct expr *item, *elem, *mapping;
@@ -497,6 +699,9 @@ static void build_verdict_map(struct expr *expr, struct stmt *verdict, struct ex
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);
@@ -505,6 +710,9 @@ static void build_verdict_map(struct expr *expr, struct stmt *verdict, struct ex
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);
@@ -516,6 +724,9 @@ static void build_verdict_map(struct expr *expr, struct stmt *verdict, struct ex
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);
@@ -544,6 +755,26 @@ static void remove_counter(const struct optimize_ctx *ctx, uint32_t from)
}
}
+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)
@@ -551,31 +782,33 @@ static void merge_stmts_vmap(const struct optimize_ctx *ctx,
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);
- verdict_a = ctx->stmt_matrix[from][k];
set = set_expr_alloc(&internal_location, NULL);
set->set_flags |= NFT_SET_ANONYMOUS;
expr_a = stmt_a->expr->right;
- build_verdict_map(expr_a, verdict_a, set);
+ 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];
-
- build_verdict_map(expr_b, verdict_b, set);
+ 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);
- remove_counter(ctx, from);
list_add(&stmt->list, &stmt_a->list);
list_del(&stmt_a->list);
stmt_free(stmt_a);
@@ -583,14 +816,37 @@ static void merge_stmts_vmap(const struct optimize_ctx *ctx,
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 expr *concat_a, *concat_b, *expr, *set;
- struct stmt *stmt, *stmt_a, *stmt_b, *verdict;
- uint32_t i, j;
+ struct stmt *stmt, *stmt_a, *verdict;
+ struct expr *concat_a, *expr, *set;
+ uint32_t i;
int k;
k = stmt_verdict_find(ctx);
@@ -608,21 +864,13 @@ static void merge_concat_stmts_vmap(const struct optimize_ctx *ctx,
set->set_flags |= NFT_SET_ANONYMOUS;
for (i = from; i <= to; i++) {
- concat_b = concat_expr_alloc(&internal_location);
- for (j = 0; j < merge->num_stmts; j++) {
- stmt_b = ctx->stmt_matrix[i][merge->stmt[j]];
- expr = stmt_b->expr->right;
- compound_expr_add(concat_b, expr_get(expr));
- }
verdict = ctx->stmt_matrix[i][k];
- build_verdict_map(concat_b, verdict, set);
- expr_free(concat_b);
+ __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);
- remove_counter(ctx, from);
list_add(&stmt->list, &orig_stmt->list);
list_del(&orig_stmt->list);
stmt_free(orig_stmt);
@@ -663,12 +911,35 @@ static bool stmt_verdict_cmp(const struct optimize_ctx *ctx,
return true;
}
-static int stmt_nat_find(const struct optimize_ctx *ctx)
+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)
+ if (ctx->stmt[i]->ops->type != STMT_NAT ||
+ ctx->stmt[i]->nat.type != nat_type)
continue;
return i;
@@ -681,16 +952,24 @@ 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) {
- 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));
+ 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;
}
@@ -699,11 +978,11 @@ static void merge_nat(const struct optimize_ctx *ctx,
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;
- int k;
- k = stmt_nat_find(ctx);
+ k = stmt_nat_find(ctx, from);
assert(k >= 0);
set = set_expr_alloc(&internal_location, NULL);
@@ -723,11 +1002,23 @@ static void merge_nat(const struct optimize_ctx *ctx,
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);
- nat_stmt->nat.addr = expr;
+ 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);
@@ -739,11 +1030,11 @@ static void merge_concat_nat(const struct optimize_ctx *ctx,
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;
- int k;
- k = stmt_nat_find(ctx);
+ k = stmt_nat_find(ctx, from);
assert(k >= 0);
set = set_expr_alloc(&internal_location, NULL);
@@ -770,11 +1061,20 @@ static void merge_concat_nat(const struct optimize_ctx *ctx,
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;
@@ -819,21 +1119,36 @@ static void rule_optimize_print(struct output_ctx *octx,
fprintf(octx->error_fp, "%s\n", line);
}
-static enum stmt_types merge_stmt_type(const struct optimize_ctx *ctx)
+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)
{
- uint32_t i;
+ const struct stmt *stmt;
+ uint32_t i, j;
- for (i = 0; i < ctx->num_stmts; i++) {
- switch (ctx->stmt[i]->ops->type) {
- case STMT_VERDICT:
- case STMT_NAT:
- return ctx->stmt[i]->ops->type;
- default:
- continue;
+ 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;
+ }
}
}
- return STMT_INVALID;
+ /* merge by verdict, even if no verdict is specified. */
+ return MERGE_BY_VERDICT;
}
static void merge_rules(const struct optimize_ctx *ctx,
@@ -841,14 +1156,14 @@ static void merge_rules(const struct optimize_ctx *ctx,
const struct merge *merge,
struct output_ctx *octx)
{
- enum stmt_types stmt_type;
+ uint32_t merge_type;
bool same_verdict;
uint32_t i;
- stmt_type = merge_stmt_type(ctx);
+ merge_type = merge_stmt_type(ctx, from, to);
- switch (stmt_type) {
- case STMT_VERDICT:
+ switch (merge_type) {
+ case MERGE_BY_VERDICT:
same_verdict = stmt_verdict_cmp(ctx, from, to);
if (merge->num_stmts > 1) {
if (same_verdict)
@@ -862,16 +1177,29 @@ static void merge_rules(const struct optimize_ctx *ctx,
merge_stmts_vmap(ctx, from, to, merge);
}
break;
- case STMT_NAT:
+ 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]);
@@ -884,17 +1212,57 @@ static void merge_rules(const struct optimize_ctx *ctx,
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;
+ 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;
}
@@ -918,10 +1286,11 @@ static int chain_optimize(struct nft_ctx *nft, struct list_head *rules)
ctx->num_rules++;
}
- ctx->rule = xzalloc(sizeof(ctx->rule) * ctx->num_rules);
- ctx->stmt_matrix = xzalloc(sizeof(struct stmt *) * 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(sizeof(struct stmt *) * MAX_STMTS);
+ ctx->stmt_matrix[i] = xzalloc_array(MAX_STMTS,
+ sizeof(**ctx->stmt_matrix));
merge = xzalloc(sizeof(*merge) * ctx->num_rules);
@@ -964,6 +1333,10 @@ static int chain_optimize(struct nft_ctx *nft, struct list_head *rules)
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;
}
@@ -974,16 +1347,16 @@ static int chain_optimize(struct nft_ctx *nft, struct list_head *rules)
}
ret = 0;
for (i = 0; i < ctx->num_rules; i++)
- xfree(ctx->stmt_matrix[i]);
+ free(ctx->stmt_matrix[i]);
- xfree(ctx->stmt_matrix);
- xfree(merge);
+ free(ctx->stmt_matrix);
+ free(merge);
err:
for (i = 0; i < ctx->num_stmts; i++)
stmt_free(ctx->stmt[i]);
- xfree(ctx->rule);
- xfree(ctx);
+ free(ctx->rule);
+ free(ctx);
return ret;
}
@@ -1017,7 +1390,7 @@ static int cmd_optimize(struct nft_ctx *nft, struct cmd *cmd)
int nft_optimize(struct nft_ctx *nft, struct list_head *cmds)
{
struct cmd *cmd;
- int ret;
+ int ret = 0;
list_for_each_entry(cmd, cmds, list) {
switch (cmd->op) {
diff --git a/src/osf.c b/src/osf.c
index cb58315d..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>
diff --git a/src/owner.c b/src/owner.c
index 2d98a2e9..65eaad3e 100644
--- a/src/owner.c
+++ b/src/owner.c
@@ -1,6 +1,15 @@
+/*
+ * 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 <stdlib.h>
#include <sys/time.h>
#include <time.h>
#include <inttypes.h>
@@ -66,7 +75,7 @@ static char *portid2name(pid_t pid, uint32_t portid, unsigned long inode)
continue;
rl = readlink(procname, tmp, sizeof(tmp));
- if (rl <= 0 || rl > (ssize_t)sizeof(tmp))
+ if (rl <= 0 || rl >= (ssize_t)sizeof(tmp))
continue;
tmp[rl] = 0;
diff --git a/src/parser_bison.y b/src/parser_bison.y
index ca5c488c..bdb73911 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -9,12 +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>
@@ -65,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--;
}
@@ -134,6 +146,51 @@ static bool already_set(const void *attr, const struct location *loc,
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) \
@@ -191,6 +248,7 @@ int nft_lex(void *, void *, void *);
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"
@@ -280,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"
@@ -317,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"
@@ -382,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"
@@ -428,6 +489,14 @@ int nft_lex(void *, void *, void *);
%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"
@@ -533,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"
@@ -615,13 +687,15 @@ int nft_lex(void *, void *, void *);
%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
@@ -629,8 +703,8 @@ 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
@@ -653,11 +727,13 @@ int nft_lex(void *, void *, void *);
%type <val> family_spec family_spec_explicit
%type <val32> int_num chain_policy
%type <prio_spec> extended_prio_spec prio_spec
+%destructor { expr_free($$.expr); } extended_prio_spec prio_spec
+
%type <string> extended_prio_name quota_unit basehook_device_name
-%destructor { xfree($$); } extended_prio_name quota_unit basehook_device_name
+%destructor { free_const($$); } extended_prio_name quota_unit basehook_device_name
%type <expr> dev_spec
-%destructor { xfree($$); } dev_spec
+%destructor { free($$); } dev_spec
%type <table> table_block_alloc table_block
%destructor { close_scope(state); table_free($$); } table_block_alloc
@@ -675,7 +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
+%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
@@ -684,11 +760,14 @@ int nft_lex(void *, void *, void *);
%destructor { obj_free($$); } obj_block_alloc
%type <list> stmt_list stateful_stmt_list set_elem_stmt_list
-%destructor { stmt_list_free($$); xfree($$); } 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
-%destructor { stmt_free($$); } counter_stmt counter_stmt_alloc stateful_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
@@ -733,8 +812,8 @@ 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 typeof_expr typeof_data_expr
-%destructor { expr_free($$); } primary_expr shift_expr and_expr typeof_expr typeof_data_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
@@ -804,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
@@ -873,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
@@ -886,9 +967,19 @@ int nft_lex(void *, void *, void *);
%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
%type <val8> boolean_keys
@@ -897,10 +988,13 @@ int nft_lex(void *, void *, void *);
%destructor { expr_free($$); } exthdr_exists_expr
%type <val> exthdr_key
-%type <val> ct_l4protoname ct_obj_type ct_cmd_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
@@ -935,16 +1029,18 @@ 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_flags : { scanner_pop_start_cond(nft->scanner, PARSER_SC_FLAGS); };
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); };
@@ -981,14 +1077,15 @@ close_scope_udplite : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_UDPL
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
{
@@ -998,19 +1095,19 @@ common_block : INCLUDE QUOTED_STRING stmt_separator
erec_queue(error(&@2, "redefinition of symbol '%s'", $2),
state->msgs);
expr_free($4);
- xfree($2);
+ 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
{
@@ -1019,10 +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);
- xfree($2);
+ free_const($2);
YYERROR;
}
- xfree($2);
+ free_const($2);
}
| error stmt_separator
{
@@ -1070,6 +1167,7 @@ base_cmd : /* empty */ add_cmd { $$ = $1; }
| 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
@@ -1318,6 +1416,14 @@ delete_cmd : TABLE table_or_id_spec
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_CHAIN, &$2, &@$, NULL);
}
+ | CHAIN chain_spec chain_block_alloc
+ '{' chain_block '}'
+ {
+ $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);
@@ -1377,6 +1483,74 @@ delete_cmd : TABLE table_or_id_spec
}
;
+destroy_cmd : TABLE table_or_id_spec
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_TABLE, &$2, &@$, NULL);
+ }
+ | CHAIN chain_or_id_spec
+ {
+ $$ = cmd_alloc(CMD_DESTROY, CMD_OBJ_CHAIN, &$2, &@$, NULL);
+ }
+ | RULE ruleid_spec
+ {
+ $$ = 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_ELEMENTS, &$2, &@$, $3);
@@ -1545,8 +1719,13 @@ 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 close_scope_counter
@@ -1561,10 +1740,53 @@ reset_cmd : COUNTERS ruleset_spec
{
$$ = cmd_alloc(CMD_RESET, CMD_OBJ_QUOTAS, &$3, &@$, NULL);
}
+ | 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
@@ -1675,29 +1897,33 @@ 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 close_scope_flags
+table_options : FLAGS STRING
{
if (strcmp($2, "dormant") == 0) {
$<table>0->flags |= TABLE_F_DORMANT;
- xfree($2);
+ free_const($2);
} else if (strcmp($2, "owner") == 0) {
$<table>0->flags |= TABLE_F_OWNER;
- xfree($2);
+ 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)) {
- xfree($1);
+ free_const($1);
YYERROR;
}
$<table>0->comment = $1;
@@ -1772,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 '}' close_scope_ct 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;
@@ -1781,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 '}' close_scope_ct 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;
@@ -1790,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 '}' close_scope_ct 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;
@@ -1836,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++;
+ }
}
;
@@ -1852,10 +2082,19 @@ chain_block : /* empty */ { $$ = $<chain>-1; }
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)) {
- xfree($2);
+ free_const($2);
YYERROR;
}
$1->comment = $2;
@@ -1871,7 +2110,7 @@ subchain_block : /* empty */ { $$ = $<chain>-1; }
}
;
-typeof_data_expr : primary_expr
+typeof_verdict_expr : primary_expr
{
struct expr *e = $1;
@@ -1903,6 +2142,17 @@ typeof_data_expr : primary_expr
}
;
+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) {
@@ -1928,25 +2178,28 @@ typeof_expr : primary_expr
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 close_scope_type
+ | set_block typeof_key_expr stmt_separator
{
- $1->key = $3;
- $$ = $1;
- }
- | set_block TYPEOF typeof_expr stmt_separator
- {
- $1->key = $3;
- datatype_set($1->key, $3->dtype);
+ if (already_set($1->key, &@2, state)) {
+ expr_free($2);
+ YYERROR;
+ }
+
+ $1->key = $2;
$$ = $1;
}
- | set_block FLAGS set_flag_list stmt_separator close_scope_flags
+ | set_block FLAGS set_flag_list stmt_separator
{
$1->flags = $3;
$$ = $1;
@@ -1969,6 +2222,10 @@ set_block : /* empty */ { $$ = $<set>-1; }
}
| set_block ELEMENTS '=' set_block_expr
{
+ if (already_set($1->init, &@2, state)) {
+ expr_free($4);
+ YYERROR;
+ }
$1->init = $4;
$$ = $1;
}
@@ -1981,7 +2238,7 @@ set_block : /* empty */ { $$ = $<set>-1; }
| set_block comment_spec stmt_separator
{
if (already_set($1->comment, &@2, state)) {
- xfree($2);
+ free_const($2);
YYERROR;
}
$1->comment = $2;
@@ -2008,15 +2265,27 @@ 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 { $$ = NFT_OBJECT_SYNPROXY; }
+ | 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; }
@@ -2027,23 +2296,24 @@ map_block : /* empty */ { $$ = $<set>-1; }
$1->timeout = $3;
$$ = $1;
}
- | map_block TYPE
- data_type_expr COLON data_type_expr
- stmt_separator close_scope_type
+ | map_block GC_INTERVAL time_spec stmt_separator
{
- $1->key = $3;
- $1->data = $5;
-
- $1->flags |= NFT_SET_MAP;
+ $1->gc_int = $3;
$$ = $1;
}
| map_block TYPE
- data_type_expr COLON INTERVAL data_type_expr
+ 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->data = $6;
- $1->data->flags |= EXPR_F_INTERVAL;
+ $1->data->flags |= $5;
$1->flags |= NFT_SET_MAP;
$$ = $1;
@@ -2052,35 +2322,49 @@ map_block : /* empty */ { $$ = $<set>-1; }
typeof_expr COLON typeof_data_expr
stmt_separator
{
- $1->key = $3;
- datatype_set($1->key, $3->dtype);
- $1->data = $5;
+ if (already_set($1->key, &@2, state)) {
+ expr_free($3);
+ expr_free($5);
+ YYERROR;
+ }
- $1->flags |= NFT_SET_MAP;
- $$ = $1;
- }
- | map_block TYPEOF
- typeof_expr COLON INTERVAL typeof_expr
- stmt_separator
- {
$1->key = $3;
- datatype_set($1->key, $3->dtype);
- $1->data = $6;
- $1->data->flags |= EXPR_F_INTERVAL;
- $1->flags |= NFT_SET_MAP;
+ 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 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 = $5;
+ $1->flags |= NFT_SET_OBJECT;
+ $$ = $1;
+ }
+ | map_block TYPEOF
+ typeof_expr COLON map_block_obj_typeof
+ stmt_separator
+ {
$1->key = $3;
$1->objtype = $5;
$1->flags |= NFT_SET_OBJECT;
$$ = $1;
}
- | map_block FLAGS set_flag_list stmt_separator close_scope_flags
+ | map_block FLAGS set_flag_list stmt_separator
{
$1->flags |= $3;
$$ = $1;
@@ -2099,7 +2383,7 @@ map_block : /* empty */ { $$ = $<set>-1; }
| map_block comment_spec stmt_separator
{
if (already_set($1->comment, &@2, state)) {
- xfree($2);
+ free_const($2);
YYERROR;
}
$1->comment = $2;
@@ -2124,7 +2408,7 @@ set_policy_spec : PERFORMANCE { $$ = NFT_SET_POL_PERFORMANCE; }
flowtable_block_alloc : /* empty */
{
- $$ = flowtable_alloc(NULL);
+ $$ = flowtable_alloc(&internal_location);
}
;
@@ -2138,10 +2422,10 @@ flowtable_block : /* empty */ { $$ = $<flowtable>-1; }
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;
}
@@ -2153,7 +2437,7 @@ flowtable_block : /* empty */ { $$ = $<flowtable>-1; }
{
$$->flags |= NFT_FLOWTABLE_COUNTER;
}
- | flowtable_block FLAGS OFFLOAD stmt_separator close_scope_flags
+ | flowtable_block FLAGS OFFLOAD stmt_separator
{
$$->flags |= FLOWTABLE_F_HW_OFFLOAD;
}
@@ -2186,17 +2470,21 @@ flowtable_list_expr : flowtable_expr_member
flowtable_expr_member : QUOTED_STRING
{
- $$ = constant_expr_alloc(&@$, &string_type,
- BYTEORDER_HOST_ENDIAN,
- strlen($1) * BITS_PER_BYTE, $1);
- xfree($1);
+ struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $1);
+
+ if (!expr)
+ YYERROR;
+
+ $$ = expr;
}
| STRING
{
- $$ = constant_expr_alloc(&@$, &string_type,
- BYTEORDER_HOST_ENDIAN,
- strlen($1) * BITS_PER_BYTE, $1);
- xfree($1);
+ struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $1);
+
+ if (!expr)
+ YYERROR;
+
+ $$ = expr;
}
| variable_expr
{
@@ -2211,12 +2499,12 @@ data_type_atom_expr : type_identifier
if (dtype == NULL) {
erec_queue(error(&@1, "unknown datatype %s", $1),
state->msgs);
- xfree($1);
+ free_const($1);
YYERROR;
}
$$ = constant_expr_alloc(&@1, dtype, dtype->byteorder,
dtype->size, NULL);
- xfree($1);
+ free_const($1);
}
| TIME
{
@@ -2239,7 +2527,7 @@ data_type_expr : data_type_atom_expr
obj_block_alloc : /* empty */
{
- $$ = obj_alloc(NULL);
+ $$ = obj_alloc(&internal_location);
}
;
@@ -2253,7 +2541,7 @@ counter_block : /* empty */ { $$ = $<obj>-1; }
| counter_block comment_spec
{
if (already_set($<obj>1->comment, &@2, state)) {
- xfree($2);
+ free_const($2);
YYERROR;
}
$<obj>1->comment = $2;
@@ -2270,7 +2558,7 @@ quota_block : /* empty */ { $$ = $<obj>-1; }
| quota_block comment_spec
{
if (already_set($<obj>1->comment, &@2, state)) {
- xfree($2);
+ free_const($2);
YYERROR;
}
$<obj>1->comment = $2;
@@ -2287,7 +2575,7 @@ ct_helper_block : /* empty */ { $$ = $<obj>-1; }
| ct_helper_block comment_spec
{
if (already_set($<obj>1->comment, &@2, state)) {
- xfree($2);
+ free_const($2);
YYERROR;
}
$<obj>1->comment = $2;
@@ -2298,6 +2586,7 @@ 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
@@ -2308,7 +2597,7 @@ ct_timeout_block : /*empty */
| ct_timeout_block comment_spec
{
if (already_set($<obj>1->comment, &@2, state)) {
- xfree($2);
+ free_const($2);
YYERROR;
}
$<obj>1->comment = $2;
@@ -2325,7 +2614,7 @@ ct_expect_block : /*empty */ { $$ = $<obj>-1; }
| ct_expect_block comment_spec
{
if (already_set($<obj>1->comment, &@2, state)) {
- xfree($2);
+ free_const($2);
YYERROR;
}
$<obj>1->comment = $2;
@@ -2342,7 +2631,7 @@ limit_block : /* empty */ { $$ = $<obj>-1; }
| limit_block comment_spec
{
if (already_set($<obj>1->comment, &@2, state)) {
- xfree($2);
+ free_const($2);
YYERROR;
}
$<obj>1->comment = $2;
@@ -2359,7 +2648,7 @@ secmark_block : /* empty */ { $$ = $<obj>-1; }
| secmark_block comment_spec
{
if (already_set($<obj>1->comment, &@2, state)) {
- xfree($2);
+ free_const($2);
YYERROR;
}
$<obj>1->comment = $2;
@@ -2376,7 +2665,7 @@ synproxy_block : /* empty */ { $$ = $<obj>-1; }
| synproxy_block comment_spec
{
if (already_set($<obj>1->comment, &@2, state)) {
- xfree($2);
+ free_const($2);
YYERROR;
}
$<obj>1->comment = $2;
@@ -2397,12 +2686,15 @@ hook_spec : TYPE close_scope_type STRING HOOK STRING dev_spec prio_spec
if (chain_type == NULL) {
erec_queue(error(&@3, "unknown chain type"),
state->msgs);
- xfree($3);
+ free_const($3);
+ free_const($5);
+ expr_free($6);
+ expr_free($7.expr);
YYERROR;
}
$<chain>0->type.loc = @3;
$<chain>0->type.str = xstrdup(chain_type);
- xfree($3);
+ free_const($3);
$<chain>0->loc = @$;
$<chain>0->hook.loc = @5;
@@ -2410,10 +2702,12 @@ hook_spec : TYPE close_scope_type STRING HOOK STRING dev_spec prio_spec
if ($<chain>0->hook.name == NULL) {
erec_queue(error(&@5, "unknown chain hook"),
state->msgs);
- xfree($5);
+ free_const($5);
+ expr_free($6);
+ expr_free($7.expr);
YYERROR;
}
- xfree($5);
+ free_const($5);
$<chain>0->dev_expr = $6;
$<chain>0->priority = $7;
@@ -2460,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
@@ -2473,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
@@ -2486,7 +2780,7 @@ extended_prio_spec : int_num
BYTEORDER_HOST_ENDIAN,
strlen(str) * BITS_PER_BYTE,
str);
- xfree($1);
+ free_const($1);
$$ = spec;
}
;
@@ -2497,12 +2791,11 @@ int_num : NUM { $$ = $1; }
dev_spec : DEVICE string
{
- struct expr *expr;
+ struct expr *expr = ifname_expr_alloc(&@$, state->msgs, $2);
+
+ if (!expr)
+ YYERROR;
- expr = constant_expr_alloc(&@$, &string_type,
- BYTEORDER_HOST_ENDIAN,
- strlen($2) * BITS_PER_BYTE, $2);
- xfree($2);
$$ = compound_expr_alloc(&@$, EXPR_LIST);
compound_expr_add($$, expr);
@@ -2520,7 +2813,7 @@ dev_spec : DEVICE string
| /* empty */ { $$ = NULL; }
;
-flags_spec : FLAGS OFFLOAD close_scope_flags
+flags_spec : FLAGS OFFLOAD
{
$<chain>0->flags |= CHAIN_F_HW_OFFLOAD;
}
@@ -2558,6 +2851,7 @@ chain_policy : ACCEPT { $$ = NF_ACCEPT; }
;
identifier : STRING
+ | LAST { $$ = xstrdup("last"); }
;
string : STRING
@@ -2571,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;
@@ -2580,6 +2874,11 @@ 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
;
@@ -2767,7 +3066,7 @@ comment_spec : COMMENT string
erec_queue(error(&@2, "comment too long, %d characters maximum allowed",
NFTNL_UDATA_COMMENT_MAXLEN),
state->msgs);
- xfree($2);
+ free_const($2);
YYERROR;
}
$$ = $2;
@@ -2804,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);
}
;
@@ -2834,10 +3133,65 @@ stateful_stmt_list : stateful_stmt
}
;
+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
@@ -2861,6 +3215,19 @@ stmt : verdict_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; }
@@ -2915,7 +3282,7 @@ 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);
}
;
@@ -2939,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
@@ -2956,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
;
@@ -2998,7 +3377,7 @@ log_arg : PREFIX string
expr = constant_expr_alloc(&@$, &string_type,
BYTEORDER_HOST_ENDIAN,
(strlen($2) + 1) * BITS_PER_BYTE, $2);
- xfree($2);
+ free_const($2);
$<stmt>0->log.prefix = expr;
$<stmt>0->log.flags |= STMT_LOG_PREFIX;
break;
@@ -3072,7 +3451,7 @@ log_arg : PREFIX string
state->msgs);
}
expr_free(expr);
- xfree($2);
+ free_const($2);
YYERROR;
}
item = variable_expr_alloc(&@$, scope, sym);
@@ -3102,7 +3481,7 @@ log_arg : PREFIX string
}
}
- xfree($2);
+ free_const($2);
$<stmt>0->log.prefix = expr;
$<stmt>0->log.flags |= STMT_LOG_PREFIX;
}
@@ -3126,7 +3505,7 @@ log_arg : PREFIX string
$<stmt>0->log.level = $2;
$<stmt>0->log.flags |= STMT_LOG_LEVEL;
}
- | FLAGS log_flags close_scope_flags
+ | FLAGS log_flags
{
$<stmt>0->log.logflags |= $2;
}
@@ -3155,10 +3534,10 @@ level_type : string
else {
erec_queue(error(&@1, "invalid log level"),
state->msgs);
- xfree($1);
+ free_const($1);
YYERROR;
}
- xfree($1);
+ free_const($1);
}
;
@@ -3204,7 +3583,7 @@ log_flag_tcp : SEQUENCE
limit_stmt : 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"),
+ erec_queue(error(&@5, "packet limit burst must be > 0"),
state->msgs);
YYERROR;
}
@@ -3217,11 +3596,6 @@ limit_stmt : LIMIT RATE limit_mode limit_rate_pkts limit_burst_pkts close_scope
}
| LIMIT RATE limit_mode limit_rate_bytes limit_burst_bytes 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;
@@ -3229,12 +3603,6 @@ limit_stmt : LIMIT RATE limit_mode limit_rate_pkts limit_burst_pkts close_scope
$$->limit.type = NFT_LIMIT_PKT_BYTES;
$$->limit.flags = $3;
}
- | LIMIT NAME stmt_expr close_scope_limit
- {
- $$ = objref_stmt_alloc(&@$);
- $$->objref.type = NFT_OBJECT_LIMIT;
- $$->objref.expr = $3;
- }
;
quota_mode : OVER { $$ = NFT_QUOTA_F_INV; }
@@ -3253,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;
@@ -3268,7 +3636,7 @@ quota_stmt : QUOTA quota_mode NUM quota_unit quota_used close_scope_quota
uint64_t rate;
erec = data_unit_parse(&@$, $4, &rate);
- xfree($4);
+ free_const($4);
if (erec != NULL) {
erec_queue(erec, state->msgs);
YYERROR;
@@ -3278,12 +3646,6 @@ quota_stmt : QUOTA quota_mode NUM quota_unit quota_used close_scope_quota
$$->quota.used = $5;
$$->quota.flags = $2;
}
- | QUOTA NAME stmt_expr close_scope_quota
- {
- $$ = objref_stmt_alloc(&@$);
- $$->objref.type = NFT_OBJECT_QUOTA;
- $$->objref.expr = $3;
- }
;
limit_mode : OVER { $$ = NFT_LIMIT_F_INV; }
@@ -3302,7 +3664,7 @@ limit_rate_pkts : NUM SLASH time_unit
}
;
-limit_burst_bytes : /* empty */ { $$ = 5; }
+limit_burst_bytes : /* empty */ { $$ = 0; }
| BURST limit_bytes { $$ = $2; }
;
@@ -3312,7 +3674,7 @@ limit_rate_bytes : NUM STRING
uint64_t rate, unit;
erec = rate_parse(&@$, $2, &rate, &unit);
- xfree($2);
+ free_const($2);
if (erec != NULL) {
erec_queue(erec, state->msgs);
YYERROR;
@@ -3334,7 +3696,7 @@ limit_bytes : NUM BYTES { $$ = $1; }
uint64_t rate;
erec = data_unit_parse(&@$, $2, &rate);
- xfree($2);
+ free_const($2);
if (erec != NULL) {
erec_queue(erec, state->msgs);
YYERROR;
@@ -3363,7 +3725,7 @@ reject_with_expr : STRING
{
$$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
current_scope(state), $1);
- xfree($1);
+ free_const($1);
}
| integer_expr { $$ = $1; }
;
@@ -3422,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
@@ -3474,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
@@ -3828,13 +4184,13 @@ queue_stmt : queue_stmt_compat close_scope_queue
{
$$ = queue_stmt_alloc(&@$, $3, 0);
}
- | QUEUE FLAGS queue_stmt_flags close_scope_flags TO queue_stmt_expr close_scope_queue
+ | QUEUE FLAGS queue_stmt_flags TO queue_stmt_expr close_scope_queue
{
- $$ = queue_stmt_alloc(&@$, $6, $3);
+ $$ = queue_stmt_alloc(&@$, $5, $3);
}
- | QUEUE FLAGS queue_stmt_flags close_scope_flags QUEUENUM queue_stmt_expr_simple close_scope_queue
+ | QUEUE FLAGS queue_stmt_flags QUEUENUM queue_stmt_expr_simple close_scope_queue
{
- $$ = queue_stmt_alloc(&@$, $6, $3);
+ $$ = queue_stmt_alloc(&@$, $5, $3);
}
;
@@ -4027,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);
}
;
@@ -4042,7 +4398,7 @@ symbol_expr : variable_expr
$$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
current_scope(state),
$1);
- xfree($1);
+ free_const($1);
}
;
@@ -4055,7 +4411,7 @@ set_ref_symbol_expr : AT identifier close_scope_at
$$ = symbol_expr_alloc(&@$, SYMBOL_SET,
current_scope(state),
$2);
- xfree($2);
+ free_const($2);
}
;
@@ -4152,10 +4508,10 @@ osf_ttl : /* empty */
else {
erec_queue(error(&@2, "invalid ttl option"),
state->msgs);
- xfree($2);
+ free_const($2);
YYERROR;
}
- xfree($2);
+ free_const($2);
}
;
@@ -4263,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);
}
;
@@ -4283,6 +4639,12 @@ meter_key_expr_alloc : concat_expr
set_elem_expr : set_elem_expr_alloc
| 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; }
@@ -4293,7 +4655,7 @@ set_elem_expr_alloc : set_elem_key_expr set_elem_stmt_list
{
$$ = set_elem_expr_alloc(&@1, $1);
list_splice_tail($2, &$$->stmt_list);
- xfree($2);
+ free($2);
}
| set_elem_key_expr
{
@@ -4319,7 +4681,7 @@ set_elem_option : TIMEOUT time_spec
| comment_spec
{
if (already_set($<expr>0->comment, &@1, state)) {
- xfree($1);
+ free_const($1);
YYERROR;
}
$<expr>0->comment = $1;
@@ -4395,6 +4757,32 @@ set_elem_stmt : COUNTER close_scope_counter
$$->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
@@ -4408,7 +4796,7 @@ set_elem_expr_option : TIMEOUT time_spec
| comment_spec
{
if (already_set($<expr>0->comment, &@1, state)) {
- xfree($1);
+ free_const($1);
YYERROR;
}
$<expr>0->comment = $1;
@@ -4460,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;
@@ -4489,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);
}
;
@@ -4509,27 +4897,34 @@ ct_obj_type : HELPER { $$ = NFT_OBJECT_CT_HELPER; }
;
ct_cmd_type : HELPERS { $$ = CMD_OBJ_CT_HELPERS; }
- | TIMEOUT { $$ = CMD_OBJ_CT_TIMEOUT; }
- | EXPECTATION { $$ = CMD_OBJ_CT_EXPECT; }
+ | 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 close_scope_type
+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;
}
- xfree($2);
+ free_const($2);
ct->l4proto = $4;
}
@@ -4543,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;
@@ -4562,7 +4956,7 @@ timeout_state : STRING COLON NUM
ts->timeout_value = $3;
ts->location = @1;
init_list_head(&ts->head);
- $$ = &ts->head;
+ $$ = ts;
}
;
@@ -4580,7 +4974,7 @@ ct_timeout_config : PROTOCOL ct_l4protoname stmt_separator
ct = &$<obj>0->ct_timeout;
list_splice_tail($4, &ct->timeout_list);
- xfree($4);
+ free($4);
}
| L3PROTOCOL family_spec_explicit stmt_separator
{
@@ -4778,9 +5172,11 @@ keyword_expr : ETHER close_scope_eth { $$ = symbol_value(&@$, "ether"); }
| SNAT close_scope_nat { $$ = symbol_value(&@$, "snat"); }
| ECN { $$ = symbol_value(&@$, "ecn"); }
| 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; }
@@ -4843,6 +5239,13 @@ primary_rhs_expr : symbol_expr { $$ = $1; }
BYTEORDER_HOST_ENDIAN,
sizeof(data) * BITS_PER_BYTE, &data);
}
+ | 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;
@@ -4916,7 +5319,7 @@ chain_expr : variable_expr
BYTEORDER_HOST_ENDIAN,
strlen($1) * BITS_PER_BYTE,
$1);
- xfree($1);
+ free_const($1);
}
;
@@ -4934,7 +5337,7 @@ meta_expr : META meta_key close_scope_meta
unsigned int key;
erec = meta_key_parse(&@$, $2, &key);
- xfree($2);
+ free_const($2);
if (erec != NULL) {
erec_queue(erec, state->msgs);
YYERROR;
@@ -5011,9 +5414,10 @@ meta_stmt : META meta_key SET stmt_expr close_scope_meta
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;
}
@@ -5252,19 +5656,6 @@ ct_stmt : CT ct_key SET stmt_expr close_scope_ct
break;
}
}
- | 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;
- }
| CT ct_dir ct_key_dir_optional SET stmt_expr close_scope_ct
{
$$ = ct_stmt_alloc(&@$, $3, $2, $5);
@@ -5298,9 +5689,31 @@ payload_expr : payload_raw_expr
| 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 close_scope_at
+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);
@@ -5318,10 +5731,10 @@ payload_base_spec : LL_HDR { $$ = PROTO_BASE_LL_HDR; }
$$ = PROTO_BASE_INNER_HDR;
} else {
erec_queue(error(&@1, "unknown raw payload base"), state->msgs);
- xfree($1);
+ free_const($1);
YYERROR;
}
- xfree($1);
+ free_const($1);
}
;
@@ -5469,6 +5882,8 @@ icmp6_hdr_field : TYPE close_scope_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 close_scope_ah
@@ -5501,7 +5916,7 @@ comp_hdr_expr : COMP comp_hdr_field close_scope_comp
;
comp_hdr_field : NEXTHDR { $$ = COMPHDR_NEXTHDR; }
- | FLAGS close_scope_flags { $$ = COMPHDR_FLAGS; }
+ | FLAGS { $$ = COMPHDR_FLAGS; }
| CPI { $$ = COMPHDR_CPI; }
;
@@ -5541,14 +5956,106 @@ tcp_hdr_expr : TCP tcp_hdr_field
| 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 NUM
+ | 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(&@$,
@@ -5562,7 +6069,7 @@ tcp_hdr_field : SPORT { $$ = TCPHDR_SPORT; }
| ACKSEQ { $$ = TCPHDR_ACKSEQ; }
| DOFF { $$ = TCPHDR_DOFF; }
| RESERVED { $$ = TCPHDR_RESERVED; }
- | FLAGS close_scope_flags { $$ = TCPHDR_FLAGS; }
+ | FLAGS { $$ = TCPHDR_FLAGS; }
| WINDOW { $$ = TCPHDR_WINDOW; }
| CHECKSUM { $$ = TCPHDR_CHECKSUM; }
| URGPTR { $$ = TCPHDR_URGPTR; }
@@ -5648,6 +6155,15 @@ 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; }
@@ -5676,7 +6192,7 @@ sctp_chunk_type : DATA { $$ = SCTP_CHUNK_TYPE_DATA; }
;
sctp_chunk_common_field : TYPE close_scope_type { $$ = SCTP_CHUNK_COMMON_TYPE; }
- | FLAGS close_scope_flags { $$ = SCTP_CHUNK_COMMON_FLAGS; }
+ | FLAGS { $$ = SCTP_CHUNK_COMMON_FLAGS; }
| LENGTH { $$ = SCTP_CHUNK_COMMON_LENGTH; }
;
@@ -5844,7 +6360,7 @@ rt4_hdr_expr : RT4 rt4_hdr_field close_scope_rt
;
rt4_hdr_field : LAST_ENT { $$ = RT4HDR_LASTENT; }
- | FLAGS close_scope_flags { $$ = RT4HDR_FLAGS; }
+ | FLAGS { $$ = RT4HDR_FLAGS; }
| TAG { $$ = RT4HDR_TAG; }
| SID '[' NUM ']'
{
@@ -5896,7 +6412,7 @@ 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;
diff --git a/src/parser_json.c b/src/parser_json.c
index fb401009..4fc0479c 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>
@@ -533,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;
@@ -546,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;
@@ -564,11 +592,45 @@ static struct expr *json_parse_payload_expr(struct json_ctx *ctx,
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);
@@ -602,12 +664,18 @@ static struct expr *json_parse_tcp_option_expr(struct json_ctx *ctx,
struct expr *expr;
if (!json_unpack(root, "{s:i, s:i, s:i}",
- "base", &kind, "offset", &offset, "len", &len)) {
+ "base", &kind, "offset", &offset, "len", &len)) {
uint32_t flag = 0;
if (kind < 0 || kind > 255)
return NULL;
+ 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);
@@ -673,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;
@@ -689,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);
+ IPOPT_FIELD_TYPE);
expr->exthdr.flags = NFT_EXTHDR_F_PRESENT;
return expr;
@@ -748,6 +816,22 @@ static struct expr *json_parse_sctp_chunk_expr(struct json_ctx *ctx,
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)
{
const struct exthdr_desc *exthdr_tbl[] = {
@@ -1076,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;
}
@@ -1454,6 +1538,7 @@ static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root)
{ "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 },
@@ -1652,13 +1737,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);
@@ -1678,7 +1768,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;
@@ -1687,8 +1777,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;
@@ -1706,6 +1796,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)
{
@@ -1719,14 +1830,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);
@@ -1779,7 +1890,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;
@@ -1826,7 +1937,7 @@ static struct stmt *json_parse_limit_stmt(struct json_ctx *ctx,
const char *key, json_t *value)
{
struct stmt *stmt;
- uint64_t rate, burst = 5;
+ uint64_t rate, burst = 0;
const char *rate_unit = "packets", *time, *burst_unit = "bytes";
int inv = 0;
@@ -1840,6 +1951,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;
@@ -1926,7 +2040,7 @@ static struct stmt *json_parse_flow_offload_stmt(struct json_ctx *ctx,
}
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);
}
@@ -1963,6 +2077,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)
{
@@ -2019,7 +2150,7 @@ static int json_parse_nat_flags(struct json_ctx *ctx, json_t *root)
}
static int json_parse_nat_type_flag(struct json_ctx *ctx,
- json_t *root, int *flags)
+ json_t *root, int *flags)
{
const struct {
const char *flag;
@@ -2134,7 +2265,6 @@ 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);
@@ -2149,7 +2279,7 @@ static struct stmt *json_parse_nat_stmt(struct json_ctx *ctx,
}
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;
@@ -2185,7 +2315,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;
@@ -2227,13 +2357,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}",
@@ -2268,6 +2421,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;
}
@@ -2507,7 +2721,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);
@@ -2542,7 +2756,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))
@@ -2657,7 +2871,14 @@ static struct stmt *json_parse_optstrip_stmt(struct json_ctx *ctx,
{
struct expr *expr = json_parse_expr(ctx, value);
- return expr ? optstrip_stmt_alloc(int_loc, expr) : NULL;
+ 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)
@@ -2676,6 +2897,7 @@ 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 },
@@ -2687,6 +2909,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 },
@@ -2697,6 +2920,7 @@ static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root)
{ "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;
@@ -2716,6 +2940,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);
@@ -2728,17 +2957,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)) {
@@ -2752,10 +2985,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)
@@ -2774,24 +3013,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 name[IFNAMSIZ];
- struct chain *chain;
+ const char *family = "", *policy = "", *type, *hookstr, *comment = NULL;
+ struct chain *chain = NULL;
+ json_t *devs = NULL;
int prio;
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)) {
@@ -2806,14 +3081,22 @@ 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.str = xstrdup(type);
chain->priority.expr = constant_expr_alloc(int_loc, &integer_type,
@@ -2827,16 +3110,15 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
return NULL;
}
- if (!json_unpack(root, "{s:s}", "dev", &name)) {
- struct expr *dev_expr, *expr;
+ json_unpack(root, "{s:o}", "dev", &devs);
- dev_expr = compound_expr_alloc(int_loc, EXPR_LIST);
- expr = constant_expr_alloc(int_loc, &integer_type,
- BYTEORDER_HOST_ENDIAN,
- strlen(name) * BITS_PER_BYTE,
- name);
- compound_expr_add(dev_expr, expr);
- chain->dev_expr = dev_expr;
+ 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)) {
@@ -2876,7 +3158,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;
@@ -2887,7 +3169,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)) {
@@ -2935,14 +3217,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;
}
@@ -2958,6 +3244,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;
@@ -2972,9 +3259,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,
@@ -2983,7 +3270,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.");
@@ -3000,14 +3287,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.");
@@ -3023,19 +3312,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)) {
- const struct datatype *dtype;
+ 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(dtype_ext);
+ set->objtype = string_to_nft_object(s);
+ }
if (set->objtype) {
set->flags |= NFT_SET_OBJECT;
- } else if ((dtype = datatype_lookup_byname(dtype_ext))) {
- set->data = constant_expr_alloc(&netlink_location,
- dtype, dtype->byteorder,
- dtype->size, NULL);
+ } 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;
@@ -3084,6 +3373,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);
@@ -3125,41 +3418,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_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 flowtable dev 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_flowtable(struct json_ctx *ctx,
json_t *root, enum cmd_ops op,
enum cmd_obj cmd_obj)
@@ -3178,7 +3436,7 @@ static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx,
if (op != CMD_DELETE &&
json_unpack_err(ctx, root, "{s:s}", "name", &h.flowtable.name)) {
return NULL;
- } else if (op == CMD_DELETE &&
+ } 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.");
@@ -3193,17 +3451,17 @@ static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx,
if (h.flowtable.name)
h.flowtable.name = xstrdup(h.flowtable.name);
- if (op == CMD_DELETE || op == CMD_LIST)
+ 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}",
+ if (json_unpack_err(ctx, root, "{s:s, s:i}",
"hook", &hook,
"prio", &prio)) {
handle_free(&h);
return NULL;
}
- json_unpack(root, "{s:o}", &devs);
+ json_unpack(root, "{s:o}", "dev", &devs);
hookstr = chain_hookname_lookup(hook);
if (!hookstr) {
@@ -3220,7 +3478,7 @@ static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx,
sizeof(int) * BITS_PER_BYTE, &prio);
if (devs) {
- flowtable->dev_expr = json_parse_flowtable_devs(ctx, devs);
+ flowtable->dev_expr = json_parse_devs(ctx, devs);
if (!flowtable->dev_expr) {
json_error(ctx, "Invalid flowtable dev.");
flowtable_free(flowtable);
@@ -3237,7 +3495,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)) {
@@ -3269,8 +3527,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;
@@ -3282,7 +3540,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)) {
@@ -3298,7 +3556,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));
@@ -3307,6 +3565,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;
@@ -3389,7 +3650,7 @@ 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)) {
@@ -3418,11 +3679,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;
@@ -3434,7 +3696,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")) {
@@ -3452,11 +3714,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)) {
@@ -3500,7 +3763,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;
@@ -3697,6 +3961,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)
{
@@ -3710,6 +4007,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;
@@ -3808,6 +4110,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 }
@@ -3830,13 +4133,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;
diff --git a/src/payload.c b/src/payload.c
index 66418cdd..44aa834c 100644
--- a/src/payload.c
+++ b/src/payload.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 <net/if_arp.h>
#include <arpa/inet.h>
#include <linux/netfilter.h>
@@ -47,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))
@@ -67,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;
@@ -114,10 +118,14 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx,
assert(desc->base <= PROTO_BASE_MAX);
if (desc->base == base->base) {
- assert(base->length > 0);
-
- if (!left->payload.is_raw)
- 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);
}
@@ -127,7 +135,8 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx,
#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_MAX 5
+#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)
@@ -157,10 +166,15 @@ static int payload_expr_build_udata(struct nftnl_udata_buf *udbuf,
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);
+ }
+
return 0;
}
-static const struct proto_desc *find_proto_desc(const struct nftnl_udata *ud)
+const struct proto_desc *find_proto_desc(const struct nftnl_udata *ud)
{
return proto_find_desc(nftnl_udata_get_u32(ud));
}
@@ -177,6 +191,7 @@ static int payload_parse_udata(const struct nftnl_udata *attr, void *data)
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;
@@ -233,11 +248,15 @@ static struct expr *payload_expr_parse_udata(const struct nftnl_udata *attr)
expr->payload.offset = offset;
expr->payload.is_raw = true;
expr->len = len;
- dtype = dtype_clone(&xinteger_type);
+ dtype = datatype_clone(&xinteger_type);
dtype->size = len;
dtype->byteorder = BYTEORDER_BIG_ENDIAN;
- dtype->refcnt = 1;
- expr->dtype = dtype;
+ __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;
@@ -386,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",
@@ -405,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:
@@ -435,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 ||
@@ -445,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)
@@ -497,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,
@@ -514,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);
@@ -533,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.
*
@@ -558,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:
@@ -734,26 +778,58 @@ static uint8_t icmp_dep_to_type(enum icmp_hdr_field_type t)
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);
- uint8_t icmp_type;
+ enum icmp_hdr_field_type icmp_dep;
- icmp_type = expr->payload.tmpl->icmp_dep;
- if (icmp_type == PROTO_ICMP_ANY)
+ 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;
- icmp_type = icmp_dep_to_type(expr->payload.tmpl->icmp_dep);
+ 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_type;
+ 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)
@@ -843,7 +919,8 @@ 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, expr->payload.base);
}
@@ -869,6 +946,38 @@ void exthdr_dependency_kill(struct payload_dep_ctx *ctx, struct expr *expr,
}
}
+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
*
@@ -880,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);
@@ -891,9 +1001,12 @@ 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;
@@ -901,11 +1014,13 @@ void payload_expr_complete(struct expr *expr, const struct proto_ctx *ctx)
continue;
if (tmpl->icmp_dep && ctx->th_dep.icmp.type &&
- ctx->th_dep.icmp.type != icmp_dep_to_type(tmpl->icmp_dep))
+ !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;
}
@@ -950,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);
@@ -959,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;
@@ -1009,29 +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 &&
- ctx->th_dep.icmp.type != icmp_dep_to_type(tmpl->icmp_dep))
+ !icmp_dep_type_match(tmpl->icmp_dep,
+ ctx->th_dep.icmp.type))
continue;
if (tmpl->len <= expr->len) {
@@ -1039,6 +1159,7 @@ 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) {
@@ -1051,8 +1172,12 @@ void payload_expr_expand(struct list_head *list, struct expr *expr,
}
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);
}
@@ -1074,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;
@@ -1130,6 +1258,8 @@ 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;
}
@@ -1178,9 +1308,42 @@ __payload_gen_icmp_echo_dependency(struct eval_ctx *ctx, const struct expr *expr
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;
@@ -1197,11 +1360,11 @@ int payload_gen_icmp_dependency(struct eval_ctx *ctx, const struct expr *expr,
break;
case PROTO_ICMP_ECHO:
/* do not test ICMP_ECHOREPLY here: its 0 */
- if (ctx->pctx.th_dep.icmp.type == ICMP_ECHO)
+ if (pctx->th_dep.icmp.type == ICMP_ECHO)
goto done;
type = ICMP_ECHO;
- if (ctx->pctx.th_dep.icmp.type)
+ if (pctx->th_dep.icmp.type)
goto bad_proto;
stmt = __payload_gen_icmp_echo_dependency(ctx, expr,
@@ -1212,21 +1375,21 @@ int payload_gen_icmp_dependency(struct eval_ctx *ctx, const struct expr *expr,
case PROTO_ICMP_MTU:
case PROTO_ICMP_ADDRESS:
type = icmp_dep_to_type(tmpl->icmp_dep);
- if (ctx->pctx.th_dep.icmp.type == type)
+ if (pctx->th_dep.icmp.type == type)
goto done;
- if (ctx->pctx.th_dep.icmp.type)
+ 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 (ctx->pctx.th_dep.icmp.type == ICMP6_ECHO_REQUEST ||
- ctx->pctx.th_dep.icmp.type == ICMP6_ECHO_REPLY)
+ if (pctx->th_dep.icmp.type == ICMP6_ECHO_REQUEST ||
+ pctx->th_dep.icmp.type == ICMP6_ECHO_REPLY)
goto done;
type = ICMP6_ECHO_REQUEST;
- if (ctx->pctx.th_dep.icmp.type)
+ if (pctx->th_dep.icmp.type)
goto bad_proto;
stmt = __payload_gen_icmp_echo_dependency(ctx, expr,
@@ -1235,13 +1398,23 @@ int payload_gen_icmp_dependency(struct eval_ctx *ctx, const struct expr *expr,
&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 (ctx->pctx.th_dep.icmp.type == type)
+ if (pctx->th_dep.icmp.type == type)
goto done;
- if (ctx->pctx.th_dep.icmp.type)
+ if (pctx->th_dep.icmp.type)
goto bad_proto;
stmt = __payload_gen_icmp_simple_dependency(ctx, expr,
&icmp6_type_type,
@@ -1252,16 +1425,54 @@ int payload_gen_icmp_dependency(struct eval_ctx *ctx, const struct expr *expr,
BUG("Unhandled icmp dependency code");
}
- ctx->pctx.th_dep.icmp.type = type;
+ pctx->th_dep.icmp.type = type;
- if (stmt_evaluate(ctx, stmt) < 0)
- return expr_error(ctx->msgs, expr,
- "icmp dependency statement is invalid");
+ 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",
- ctx->pctx.th_dep.icmp.type, type);
+ 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 a013a00d..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>
@@ -88,6 +87,30 @@ int proto_find_num(const struct proto_desc *base,
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),
};
@@ -154,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");
@@ -177,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];
@@ -185,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);
}
@@ -224,6 +254,8 @@ void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base,
ctx->protocol[base].protos[i].location = *loc;
}
break;
+ case PROTO_BASE_INNER_HDR:
+ break;
default:
BUG("unknown protocol base %d", base);
}
@@ -272,6 +304,8 @@ const struct proto_desc *proto_ctx_find_conflict(struct proto_ctx *ctx,
#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)
@@ -404,10 +438,10 @@ const struct datatype icmp_type_type = {
.sym_tbl = &icmp_type_tbl,
};
-#define ICMP46HDR_FIELD(__token, __struct, __member, __dep) \
+#define ICMP46HDR_FIELD(__token, __dtype, __struct, __member, __dep) \
{ \
.token = (__token), \
- .dtype = &integer_type, \
+ .dtype = &__dtype, \
.byteorder = BYTEORDER_BIG_ENDIAN, \
.offset = offsetof(__struct, __member) * 8, \
.len = field_sizeof(__struct, __member) * 8, \
@@ -415,7 +449,7 @@ const struct datatype icmp_type_type = {
}
#define ICMPHDR_FIELD(__token, __member, __dep) \
- ICMP46HDR_FIELD(__token, struct icmphdr, __member, __dep)
+ ICMP46HDR_FIELD(__token, integer_type, struct icmphdr, __member, __dep)
#define ICMPHDR_TYPE(__name, __type, __member) \
HDR_TYPE(__name, __type, struct icmphdr, __member)
@@ -509,6 +543,10 @@ const struct proto_desc proto_udp = {
[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 = {
@@ -684,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),
@@ -697,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
},
@@ -735,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) \
@@ -758,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),
@@ -767,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),
@@ -834,7 +913,7 @@ const struct datatype icmp6_type_type = {
};
#define ICMP6HDR_FIELD(__token, __member, __dep) \
- ICMP46HDR_FIELD(__token, struct icmp6_hdr, __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)
@@ -854,6 +933,12 @@ const struct proto_desc proto_icmp6 = {
[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),
},
};
@@ -884,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),
@@ -949,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),
@@ -1129,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 = {
@@ -1146,7 +1286,7 @@ const struct proto_desc proto_netdev = {
},
};
-static const struct proto_desc *proto_definitions[PROTO_DESC_MAX + 1] = {
+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,
@@ -1164,6 +1304,10 @@ static const struct proto_desc *proto_definitions[PROTO_DESC_MAX + 1] = {
[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)
diff --git a/src/rt.c b/src/rt.c
index d7aa5edd..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[] = {
diff --git a/src/rule.c b/src/rule.c
index 799092eb..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>
@@ -27,6 +26,7 @@
#include <cache.h>
#include <owner.h>
#include <intervals.h>
+#include "nftutils.h"
#include <libnftnl/common.h>
#include <libnftnl/ruleset.h>
@@ -76,7 +76,7 @@ static uint32_t udp_dflt_timeout[] = {
[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,
@@ -104,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.name);
- 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)
@@ -146,11 +146,12 @@ 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);
@@ -161,7 +162,7 @@ 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;
@@ -190,16 +191,16 @@ void set_free(struct set *set)
if (--set->refcnt > 0)
return;
- if (set->init != NULL)
- expr_free(set->init);
+
+ expr_free(set->init);
if (set->comment)
- xfree(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);
expr_free(set->data);
- xfree(set);
+ free(set);
}
struct set *set_lookup_fuzzy(const char *set_name,
@@ -453,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);
@@ -476,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)
@@ -554,16 +557,16 @@ 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);
- xfree(scope);
+ free(scope);
}
void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr)
@@ -594,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);
}
}
@@ -695,17 +698,16 @@ const char *chain_hookname_lookup(const char *name)
/* internal ID to uniquely identify a set in the batch */
static uint32_t chain_id;
-struct chain *chain_alloc(const char *name)
+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;
@@ -727,16 +729,20 @@ void chain_free(struct chain *chain)
list_for_each_entry_safe(rule, next, &chain->rules, list)
rule_free(rule);
handle_free(&chain->handle);
- scope_release(&chain->scope);
- xfree(chain->type.str);
+ free_const(chain->type.str);
expr_free(chain->dev_expr);
for (i = 0; i < chain->dev_array_len; i++)
- xfree(chain->dev_array[i]);
- xfree(chain->dev_array);
+ free_const(chain->dev_array[i]);
+ free(chain->dev_array);
expr_free(chain->priority.expr);
expr_free(chain->policy);
- xfree(chain->comment);
- xfree(chain);
+ free_const(chain->comment);
+
+ /* MUST be released after all expressions, they could
+ * hold refcounts.
+ */
+ scope_release(&chain->scope);
+ free(chain);
}
struct chain *chain_binding_lookup(const struct table *table,
@@ -864,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" },
@@ -873,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" },
@@ -927,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;
@@ -936,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;
}
}
@@ -969,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) {
@@ -987,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;
}
@@ -1058,13 +1069,19 @@ static void chain_print_declaration(const struct chain *chain,
void chain_rules_print(const struct chain *chain, struct output_ctx *octx,
const char *indent)
{
+ unsigned int flags = octx->flags;
struct rule *rule;
+ 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%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)
@@ -1085,8 +1102,21 @@ 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.str, chain->hook.name,
+ 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->hook.num,
chain->priority.expr),
@@ -1101,6 +1131,7 @@ 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);
@@ -1127,7 +1158,7 @@ void table_free(struct table *table)
if (--table->refcnt > 0)
return;
if (table->comment)
- xfree(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)
@@ -1157,7 +1188,7 @@ void table_free(struct table *table)
cache_free(&table->set_cache);
cache_free(&table->obj_cache);
cache_free(&table->ft_cache);
- xfree(table);
+ free(table);
}
struct table *table_get(struct table *table)
@@ -1227,6 +1258,11 @@ 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, " #");
@@ -1272,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;
@@ -1279,104 +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;
-}
-
-void cmd_add_loc(struct cmd *cmd, uint16_t offset, const struct location *loc)
-{
- if (cmd->num_attrs >= NFT_NLATTR_LOC_MAX)
- return;
-
- cmd->attr[cmd->num_attrs].offset = offset;
- cmd->attr[cmd->num_attrs].location = loc;
- cmd->num_attrs++;
-}
-
-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);
- 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) {
- list_for_each_entry(rule, &chain->rules, list) {
- memset(&h, 0, sizeof(h));
- handle_merge(&h, &rule->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_get(rule));
- list_add_tail(&new->list, &new_cmds);
- }
- }
- list_splice(&new_cmds, &cmd->list);
- break;
- case CMD_OBJ_SET:
- case CMD_OBJ_MAP:
- set = cmd->set;
- if (!set->init)
- break;
+ 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);
- 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;
- }
+ return cmd;
}
struct markup *markup_alloc(uint32_t format)
@@ -1391,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)
@@ -1409,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)
@@ -1424,6 +1370,8 @@ void cmd_free(struct cmd *cmd)
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;
@@ -1462,18 +1410,19 @@ 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_elements(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;
@@ -1489,7 +1438,7 @@ static int do_add_elements(struct netlink_ctx *ctx, struct cmd *cmd,
set_to_intervals(set, init, true) < 0)
return -1;
- return __do_add_elements(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,
@@ -1497,7 +1446,7 @@ static int do_add_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
{
struct set *set = cmd->set;
- return __do_add_elements(ctx, set, set->init, flags);
+ return __do_add_elements(ctx, cmd, set, set->init, flags);
}
static int do_add_set(struct netlink_ctx *ctx, struct cmd *cmd,
@@ -1515,7 +1464,13 @@ static int do_add_set(struct netlink_ctx *ctx, struct cmd *cmd,
return -1;
}
- return mnl_nft_set_add(ctx, cmd, flags);
+ if (mnl_nft_set_add(ctx, cmd, flags) < 0)
+ return -1;
+
+ if (set_is_anonymous(set->flags))
+ return __do_add_elements(ctx, cmd, set, set->init, flags);
+
+ return 0;
}
static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)
@@ -1591,7 +1546,7 @@ static int do_delete_setelems(struct netlink_ctx *ctx, struct cmd *cmd)
set_to_intervals(set, expr, false) < 0)
return -1;
- if (mnl_nft_setelem_del(ctx, &cmd->handle, cmd->elem.expr) < 0)
+ if (mnl_nft_setelem_del(ctx, cmd, &cmd->handle, cmd->elem.expr) < 0)
return -1;
return 0;
@@ -1633,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;
@@ -1642,11 +1596,6 @@ 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;
@@ -1664,13 +1613,12 @@ static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
!set_is_literal(set->flags))
continue;
if (cmd->obj == CMD_OBJ_METERS &&
- !set_is_meter(set->flags))
+ !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");
@@ -1682,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;
@@ -1700,18 +1649,18 @@ void obj_free(struct obj *obj)
{
if (--obj->refcnt > 0)
return;
- xfree(obj->comment);
+ free_const(obj->comment);
handle_free(&obj->handle);
if (obj->type == NFT_OBJECT_CT_TIMEOUT) {
struct timeout_state *ts, *next;
list_for_each_entry_safe(ts, next, &obj->ct_timeout.timeout_list, head) {
list_del(&ts->head);
- xfree(ts->timeout_str);
- xfree(ts);
+ free_const(ts->timeout_str);
+ free(ts);
}
}
- xfree(obj);
+ free(obj);
}
struct obj *obj_lookup_fuzzy(const char *obj_name,
@@ -1736,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);
}
@@ -1754,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;
}
}
@@ -1980,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]);
@@ -1998,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]);
@@ -2090,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;
@@ -2116,10 +2069,10 @@ void flowtable_free(struct flowtable *flowtable)
if (flowtable->dev_array != NULL) {
for (i = 0; i < flowtable->dev_array_len; i++)
- xfree(flowtable->dev_array[i]);
- xfree(flowtable->dev_array);
+ free_const(flowtable->dev_array[i]);
+ free(flowtable->dev_array);
}
- xfree(flowtable);
+ free(flowtable);
}
static void flowtable_print_declaration(const struct flowtable *flowtable,
@@ -2265,15 +2218,10 @@ static int do_list_ruleset(struct netlink_ctx *ctx, struct cmd *cmd)
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;
}
@@ -2297,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,
@@ -2309,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->chain_cache.list, cache.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");
@@ -2361,11 +2310,13 @@ 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_cache_find(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, set);
@@ -2398,7 +2349,7 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
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:
@@ -2408,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);
@@ -2427,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:
@@ -2452,7 +2407,7 @@ 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)
+static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd, bool reset)
{
struct set *set, *new_set;
struct expr *init;
@@ -2470,7 +2425,7 @@ 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,
- cmd->elem.set, new_set, init);
+ cmd->elem.set, new_set, init, reset);
if (err >= 0)
__do_list_set(ctx, cmd, new_set);
@@ -2486,7 +2441,7 @@ static int do_command_get(struct netlink_ctx *ctx, struct cmd *cmd)
{
switch (cmd->obj) {
case CMD_OBJ_ELEMENTS:
- return do_get_setelems(ctx, cmd);
+ return do_get_setelems(ctx, cmd, false);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -2515,6 +2470,23 @@ 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);
}
@@ -2632,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);
@@ -2778,10 +2751,8 @@ static void stmt_reduce(const struct rule *rule)
/* Must not merge across other statements */
if (stmt->ops->type != STMT_EXPRESSION) {
- if (idx < 2)
- continue;
-
- payload_do_merge(sa, idx);
+ if (idx >= 2)
+ payload_do_merge(sa, idx);
idx = 0;
continue;
}
@@ -2795,7 +2766,6 @@ static void stmt_reduce(const struct rule *rule)
switch (stmt->expr->op) {
case OP_EQ:
case OP_IMPLICIT:
- case OP_NEQ:
break;
default:
continue;
@@ -2806,7 +2776,8 @@ static void stmt_reduce(const struct rule *rule)
switch (stmt->expr->op) {
case OP_EQ:
case OP_IMPLICIT:
- if (stmt->expr->left->meta.key == NFT_META_PROTOCOL) {
+ 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);
diff --git a/src/scanner.l b/src/scanner.l
index 2154281e..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>
@@ -118,12 +121,12 @@ digit [0-9]
hexdigit [0-9a-fA-F]
decstring {digit}+
hexstring 0[xX]{hexdigit}+
-numberstring ({decstring}|{hexstring})
letter [a-zA-Z]
string ({letter}|[_.])({letter}|{digit}|[/\-_\.])*
quotedstring \"[^"]*\"
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)?
@@ -201,11 +204,12 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
%s SCANSTATE_CT
%s SCANSTATE_COUNTER
%s SCANSTATE_ETH
-%s SCANSTATE_FLAGS
+%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
@@ -215,6 +219,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
%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
@@ -339,7 +345,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"jump" { return JUMP; }
"goto" { return GOTO; }
"return" { return RETURN; }
-<SCANSTATE_EXPR_QUEUE,SCANSTATE_STMT_DUP,SCANSTATE_STMT_FWD,SCANSTATE_STMT_NAT,SCANSTATE_STMT_TPROXY,SCANSTATE_FLAGS,SCANSTATE_IP,SCANSTATE_IP6>"to" { return TO; } /* XXX: SCANSTATE_FLAGS and SCANSTATE_IP here are workarounds */
+<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; }
@@ -358,19 +364,16 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"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; }
"comment" { return COMMENT; }
-<SCANSTATE_FLAGS>{
- "constant" { return CONSTANT; }
- "dynamic" { return DYNAMIC; }
-
- /* log flags */
- "all" { return ALL; }
-}
+"constant" { return CONSTANT; }
"interval" { return INTERVAL; }
+"dynamic" { return DYNAMIC; }
"auto-merge" { return AUTOMERGE; }
"timeout" { return TIMEOUT; }
"gc-interval" { return GC_INTERVAL; }
@@ -403,13 +406,19 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
<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>"prefix" { return PREFIX; }
+<SCANSTATE_STMT_LOG,SCANSTATE_STMT_NAT,SCANSTATE_IP,SCANSTATE_IP6>"prefix" { return PREFIX; }
<SCANSTATE_STMT_LOG>{
"snaplen" { return SNAPLEN; }
"queue-threshold" { return QUEUE_THRESHOLD; }
@@ -418,7 +427,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
}
"queue" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_QUEUE); return QUEUE;}
-<SCANSTATE_FLAGS,SCANSTATE_EXPR_QUEUE>{
+<SCANSTATE_EXPR_QUEUE>{
"num" { return QUEUENUM;}
"bypass" { return BYPASS;}
"fanout" { return FANOUT;}
@@ -437,10 +446,11 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"quota" { scanner_push_start_cond(yyscanner, SCANSTATE_QUOTA); return QUOTA; }
<SCANSTATE_QUOTA>{
- "used" { return USED; }
"until" { return UNTIL; }
}
+<SCANSTATE_QUOTA,SCANSTATE_LAST>"used" { return USED; }
+
"hour" { return HOUR; }
"day" { return DAY; }
@@ -497,7 +507,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
}
"ip" { scanner_push_start_cond(yyscanner, SCANSTATE_IP); return IP; }
-<SCANSTATE_IP,SCANSTATE_IP6,SCANSTATE_EXPR_OSF>{
+<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>{
@@ -514,7 +524,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
<SCANSTATE_EXPR_OSF,SCANSTATE_IP>{
"ttl" { return TTL; }
}
-<SCANSTATE_CT,SCANSTATE_IP,SCANSTATE_META,SCANSTATE_TYPE>"protocol" { return PROTOCOL; }
+<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; }
}
@@ -579,6 +589,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"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; }
@@ -612,7 +624,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
<SCANSTATE_EXPR_COMP>{
"cpi" { return CPI; }
}
-"flags" { scanner_push_start_cond(yyscanner, SCANSTATE_FLAGS); return FLAGS; }
+"flags" { return FLAGS; }
"udp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_UDP); return UDP; }
"udplite" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_UDPLITE); return UDPLITE; }
@@ -625,6 +637,17 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
<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; }
+
+"geneve" { return GENEVE; }
+
+"gre" { scanner_push_start_cond(yyscanner, SCANSTATE_GRE); return GRE; }
+"gretap" { scanner_push_start_cond(yyscanner, SCANSTATE_GRE); return GRETAP; }
"tcp" { scanner_push_start_cond(yyscanner, SCANSTATE_TCP); return TCP; }
@@ -781,6 +804,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"notrack" { return NOTRACK; }
+"all" { return ALL; }
+
<SCANSTATE_CMD_EXPORT,SCANSTATE_CMD_IMPORT,SCANSTATE_CMD_MONITOR>{
"xml" { return XML; }
"json" { return JSON; }
@@ -803,6 +828,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"secmark" { scanner_push_start_cond(yyscanner, SCANSTATE_SECMARK); return SECMARK; }
+"xt" { scanner_push_start_cond(yyscanner, SCANSTATE_XT); return XT; }
+
{addrstring} {
yylval->string = xstrdup(yytext);
return STRING;
@@ -819,9 +846,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
return STRING;
}
-{numberstring} {
+{hexstring} {
errno = 0;
- yylval->val = strtoull(yytext, NULL, 0);
+ yylval->val = strtoull(yytext, NULL, 16);
if (errno != 0) {
yylval->string = xstrdup(yytext);
return STRING;
@@ -829,6 +856,19 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
return NUM;
}
+{decstring} {
+ int base = yytext[0] == '0' ? 8 : 10;
+ char *end;
+
+ errno = 0;
+ yylval->val = strtoull(yytext, &end, base);
+ if (errno != 0 || *end) {
+ yylval->string = xstrdup(yytext);
+ return STRING;
+ }
+ return NUM;
+ }
+
{classid}/[ \t\n:\-},] {
yylval->string = xstrdup(yytext);
return STRING;
@@ -861,6 +901,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
{tab}+
{space}+
+{comment_line} {
+ reset_pos(yyget_extra(yyscanner), yylloc);
+ }
{comment}
<<EOF>> {
@@ -932,9 +975,59 @@ static void scanner_push_file(struct nft_ctx *nft, void *scanner,
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;
+
+ 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 struct input_descriptor *parent_indesc)
+ const struct input_descriptor *parent_indesc,
+ enum nft_include_type includetype)
+
{
struct parser_state *state = yyget_extra(scanner);
struct error_record *erec;
@@ -946,12 +1039,24 @@ static int include_file(struct nft_ctx *nft, void *scanner,
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;
}
+
+ 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:
@@ -1012,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--) {
@@ -1024,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, indesc);
+ ret = include_file(nft, scanner, path, loc, indesc, NFT_INCLUDE);
if (ret != 0)
goto err;
}
@@ -1061,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, NULL);
+ return include_file(nft, nft->scanner, filename, loc, NULL, NFT_CMDLINE);
}
static bool search_in_include_path(const char *filename)
@@ -1148,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)
@@ -1177,6 +1284,8 @@ void scanner_destroy(struct nft_ctx *nft)
struct parser_state *state = yyget_extra(nft->scanner);
input_descriptor_list_destroy(state);
+ free(state->startcond_active);
+
yylex_destroy(nft->scanner);
}
@@ -1185,6 +1294,7 @@ 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);
}
@@ -1193,6 +1303,8 @@ 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! */
@@ -1202,6 +1314,10 @@ void scanner_pop_start_cond(void *scanner, enum startcond_type t)
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);
diff --git a/src/sctp_chunk.c b/src/sctp_chunk.c
index 6e73e72f..24a07e20 100644
--- a/src/sctp_chunk.c
+++ b/src/sctp_chunk.c
@@ -6,10 +6,11 @@
* later) as published by the Free Software Foundation.
*/
+#include <nft.h>
+
#include <exthdr.h>
#include <sctp_chunk.h>
-#include <string.h>
#define PHT(__token, __offset, __len) \
PROTO_HDR_TEMPLATE(__token, &integer_type, BYTEORDER_BIG_ENDIAN, \
diff --git a/src/segtree.c b/src/segtree.c
index f9cac373..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>
@@ -126,9 +126,8 @@ static struct expr *get_set_interval_find(const struct set *cache_set,
case EXPR_VALUE:
if (expr_basetype(i->key)->type != TYPE_STRING)
break;
- /* string type, check if its a range (wildcard), so
- * fall through.
- */
+ /* string type, check if its a range (wildcard). */
+ /* fall-through */
case EXPR_PREFIX:
case EXPR_RANGE:
range_expr_value_low(val, i);
@@ -158,6 +157,8 @@ static struct expr *expr_value(struct expr *expr)
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));
}
@@ -493,12 +494,49 @@ static struct expr *interval_to_range(struct expr *low, struct expr *i, mpz_t ra
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;
unsigned int n, m, size;
- mpz_t range, p;
bool interval;
if (set->size == 0)
@@ -507,9 +545,6 @@ 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) {
@@ -568,32 +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)) {
- if (expr_basetype(low)->type == TYPE_STRING)
- mpz_switch_byteorder(expr_value(low)->value, low->len / BITS_PER_BYTE);
- low->flags |= EXPR_F_KERNEL;
- compound_expr_add(set, expr_get(low));
- } else if (range_is_prefix(range) && !mpz_cmp_ui(p, 0)) {
- struct expr *expr;
-
- 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);
-
- compound_expr_add(set, expr);
- } else {
- struct expr *expr = interval_to_range(low, i, range);
-
- compound_expr_add(set, expr);
- }
+ add_interval(set, low, i);
if (i->flags & EXPR_F_INTERVAL_END) {
expr_free(low);
@@ -610,32 +620,18 @@ void interval_map_decompose(struct expr *set)
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_clone(expr_value(low)), i);
- i = set_elem_expr_alloc(&low->location, i);
- if (low->etype == EXPR_MAPPING) {
- i = mapping_expr_alloc(&i->location, i,
- expr_clone(low->right));
- interval_expr_copy(i->left, low->left);
- } else {
- interval_expr_copy(i, low);
- }
- i->flags |= EXPR_F_KERNEL;
-
+ add_interval(set, low, i);
expr_free(low);
}
- compound_expr_add(set, i);
+ expr_free(i);
+
out:
if (catchall)
compound_expr_add(set, catchall);
- mpz_clear(range);
- mpz_clear(p);
-
- xfree(ranges);
- xfree(elements);
+ free(ranges);
+ free(elements);
}
diff --git a/src/socket.c b/src/socket.c
index eb075153..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>
diff --git a/src/statement.c b/src/statement.c
index 30caf9c7..ab144d63 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -8,12 +8,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 <stdint.h>
#include <inttypes.h>
-#include <string.h>
#include <syslog.h>
#include <rule.h>
@@ -52,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)
@@ -184,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 = {
@@ -249,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",
@@ -455,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);
@@ -465,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 != 5) {
+ if (stmt->limit.burst != 0) {
uint64_t burst;
data_unit = get_rate(stmt->limit.burst, &burst);
@@ -819,6 +847,7 @@ 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)
@@ -960,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, ":");
@@ -997,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 c3e07d78..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>
@@ -119,6 +118,13 @@ static const struct exthdr_desc tcpopt_mptcp = {
[TCPOPT_MPTCP_SUBTYPE] = PHT("subtype", 16, 4),
},
};
+
+static const struct exthdr_desc tcpopt_fallback = {
+ .templates = {
+ [TCPOPT_COMMON_KIND] = PHT("kind", 0, 8),
+ [TCPOPT_COMMON_LENGTH] = PHT("length", 8, 8),
+ },
+};
#undef PHT
const struct exthdr_desc *tcpopt_protocols[] = {
@@ -134,6 +140,17 @@ const struct exthdr_desc *tcpopt_protocols[] = {
[TCPOPT_KIND_FASTOPEN] = &tcpopt_fastopen,
};
+static void tcpopt_assign_tmpl(struct expr *expr,
+ const struct proto_hdr_template *tmpl,
+ const struct exthdr_desc *desc)
+{
+ expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
+
+ expr->exthdr.desc = desc;
+ expr->exthdr.tmpl = tmpl;
+ expr->exthdr.offset = tmpl->offset;
+}
+
/**
* tcpopt_expr_alloc - allocate tcp option extension expression
*
@@ -183,32 +200,38 @@ struct expr *tcpopt_expr_alloc(const struct location *loc,
desc = tcpopt_protocols[kind];
if (!desc) {
- if (field != TCPOPT_COMMON_KIND || kind > 255)
+ 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);
- desc = tcpopt_protocols[TCPOPT_NOP];
- tmpl = &desc->templates[field];
- expr->exthdr.desc = desc;
- expr->exthdr.tmpl = tmpl;
- expr->exthdr.op = NFT_EXTHDR_OP_TCPOPT;
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;
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.raw_type = desc->type;
- expr->exthdr.offset = tmpl->offset;
+ tcpopt_assign_tmpl(expr, tmpl, desc);
return expr;
}
diff --git a/src/utils.c b/src/utils.c
index 925841c5..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;
@@ -100,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 80f0ea03..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>
diff --git a/src/xt.c b/src/xt.c
index 789de992..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,43 +206,23 @@ 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
+ 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);
}
@@ -245,44 +230,23 @@ 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
+ 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);
}
@@ -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)
@@ -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 f78cc901..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 --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))"
[ "$failed" -eq 0 ]
diff --git a/tests/monitor/run-tests.sh b/tests/monitor/run-tests.sh
index b5ca47d9..f1ac790a 100755
--- a/tests/monitor/run-tests.sh
+++ b/tests/monitor/run-tests.sh
@@ -161,7 +161,10 @@ for variant in $variants; do
output_append=${variant}_output_append
for testcase in ${testcases:-testcases/*.t}; do
- echo "$variant: running tests from file $(basename $testcase)"
+ filename=$(basename $testcase)
+ echo "$variant: running tests from file $filename"
+ rc_start=$rc
+
# files are like this:
#
# I add table ip t
@@ -199,6 +202,10 @@ for variant in $variants; do
$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 2afe33c8..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
index b0649cdf..5053c596 100644
--- a/tests/monitor/testcases/set-interval.t
+++ b/tests/monitor/testcases/set-interval.t
@@ -27,4 +27,4 @@ J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "ex
# ... 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 -
-{"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"]}]}]}}}]}}}
+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 2d9c92de..67be5c85 100644
--- a/tests/monitor/testcases/simple.t
+++ b/tests/monitor/testcases/simple.t
@@ -15,13 +15,13 @@ J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "ex
I insert rule ip t c counter accept
O insert 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}]}}}
+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 delete rule ip t c handle 2
O add rule ip t c handle 5 accept comment "foo bar"
-J {"add": {"rule": {"family": "ip", "table": "t", "chain": "c", "handle": 0, "comment": "foo bar", "expr": [{"accept": null}]}}}
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/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..b8a977ed
--- /dev/null
+++ b/tests/py/any/last.t.json.output
@@ -0,0 +1,14 @@
+# last
+[
+ {
+ "last": null
+ }
+]
+
+# last used 300s
+[
+ {
+ "last": null
+ }
+]
+
diff --git a/tests/py/any/last.t.payload b/tests/py/any/last.t.payload
new file mode 100644
index 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 86e8d430..2a84e3f5 100644
--- a/tests/py/any/limit.t
+++ b/tests/py/any/limit.t
@@ -9,11 +9,11 @@
*bridge;test-bridge;output
*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
@@ -22,7 +22,6 @@ 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
@@ -33,13 +32,12 @@ 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
@@ -47,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 b41ae60a..73160b27 100644
--- a/tests/py/any/limit.t.json
+++ b/tests/py/any/limit.t.json
@@ -114,22 +114,11 @@
}
]
-# limit rate 1023000 mbytes/second
-[
- {
- "limit": {
- "per": "second",
- "rate": 1023000,
- "rate_unit": "mbytes"
- }
- }
-]
-
# limit rate 1 bytes / second
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"per": "second",
"rate": 1,
@@ -142,7 +131,7 @@
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"per": "second",
"rate": 1,
@@ -155,7 +144,7 @@
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"per": "second",
"rate": 1,
@@ -203,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
[
{
@@ -343,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
[
{
@@ -396,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
index e6f26496..2c94d2de 100644
--- a/tests/py/any/limit.t.json.output
+++ b/tests/py/any/limit.t.json.output
@@ -57,7 +57,7 @@
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"per": "second",
"rate": 1,
@@ -70,7 +70,7 @@
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"per": "second",
"rate": 2,
@@ -83,7 +83,7 @@
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"per": "second",
"rate": 1025,
@@ -96,7 +96,7 @@
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"per": "second",
"rate": 1023,
@@ -109,7 +109,7 @@
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"per": "second",
"rate": 10230,
@@ -118,19 +118,6 @@
}
]
-# limit rate 1023000 mbytes/second
-[
- {
- "limit": {
- "burst": 5,
- "burst_unit": "bytes",
- "per": "second",
- "rate": 1023000,
- "rate_unit": "mbytes"
- }
- }
-]
-
# limit rate over 400/minute
[
{
@@ -195,7 +182,7 @@
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"inv": true,
"per": "second",
@@ -209,7 +196,7 @@
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"inv": true,
"per": "second",
@@ -223,7 +210,7 @@
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"inv": true,
"per": "second",
@@ -237,7 +224,7 @@
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"inv": true,
"per": "second",
@@ -251,7 +238,7 @@
[
{
"limit": {
- "burst": 5,
+ "burst": 0,
"burst_unit": "bytes",
"inv": true,
"per": "second",
@@ -260,18 +247,3 @@
}
}
]
-
-# limit rate over 1023000 mbytes/second
-[
- {
- "limit": {
- "burst": 5,
- "burst_unit": "bytes",
- "inv": true,
- "per": "second",
- "rate": 1023000,
- "rate_unit": "mbytes"
- }
- }
-]
-
diff --git a/tests/py/any/limit.t.payload b/tests/py/any/limit.t.payload
index 3bd85f4e..dc6701b3 100644
--- a/tests/py/any/limit.t.payload
+++ b/tests/py/any/limit.t.payload
@@ -24,39 +24,35 @@ ip test-ip4 output
# limit rate 1 kbytes/second
ip test-ip4 output
- [ limit rate 1024/second burst 5 type bytes flags 0x0 ]
+ [ limit rate 1024/second burst 0 type bytes flags 0x0 ]
# limit rate 2 kbytes/second
ip test-ip4 output
- [ limit rate 2048/second burst 5 type bytes flags 0x0 ]
+ [ limit rate 2048/second burst 0 type bytes flags 0x0 ]
# limit rate 1025 kbytes/second
ip test-ip4 output
- [ limit rate 1049600/second burst 5 type bytes flags 0x0 ]
+ [ limit rate 1049600/second burst 0 type bytes flags 0x0 ]
# limit rate 1023 mbytes/second
ip test-ip4 output
- [ limit rate 1072693248/second burst 5 type bytes flags 0x0 ]
+ [ limit rate 1072693248/second burst 0 type bytes flags 0x0 ]
# limit rate 10230 mbytes/second
ip test-ip4 output
- [ limit rate 10726932480/second burst 5 type bytes flags 0x0 ]
-
-# limit rate 1023000 mbytes/second
-ip test-ip4 output
- [ limit rate 1072693248000/second burst 5 type bytes flags 0x0 ]
+ [ limit rate 10726932480/second burst 0 type bytes flags 0x0 ]
# limit rate 1 bytes / second
ip
- [ limit rate 1/second burst 5 type bytes flags 0x0 ]
+ [ limit rate 1/second burst 0 type bytes flags 0x0 ]
# limit rate 1 kbytes / second
ip
- [ limit rate 1024/second burst 5 type bytes flags 0x0 ]
+ [ limit rate 1024/second burst 0 type bytes flags 0x0 ]
# limit rate 1 mbytes / second
ip
- [ limit rate 1048576/second burst 5 type bytes flags 0x0 ]
+ [ limit rate 1048576/second burst 0 type bytes flags 0x0 ]
# limit rate 1025 bytes/second burst 512 bytes
@@ -71,10 +67,6 @@ 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 5 type packets flags 0x1 ]
@@ -101,27 +93,23 @@ ip test-ip4 output
# limit rate over 1 kbytes/second
ip test-ip4 output
- [ limit rate 1024/second burst 5 type bytes flags 0x1 ]
+ [ limit rate 1024/second burst 0 type bytes flags 0x1 ]
# limit rate over 2 kbytes/second
ip test-ip4 output
- [ limit rate 2048/second burst 5 type bytes flags 0x1 ]
+ [ limit rate 2048/second burst 0 type bytes flags 0x1 ]
# limit rate over 1025 kbytes/second
ip test-ip4 output
- [ limit rate 1049600/second burst 5 type bytes flags 0x1 ]
+ [ limit rate 1049600/second burst 0 type bytes flags 0x1 ]
# limit rate over 1023 mbytes/second
ip test-ip4 output
- [ limit rate 1072693248/second burst 5 type bytes flags 0x1 ]
+ [ limit rate 1072693248/second burst 0 type bytes flags 0x1 ]
# limit rate over 10230 mbytes/second
ip test-ip4 output
- [ limit rate 10726932480/second burst 5 type bytes flags 0x1 ]
-
-# limit rate over 1023000 mbytes/second
-ip test-ip4 output
- [ limit rate 1072693248000/second burst 5 type bytes flags 0x1 ]
+ [ limit rate 10726932480/second burst 0 type bytes flags 0x1 ]
# limit rate over 1025 bytes/second burst 512 bytes
ip test-ip4 output
@@ -134,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 12fabb79..bd10c56d 100644
--- a/tests/py/any/meta.t
+++ b/tests/py/any/meta.t
@@ -56,7 +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/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
@@ -224,3 +224,7 @@ 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 4734bbf9..2af3f623 100644
--- a/tests/py/any/meta.t.json
+++ b/tests/py/any/meta.t.json
@@ -667,17 +667,17 @@
{
"match": {
"left": {
- "meta": {
- "key": "mark"
- }
+ "&": [
+ {
+ "meta": {
+ "key": "mark"
+ }
+ },
+ 4294967040
+ ]
},
"op": "==",
- "right": {
- "prefix": {
- "addr": 4294967040,
- "len": 24
- }
- }
+ "right": 4294967040
}
}
]
@@ -2758,3 +2758,63 @@
"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.payload b/tests/py/any/meta.t.payload
index 16dc1211..49dd729b 100644
--- a/tests/py/any/meta.t.payload
+++ b/tests/py/any/meta.t.payload
@@ -1072,3 +1072,28 @@ ip test-ip4 input
[ 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/queue.t b/tests/py/any/queue.t
index f12acfaf..2e511362 100644
--- a/tests/py/any/queue.t
+++ b/tests/py/any/queue.t
@@ -3,7 +3,6 @@
*ip;test-ip4;output
*ip6;test-ip6;output
*inet;test-inet;output
-*arp;test-arp;output
*bridge;test-bridge;output
queue;ok;queue to 0
diff --git a/tests/py/any/rawpayload.t b/tests/py/any/rawpayload.t
index 128e8088..5bc9d35f 100644
--- a/tests/py/any/rawpayload.t
+++ b/tests/py/any/rawpayload.t
@@ -19,4 +19,6 @@ meta l4proto tcp @th,16,16 { 22, 23, 80};ok;tcp dport { 22, 23, 80}
@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 b5115e0d..4cae4d49 100644
--- a/tests/py/any/rawpayload.t.json
+++ b/tests/py/any/rawpayload.t.json
@@ -156,6 +156,37 @@
}
]
+# 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
[
{
diff --git a/tests/py/any/rawpayload.t.payload b/tests/py/any/rawpayload.t.payload
index 61c41cb9..fe2377e6 100644
--- a/tests/py/any/rawpayload.t.payload
+++ b/tests/py/any/rawpayload.t.payload
@@ -48,6 +48,14 @@ 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 ]
diff --git a/tests/py/bridge/meta.t b/tests/py/bridge/meta.t
index d77ebd89..171aa610 100644
--- a/tests/py/bridge/meta.t
+++ b/tests/py/bridge/meta.t
@@ -9,3 +9,5 @@ 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/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/vlan.t b/tests/py/bridge/vlan.t
index 924ed4ed..8fa90dac 100644
--- a/tests/py/bridge/vlan.t
+++ b/tests/py/bridge/vlan.t
@@ -47,3 +47,10 @@ 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 e7640f9a..7dfcdb4b 100644
--- a/tests/py/bridge/vlan.t.json
+++ b/tests/py/bridge/vlan.t.json
@@ -761,3 +761,134 @@
}
}
]
+
+# 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 2f90c8ff..eea2d411 100644
--- a/tests/py/bridge/vlan.t.json.output
+++ b/tests/py/bridge/vlan.t.json.output
@@ -202,3 +202,34 @@
}
}
]
+
+# 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 6c8d595a..2592bb96 100644
--- a/tests/py/bridge/vlan.t.payload
+++ b/tests/py/bridge/vlan.t.payload
@@ -276,3 +276,39 @@ bridge
[ 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 d2c7d74a..f3341947 100644
--- a/tests/py/bridge/vlan.t.payload.netdev
+++ b/tests/py/bridge/vlan.t.payload.netdev
@@ -322,3 +322,47 @@ netdev
[ 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/dccp.t b/tests/py/inet/dccp.t
index 90142f53..99cddbe7 100644
--- a/tests/py/inet/dccp.t
+++ b/tests/py/inet/dccp.t
@@ -23,3 +23,8 @@ dccp type {request, response, data, ack, dataack, closereq, close, reset, sync,
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 806ef5ee..9f47e97b 100644
--- a/tests/py/inet/dccp.t.json
+++ b/tests/py/inet/dccp.t.json
@@ -230,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 fbe9dc5b..c0b87be1 100644
--- a/tests/py/inet/dccp.t.payload
+++ b/tests/py/inet/dccp.t.payload
@@ -99,3 +99,17 @@ inet test-inet input
[ 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/ether.t b/tests/py/inet/ether.t
index c4b1ced7..8625f70b 100644
--- a/tests/py/inet/ether.t
+++ b/tests/py/inet/ether.t
@@ -12,3 +12,9 @@ tcp dport 22 iiftype ether ether saddr 00:0f:54:0c:11:4 accept;ok;tcp dport 22 e
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 e9208008..0128d5f0 100644
--- a/tests/py/inet/ether.t.payload.bridge
+++ b/tests/py/inet/ether.t.payload.bridge
@@ -26,3 +26,19 @@ bridge test-bridge input
[ cmp eq reg 1 0x0c540f00 0x00000411 ]
[ immediate reg 0 accept ]
+# vlan id 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 ]
+ [ 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 a604f603..7c91f412 100644
--- a/tests/py/inet/ether.t.payload.ip
+++ b/tests/py/inet/ether.t.payload.ip
@@ -30,3 +30,23 @@ ip test-ip4 input
[ cmp eq reg 1 0x0c540f00 0x00000411 ]
[ immediate reg 0 accept ]
+# vlan id 1
+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 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# ether type vlan vlan id 2
+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 ]
+ [ cmp eq reg 1 0x00000200 ]
+
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/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 c46a2263..9648255d 100644
--- a/tests/py/inet/ipsec.t.payload
+++ b/tests/py/inet/ipsec.t.payload
@@ -37,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/meta.t b/tests/py/inet/meta.t
index 423cc5f3..7d2515c9 100644
--- a/tests/py/inet/meta.t
+++ b/tests/py/inet/meta.t
@@ -21,3 +21,13 @@ 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 723a36f7..0fee165f 100644
--- a/tests/py/inet/meta.t.json
+++ b/tests/py/inet/meta.t.json
@@ -289,3 +289,281 @@
}
}
]
+
+# 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 fd054549..7184fa0c 100644
--- a/tests/py/inet/meta.t.payload
+++ b/tests/py/inet/meta.t.payload
@@ -97,3 +97,93 @@ inet test-inet input
[ 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/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/tcp.t b/tests/py/inet/tcp.t
index f51ebd36..f4bdac17 100644
--- a/tests/py/inet/tcp.t
+++ b/tests/py/inet/tcp.t
@@ -68,8 +68,8 @@ tcp flags != { fin, urg, ecn, cwr} drop;ok
tcp flags cwr;ok
tcp flags != cwr;ok
tcp flags == syn;ok
-tcp flags fin,syn / fin,syn;ok
-tcp flags != syn / fin,syn;ok
+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
@@ -77,12 +77,12 @@ 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 syn / fin,syn,rst,ack
-tcp flags & (fin | syn | rst | ack) == syn;ok;tcp flags syn / fin,syn,rst,ack
-tcp flags & (fin | syn | rst | ack) != syn;ok;tcp flags != syn / fin,syn,rst,ack
-tcp flags & (fin | syn | rst | ack) == (syn | ack);ok;tcp flags syn,ack / fin,syn,rst,ack
-tcp flags & (fin | syn | rst | ack) != (syn | ack);ok;tcp flags != syn,ack / fin,syn,rst,ack
-tcp flags & (syn | ack) == (syn | ack);ok;tcp flags syn,ack / syn,ack
+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
diff --git a/tests/py/inet/tcp.t.json b/tests/py/inet/tcp.t.json
index 8439c2b5..d3a846cf 100644
--- a/tests/py/inet/tcp.t.json
+++ b/tests/py/inet/tcp.t.json
@@ -1712,7 +1712,7 @@
}
]
-# tcp flags & (fin | syn | rst | ack) == (syn | ack)
+# tcp flags & (fin | syn | rst | ack) == syn | ack
[
{
"match": {
@@ -1741,7 +1741,7 @@
}
]
-# tcp flags & (fin | syn | rst | ack) != (syn | ack)
+# tcp flags & (syn | ack) == syn | ack
[
{
"match": {
@@ -1754,14 +1754,12 @@
}
},
[
- "fin",
"syn",
- "rst",
"ack"
]
]
},
- "op": "!=",
+ "op": "==",
"right": [
"syn",
"ack"
@@ -1770,7 +1768,7 @@
}
]
-# tcp flags & (syn | ack) == (syn | ack)
+# tcp flags & (fin | syn | rst | ack) != syn | ack
[
{
"match": {
@@ -1782,17 +1780,31 @@
"protocol": "tcp"
}
},
- [
- "syn",
- "ack"
- ]
+ {
+ "|": [
+ {
+ "|": [
+ {
+ "|": [
+ "fin",
+ "syn"
+ ]
+ },
+ "rst"
+ ]
+ },
+ "ack"
+ ]
+ }
]
},
- "op": "==",
- "right": [
- "syn",
- "ack"
- ]
+ "op": "!=",
+ "right": {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ }
}
}
]
diff --git a/tests/py/inet/tcp.t.json.output b/tests/py/inet/tcp.t.json.output
index c471e8d8..e186e127 100644
--- a/tests/py/inet/tcp.t.json.output
+++ b/tests/py/inet/tcp.t.json.output
@@ -208,3 +208,282 @@
}
}
]
+
+# tcp flags fin,syn / fin,syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ "fin",
+ "syn"
+ ]
+ }
+ ]
+ },
+ "op": "==",
+ "right": {
+ "|": [
+ "fin",
+ "syn"
+ ]
+ }
+ }
+ }
+]
+
+# tcp flags != syn / fin,syn
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "flags",
+ "protocol": "tcp"
+ }
+ },
+ {
+ "|": [
+ "fin",
+ "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 & (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"
+ ]
+ }
+ }
+ }
+]
+
diff --git a/tests/py/inet/tcp.t.payload b/tests/py/inet/tcp.t.payload
index 1cfe500b..bc6bb989 100644
--- a/tests/py/inet/tcp.t.payload
+++ b/tests/py/inet/tcp.t.payload
@@ -442,7 +442,7 @@ inet test-inet input
[ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000002 ]
-# tcp flags & (fin | syn | rst | ack) == (syn | ack)
+# tcp flags & (fin | syn | rst | ack) == syn | ack
inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -450,7 +450,7 @@ inet test-inet input
[ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
[ cmp eq reg 1 0x00000012 ]
-# tcp flags & (fin | syn | rst | ack) != (syn | ack)
+# tcp flags & (fin | syn | rst | ack) != syn | ack
inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
@@ -458,7 +458,7 @@ inet test-inet input
[ bitwise reg 1 = ( reg 1 & 0x00000017 ) ^ 0x00000000 ]
[ cmp neq reg 1 0x00000012 ]
-# tcp flags & (syn | ack) == (syn | ack)
+# tcp flags & (syn | ack) == syn | ack
inet test-inet input
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
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 24bf8f60..2f419042 100644
--- a/tests/py/inet/tproxy.t.payload
+++ b/tests/py/inet/tproxy.t.payload
@@ -61,3 +61,15 @@ inet x y
[ 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/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 a387863e..a0a22289 100644
--- a/tests/py/ip/ct.t
+++ b/tests/py/ip/ct.t
@@ -28,3 +28,9 @@ meta mark set ct original saddr . meta mark map { 1.1.1.1 . 0x00000014 : 0x00000
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 3288413f..915632ae 100644
--- a/tests/py/ip/ct.t.json
+++ b/tests/py/ip/ct.t.json
@@ -325,3 +325,157 @@
}
}
]
+
+# 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 49f06a84..692011d0 100644
--- a/tests/py/ip/ct.t.payload
+++ b/tests/py/ip/ct.t.payload
@@ -84,3 +84,53 @@ 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 889f0fd7..881571db 100644
--- a/tests/py/ip/dnat.t
+++ b/tests/py/ip/dnat.t
@@ -19,3 +19,5 @@ dnat ip to ip saddr . tcp dport map { 192.168.1.2 . 80 : 10.141.10.0/24 . 8888
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 ede4d04b..fe15d072 100644
--- a/tests/py/ip/dnat.t.json
+++ b/tests/py/ip/dnat.t.json
@@ -595,3 +595,149 @@
}
]
+# 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 e53838a3..439c6abe 100644
--- a/tests/py/ip/dnat.t.payload.ip
+++ b/tests/py/ip/dnat.t.payload.ip
@@ -180,3 +180,25 @@ ip
[ 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/ip.t b/tests/py/ip/ip.t
index d5a4d8a5..e6999c29 100644
--- a/tests/py/ip/ip.t
+++ b/tests/py/ip/ip.t
@@ -48,12 +48,15 @@ ip id != 33-45;ok
ip id { 33, 55, 67, 88};ok
ip id != { 33, 55, 67, 88};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 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
@@ -127,3 +130,8 @@ 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 b1085035..a170e5c1 100644
--- a/tests/py/ip/ip.t.json
+++ b/tests/py/ip/ip.t.json
@@ -384,7 +384,7 @@
}
]
-# ip frag-off 222 accept
+# ip frag-off 0xde accept
[
{
"match": {
@@ -403,7 +403,7 @@
}
]
-# ip frag-off != 233
+# ip frag-off != 0xe9
[
{
"match": {
@@ -419,7 +419,7 @@
}
]
-# ip frag-off 33-45
+# ip frag-off 0x21-0x2d
[
{
"match": {
@@ -437,7 +437,7 @@
}
]
-# ip frag-off != 33-45
+# ip frag-off != 0x21-0x2d
[
{
"match": {
@@ -455,7 +455,7 @@
}
]
-# ip frag-off { 33, 55, 67, 88}
+# ip frag-off { 0x21, 0x37, 0x43, 0x58}
[
{
"match": {
@@ -478,7 +478,7 @@
}
]
-# ip frag-off != { 33, 55, 67, 88}
+# ip frag-off != { 0x21, 0x37, 0x43, 0x58}
[
{
"match": {
@@ -501,6 +501,69 @@
}
]
+# ip frag-off & 0x1fff != 0x0
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "frag-off",
+ "protocol": "ip"
+ }
+ },
+ 8191
+ ]
+ },
+ "op": "!=",
+ "right": 0
+ }
+ }
+]
+
+# ip frag-off & 0x2000 != 0x0
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "frag-off",
+ "protocol": "ip"
+ }
+ },
+ 8192
+ ]
+ },
+ "op": "!=",
+ "right": 0
+ }
+ }
+]
+
+# ip frag-off & 0x4000 != 0x0
+[
+ {
+ "match": {
+ "left": {
+ "&": [
+ {
+ "payload": {
+ "field": "frag-off",
+ "protocol": "ip"
+ }
+ },
+ 16384
+ ]
+ },
+ "op": "!=",
+ "right": 0
+ }
+ }
+]
+
# ip ttl 0 drop
[
{
@@ -1685,3 +1748,85 @@
}
]
+# 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 b9fcb515..d7ddf7be 100644
--- a/tests/py/ip/ip.t.payload
+++ b/tests/py/ip/ip.t.payload
@@ -124,29 +124,29 @@ 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]
@@ -154,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]
@@ -162,6 +162,24 @@ ip test-ip4 input
[ payload load 2b @ network header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
+# ip frag-off & 0x1fff != 0x0
+ip test-ip4 input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff1f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# ip frag-off & 0x2000 != 0x0
+ip test-ip4 input
+ [ payload load 2b @ network header + 6 => reg 1 ]
+ [ 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
[ payload load 1b @ network header + 8 => reg 1 ]
@@ -523,3 +541,26 @@ 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 c6f8d4e5..53f881d3 100644
--- a/tests/py/ip/ip.t.payload.bridge
+++ b/tests/py/ip/ip.t.payload.bridge
@@ -162,7 +162,7 @@ bridge test-bridge 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
bridge test-bridge input
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x00000008 ]
@@ -170,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 ]
@@ -185,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]
@@ -202,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]
@@ -212,6 +212,30 @@ bridge test-bridge input
[ payload load 2b @ network header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
+# 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 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff1f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# 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 ]
+ [ 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
[ meta load protocol => reg 1 ]
@@ -684,3 +708,31 @@ bridge
[ 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 e26d0dac..08674c98 100644
--- a/tests/py/ip/ip.t.payload.inet
+++ b/tests/py/ip/ip.t.payload.inet
@@ -162,7 +162,7 @@ inet test-inet 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
inet test-inet input
[ meta load nfproto => reg 1 ]
[ cmp eq reg 1 0x00000002 ]
@@ -170,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 ]
@@ -185,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]
@@ -202,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]
@@ -212,6 +212,30 @@ inet test-inet input
[ payload load 2b @ network header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
+# 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 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff1f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# 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 ]
+ [ 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
[ meta load nfproto => reg 1 ]
@@ -684,3 +708,31 @@ inet
[ 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 de990f5b..8220b05d 100644
--- a/tests/py/ip/ip.t.payload.netdev
+++ b/tests/py/ip/ip.t.payload.netdev
@@ -96,7 +96,7 @@ netdev test-netdev ingress
[ 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 ]
@@ -104,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 ]
@@ -119,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]
@@ -136,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]
@@ -146,6 +146,30 @@ netdev test-netdev ingress
[ payload load 2b @ network header + 6 => reg 1 ]
[ lookup reg 1 set __set%d 0x1 ]
+# 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 ]
+ [ bitwise reg 1 = ( reg 1 & 0x0000ff1f ) ^ 0x00000000 ]
+ [ cmp neq reg 1 0x00000000 ]
+
+# 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 ]
+ [ 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
[ meta load protocol => reg 1 ]
@@ -684,3 +708,31 @@ netdev
[ 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/meta.t b/tests/py/ip/meta.t
index 5a05923a..a88a6145 100644
--- a/tests/py/ip/meta.t
+++ b/tests/py/ip/meta.t
@@ -15,3 +15,8 @@ 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 3df31ce3..25936dba 100644
--- a/tests/py/ip/meta.t.json
+++ b/tests/py/ip/meta.t.json
@@ -156,3 +156,81 @@
}
}
]
+
+# 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 afde5cc1..880ac5d6 100644
--- a/tests/py/ip/meta.t.payload
+++ b/tests/py/ip/meta.t.payload
@@ -51,3 +51,28 @@ ip test-ip4 input
[ 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.json.output b/tests/py/ip/numgen.t.json.output
index b54121ca..06ad1ecc 100644
--- a/tests/py/ip/numgen.t.json.output
+++ b/tests/py/ip/numgen.t.json.output
@@ -80,3 +80,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 3349c68b..b4eadf85 100644
--- a/tests/py/ip/numgen.t.payload
+++ b/tests/py/ip/numgen.t.payload
@@ -27,3 +27,14 @@ 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 424ad7b4..4bed47c1 100644
--- a/tests/py/ip/redirect.t.payload
+++ b/tests/py/ip/redirect.t.payload
@@ -207,12 +207,12 @@ 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 ]
diff --git a/tests/py/ip/sets.t b/tests/py/ip/sets.t
index a224d0fe..46d9686b 100644
--- a/tests/py/ip/sets.t
+++ b/tests/py/ip/sets.t
@@ -52,6 +52,9 @@ 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 }
diff --git a/tests/py/ip/sets.t.json b/tests/py/ip/sets.t.json
index d24b3918..44ca1528 100644
--- a/tests/py/ip/sets.t.json
+++ b/tests/py/ip/sets.t.json
@@ -272,3 +272,34 @@
}
]
+# 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 d7d70b0c..fd6517a5 100644
--- a/tests/py/ip/sets.t.payload.inet
+++ b/tests/py/ip/sets.t.payload.inet
@@ -75,6 +75,15 @@ inet
[ 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
diff --git a/tests/py/ip/sets.t.payload.ip b/tests/py/ip/sets.t.payload.ip
index 97a96693..d9cc32b6 100644
--- a/tests/py/ip/sets.t.payload.ip
+++ b/tests/py/ip/sets.t.payload.ip
@@ -73,3 +73,11 @@ 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 d4317d29..d41b9e8b 100644
--- a/tests/py/ip/sets.t.payload.netdev
+++ b/tests/py/ip/sets.t.payload.netdev
@@ -95,3 +95,13 @@ netdev
[ 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/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/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.payload.netdev b/tests/py/ip6/frag.t.payload.netdev
index 821d5679..05620754 100644
--- a/tests/py/ip6/frag.t.payload.netdev
+++ b/tests/py/ip6/frag.t.payload.netdev
@@ -1,1441 +1,102 @@
-# frag frag-off 22
-netdev
- [ 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 22
-netdev
- [ 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
- [ 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 != 233
-netdev
- [ 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
- [ 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
- [ 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
- [ 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-45
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off != { 33, 55, 67, 88}
-__set%d test-netdev 3
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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 frag-off != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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
- [ 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 reserved2 1
-netdev
- [ 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
- [ 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 0
-netdev
- [ 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
- [ 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 more-fragments 1
-netdev
- [ 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 frag-off 22
-netdev
- [ 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 22
-netdev
- [ 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
- [ 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 != 233
-netdev
- [ 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
- [ 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
- [ 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
- [ 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-45
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off != { 33, 55, 67, 88}
-__set%d test-netdev 3
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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 frag-off != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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
- [ 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 reserved2 1
-netdev
- [ 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
- [ 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 0
-netdev
- [ 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
- [ 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 more-fragments 1
-netdev
- [ 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 frag-off 22
-netdev
- [ 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 22
-netdev
- [ 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
- [ 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 != 233
-netdev
- [ 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
- [ 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
- [ 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
- [ 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-45
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off != { 33, 55, 67, 88}
-__set%d test-netdev 3
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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 frag-off != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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
- [ 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 reserved2 1
-netdev
- [ 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
- [ 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 0
-netdev
- [ 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
- [ 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 more-fragments 1
-netdev
- [ 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 nexthdr tcp
-netdev
- [ 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 tcp
-netdev
- [ 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
- [ 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 != icmp
-netdev
- [ 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
-__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
- [ 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
-__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
- [ 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
-__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
- [ 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, ah, comp, udp, udplite, tcp, dccp, sctp}
-__set%d test-netdev 3
-__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
- [ 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
- [ 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 esp
-netdev
- [ 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
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x0000dd86 ]
- [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000033 ]
-
-# frag nexthdr ah
-netdev
- [ 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
- [ 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 22
-netdev
- [ 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
- [ 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 != 233
-netdev
- [ 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
- [ 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
- [ 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
- [ 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-45
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
-netdev
- [ 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 reserved != { 33, 55, 67, 88}
-__set%d test-netdev 3
-__set%d test-netdev 0
- element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
-netdev
- [ 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 reserved { 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
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-netdev
- [ 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 reserved != { 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
- [ 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
- [ 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 22
-netdev
- [ 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
- [ 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 != 233
-netdev
- [ 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
- [ 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
- [ 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
- [ 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-45
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off != { 33, 55, 67, 88}
-__set%d test-netdev 3
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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 frag-off != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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
- [ 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 reserved2 1
-netdev
- [ 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
- [ 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 0
-netdev
- [ 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
- [ 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 more-fragments 1
-netdev
- [ 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
- [ 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 1
-netdev
- [ 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
- [ 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 22
-netdev
- [ 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
- [ 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
-netdev
- [ 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
- [ 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
- [ 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
- [ 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-45
-netdev
- [ 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
-__set%d test-netdev 0
- element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
-netdev
- [ 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 ]
-
-# frag id != { 33, 55, 67, 88}
-__set%d test-netdev 3
-__set%d test-netdev 0
- element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
-netdev
- [ 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 ]
-
-# frag id { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-netdev
- [ 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 ]
-
-# frag id != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-netdev
- [ 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 ]
-
-# frag nexthdr tcp
-netdev
- [ 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 tcp
-netdev
+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
- [ 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 != icmp
-netdev
+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
-__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
- [ 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
+__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
+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
-__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
- [ 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, ah, comp, udp, udplite, tcp, dccp, sctp}
-__set%d test-netdev 3
+__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
+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
+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 esp
-netdev
- [ 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
- [ meta load protocol => reg 1 ]
- [ cmp eq reg 1 0x0000dd86 ]
- [ exthdr load ipv6 1b @ 44 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000033 ]
-
# frag nexthdr ah
-netdev
+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
+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 22
-netdev
- [ 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
- [ 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 != 233
-netdev
+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
+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
- [ 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
- [ 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-45
-netdev
+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
+__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
- [ 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
-__set%d test-netdev 0
- element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
-netdev
+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
+__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
+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 reserved != { 33, 55, 67, 88}
-__set%d test-netdev 3
-__set%d test-netdev 0
- element 00000021 : 0 [end] element 00000037 : 0 [end] element 00000043 : 0 [end] element 00000058 : 0 [end]
-netdev
- [ 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 reserved { 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
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end]
-netdev
- [ 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 reserved != { 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
- [ 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
- [ 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 22
-netdev
+netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
@@ -1443,15 +104,7 @@ netdev
[ cmp eq reg 1 0x0000b000 ]
# frag frag-off != 233
-netdev
- [ 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 != 233
-netdev
+netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
@@ -1459,7 +112,7 @@ netdev
[ cmp neq reg 1 0x00004807 ]
# frag frag-off 33-45
-netdev
+netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
@@ -1467,25 +120,8 @@ netdev
[ cmp gte reg 1 0x00000801 ]
[ cmp lte reg 1 0x00006801 ]
-# frag frag-off 33-45
-netdev
- [ 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
- [ 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-45
-netdev
+netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
[ exthdr load ipv6 2b @ 44 + 2 => reg 1 ]
@@ -1493,103 +129,29 @@ netdev
[ range neq reg 1 0x00000801 0x00006801 ]
# frag frag-off { 33, 55, 67, 88}
-__set%d test-netdev 3
+__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
+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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off != { 33, 55, 67, 88}
-__set%d test-netdev 3
+__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
+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 frag-off { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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 frag-off != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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
- [ 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 reserved2 1
-netdev
+netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
[ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
@@ -1597,15 +159,7 @@ netdev
[ cmp eq reg 1 0x00000002 ]
# frag more-fragments 0
-netdev
- [ 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 0
-netdev
+netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
[ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
@@ -1613,15 +167,7 @@ netdev
[ cmp eq reg 1 0x00000000 ]
# frag more-fragments 1
-netdev
- [ 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 more-fragments 1
-netdev
+netdev test-netdev ingress
[ meta load protocol => reg 1 ]
[ cmp eq reg 1 0x0000dd86 ]
[ exthdr load ipv6 1b @ 44 + 3 => reg 1 ]
@@ -1629,558 +175,58 @@ netdev
[ cmp eq reg 1 0x00000001 ]
# frag id 1
-netdev
- [ 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 1
-netdev
+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
- [ 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 22
-netdev
+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
- [ 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
-netdev
+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
+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
- [ 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
- [ 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-45
-netdev
+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
+__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
+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
-__set%d test-netdev 0
- element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 21000000 : 0 [end] element 37000000 : 0 [end] element 43000000 : 0 [end] element 58000000 : 0 [end]
-netdev
- [ 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 ]
-
# frag id != { 33, 55, 67, 88}
-__set%d test-netdev 3
+__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
- [ 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 ]
-
-# frag id { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-netdev
- [ 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 ]
-
-# frag id != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 21000000 : 0 [end] element 38000000 : 1 [end]
-netdev
+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 ]
-# frag frag-off 22
-netdev
- [ 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 22
-netdev
- [ 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
- [ 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 != 233
-netdev
- [ 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
- [ 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
- [ 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
- [ 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-45
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off != { 33, 55, 67, 88}
-__set%d test-netdev 3
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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 frag-off != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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
- [ 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 reserved2 1
-netdev
- [ 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
- [ 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 0
-netdev
- [ 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
- [ 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 more-fragments 1
-netdev
- [ 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 frag-off 22
-netdev
- [ 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 22
-netdev
- [ 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
- [ 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 != 233
-netdev
- [ 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
- [ 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
- [ 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
- [ 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-45
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off != { 33, 55, 67, 88}
-__set%d test-netdev 3
-__set%d test-netdev 0
- element 00000801 : 0 [end] element 0000b801 : 0 [end] element 00001802 : 0 [end] element 0000c002 : 0 [end]
-netdev
- [ 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 frag-off { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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 frag-off != { 33-55}
-__set%d test-netdev 7
-__set%d test-netdev 0
- element 00000000 : 1 [end] element 00000801 : 0 [end] element 0000b901 : 1 [end]
-netdev
- [ 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
- [ 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 reserved2 1
-netdev
- [ 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
- [ 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 0
-netdev
- [ 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
- [ 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 more-fragments 1
-netdev
- [ 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 ]
-
diff --git a/tests/py/ip6/icmpv6.t b/tests/py/ip6/icmpv6.t
index 4de6ee23..35dad2be 100644
--- a/tests/py/ip6/icmpv6.t
+++ b/tests/py/ip6/icmpv6.t
@@ -85,3 +85,15 @@ icmpv6 max-delay {33, 55, 67, 88};ok
icmpv6 max-delay != {33, 55, 67, 88};ok
icmpv6 type parameter-problem icmpv6 code no-route;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 2251be82..224a8e81 100644
--- a/tests/py/ip6/icmpv6.t.json
+++ b/tests/py/ip6/icmpv6.t.json
@@ -1163,3 +1163,263 @@
}
}
]
+
+# 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": [
+ "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 taddr 2001:db8::133
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "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 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": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "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 type { nd-neighbor-solicit, nd-neighbor-advert } icmpv6 taddr 2001:db8::133
+[
+ {
+ "match": {
+ "left": {
+ "payload": {
+ "field": "type",
+ "protocol": "icmpv6"
+ }
+ },
+ "op": "==",
+ "right": {
+ "set": [
+ "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.payload.ip6 b/tests/py/ip6/icmpv6.t.payload.ip6
index 0e96be2d..fcaf4812 100644
--- a/tests/py/ip6/icmpv6.t.payload.ip6
+++ b/tests/py/ip6/icmpv6.t.payload.ip6
@@ -561,3 +561,83 @@ ip6
[ 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 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 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 { 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 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 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 2ffe318e..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
diff --git a/tests/py/ip6/ip6.t.json b/tests/py/ip6/ip6.t.json
index cf802175..49e5a2dd 100644
--- a/tests/py/ip6/ip6.t.json
+++ b/tests/py/ip6/ip6.t.json
@@ -135,6 +135,106 @@
}
]
+# 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": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ "op": "==",
+ "right": "@map3"
+ }
+ }
+]
+
+# ip6 dscp . ip6 daddr @map4
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "dscp",
+ "protocol": "ip6"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip6"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": "@map4"
+ }
+ }
+]
+
# ip6 flowlabel 22
[
{
diff --git a/tests/py/ip6/ip6.t.payload.inet b/tests/py/ip6/ip6.t.payload.inet
index 20dfe549..dbb430af 100644
--- a/tests/py/ip6/ip6.t.payload.inet
+++ b/tests/py/ip6/ip6.t.payload.inet
@@ -53,6 +53,50 @@ ip6 test-ip6 input
[ 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 ]
diff --git a/tests/py/ip6/ip6.t.payload.ip6 b/tests/py/ip6/ip6.t.payload.ip6
index f8e3ca3c..b1289232 100644
--- a/tests/py/ip6/ip6.t.payload.ip6
+++ b/tests/py/ip6/ip6.t.payload.ip6
@@ -41,6 +41,42 @@ ip6 test-ip6 input
[ 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 ]
diff --git a/tests/py/ip6/meta.t b/tests/py/ip6/meta.t
index 471e1481..c177b081 100644
--- a/tests/py/ip6/meta.t
+++ b/tests/py/ip6/meta.t
@@ -14,3 +14,6 @@ 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 351320d7..1a2394d8 100644
--- a/tests/py/ip6/meta.t.json
+++ b/tests/py/ip6/meta.t.json
@@ -194,3 +194,120 @@
}
}
]
+
+# 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.payload b/tests/py/ip6/meta.t.payload
index 0e3db6ba..6a37f1de 100644
--- a/tests/py/ip6/meta.t.payload
+++ b/tests/py/ip6/meta.t.payload
@@ -60,3 +60,23 @@ ip6 test-ip6 input
[ 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/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 e9a20316..cfc29013 100644
--- a/tests/py/ip6/redirect.t.payload.ip6
+++ b/tests/py/ip6/redirect.t.payload.ip6
@@ -191,12 +191,12 @@ 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 ]
diff --git a/tests/py/ip6/sets.t b/tests/py/ip6/sets.t
index 3b99d661..17fd62f5 100644
--- a/tests/py/ip6/sets.t
+++ b/tests/py/ip6/sets.t
@@ -41,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/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/nft-test.py b/tests/py/nft-test.py
index b66a33c2..a7d27c25 100755
--- a/tests/py/nft-test.py
+++ b/tests/py/nft-test.py
@@ -86,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
@@ -366,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 \
@@ -384,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.
@@ -490,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.
@@ -1091,14 +1144,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
@@ -1108,9 +1175,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()
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/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 f77d850e..86c83126 100755
--- a/tests/shell/run-tests.sh
+++ b/tests/shell/run-tests.sh
@@ -1,57 +1,617 @@
#!/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=
-if [ "${1}" != "run" ]; then
- if unshare -f -n true; then
- unshare -n "${0}" run $@
- exit $?
+if [ -z "$NFT_TEST_RANDOM_SEED" ] ; then
+ # Choose a random value.
+ n="$SRANDOM"
+ [ -z "$n" ] && n="$RANDOM"
+else
+ # 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
- msg_warn "cannot run in own namespace, connectivity might break"
fi
-shift
+# 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
-[ -z "$NFT" ] && NFT=$SRC_NFT
-${NFT} > /dev/null 2>&1
-ret=$?
-if [ ${ret} -eq 126 ] || [ ${ret} -eq 127 ]; then
- msg_error "cannot execute nft command: ${NFT}"
+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_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
+
+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
+
+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
- msg_info "using nft command: ${NFT}"
+ NFT_TEST_HAS_REALROOT="$(bool_y "$NFT_TEST_HAS_REALROOT")"
fi
+export NFT_TEST_HAS_REALROOT
-if [ ! -d "$TESTDIR" ] ; then
- msg_error "missing testdir $TESTDIR"
+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
-FIND="$(which find)"
-if [ ! -x "$FIND" ] ; then
- msg_error "no find binary found"
+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
-MODPROBE="$(which modprobe)"
-if [ ! -x "$MODPROBE" ] ; then
- msg_error "no modprobe binary found"
+# 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
+
+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)"
@@ -59,23 +619,102 @@ if [ ! -x "$DIFF" ] ; then
DIFF=true
fi
-if [ "$1" == "-v" ] ; then
- VERBOSE=y
- shift
-fi
+JOBS_PIDLIST_ARR=()
+declare -A JOBS_PIDLIST
-if [ "$1" == "-g" ] ; then
- DUMPGEN=y
- shift
-fi
+_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")
-for arg in "$@"; do
- SINGLE+=" $arg"
- VERBOSE=y
+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 \
@@ -87,6 +726,7 @@ kernel_cleanup() {
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_synproxy nft_connlimit \
nft_chain_nat \
nft_chain_route_ipv4 nft_chain_route_ipv6 \
nft_dup_netdev nft_fwd_netdev \
@@ -97,67 +737,262 @@ kernel_cleanup() {
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[@]}"
+
+ 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"
- msg_info "[EXECUTING] $testfile"
- test_output=$(NFT="$NFT" DIFF=$DIFF ${testfile} 2>&1)
- rc_got=$?
- echo -en "\033[1A\033[K" # clean the [EXECUTING] foobar line
+ 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 ] ; 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 ] ; 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
-[ "$failed" -eq 0 ]
+
+# ( \
+# 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/chains/0040mark_shift_0 b/tests/shell/testcases/bitwise/0040mark_binop_0
index ef3dccfa..4ecc9d3d 100755
--- a/tests/shell/testcases/chains/0040mark_shift_0
+++ b/tests/shell/testcases/bitwise/0040mark_binop_0
@@ -1,10 +1,12 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
set -e
RULESET="
add table t
- add chain t c { type filter hook output priority mangle; }
+ add chain t c { type filter hook output priority filter; }
add rule t c oif lo ct mark set (meta mark | 0x10) << 8
"
diff --git a/tests/shell/testcases/chains/0040mark_shift_1 b/tests/shell/testcases/bitwise/0040mark_binop_1
index b609f5ef..bd9e028d 100755
--- a/tests/shell/testcases/chains/0040mark_shift_1
+++ b/tests/shell/testcases/bitwise/0040mark_binop_1
@@ -1,10 +1,12 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_bitshift)
+
set -e
RULESET="
add table t
- add chain t c { type filter hook input priority mangle; }
+ 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
"
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/chains/dumps/0040mark_shift_0.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_0.nft
index 52d59d2c..fc0a600a 100644
--- a/tests/shell/testcases/chains/dumps/0040mark_shift_0.nft
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_0.nft
@@ -1,6 +1,6 @@
table ip t {
chain c {
- type filter hook output priority mangle; policy accept;
+ 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/chains/dumps/0040mark_shift_1.nft b/tests/shell/testcases/bitwise/dumps/0040mark_binop_1.nft
index 56ec8dc7..dbaacefb 100644
--- a/tests/shell/testcases/chains/dumps/0040mark_shift_1.nft
+++ b/tests/shell/testcases/bitwise/dumps/0040mark_binop_1.nft
@@ -1,6 +1,6 @@
table ip t {
chain c {
- type filter hook input priority mangle; policy accept;
+ 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/0008_delete_by_handle_0 b/tests/shell/testcases/cache/0008_delete_by_handle_0
index 529d6b85..0db4c693 100755
--- a/tests/shell/testcases/cache/0008_delete_by_handle_0
+++ b/tests/shell/testcases/cache/0008_delete_by_handle_0
@@ -16,7 +16,7 @@ $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\; }
+$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
diff --git a/tests/shell/testcases/cache/0010_implicit_chain_0 b/tests/shell/testcases/cache/0010_implicit_chain_0
index 0ab0db95..834dc6e4 100755
--- a/tests/shell/testcases/cache/0010_implicit_chain_0
+++ b/tests/shell/testcases/cache/0010_implicit_chain_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_chain_binding)
+
set -e
EXPECTED="table ip f {
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/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/0021prio_0 b/tests/shell/testcases/chains/0021prio_0
index d450dc0b..ceda1558 100755
--- a/tests/shell/testcases/chains/0021prio_0
+++ b/tests/shell/testcases/chains/0021prio_0
@@ -69,7 +69,7 @@ done
family=netdev
echo "add table $family x"
gen_chains $family ingress filter lo
-gen_chains $family egress filter lo
+[ "$NFT_TEST_HAVE_netdev_egress" != n ] && gen_chains $family egress filter lo
family=bridge
echo "add table $family x"
@@ -83,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/0041chain_binding_0 b/tests/shell/testcases/chains/0041chain_binding_0
index 4b541bb5..141a4b6d 100755
--- a/tests/shell/testcases/chains/0041chain_binding_0
+++ b/tests/shell/testcases/chains/0041chain_binding_0
@@ -6,6 +6,11 @@ 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 {
diff --git a/tests/shell/testcases/chains/0042chain_variable_0 b/tests/shell/testcases/chains/0042chain_variable_0
index 58535f76..c5de495e 100755
--- a/tests/shell/testcases/chains/0042chain_variable_0
+++ b/tests/shell/testcases/chains/0042chain_variable_0
@@ -1,8 +1,11 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_netdev_chain_multidevice)
+
set -e
-ip link add name dummy0 type dummy
+ip link add name d23456789012345 type dummy
+
EXPECTED="define if_main = \"lo\"
@@ -14,24 +17,55 @@ table netdev filter1 {
$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, dummy0 } priority -500; policy accept;
+ type filter hook ingress devices = { \$if_main, d23456789012345 } priority -500; policy accept;
}
}"
$NFT -f - <<< $EXPECTED
-EXPECTED="define if_main = { lo, dummy0 }
+
+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
index bff46468..a6973b99 100755
--- a/tests/shell/testcases/chains/0043chain_ingress_0
+++ b/tests/shell/testcases/chains/0043chain_ingress_0
@@ -1,7 +1,8 @@
#!/bin/bash
-set -e
+# 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;
@@ -14,11 +15,5 @@ RULESET="table inet filter {
}
}"
-# Test auto-removal of chain hook on netns removal
-unshare -n bash -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\; } ; \
-" || exit 1
-
$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/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/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/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/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/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
index 12931aad..84a908d3 100644
--- a/tests/shell/testcases/chains/dumps/0042chain_variable_0.nft
+++ b/tests/shell/testcases/chains/dumps/0042chain_variable_0.nft
@@ -5,11 +5,15 @@ table netdev filter1 {
}
table netdev filter2 {
chain Main_Ingress2 {
- type filter hook ingress devices = { dummy0, lo } priority -500; policy accept;
+ type filter hook ingress devices = { d23456789012345, lo } priority -500; policy accept;
}
}
table netdev filter3 {
chain Main_Ingress3 {
- type filter hook ingress devices = { dummy0, lo } priority -500; policy accept;
+ 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.nft b/tests/shell/testcases/chains/dumps/0043chain_ingress_0.nft
index 74670423..8483b265 100644
--- a/tests/shell/testcases/chains/dumps/0043chain_ingress.nft
+++ b/tests/shell/testcases/chains/dumps/0043chain_ingress_0.nft
@@ -1,10 +1,12 @@
table inet filter {
chain ingress {
- type filter hook ingress device \"lo\" priority filter; policy accept;
+ 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..77f828d5
--- /dev/null
+++ b/tests/shell/testcases/chains/netdev_chain_dev_gone
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+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..e6b65996
--- /dev/null
+++ b/tests/shell/testcases/chains/netdev_netns_gone
@@ -0,0 +1,35 @@
+#!/bin/bash
+
+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/0012flowtable_variable_0 b/tests/shell/testcases/flowtable/0012flowtable_variable_0
index 8e334224..9c03820f 100755
--- a/tests/shell/testcases/flowtable/0012flowtable_variable_0
+++ b/tests/shell/testcases/flowtable/0012flowtable_variable_0
@@ -1,7 +1,15 @@
#!/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 }
diff --git a/tests/shell/testcases/flowtable/0013addafterdelete_0 b/tests/shell/testcases/flowtable/0013addafterdelete_0
index b23ab978..56c9834f 100755
--- a/tests/shell/testcases/flowtable/0013addafterdelete_0
+++ b/tests/shell/testcases/flowtable/0013addafterdelete_0
@@ -7,7 +7,6 @@ RULESET='table inet filter {
flowtable f {
hook ingress priority filter - 1
devices = { lo }
- counter
}
}'
@@ -20,7 +19,6 @@ table inet filter {
flowtable f {
hook ingress priority filter - 1
devices = { lo }
- counter
}
}'
diff --git a/tests/shell/testcases/flowtable/0014addafterdelete_0 b/tests/shell/testcases/flowtable/0014addafterdelete_0
index 6a24c4b9..1ac65104 100755
--- a/tests/shell/testcases/flowtable/0014addafterdelete_0
+++ b/tests/shell/testcases/flowtable/0014addafterdelete_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_flowtable_counter)
+
set -e
RULESET='table inet filter {
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
index 1cbb2f11..df1c51a2 100644
--- a/tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.nft
+++ b/tests/shell/testcases/flowtable/dumps/0012flowtable_variable_0.nft
@@ -1,14 +1,14 @@
table ip filter1 {
flowtable Main_ft1 {
hook ingress priority filter
- devices = { dummy1, lo }
+ devices = { lo }
counter
}
}
table ip filter2 {
flowtable Main_ft2 {
hook ingress priority filter
- devices = { dummy1, lo }
+ 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/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/0013objects_0 b/tests/shell/testcases/listing/0013objects_0
index 4d39143d..c78ada94 100755
--- a/tests/shell/testcases/listing/0013objects_0
+++ b/tests/shell/testcases/listing/0013objects_0
@@ -1,47 +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 -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/0020flowtable_0 b/tests/shell/testcases/listing/0020flowtable_0
index 47488d8e..0e89f5dd 100755
--- a/tests/shell/testcases/listing/0020flowtable_0
+++ b/tests/shell/testcases/listing/0020flowtable_0
@@ -1,7 +1,11 @@
#!/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 }
@@ -41,13 +45,13 @@ EXPECTED3="table ip filter {
}
}"
-ip link add d0 type dummy || {
- echo "Skipping, no dummy interface available"
- exit 0
+iface_cleanup() {
+ ip link del d0 &>/dev/null || :
}
-trap "ip link del d0" EXIT
+trap 'iface_cleanup' EXIT
+iface_cleanup
-set -e
+ip link add d0 type dummy
$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/listing/0021ruleset_json_terse_0 b/tests/shell/testcases/listing/0021ruleset_json_terse_0
index c739ac3f..98a7ce8a 100755
--- a/tests/shell/testcases/listing/0021ruleset_json_terse_0
+++ b/tests/shell/testcases/listing/0021ruleset_json_terse_0
@@ -6,7 +6,14 @@ $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 -j -t list ruleset | grep '192'
-then
- exit 1
+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/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.nft b/tests/shell/testcases/listing/dumps/meta_time.nft
new file mode 100644
index 00000000..9121aef5
--- /dev/null
+++ b/tests/shell/testcases/listing/dumps/meta_time.nft
@@ -0,0 +1,32 @@
+table ip t {
+ chain c {
+ meta hour "01:00"-"01:59"
+ meta hour "02:00"-"02:59"
+ meta hour "03:00"-"03:59"
+ meta hour "04:00"-"04:59"
+ meta hour "05:00"-"05:59"
+ meta hour "06:00"-"06:59"
+ meta hour "07:00"-"07:59"
+ meta hour "08:00"-"08:59"
+ meta hour "09:00"-"09:59"
+ meta hour "10:00"-"10:59"
+ meta hour "11:00"-"11:59"
+ meta hour "12:00"-"12:59"
+ meta hour "13:00"-"13:59"
+ meta hour "14:00"-"14:59"
+ meta hour "15:00"-"15:59"
+ meta hour "16:00"-"16:59"
+ meta hour "17:00"-"17:59"
+ meta hour "18:00"-"18:59"
+ meta hour "19:00"-"19:59"
+ meta hour "20:00"-"20:59"
+ meta hour "21:00"-"21:59"
+ meta hour "22:00"-"22:59"
+ meta hour "23:00"-"23:59"
+ meta hour "00:00"-"00:59"
+ meta hour "04:00"-"15:00"
+ meta hour "05:00"-"16:00"
+ meta hour "06:00"-"17:00"
+ meta hour "07:00"-"18:00"
+ }
+}
diff --git a/tests/shell/testcases/listing/meta_time b/tests/shell/testcases/listing/meta_time
new file mode 100755
index 00000000..39fa4387
--- /dev/null
+++ b/tests/shell/testcases/listing/meta_time
@@ -0,0 +1,59 @@
+#!/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
+
+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"
diff --git a/tests/shell/testcases/maps/0004interval_map_create_once_0 b/tests/shell/testcases/maps/0004interval_map_create_once_0
index 3de0c9de..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
@@ -64,3 +68,7 @@ if [ "$EXPECTED" != "$GET" ] ; then
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/0009vmap_0 b/tests/shell/testcases/maps/0009vmap_0
index 7627c81d..4e133b72 100755
--- a/tests/shell/testcases/maps/0009vmap_0
+++ b/tests/shell/testcases/maps/0009vmap_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
set -e
EXPECTED="table inet filter {
@@ -12,7 +14,7 @@ EXPECTED="table inet filter {
chain prerouting {
type filter hook prerouting priority -300; policy accept;
- iif vmap { "lo" : jump wan_input }
+ iif vmap { "lo" counter : jump wan_input }
}
}"
diff --git a/tests/shell/testcases/maps/0010concat_map_0 b/tests/shell/testcases/maps/0010concat_map_0
index 4848d972..859bbfcf 100755
--- a/tests/shell/testcases/maps/0010concat_map_0
+++ b/tests/shell/testcases/maps/0010concat_map_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_inet_nat)
+
set -e
EXPECTED="table inet x {
diff --git a/tests/shell/testcases/maps/0011vmap_0 b/tests/shell/testcases/maps/0011vmap_0
index 83704d48..3e6fa78d 100755
--- a/tests/shell/testcases/maps/0011vmap_0
+++ b/tests/shell/testcases/maps/0011vmap_0
@@ -22,4 +22,12 @@ EXPECTED="table inet filter {
}"
$NFT -f - <<< "$EXPECTED"
-$NFT 'add element inet filter portmap { 22 : jump ssh_input, * : drop }'
+
+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_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
index 70d7fd3b..c8d20cee 100755
--- a/tests/shell/testcases/maps/0013map_0
+++ b/tests/shell/testcases/maps/0013map_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
set -e
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 6d21e388..21200c3c 100755
--- a/tests/shell/testcases/sets/0024named_objects_0
+++ b/tests/shell/testcases/maps/0024named_objects_0
@@ -18,15 +18,6 @@ table inet x {
quota user124 {
over 2000 bytes
}
- synproxy https-synproxy {
- mss 1460
- wscale 7
- timestamp sack-perm
- }
- synproxy other-synproxy {
- mss 1460
- wscale 5
- }
set y {
type ipv4_addr
}
@@ -34,15 +25,9 @@ table inet x {
type ipv4_addr : quota
elements = { 192.168.2.2 : "user124", 192.168.2.3 : "user124"}
}
- 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;
counter name ip saddr map { 192.168.2.2 : "user123", 1.1.1.1 : "user123", 2.2.2.2 : "user123"}
- synproxy name ip saddr map { 192.168.1.0/24 : "https-synproxy", 192.168.2.0/24 : "other-synproxy" }
quota name ip saddr map @test drop
}
}"
diff --git a/tests/shell/testcases/maps/anon_objmap_concat b/tests/shell/testcases/maps/anon_objmap_concat
index 07820b7c..34465f1d 100755
--- a/tests/shell/testcases/maps/anon_objmap_concat
+++ b/tests/shell/testcases/maps/anon_objmap_concat
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
set -e
dumpfile=$(dirname $0)/dumps/$(basename $0).nft
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
index c556fece..c37574ad 100644
--- a/tests/shell/testcases/maps/dumps/0009vmap_0.nft
+++ b/tests/shell/testcases/maps/dumps/0009vmap_0.nft
@@ -8,6 +8,6 @@ table inet filter {
chain prerouting {
type filter hook prerouting priority raw; policy accept;
- iif vmap { "lo" : jump wan_input }
+ 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/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/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_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/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 52d1bf64..2ffa4f2f 100644
--- a/tests/shell/testcases/sets/dumps/0024named_objects_0.nft
+++ b/tests/shell/testcases/maps/dumps/0024named_objects_0.nft
@@ -15,17 +15,6 @@ table inet x {
over 2000 bytes
}
- synproxy https-synproxy {
- mss 1460
- wscale 7
- timestamp sack-perm
- }
-
- synproxy other-synproxy {
- mss 1460
- wscale 5
- }
-
set y {
type ipv4_addr
}
@@ -35,16 +24,9 @@ table inet x {
elements = { 192.168.2.2 : "user124", 192.168.2.3 : "user124" }
}
- 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;
counter name ip saddr map { 1.1.1.1 : "user123", 2.2.2.2 : "user123", 192.168.2.2 : "user123" }
- synproxy name ip saddr map { 192.168.1.0/24 : "https-synproxy", 192.168.2.0/24 : "other-synproxy" }
quota name ip saddr map @test drop
}
}
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/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/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
index 33041557..19c24feb 100644
--- a/tests/shell/testcases/maps/dumps/typeof_integer_0.nft
+++ b/tests/shell/testcases/maps/dumps/typeof_integer_0.nft
@@ -13,8 +13,8 @@ table inet t {
}
chain c {
- udp length . @ih,32,32 vmap @m1
- udp length . @ih,32,32 vmap @m2
+ 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_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_raw_0.nft b/tests/shell/testcases/maps/dumps/typeof_raw_0.nft
index e876425b..476169f2 100644
--- a/tests/shell/testcases/maps/dumps/typeof_raw_0.nft
+++ b/tests/shell/testcases/maps/dumps/typeof_raw_0.nft
@@ -7,7 +7,7 @@ table ip x {
}
chain y {
- ip saddr . @ih,32,32 vmap @y
- ip saddr . @ih,32,32 vmap { 4.4.4.4 . 0x34 : accept, 5.5.5.5 . 0x45 : drop }
+ 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..5604f6ca
--- /dev/null
+++ b/tests/shell/testcases/maps/named_limits
@@ -0,0 +1,59 @@
+#!/bin/bash
+
+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/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
index d51510af..e93604e8 100755
--- a/tests/shell/testcases/maps/typeof_integer_0
+++ b/tests/shell/testcases/maps/typeof_integer_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
EXPECTED="table inet t {
map m1 {
typeof udp length . @ih,32,32 : verdict
@@ -13,8 +15,8 @@ EXPECTED="table inet t {
}
chain c {
- udp length . @ih,32,32 vmap @m1
- udp length . @ih,32,32 vmap @m2
+ 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/typeof_maps_0 b/tests/shell/testcases/maps/typeof_maps_0
index 5cf5ddde..98517fd5 100755
--- a/tests/shell/testcases/maps/typeof_maps_0
+++ b/tests/shell/testcases/maps/typeof_maps_0
@@ -4,10 +4,23 @@
# without typeof, this is 'type string' and 'type integer',
# but neither could be used because it lacks size information.
-EXPECTED="table inet t {
+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 }
+ elements = { Linux : 0x00000001 }
}
map m2 {
@@ -32,8 +45,7 @@ EXPECTED="table inet t {
elements = { 23 . eth0 : accept }
}
- chain c {
- ct mark set osf name map @m1
+ 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
@@ -42,6 +54,48 @@ EXPECTED="table inet t {
}
}"
-set -e
-$NFT -f - <<< $EXPECTED
+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_raw_0 b/tests/shell/testcases/maps/typeof_raw_0
index e3da7825..bcd2c6d8 100755
--- a/tests/shell/testcases/maps/typeof_raw_0
+++ b/tests/shell/testcases/maps/typeof_raw_0
@@ -7,8 +7,8 @@ EXPECTED="table ip x {
}
chain y {
- ip saddr . @ih,32,32 vmap @y
- ip saddr . @ih,32,32 vmap { 4.4.4.4 . 0x34 : accept, 5.5.5.5 . 0x45 : drop}
+ 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/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..4038d1c1
--- /dev/null
+++ b/tests/shell/testcases/maps/vmap_unary
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+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/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/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/0025empty_dynset_0 b/tests/shell/testcases/nft-f/0025empty_dynset_0
index b66c802f..fbdb5793 100755
--- a/tests/shell/testcases/nft-f/0025empty_dynset_0
+++ b/tests/shell/testcases/nft-f/0025empty_dynset_0
@@ -1,5 +1,7 @@
#!/bin/bash
+set -e
+
RULESET="table ip foo {
set inflows {
type ipv4_addr . inet_service . ifname . ipv4_addr . inet_service
@@ -20,3 +22,9 @@ RULESET="table ip foo {
}"
$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/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..8f3f3a81
--- /dev/null
+++ b/tests/shell/testcases/nft-f/dumps/0012different_defines_0.json-nft
@@ -0,0 +1,782 @@
+{
+ "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/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/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/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/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
index 2bb35592..33b9e4ff 100644
--- a/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.nft
+++ b/tests/shell/testcases/nft-f/dumps/0025empty_dynset_0.nft
@@ -13,6 +13,6 @@ table ip foo {
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 }
+ 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/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/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/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/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/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/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
index 7a6ecb76..f6c119ec 100644
--- a/tests/shell/testcases/optimizations/dumps/merge_nat.nft
+++ b/tests/shell/testcases/optimizations/dumps/merge_nat.nft
@@ -1,20 +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 }
- }
-}
-table ip test3 {
- chain y {
- 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 }
+ 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_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
index 6dbfff2e..f56cea1c 100644
--- a/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat.nft
@@ -1,5 +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, "eth2" . 1.1.1.3 . 2.2.2.5 } accept
+ 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
index c0f9ce0c..780aa09a 100644
--- a/tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.nft
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_concat_vmap.nft
@@ -1,4 +1,8 @@
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
index 5a9b3006..8ecbd927 100644
--- a/tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.nft
+++ b/tests/shell/testcases/optimizations/dumps/merge_stmts_vmap.nft
@@ -6,4 +6,8 @@ table ip x {
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_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
index 05b9e575..c981acf0 100644
--- a/tests/shell/testcases/optimizations/dumps/merge_vmaps.nft
+++ b/tests/shell/testcases/optimizations/dumps/merge_vmaps.nft
@@ -1,4 +1,10 @@
table ip x {
+ set s {
+ type ipv4_addr
+ size 65535
+ flags dynamic
+ }
+
chain filter_in_tcp {
}
@@ -6,6 +12,7 @@ table ip x {
}
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.input b/tests/shell/testcases/optimizations/dumps/single_anon_set.nft.input
deleted file mode 100644
index 35b93832..00000000
--- a/tests/shell/testcases/optimizations/dumps/single_anon_set.nft.input
+++ /dev/null
@@ -1,35 +0,0 @@
-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
- }
-}
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
index 290cfcfe..3ffcbd57 100755
--- a/tests/shell/testcases/optimizations/merge_nat
+++ b/tests/shell/testcases/optimizations/merge_nat
@@ -4,6 +4,7 @@ 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
}
@@ -13,17 +14,11 @@ $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
- }
-}"
-
-$NFT -o -f - <<< $RULESET
-
-RULESET="table ip test3 {
- chain y {
- 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
+ ip saddr 10.141.11.0/24 masquerade
+ ip saddr 10.141.13.0/24 masquerade
}
}"
@@ -31,8 +26,12 @@ $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
}
}"
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
index 0c35636e..ec7a9dd6 100755
--- a/tests/shell/testcases/optimizations/merge_stmts
+++ b/tests/shell/testcases/optimizations/merge_stmts
@@ -4,9 +4,9 @@ set -e
RULESET="table ip x {
chain y {
- ip daddr 192.168.0.1 counter accept
- ip daddr 192.168.0.2 counter accept
- ip daddr 192.168.0.3 counter accept
+ 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"
}
}"
diff --git a/tests/shell/testcases/optimizations/merge_stmts_concat b/tests/shell/testcases/optimizations/merge_stmts_concat
index 941e9a5a..4db4a6f9 100755
--- a/tests/shell/testcases/optimizations/merge_stmts_concat
+++ b/tests/shell/testcases/optimizations/merge_stmts_concat
@@ -1,12 +1,36 @@
#!/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
}
}"
diff --git a/tests/shell/testcases/optimizations/merge_stmts_concat_vmap b/tests/shell/testcases/optimizations/merge_stmts_concat_vmap
index 5c0ae60c..657d0aea 100755
--- a/tests/shell/testcases/optimizations/merge_stmts_concat_vmap
+++ b/tests/shell/testcases/optimizations/merge_stmts_concat_vmap
@@ -3,6 +3,10 @@
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
diff --git a/tests/shell/testcases/optimizations/merge_stmts_vmap b/tests/shell/testcases/optimizations/merge_stmts_vmap
index 79350076..e5357c0f 100755
--- a/tests/shell/testcases/optimizations/merge_stmts_vmap
+++ b/tests/shell/testcases/optimizations/merge_stmts_vmap
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
set -e
RULESET="table ip x {
@@ -12,6 +14,10 @@ RULESET="table ip x {
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
index f3dc0721..eb04bec3 100755
--- a/tests/shell/testcases/optimizations/merge_vmap_raw
+++ b/tests/shell/testcases/optimizations/merge_vmap_raw
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
set -e
RULESET="table inet x {
diff --git a/tests/shell/testcases/optimizations/merge_vmaps b/tests/shell/testcases/optimizations/merge_vmaps
index 0922a221..e2e4be15 100755
--- a/tests/shell/testcases/optimizations/merge_vmaps
+++ b/tests/shell/testcases/optimizations/merge_vmaps
@@ -3,11 +3,16 @@
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,
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
index 7275e360..632e965f 100755
--- a/tests/shell/testcases/optimizations/single_anon_set
+++ b/tests/shell/testcases/optimizations/single_anon_set
@@ -2,12 +2,52 @@
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.
-dumpfile=$(dirname $0)/dumps/$(basename $0).nft
+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 "$dumpfile".input
+$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_chain_0 b/tests/shell/testcases/optionals/comments_chain_0
index fba961c7..1a84cfa6 100755
--- a/tests/shell/testcases/optionals/comments_chain_0
+++ b/tests/shell/testcases/optionals/comments_chain_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_comment)
+
EXPECTED='table ip test_table {
chain test_chain {
comment "test"
diff --git a/tests/shell/testcases/optionals/comments_objects_0 b/tests/shell/testcases/optionals/comments_objects_0
index 7437c77b..28041ebd 100755
--- a/tests/shell/testcases/optionals/comments_objects_0
+++ b/tests/shell/testcases/optionals/comments_objects_0
@@ -1,9 +1,25 @@
#!/bin/bash
-EXPECTED='table ip filter {
+# 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 "test1"
+ comment "'"$COMMENT128"'"
}
counter c {
@@ -39,6 +55,4 @@ EXPECTED='table ip filter {
}
'
-set -e
-
-$NFT -f - <<< "$EXPECTED"
+$NFT -f - <<< "$RULESET"
diff --git a/tests/shell/testcases/optionals/comments_table_0 b/tests/shell/testcases/optionals/comments_table_0
index a0dfd749..56bb206b 100755
--- a/tests/shell/testcases/optionals/comments_table_0
+++ b/tests/shell/testcases/optionals/comments_table_0
@@ -1,5 +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/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_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
index b760ced6..13822209 100644
--- a/tests/shell/testcases/optionals/dumps/comments_objects_0.nft
+++ b/tests/shell/testcases/optionals/dumps/comments_objects_0.nft
@@ -1,6 +1,11 @@
table ip filter {
+ quota foo1 {
+ comment "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678"
+ 0 bytes
+ }
+
quota q {
- comment "test1"
+ comment "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678"
over 1200 bytes
}
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/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/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/update_object_handles_0 b/tests/shell/testcases/optionals/update_object_handles_0
index 8b12b8c5..ccd96779 100755
--- a/tests/shell/testcases/optionals/update_object_handles_0
+++ b/tests/shell/testcases/optionals/update_object_handles_0
@@ -1,5 +1,7 @@
#!/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
diff --git a/tests/shell/testcases/owner/0001-flowtable-uaf b/tests/shell/testcases/owner/0001-flowtable-uaf
index 4efbe75c..c07e8d6a 100755
--- a/tests/shell/testcases/owner/0001-flowtable-uaf
+++ b/tests/shell/testcases/owner/0001-flowtable-uaf
@@ -1,11 +1,14 @@
#!/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 }
}
}
@@ -16,6 +19,7 @@ $NFT -f - <<EOF
table t {
flags owner
flowtable f {
+ hook ingress priority 0
devices = { lo }
}
}
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..18a57a9b
--- /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:pipefile,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..9f4587d2
--- /dev/null
+++ b/tests/shell/testcases/packetpath/payload
@@ -0,0 +1,180 @@
+#!/bin/bash
+
+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..84a0000a
--- /dev/null
+++ b/tests/shell/testcases/packetpath/set_lookups
@@ -0,0 +1,64 @@
+#!/bin/bash
+
+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..88552226
--- /dev/null
+++ b/tests/shell/testcases/packetpath/tcp_options
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+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/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/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/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/0034get_element_0 b/tests/shell/testcases/sets/0034get_element_0
index 3343529b..32375b9f 100755
--- a/tests/shell/testcases/sets/0034get_element_0
+++ b/tests/shell/testcases/sets/0034get_element_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
RC=0
check() { # (set, elems, expected)
diff --git a/tests/shell/testcases/sets/0036add_set_element_expiration_0 b/tests/shell/testcases/sets/0036add_set_element_expiration_0
index 3097d077..d961ffd4 100755
--- a/tests/shell/testcases/sets/0036add_set_element_expiration_0
+++ b/tests/shell/testcases/sets/0036add_set_element_expiration_0
@@ -1,15 +1,25 @@
#!/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 | grep -v '# new generation')
+test_output=$($NFT -e -f - <<< "$RULESET" 2>&1 | grep -v '# new generation' | drop_seconds)
-if [ "$test_output" != "$RULESET" ] ; then
- $DIFF -u <(echo "$test_output") <(echo "$RULESET")
+if [ "$test_output" != "$EXPECTED" ] ; then
+ $DIFF -u <(echo "$test_output") <(echo "$EXPECTED")
exit 1
fi
diff --git a/tests/shell/testcases/sets/0038meter_list_0 b/tests/shell/testcases/sets/0038meter_list_0
index e9e0f6fb..7c37c1d8 100755
--- a/tests/shell/testcases/sets/0038meter_list_0
+++ b/tests/shell/testcases/sets/0038meter_list_0
@@ -14,7 +14,12 @@ RULESET="
"
expected_output="table ip t {
- meter m {
+ set s {
+ type ipv4_addr
+ size 256
+ flags dynamic,timeout
+ }
+ set m {
type ipv4_addr
size 128
flags dynamic
diff --git a/tests/shell/testcases/sets/0043concatenated_ranges_0 b/tests/shell/testcases/sets/0043concatenated_ranges_0
index 11767373..a3dbf5bf 100755
--- a/tests/shell/testcases/sets/0043concatenated_ranges_0
+++ b/tests/shell/testcases/sets/0043concatenated_ranges_0
@@ -1,4 +1,7 @@
-#!/bin/sh -e
+#!/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
#
@@ -14,12 +17,7 @@
# - delete them
# - make sure they can't be deleted again
-if [ "$(ps -o comm= $PPID)" = "run-tests.sh" ]; then
- # Skip some permutations on a full test suite run to keep it quick
- TYPES="ipv4_addr ipv6_addr ether_addr inet_service"
-else
- TYPES="ipv4_addr ipv6_addr ether_addr inet_proto inet_service mark"
-fi
+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"
@@ -147,7 +145,7 @@ for ta in ${TYPES}; do
eval add_b=\$ADD_${tb}
eval add_c=\$ADD_${tc}
${NFT} add element inet filter test \
- "{ ${add_a} . ${add_b} . ${add_c} timeout 1s${mapv}}"
+ "{ ${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 ]
@@ -180,6 +178,10 @@ for ta in ${TYPES}; do
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 ]
diff --git a/tests/shell/testcases/sets/0043concatenated_ranges_1 b/tests/shell/testcases/sets/0043concatenated_ranges_1
index bab189c5..bb3bf6b2 100755
--- a/tests/shell/testcases/sets/0043concatenated_ranges_1
+++ b/tests/shell/testcases/sets/0043concatenated_ranges_1
@@ -1,7 +1,9 @@
-#!/bin/sh -e
+#!/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 ]
diff --git a/tests/shell/testcases/sets/0044interval_overlap_0 b/tests/shell/testcases/sets/0044interval_overlap_0
index face90f2..b0f51cc8 100755
--- a/tests/shell/testcases/sets/0044interval_overlap_0
+++ b/tests/shell/testcases/sets/0044interval_overlap_0
@@ -1,4 +1,6 @@
-#!/bin/sh -e
+#!/bin/bash -e
+#
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
#
# 0044interval_overlap_0 - Add overlapping and non-overlapping intervals
#
@@ -115,7 +117,11 @@ add_elements() {
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
@@ -146,7 +152,9 @@ add_elements() {
$NFT add table t
$NFT add set t s '{ type inet_service ; flags interval ; }'
-$NFT add set t c '{ type inet_service . 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
@@ -155,7 +163,9 @@ 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; }"
-$NFT add set t c "{ type inet_service . 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))
diff --git a/tests/shell/testcases/sets/0044interval_overlap_1 b/tests/shell/testcases/sets/0044interval_overlap_1
index eeea1943..cdd0c844 100755
--- a/tests/shell/testcases/sets/0044interval_overlap_1
+++ b/tests/shell/testcases/sets/0044interval_overlap_1
@@ -1,4 +1,6 @@
-#!/bin/sh -e
+#!/bin/bash -e
+#
+# NFT_TEST_SKIP(NFT_TEST_SKIP_slow)
#
# 0044interval_overlap_1 - Single-sized intervals can never overlap partially
#
diff --git a/tests/shell/testcases/sets/0046netmap_0 b/tests/shell/testcases/sets/0046netmap_0
index 2804a4a2..7533623e 100755
--- a/tests/shell/testcases/sets/0046netmap_0
+++ b/tests/shell/testcases/sets/0046netmap_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_netmap)
+
EXPECTED="table ip x {
chain y {
type nat hook postrouting priority srcnat; policy accept;
@@ -8,6 +10,12 @@ EXPECTED="table ip x {
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
diff --git a/tests/shell/testcases/sets/0047nat_0 b/tests/shell/testcases/sets/0047nat_0
index cb1d4d68..757605ee 100755
--- a/tests/shell/testcases/sets/0047nat_0
+++ b/tests/shell/testcases/sets/0047nat_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
EXPECTED="table ip x {
map y {
type ipv4_addr : interval ipv4_addr
@@ -8,6 +10,12 @@ EXPECTED="table ip x {
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
@@ -18,3 +26,17 @@ EXPECTED="table ip x {
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
index e62d25df..95babdc9 100755
--- a/tests/shell/testcases/sets/0048set_counters_0
+++ b/tests/shell/testcases/sets/0048set_counters_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
set -e
EXPECTED="table ip x {
diff --git a/tests/shell/testcases/sets/0049set_define_0 b/tests/shell/testcases/sets/0049set_define_0
index 1d512f7b..756afdc1 100755
--- a/tests/shell/testcases/sets/0049set_define_0
+++ b/tests/shell/testcases/sets/0049set_define_0
@@ -14,3 +14,15 @@ table inet filter {
"
$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/0051set_interval_counter_0 b/tests/shell/testcases/sets/0051set_interval_counter_0
index ea90e264..6e67a43c 100755
--- a/tests/shell/testcases/sets/0051set_interval_counter_0
+++ b/tests/shell/testcases/sets/0051set_interval_counter_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
set -e
EXPECTED="table ip x {
diff --git a/tests/shell/testcases/sets/0059set_update_multistmt_0 b/tests/shell/testcases/sets/0059set_update_multistmt_0
index 107bfb87..2aeba2c5 100755
--- a/tests/shell/testcases/sets/0059set_update_multistmt_0
+++ b/tests/shell/testcases/sets/0059set_update_multistmt_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_with_two_expressions)
+
RULESET="table x {
set y {
type ipv4_addr
diff --git a/tests/shell/testcases/sets/0060set_multistmt_0 b/tests/shell/testcases/sets/0060set_multistmt_0
index 6bd147c3..8e17444e 100755
--- a/tests/shell/testcases/sets/0060set_multistmt_0
+++ b/tests/shell/testcases/sets/0060set_multistmt_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_with_two_expressions)
+
RULESET="table x {
set y {
type ipv4_addr
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/0062set_connlimit_0 b/tests/shell/testcases/sets/0062set_connlimit_0
index 48d589fe..48aa6fce 100755
--- a/tests/shell/testcases/sets/0062set_connlimit_0
+++ b/tests/shell/testcases/sets/0062set_connlimit_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_set_expr)
+
set -e
RULESET="table ip x {
@@ -24,3 +26,6 @@ RULESET="table ip x {
}"
$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
index faca56a1..edd015d0 100755
--- a/tests/shell/testcases/sets/0063set_catchall_0
+++ b/tests/shell/testcases/sets/0063set_catchall_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_catchall_element)
+
set -e
RULESET="table ip x {
diff --git a/tests/shell/testcases/sets/0064map_catchall_0 b/tests/shell/testcases/sets/0064map_catchall_0
index 43685160..fd289372 100755
--- a/tests/shell/testcases/sets/0064map_catchall_0
+++ b/tests/shell/testcases/sets/0064map_catchall_0
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_catchall_element)
+
set -e
RULESET="table ip x {
diff --git a/tests/shell/testcases/sets/0067nat_concat_interval_0 b/tests/shell/testcases/sets/0067nat_concat_interval_0
index 530771b0..81621957 100755
--- a/tests/shell/testcases/sets/0067nat_concat_interval_0
+++ b/tests/shell/testcases/sets/0067nat_concat_interval_0
@@ -1,21 +1,8 @@
#!/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_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
-$NFT -f - <<< $EXPECTED
-$NFT add element ip nat ipportmap { 192.168.2.0/24 : 10.141.11.5-10.141.11.20 . 8888-8999 }
+set -e
EXPECTED="table ip nat {
map ipportmap2 {
@@ -42,3 +29,30 @@ EXPECTED="table ip nat {
$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
index 2cbc9868..e61010c7 100755
--- a/tests/shell/testcases/sets/0068interval_stack_overflow_0
+++ b/tests/shell/testcases/sets/0068interval_stack_overflow_0
@@ -6,9 +6,18 @@ 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 < 255; i++)); do
+ for ((i = 1; i < $HOWMANY; i++)); do
for ((j = 1; j < 255; j++)); do
echo "10.0.$i.$j,"
done
@@ -27,3 +36,10 @@ table inet test68_table {
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/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/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/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/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/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
index e14c3395..5ac6b346 100644
--- a/tests/shell/testcases/sets/dumps/0046netmap_0.nft
+++ b/tests/shell/testcases/sets/dumps/0046netmap_0.nft
@@ -4,3 +4,9 @@ table ip x {
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
index e7968054..9fa9fc74 100644
--- a/tests/shell/testcases/sets/dumps/0047nat_0.nft
+++ b/tests/shell/testcases/sets/dumps/0047nat_0.nft
@@ -6,8 +6,25 @@ table ip x {
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/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
index 998b387a..d654420c 100644
--- a/tests/shell/testcases/sets/dumps/0049set_define_0.nft
+++ b/tests/shell/testcases/sets/dumps/0049set_define_0.nft
@@ -1,4 +1,11 @@
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/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/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/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/0055tcpflags_0.json-nft b/tests/shell/testcases/sets/dumps/0055tcpflags_0.json-nft
new file mode 100644
index 00000000..cd39f090
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0055tcpflags_0.json-nft
@@ -0,0 +1,190 @@
+{
+ "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",
+ "psh"
+ ]
+ },
+ "ack"
+ ]
+ },
+ "urg"
+ ]
+ },
+ {
+ "|": [
+ {
+ "|": [
+ "fin",
+ "psh"
+ ]
+ },
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ {
+ "|": [
+ "fin",
+ "ack"
+ ]
+ },
+ "urg"
+ ]
+ },
+ {
+ "|": [
+ "fin",
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ {
+ "|": [
+ {
+ "|": [
+ "syn",
+ "psh"
+ ]
+ },
+ "ack"
+ ]
+ },
+ "urg"
+ ]
+ },
+ {
+ "|": [
+ {
+ "|": [
+ "syn",
+ "psh"
+ ]
+ },
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ },
+ "urg"
+ ]
+ },
+ {
+ "|": [
+ "syn",
+ "ack"
+ ]
+ },
+ "syn",
+ {
+ "|": [
+ {
+ "|": [
+ {
+ "|": [
+ "rst",
+ "psh"
+ ]
+ },
+ "ack"
+ ]
+ },
+ "urg"
+ ]
+ },
+ {
+ "|": [
+ {
+ "|": [
+ "rst",
+ "psh"
+ ]
+ },
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ {
+ "|": [
+ "rst",
+ "ack"
+ ]
+ },
+ "urg"
+ ]
+ },
+ {
+ "|": [
+ "rst",
+ "ack"
+ ]
+ },
+ "rst",
+ {
+ "|": [
+ {
+ "|": [
+ "psh",
+ "ack"
+ ]
+ },
+ "urg"
+ ]
+ },
+ {
+ "|": [
+ "psh",
+ "ack"
+ ]
+ },
+ {
+ "|": [
+ "ack",
+ "urg"
+ ]
+ },
+ "ack"
+ ]
+ }
+ }
+ ]
+}
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/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
index 1b0ffae4..c1cc3b51 100644
--- a/tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.nft
+++ b/tests/shell/testcases/sets/dumps/0059set_update_multistmt_0.nft
@@ -8,6 +8,6 @@ table ip x {
chain z {
type filter hook output priority filter; policy accept;
- update @y { ip daddr limit rate 1/second counter }
+ 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
index f23db534..df68fcdf 100644
--- a/tests/shell/testcases/sets/dumps/0060set_multistmt_0.nft
+++ b/tests/shell/testcases/sets/dumps/0060set_multistmt_0.nft
@@ -1,9 +1,9 @@
table ip x {
set y {
type ipv4_addr
- limit rate 1/second counter
- elements = { 1.1.1.1 limit rate 1/second counter packets 0 bytes 0, 4.4.4.4 limit rate 1/second counter packets 0 bytes 0,
- 5.5.5.5 limit rate 1/second counter packets 0 bytes 0 }
+ 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 {
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/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/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/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
index 3226da15..9ac3774a 100644
--- a/tests/shell/testcases/sets/dumps/0067nat_concat_interval_0.nft
+++ b/tests/shell/testcases/sets/dumps/0067nat_concat_interval_0.nft
@@ -1,10 +1,4 @@
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 }
- }
-
map ipportmap2 {
type ipv4_addr . ipv4_addr : interval ipv4_addr . inet_service
flags interval
@@ -17,10 +11,25 @@ table ip nat {
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 map @ipportmap
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/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/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
index 6b073ae2..77a8baf5 100644
--- a/tests/shell/testcases/sets/dumps/sets_with_ifnames.nft
+++ b/tests/shell/testcases/sets/dumps/sets_with_ifnames.nft
@@ -29,11 +29,19 @@ table inet testifsets {
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 {
@@ -48,4 +56,7 @@ table inet testifsets {
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
index 499ff167..4d6abaaa 100644
--- a/tests/shell/testcases/sets/dumps/typeof_raw_0.nft
+++ b/tests/shell/testcases/sets/dumps/typeof_raw_0.nft
@@ -6,7 +6,7 @@ table inet t {
}
chain y {
- ip saddr . @ih,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }
- ip daddr . @ih,32,32 @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
index 68b4dcc5..63fc5b14 100644
--- a/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
+++ b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
@@ -50,6 +50,16 @@ table inet t {
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
}
@@ -85,4 +95,12 @@ table inet t {
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/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
index f4ef4db5..a4bc5072 100755
--- a/tests/shell/testcases/sets/sets_with_ifnames
+++ b/tests/shell/testcases/sets/sets_with_ifnames
@@ -1,5 +1,7 @@
#!/bin/bash
+# NFT_TEST_REQUIRES(NFT_TEST_HAVE_pipapo)
+
dumpfile=$(dirname $0)/dumps/$(basename $0).nft
[ -z "$NFT" ] && exit 111
@@ -13,6 +15,7 @@ ns2="nft2ifname-$rnd"
cleanup()
{
ip netns del "$ns1"
+ ip netns del "$ns2"
}
trap cleanup EXIT
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
index 36396b5c..66042eb4 100755
--- a/tests/shell/testcases/sets/typeof_raw_0
+++ b/tests/shell/testcases/sets/typeof_raw_0
@@ -7,8 +7,8 @@ EXPECTED="table inet t {
}
chain y {
- ip saddr . @ih,32,32 { 1.1.1.1 . 0x14, 2.2.2.2 . 0x1e }
- ip daddr . @ih,32,32 @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/typeof_sets_0 b/tests/shell/testcases/sets/typeof_sets_0
index 5fc6a121..016227da 100755
--- a/tests/shell/testcases/sets/typeof_sets_0
+++ b/tests/shell/testcases/sets/typeof_sets_0
@@ -4,12 +4,76 @@
# s1 and s2 are identical, they just use different
# ways for declaration.
-EXPECTED="table inet t {
+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 }
@@ -18,12 +82,7 @@ EXPECTED="table inet t {
set s3 {
typeof meta ibrpvid
elements = { 2, 3, 103 }
- }
-
- set s4 {
- typeof frag frag-off
- elements = { 1, 1024 }
- }
+ }$INPUT_FRAG_SET
set s5 {
typeof ip option ra value
@@ -38,12 +97,7 @@ EXPECTED="table inet t {
set s7 {
typeof sctp chunk init num-inbound-streams
elements = { 1, 4 }
- }
-
- set s8 {
- typeof ip version
- elements = { 4, 6 }
- }
+ }$INPUT_VERSION_SET
set s9 {
typeof ip hdrlength
@@ -55,18 +109,19 @@ EXPECTED="table inet t {
elements = { \"eth0\" . 10.1.1.2 . 42 }
}
- chain c1 {
- osf name @s1 accept
+ 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
}
-
- chain c4 {
- frag frag-off @s4 accept
- }
-
+$INPUT_FRAG_CHAIN
chain c5 {
ip option ra value @s5 accept
}
@@ -74,24 +129,115 @@ EXPECTED="table inet t {
chain c6 {
tcp option maxseg size @s6 accept
}
+$INPUT_SCTP_CHAIN
+$INPUT_VERSION_CHAIN
+ chain c9 {
+ ip hdrlength @s9 accept
+ }
- chain c7 {
- sctp chunk init num-inbound-streams @s7 accept
+ chain c10 {
+ meta iifname . ip saddr . ipsec in reqid @s10 accept
}
- chain c8 {
- ip version @s8 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 {
- meta iifname . ip saddr . ipsec in reqid @s10 accept
+ 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
}
}"
-set -e
-$NFT -f - <<< $EXPECTED
+$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..07820b7c
--- /dev/null
+++ b/tests/shell/testcases/sets/typeof_sets_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/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/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/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/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"